blob: ff0e68f0386bbda0ea1d2273a7f439639eaae04e [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>
37#include <linux/sched.h>
38#include <linux/poll.h>
39#include <linux/spinlock.h>
Corey Minyardd6dfd132006-03-31 02:30:41 -080040#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/slab.h>
42#include <linux/ipmi.h>
43#include <linux/ipmi_smi.h>
44#include <linux/notifier.h>
45#include <linux/init.h>
46#include <linux/proc_fs.h>
Corey Minyard393d2cc2005-11-07 00:59:54 -080047#include <linux/rcupdate.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#define PFX "IPMI message handler: "
Corey Minyard1fdd75b2005-09-06 15:18:42 -070050
Corey Minyardb9675132006-12-06 20:41:02 -080051#define IPMI_DRIVER_VERSION "39.1"
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
54static int ipmi_init_msghandler(void);
55
56static int initialized = 0;
57
Corey Minyard3b625942005-06-23 22:01:42 -070058#ifdef CONFIG_PROC_FS
Adrian Bunk456229a2006-06-27 02:55:07 -070059static struct proc_dir_entry *proc_ipmi_root = NULL;
Corey Minyard3b625942005-06-23 22:01:42 -070060#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Corey Minyardb9675132006-12-06 20:41:02 -080062/* Remain in auto-maintenance mode for this amount of time (in ms). */
63#define IPMI_MAINTENANCE_MODE_TIMEOUT 30000
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#define MAX_EVENTS_IN_QUEUE 25
66
67/* Don't let a message sit in a queue forever, always time it with at lest
68 the max message timer. This is in milliseconds. */
69#define MAX_MSG_TIMEOUT 60000
70
Corey Minyard393d2cc2005-11-07 00:59:54 -080071
72/*
73 * The main "user" data structure.
74 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070075struct ipmi_user
76{
77 struct list_head link;
78
Corey Minyard393d2cc2005-11-07 00:59:54 -080079 /* Set to "0" when the user is destroyed. */
80 int valid;
81
82 struct kref refcount;
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 /* The upper layer that handles receive messages. */
85 struct ipmi_user_hndl *handler;
86 void *handler_data;
87
88 /* The interface this user is bound to. */
89 ipmi_smi_t intf;
90
91 /* Does this interface receive IPMI events? */
92 int gets_events;
93};
94
95struct cmd_rcvr
96{
97 struct list_head link;
98
99 ipmi_user_t user;
100 unsigned char netfn;
101 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -0700102 unsigned int chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800103
104 /*
105 * This is used to form a linked lised during mass deletion.
106 * Since this is in an RCU list, we cannot use the link above
107 * or change any data until the RCU period completes. So we
108 * use this next variable during mass deletion so we can have
109 * a list and don't have to wait and restart the search on
110 * every individual deletion of a command. */
111 struct cmd_rcvr *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112};
113
114struct seq_table
115{
116 unsigned int inuse : 1;
117 unsigned int broadcast : 1;
118
119 unsigned long timeout;
120 unsigned long orig_timeout;
121 unsigned int retries_left;
122
123 /* To verify on an incoming send message response that this is
124 the message that the response is for, we keep a sequence id
125 and increment it every time we send a message. */
126 long seqid;
127
128 /* This is held so we can properly respond to the message on a
129 timeout, and it is used to hold the temporary data for
130 retransmission, too. */
131 struct ipmi_recv_msg *recv_msg;
132};
133
134/* Store the information in a msgid (long) to allow us to find a
135 sequence table entry from the msgid. */
136#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
137
138#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
139 do { \
140 seq = ((msgid >> 26) & 0x3f); \
141 seqid = (msgid & 0x3fffff); \
Corey Minyarde8b33612005-09-06 15:18:45 -0700142 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
145
146struct ipmi_channel
147{
148 unsigned char medium;
149 unsigned char protocol;
Corey Minyardc14979b2005-09-06 15:18:38 -0700150
151 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
152 but may be changed by the user. */
153 unsigned char address;
154
155 /* My LUN. This should generally stay the SMS LUN, but just in
156 case... */
157 unsigned char lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158};
159
Corey Minyard3b625942005-06-23 22:01:42 -0700160#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161struct ipmi_proc_entry
162{
163 char *name;
164 struct ipmi_proc_entry *next;
165};
Corey Minyard3b625942005-06-23 22:01:42 -0700166#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
Corey Minyard50c812b2006-03-26 01:37:21 -0800168struct bmc_device
169{
170 struct platform_device *dev;
171 struct ipmi_device_id id;
172 unsigned char guid[16];
173 int guid_set;
174
175 struct kref refcount;
176
177 /* bmc device attributes */
178 struct device_attribute device_id_attr;
179 struct device_attribute provides_dev_sdrs_attr;
180 struct device_attribute revision_attr;
181 struct device_attribute firmware_rev_attr;
182 struct device_attribute version_attr;
183 struct device_attribute add_dev_support_attr;
184 struct device_attribute manufacturer_id_attr;
185 struct device_attribute product_id_attr;
186 struct device_attribute guid_attr;
187 struct device_attribute aux_firmware_rev_attr;
188};
189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#define IPMI_IPMB_NUM_SEQ 64
Corey Minyardc14979b2005-09-06 15:18:38 -0700191#define IPMI_MAX_CHANNELS 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192struct ipmi_smi
193{
194 /* What interface number are we? */
195 int intf_num;
196
Corey Minyard393d2cc2005-11-07 00:59:54 -0800197 struct kref refcount;
198
Corey Minyardbca03242006-12-06 20:40:57 -0800199 /* Used for a list of interfaces. */
200 struct list_head link;
201
Corey Minyard393d2cc2005-11-07 00:59:54 -0800202 /* The list of upper layers that are using me. seq_lock
203 * protects this. */
204 struct list_head users;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Corey Minyardb2c03942006-12-06 20:41:00 -0800206 /* Information to supply to users. */
207 unsigned char ipmi_version_major;
208 unsigned char ipmi_version_minor;
209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 /* Used for wake ups at startup. */
211 wait_queue_head_t waitq;
212
Corey Minyard50c812b2006-03-26 01:37:21 -0800213 struct bmc_device *bmc;
214 char *my_dev_name;
Corey Minyard759643b2006-12-06 20:40:59 -0800215 char *sysfs_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Corey Minyardb2c03942006-12-06 20:41:00 -0800217 /* This is the lower-layer's sender routine. Note that you
218 * must either be holding the ipmi_interfaces_mutex or be in
219 * an umpreemptible region to use this. You must fetch the
220 * value into a local variable and make sure it is not NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 struct ipmi_smi_handlers *handlers;
222 void *send_info;
223
Corey Minyard3b625942005-06-23 22:01:42 -0700224#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 /* A list of proc entries for this interface. This does not
226 need a lock, only one thread creates it and only one thread
227 destroys it. */
Corey Minyard3b625942005-06-23 22:01:42 -0700228 spinlock_t proc_entry_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 struct ipmi_proc_entry *proc_entries;
Corey Minyard3b625942005-06-23 22:01:42 -0700230#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
Corey Minyard50c812b2006-03-26 01:37:21 -0800232 /* Driver-model device for the system interface. */
233 struct device *si_dev;
234
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 /* A table of sequence numbers for this interface. We use the
236 sequence numbers for IPMB messages that go out of the
237 interface to match them up with their responses. A routine
238 is called periodically to time the items in this list. */
239 spinlock_t seq_lock;
240 struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
241 int curr_seq;
242
243 /* Messages that were delayed for some reason (out of memory,
244 for instance), will go in here to be processed later in a
245 periodic timer interrupt. */
246 spinlock_t waiting_msgs_lock;
247 struct list_head waiting_msgs;
248
249 /* The list of command receivers that are registered for commands
250 on this interface. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800251 struct mutex cmd_rcvrs_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 struct list_head cmd_rcvrs;
253
254 /* Events that were queues because no one was there to receive
255 them. */
256 spinlock_t events_lock; /* For dealing with event stuff. */
257 struct list_head waiting_events;
258 unsigned int waiting_events_count; /* How many events in queue? */
Corey Minyardb2c03942006-12-06 20:41:00 -0800259 int delivering_events;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 /* The event receiver for my BMC, only really used at panic
262 shutdown as a place to store this. */
263 unsigned char event_receiver;
264 unsigned char event_receiver_lun;
265 unsigned char local_sel_device;
266 unsigned char local_event_generator;
267
Corey Minyardb9675132006-12-06 20:41:02 -0800268 /* For handling of maintenance mode. */
269 int maintenance_mode;
270 int maintenance_mode_enable;
271 int auto_maintenance_timeout;
272 spinlock_t maintenance_mode_lock; /* Used in a timer... */
273
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 /* A cheap hack, if this is non-null and a message to an
275 interface comes in with a NULL user, call this routine with
276 it. Note that the message will still be freed by the
277 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700278 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
280 /* When we are scanning the channels for an SMI, this will
281 tell which channel we are scanning. */
282 int curr_channel;
283
284 /* Channel information */
285 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
286
287 /* Proc FS stuff. */
288 struct proc_dir_entry *proc_dir;
289 char proc_dir_name[10];
290
291 spinlock_t counter_lock; /* For making counters atomic. */
292
293 /* Commands we got that were invalid. */
294 unsigned int sent_invalid_commands;
295
296 /* Commands we sent to the MC. */
297 unsigned int sent_local_commands;
298 /* Responses from the MC that were delivered to a user. */
299 unsigned int handled_local_responses;
300 /* Responses from the MC that were not delivered to a user. */
301 unsigned int unhandled_local_responses;
302
303 /* Commands we sent out to the IPMB bus. */
304 unsigned int sent_ipmb_commands;
305 /* Commands sent on the IPMB that had errors on the SEND CMD */
306 unsigned int sent_ipmb_command_errs;
307 /* Each retransmit increments this count. */
308 unsigned int retransmitted_ipmb_commands;
309 /* When a message times out (runs out of retransmits) this is
310 incremented. */
311 unsigned int timed_out_ipmb_commands;
312
313 /* This is like above, but for broadcasts. Broadcasts are
314 *not* included in the above count (they are expected to
315 time out). */
316 unsigned int timed_out_ipmb_broadcasts;
317
318 /* Responses I have sent to the IPMB bus. */
319 unsigned int sent_ipmb_responses;
320
321 /* The response was delivered to the user. */
322 unsigned int handled_ipmb_responses;
323 /* The response had invalid data in it. */
324 unsigned int invalid_ipmb_responses;
325 /* The response didn't have anyone waiting for it. */
326 unsigned int unhandled_ipmb_responses;
327
328 /* Commands we sent out to the IPMB bus. */
329 unsigned int sent_lan_commands;
330 /* Commands sent on the IPMB that had errors on the SEND CMD */
331 unsigned int sent_lan_command_errs;
332 /* Each retransmit increments this count. */
333 unsigned int retransmitted_lan_commands;
334 /* When a message times out (runs out of retransmits) this is
335 incremented. */
336 unsigned int timed_out_lan_commands;
337
338 /* Responses I have sent to the IPMB bus. */
339 unsigned int sent_lan_responses;
340
341 /* The response was delivered to the user. */
342 unsigned int handled_lan_responses;
343 /* The response had invalid data in it. */
344 unsigned int invalid_lan_responses;
345 /* The response didn't have anyone waiting for it. */
346 unsigned int unhandled_lan_responses;
347
348 /* The command was delivered to the user. */
349 unsigned int handled_commands;
350 /* The command had invalid data in it. */
351 unsigned int invalid_commands;
352 /* The command didn't have anyone waiting for it. */
353 unsigned int unhandled_commands;
354
355 /* Invalid data in an event. */
356 unsigned int invalid_events;
357 /* Events that were received with the proper format. */
358 unsigned int events;
359};
Corey Minyard50c812b2006-03-26 01:37:21 -0800360#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Corey Minyard50c812b2006-03-26 01:37:21 -0800362/**
363 * The driver model view of the IPMI messaging driver.
364 */
365static struct device_driver ipmidriver = {
366 .name = "ipmi",
367 .bus = &platform_bus_type
368};
369static DEFINE_MUTEX(ipmidriver_mutex);
370
Corey Minyardbca03242006-12-06 20:40:57 -0800371static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces);
372static DEFINE_MUTEX(ipmi_interfaces_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374/* List of watchers that want to know when smi's are added and
375 deleted. */
376static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
Corey Minyardb2c03942006-12-06 20:41:00 -0800377static DEFINE_MUTEX(smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Corey Minyard393d2cc2005-11-07 00:59:54 -0800380static void free_recv_msg_list(struct list_head *q)
381{
382 struct ipmi_recv_msg *msg, *msg2;
383
384 list_for_each_entry_safe(msg, msg2, q, link) {
385 list_del(&msg->link);
386 ipmi_free_recv_msg(msg);
387 }
388}
389
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800390static void free_smi_msg_list(struct list_head *q)
391{
392 struct ipmi_smi_msg *msg, *msg2;
393
394 list_for_each_entry_safe(msg, msg2, q, link) {
395 list_del(&msg->link);
396 ipmi_free_smi_msg(msg);
397 }
398}
399
Corey Minyard393d2cc2005-11-07 00:59:54 -0800400static void clean_up_interface_data(ipmi_smi_t intf)
401{
402 int i;
403 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800404 struct list_head list;
405
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800406 free_smi_msg_list(&intf->waiting_msgs);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800407 free_recv_msg_list(&intf->waiting_events);
408
409 /* Wholesale remove all the entries from the list in the
410 * interface and wait for RCU to know that none are in use. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800411 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800412 list_add_rcu(&list, &intf->cmd_rcvrs);
413 list_del_rcu(&intf->cmd_rcvrs);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800414 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800415 synchronize_rcu();
416
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 Minyardbca03242006-12-06 20:40:57 -0800454 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
455 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
1772static int ipmb_file_read_proc(char *page, char **start, off_t off,
1773 int count, int *eof, void *data)
1774{
1775 char *out = (char *) page;
1776 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001777 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001778 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
Corey Minyarde8b33612005-09-06 15:18:45 -07001780 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001781 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1782 out[rv-1] = '\n'; /* Replace the final space with a newline */
1783 out[rv] = '\0';
1784 rv++;
1785 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786}
1787
1788static int version_file_read_proc(char *page, char **start, off_t off,
1789 int count, int *eof, void *data)
1790{
1791 char *out = (char *) page;
1792 ipmi_smi_t intf = data;
1793
1794 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001795 ipmi_version_major(&intf->bmc->id),
1796 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797}
1798
1799static int stat_file_read_proc(char *page, char **start, off_t off,
1800 int count, int *eof, void *data)
1801{
1802 char *out = (char *) page;
1803 ipmi_smi_t intf = data;
1804
1805 out += sprintf(out, "sent_invalid_commands: %d\n",
1806 intf->sent_invalid_commands);
1807 out += sprintf(out, "sent_local_commands: %d\n",
1808 intf->sent_local_commands);
1809 out += sprintf(out, "handled_local_responses: %d\n",
1810 intf->handled_local_responses);
1811 out += sprintf(out, "unhandled_local_responses: %d\n",
1812 intf->unhandled_local_responses);
1813 out += sprintf(out, "sent_ipmb_commands: %d\n",
1814 intf->sent_ipmb_commands);
1815 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1816 intf->sent_ipmb_command_errs);
1817 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1818 intf->retransmitted_ipmb_commands);
1819 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1820 intf->timed_out_ipmb_commands);
1821 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1822 intf->timed_out_ipmb_broadcasts);
1823 out += sprintf(out, "sent_ipmb_responses: %d\n",
1824 intf->sent_ipmb_responses);
1825 out += sprintf(out, "handled_ipmb_responses: %d\n",
1826 intf->handled_ipmb_responses);
1827 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1828 intf->invalid_ipmb_responses);
1829 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1830 intf->unhandled_ipmb_responses);
1831 out += sprintf(out, "sent_lan_commands: %d\n",
1832 intf->sent_lan_commands);
1833 out += sprintf(out, "sent_lan_command_errs: %d\n",
1834 intf->sent_lan_command_errs);
1835 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1836 intf->retransmitted_lan_commands);
1837 out += sprintf(out, "timed_out_lan_commands: %d\n",
1838 intf->timed_out_lan_commands);
1839 out += sprintf(out, "sent_lan_responses: %d\n",
1840 intf->sent_lan_responses);
1841 out += sprintf(out, "handled_lan_responses: %d\n",
1842 intf->handled_lan_responses);
1843 out += sprintf(out, "invalid_lan_responses: %d\n",
1844 intf->invalid_lan_responses);
1845 out += sprintf(out, "unhandled_lan_responses: %d\n",
1846 intf->unhandled_lan_responses);
1847 out += sprintf(out, "handled_commands: %d\n",
1848 intf->handled_commands);
1849 out += sprintf(out, "invalid_commands: %d\n",
1850 intf->invalid_commands);
1851 out += sprintf(out, "unhandled_commands: %d\n",
1852 intf->unhandled_commands);
1853 out += sprintf(out, "invalid_events: %d\n",
1854 intf->invalid_events);
1855 out += sprintf(out, "events: %d\n",
1856 intf->events);
1857
1858 return (out - ((char *) page));
1859}
1860
1861int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1862 read_proc_t *read_proc, write_proc_t *write_proc,
1863 void *data, struct module *owner)
1864{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001866#ifdef CONFIG_PROC_FS
1867 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 struct ipmi_proc_entry *entry;
1869
1870 /* Create a list element. */
1871 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1872 if (!entry)
1873 return -ENOMEM;
1874 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1875 if (!entry->name) {
1876 kfree(entry);
1877 return -ENOMEM;
1878 }
1879 strcpy(entry->name, name);
1880
1881 file = create_proc_entry(name, 0, smi->proc_dir);
1882 if (!file) {
1883 kfree(entry->name);
1884 kfree(entry);
1885 rv = -ENOMEM;
1886 } else {
1887 file->nlink = 1;
1888 file->data = data;
1889 file->read_proc = read_proc;
1890 file->write_proc = write_proc;
1891 file->owner = owner;
1892
Corey Minyard3b625942005-06-23 22:01:42 -07001893 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 /* Stick it on the list. */
1895 entry->next = smi->proc_entries;
1896 smi->proc_entries = entry;
Corey Minyard3b625942005-06-23 22:01:42 -07001897 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 }
Corey Minyard3b625942005-06-23 22:01:42 -07001899#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
1901 return rv;
1902}
1903
1904static int add_proc_entries(ipmi_smi_t smi, int num)
1905{
1906 int rv = 0;
1907
Corey Minyard3b625942005-06-23 22:01:42 -07001908#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 sprintf(smi->proc_dir_name, "%d", num);
1910 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1911 if (!smi->proc_dir)
1912 rv = -ENOMEM;
1913 else {
1914 smi->proc_dir->owner = THIS_MODULE;
1915 }
1916
1917 if (rv == 0)
1918 rv = ipmi_smi_add_proc_entry(smi, "stats",
1919 stat_file_read_proc, NULL,
1920 smi, THIS_MODULE);
1921
1922 if (rv == 0)
1923 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1924 ipmb_file_read_proc, NULL,
1925 smi, THIS_MODULE);
1926
1927 if (rv == 0)
1928 rv = ipmi_smi_add_proc_entry(smi, "version",
1929 version_file_read_proc, NULL,
1930 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001931#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
1933 return rv;
1934}
1935
1936static void remove_proc_entries(ipmi_smi_t smi)
1937{
Corey Minyard3b625942005-06-23 22:01:42 -07001938#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 struct ipmi_proc_entry *entry;
1940
Corey Minyard3b625942005-06-23 22:01:42 -07001941 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 while (smi->proc_entries) {
1943 entry = smi->proc_entries;
1944 smi->proc_entries = entry->next;
1945
1946 remove_proc_entry(entry->name, smi->proc_dir);
1947 kfree(entry->name);
1948 kfree(entry);
1949 }
Corey Minyard3b625942005-06-23 22:01:42 -07001950 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001952#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953}
1954
Corey Minyard50c812b2006-03-26 01:37:21 -08001955static int __find_bmc_guid(struct device *dev, void *data)
1956{
1957 unsigned char *id = data;
1958 struct bmc_device *bmc = dev_get_drvdata(dev);
1959 return memcmp(bmc->guid, id, 16) == 0;
1960}
1961
1962static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1963 unsigned char *guid)
1964{
1965 struct device *dev;
1966
1967 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1968 if (dev)
1969 return dev_get_drvdata(dev);
1970 else
1971 return NULL;
1972}
1973
1974struct prod_dev_id {
1975 unsigned int product_id;
1976 unsigned char device_id;
1977};
1978
1979static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1980{
1981 struct prod_dev_id *id = data;
1982 struct bmc_device *bmc = dev_get_drvdata(dev);
1983
1984 return (bmc->id.product_id == id->product_id
Corey Minyard50c812b2006-03-26 01:37:21 -08001985 && bmc->id.device_id == id->device_id);
1986}
1987
1988static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1989 struct device_driver *drv,
Corey Minyardf0b55da2006-12-06 20:40:54 -08001990 unsigned int product_id, unsigned char device_id)
Corey Minyard50c812b2006-03-26 01:37:21 -08001991{
1992 struct prod_dev_id id = {
1993 .product_id = product_id,
1994 .device_id = device_id,
1995 };
1996 struct device *dev;
1997
1998 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
1999 if (dev)
2000 return dev_get_drvdata(dev);
2001 else
2002 return NULL;
2003}
2004
2005static ssize_t device_id_show(struct device *dev,
2006 struct device_attribute *attr,
2007 char *buf)
2008{
2009 struct bmc_device *bmc = dev_get_drvdata(dev);
2010
2011 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
2012}
2013
2014static ssize_t provides_dev_sdrs_show(struct device *dev,
2015 struct device_attribute *attr,
2016 char *buf)
2017{
2018 struct bmc_device *bmc = dev_get_drvdata(dev);
2019
2020 return snprintf(buf, 10, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002021 (bmc->id.device_revision & 0x80) >> 7);
Corey Minyard50c812b2006-03-26 01:37:21 -08002022}
2023
2024static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
2025 char *buf)
2026{
2027 struct bmc_device *bmc = dev_get_drvdata(dev);
2028
2029 return snprintf(buf, 20, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002030 bmc->id.device_revision & 0x0F);
Corey Minyard50c812b2006-03-26 01:37:21 -08002031}
2032
2033static ssize_t firmware_rev_show(struct device *dev,
2034 struct device_attribute *attr,
2035 char *buf)
2036{
2037 struct bmc_device *bmc = dev_get_drvdata(dev);
2038
2039 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
2040 bmc->id.firmware_revision_2);
2041}
2042
2043static ssize_t ipmi_version_show(struct device *dev,
2044 struct device_attribute *attr,
2045 char *buf)
2046{
2047 struct bmc_device *bmc = dev_get_drvdata(dev);
2048
2049 return snprintf(buf, 20, "%u.%u\n",
2050 ipmi_version_major(&bmc->id),
2051 ipmi_version_minor(&bmc->id));
2052}
2053
2054static ssize_t add_dev_support_show(struct device *dev,
2055 struct device_attribute *attr,
2056 char *buf)
2057{
2058 struct bmc_device *bmc = dev_get_drvdata(dev);
2059
2060 return snprintf(buf, 10, "0x%02x\n",
2061 bmc->id.additional_device_support);
2062}
2063
2064static ssize_t manufacturer_id_show(struct device *dev,
2065 struct device_attribute *attr,
2066 char *buf)
2067{
2068 struct bmc_device *bmc = dev_get_drvdata(dev);
2069
2070 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
2071}
2072
2073static ssize_t product_id_show(struct device *dev,
2074 struct device_attribute *attr,
2075 char *buf)
2076{
2077 struct bmc_device *bmc = dev_get_drvdata(dev);
2078
2079 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
2080}
2081
2082static ssize_t aux_firmware_rev_show(struct device *dev,
2083 struct device_attribute *attr,
2084 char *buf)
2085{
2086 struct bmc_device *bmc = dev_get_drvdata(dev);
2087
2088 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
2089 bmc->id.aux_firmware_revision[3],
2090 bmc->id.aux_firmware_revision[2],
2091 bmc->id.aux_firmware_revision[1],
2092 bmc->id.aux_firmware_revision[0]);
2093}
2094
2095static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
2096 char *buf)
2097{
2098 struct bmc_device *bmc = dev_get_drvdata(dev);
2099
2100 return snprintf(buf, 100, "%Lx%Lx\n",
2101 (long long) bmc->guid[0],
2102 (long long) bmc->guid[8]);
2103}
2104
Jeff Garzik5e593932006-10-11 01:22:21 -07002105static void remove_files(struct bmc_device *bmc)
Corey Minyard50c812b2006-03-26 01:37:21 -08002106{
Corey Minyardf0b55da2006-12-06 20:40:54 -08002107 if (!bmc->dev)
2108 return;
2109
Corey Minyard50c812b2006-03-26 01:37:21 -08002110 device_remove_file(&bmc->dev->dev,
2111 &bmc->device_id_attr);
2112 device_remove_file(&bmc->dev->dev,
2113 &bmc->provides_dev_sdrs_attr);
2114 device_remove_file(&bmc->dev->dev,
2115 &bmc->revision_attr);
2116 device_remove_file(&bmc->dev->dev,
2117 &bmc->firmware_rev_attr);
2118 device_remove_file(&bmc->dev->dev,
2119 &bmc->version_attr);
2120 device_remove_file(&bmc->dev->dev,
2121 &bmc->add_dev_support_attr);
2122 device_remove_file(&bmc->dev->dev,
2123 &bmc->manufacturer_id_attr);
2124 device_remove_file(&bmc->dev->dev,
2125 &bmc->product_id_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002126
Corey Minyard50c812b2006-03-26 01:37:21 -08002127 if (bmc->id.aux_firmware_revision_set)
2128 device_remove_file(&bmc->dev->dev,
2129 &bmc->aux_firmware_rev_attr);
2130 if (bmc->guid_set)
2131 device_remove_file(&bmc->dev->dev,
2132 &bmc->guid_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002133}
2134
2135static void
2136cleanup_bmc_device(struct kref *ref)
2137{
2138 struct bmc_device *bmc;
2139
2140 bmc = container_of(ref, struct bmc_device, refcount);
2141
2142 remove_files(bmc);
Corey Minyardf0b55da2006-12-06 20:40:54 -08002143 if (bmc->dev)
2144 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";
2174 bmc->device_id_attr.attr.owner = THIS_MODULE;
2175 bmc->device_id_attr.attr.mode = S_IRUGO;
2176 bmc->device_id_attr.show = device_id_show;
2177
2178 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
2179 bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
2180 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2181 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2182
2183 bmc->revision_attr.attr.name = "revision";
2184 bmc->revision_attr.attr.owner = THIS_MODULE;
2185 bmc->revision_attr.attr.mode = S_IRUGO;
2186 bmc->revision_attr.show = revision_show;
2187
2188 bmc->firmware_rev_attr.attr.name = "firmware_revision";
2189 bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
2190 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2191 bmc->firmware_rev_attr.show = firmware_rev_show;
2192
2193 bmc->version_attr.attr.name = "ipmi_version";
2194 bmc->version_attr.attr.owner = THIS_MODULE;
2195 bmc->version_attr.attr.mode = S_IRUGO;
2196 bmc->version_attr.show = ipmi_version_show;
2197
2198 bmc->add_dev_support_attr.attr.name = "additional_device_support";
2199 bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
2200 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2201 bmc->add_dev_support_attr.show = add_dev_support_show;
2202
2203 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
2204 bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
2205 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2206 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2207
2208 bmc->product_id_attr.attr.name = "product_id";
2209 bmc->product_id_attr.attr.owner = THIS_MODULE;
2210 bmc->product_id_attr.attr.mode = S_IRUGO;
2211 bmc->product_id_attr.show = product_id_show;
2212
2213 bmc->guid_attr.attr.name = "guid";
2214 bmc->guid_attr.attr.owner = THIS_MODULE;
2215 bmc->guid_attr.attr.mode = S_IRUGO;
2216 bmc->guid_attr.show = guid_show;
2217
2218 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
2219 bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
2220 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2221 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2222
Jeff Garzik5e593932006-10-11 01:22:21 -07002223 err = device_create_file(&bmc->dev->dev,
2224 &bmc->device_id_attr);
2225 if (err) goto out;
2226 err = device_create_file(&bmc->dev->dev,
2227 &bmc->provides_dev_sdrs_attr);
2228 if (err) goto out_devid;
2229 err = device_create_file(&bmc->dev->dev,
2230 &bmc->revision_attr);
2231 if (err) goto out_sdrs;
2232 err = device_create_file(&bmc->dev->dev,
2233 &bmc->firmware_rev_attr);
2234 if (err) goto out_rev;
2235 err = device_create_file(&bmc->dev->dev,
2236 &bmc->version_attr);
2237 if (err) goto out_firm;
2238 err = device_create_file(&bmc->dev->dev,
2239 &bmc->add_dev_support_attr);
2240 if (err) goto out_version;
2241 err = device_create_file(&bmc->dev->dev,
2242 &bmc->manufacturer_id_attr);
2243 if (err) goto out_add_dev;
2244 err = device_create_file(&bmc->dev->dev,
2245 &bmc->product_id_attr);
2246 if (err) goto out_manu;
2247 if (bmc->id.aux_firmware_revision_set) {
2248 err = device_create_file(&bmc->dev->dev,
2249 &bmc->aux_firmware_rev_attr);
2250 if (err) goto out_prod_id;
2251 }
2252 if (bmc->guid_set) {
2253 err = device_create_file(&bmc->dev->dev,
2254 &bmc->guid_attr);
2255 if (err) goto out_aux_firm;
2256 }
2257
2258 return 0;
2259
2260out_aux_firm:
2261 if (bmc->id.aux_firmware_revision_set)
2262 device_remove_file(&bmc->dev->dev,
2263 &bmc->aux_firmware_rev_attr);
2264out_prod_id:
2265 device_remove_file(&bmc->dev->dev,
2266 &bmc->product_id_attr);
2267out_manu:
2268 device_remove_file(&bmc->dev->dev,
2269 &bmc->manufacturer_id_attr);
2270out_add_dev:
2271 device_remove_file(&bmc->dev->dev,
2272 &bmc->add_dev_support_attr);
2273out_version:
2274 device_remove_file(&bmc->dev->dev,
2275 &bmc->version_attr);
2276out_firm:
2277 device_remove_file(&bmc->dev->dev,
2278 &bmc->firmware_rev_attr);
2279out_rev:
2280 device_remove_file(&bmc->dev->dev,
2281 &bmc->revision_attr);
2282out_sdrs:
2283 device_remove_file(&bmc->dev->dev,
2284 &bmc->provides_dev_sdrs_attr);
2285out_devid:
2286 device_remove_file(&bmc->dev->dev,
2287 &bmc->device_id_attr);
2288out:
2289 return err;
2290}
2291
Corey Minyard759643b2006-12-06 20:40:59 -08002292static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
2293 const char *sysfs_name)
Corey Minyard50c812b2006-03-26 01:37:21 -08002294{
2295 int rv;
2296 struct bmc_device *bmc = intf->bmc;
2297 struct bmc_device *old_bmc;
2298 int size;
2299 char dummy[1];
2300
2301 mutex_lock(&ipmidriver_mutex);
2302
2303 /*
2304 * Try to find if there is an bmc_device struct
2305 * representing the interfaced BMC already
2306 */
2307 if (bmc->guid_set)
2308 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
2309 else
2310 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
2311 bmc->id.product_id,
2312 bmc->id.device_id);
2313
2314 /*
2315 * If there is already an bmc_device, free the new one,
2316 * otherwise register the new BMC device
2317 */
2318 if (old_bmc) {
2319 kfree(bmc);
2320 intf->bmc = old_bmc;
2321 bmc = old_bmc;
2322
2323 kref_get(&bmc->refcount);
2324 mutex_unlock(&ipmidriver_mutex);
2325
2326 printk(KERN_INFO
2327 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
2328 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2329 bmc->id.manufacturer_id,
2330 bmc->id.product_id,
2331 bmc->id.device_id);
2332 } else {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002333 char name[14];
2334 unsigned char orig_dev_id = bmc->id.device_id;
2335 int warn_printed = 0;
2336
2337 snprintf(name, sizeof(name),
2338 "ipmi_bmc.%4.4x", bmc->id.product_id);
2339
2340 while (ipmi_find_bmc_prod_dev_id(&ipmidriver,
2341 bmc->id.product_id,
2342 bmc->id.device_id))
2343 {
2344 if (!warn_printed) {
2345 printk(KERN_WARNING PFX
2346 "This machine has two different BMCs"
2347 " with the same product id and device"
2348 " id. This is an error in the"
2349 " firmware, but incrementing the"
2350 " device id to work around the problem."
2351 " Prod ID = 0x%x, Dev ID = 0x%x\n",
2352 bmc->id.product_id, bmc->id.device_id);
2353 warn_printed = 1;
2354 }
2355 bmc->id.device_id++; /* Wraps at 255 */
2356 if (bmc->id.device_id == orig_dev_id) {
2357 printk(KERN_ERR PFX
2358 "Out of device ids!\n");
2359 break;
2360 }
2361 }
2362
2363 bmc->dev = platform_device_alloc(name, bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08002364 if (!bmc->dev) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002365 mutex_unlock(&ipmidriver_mutex);
Corey Minyard50c812b2006-03-26 01:37:21 -08002366 printk(KERN_ERR
2367 "ipmi_msghandler:"
2368 " Unable to allocate platform device\n");
2369 return -ENOMEM;
2370 }
2371 bmc->dev->dev.driver = &ipmidriver;
2372 dev_set_drvdata(&bmc->dev->dev, bmc);
2373 kref_init(&bmc->refcount);
2374
Zhang, Yanminb48f5452006-11-16 01:19:08 -08002375 rv = platform_device_add(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002376 mutex_unlock(&ipmidriver_mutex);
2377 if (rv) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002378 platform_device_put(bmc->dev);
2379 bmc->dev = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002380 printk(KERN_ERR
2381 "ipmi_msghandler:"
2382 " Unable to register bmc device: %d\n",
2383 rv);
2384 /* Don't go to out_err, you can only do that if
2385 the device is registered already. */
2386 return rv;
2387 }
2388
Jeff Garzik5e593932006-10-11 01:22:21 -07002389 rv = create_files(bmc);
2390 if (rv) {
2391 mutex_lock(&ipmidriver_mutex);
2392 platform_device_unregister(bmc->dev);
2393 mutex_unlock(&ipmidriver_mutex);
2394
2395 return rv;
2396 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002397
2398 printk(KERN_INFO
2399 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2400 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2401 bmc->id.manufacturer_id,
2402 bmc->id.product_id,
2403 bmc->id.device_id);
2404 }
2405
2406 /*
2407 * create symlink from system interface device to bmc device
2408 * and back.
2409 */
Corey Minyard759643b2006-12-06 20:40:59 -08002410 intf->sysfs_name = kstrdup(sysfs_name, GFP_KERNEL);
2411 if (!intf->sysfs_name) {
2412 rv = -ENOMEM;
2413 printk(KERN_ERR
2414 "ipmi_msghandler: allocate link to BMC: %d\n",
2415 rv);
2416 goto out_err;
2417 }
2418
Corey Minyard50c812b2006-03-26 01:37:21 -08002419 rv = sysfs_create_link(&intf->si_dev->kobj,
Corey Minyard759643b2006-12-06 20:40:59 -08002420 &bmc->dev->dev.kobj, intf->sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002421 if (rv) {
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 printk(KERN_ERR
2425 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2426 rv);
2427 goto out_err;
2428 }
2429
Corey Minyard759643b2006-12-06 20:40:59 -08002430 size = snprintf(dummy, 0, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002431 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2432 if (!intf->my_dev_name) {
Corey Minyard759643b2006-12-06 20:40:59 -08002433 kfree(intf->sysfs_name);
2434 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002435 rv = -ENOMEM;
2436 printk(KERN_ERR
2437 "ipmi_msghandler: allocate link from BMC: %d\n",
2438 rv);
2439 goto out_err;
2440 }
Corey Minyard759643b2006-12-06 20:40:59 -08002441 snprintf(intf->my_dev_name, size+1, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002442
2443 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2444 intf->my_dev_name);
2445 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002446 kfree(intf->sysfs_name);
2447 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002448 kfree(intf->my_dev_name);
2449 intf->my_dev_name = NULL;
2450 printk(KERN_ERR
2451 "ipmi_msghandler:"
2452 " Unable to create symlink to bmc: %d\n",
2453 rv);
2454 goto out_err;
2455 }
2456
2457 return 0;
2458
2459out_err:
2460 ipmi_bmc_unregister(intf);
2461 return rv;
2462}
2463
2464static int
2465send_guid_cmd(ipmi_smi_t intf, int chan)
2466{
2467 struct kernel_ipmi_msg msg;
2468 struct ipmi_system_interface_addr si;
2469
2470 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2471 si.channel = IPMI_BMC_CHANNEL;
2472 si.lun = 0;
2473
2474 msg.netfn = IPMI_NETFN_APP_REQUEST;
2475 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2476 msg.data = NULL;
2477 msg.data_len = 0;
2478 return i_ipmi_request(NULL,
2479 intf,
2480 (struct ipmi_addr *) &si,
2481 0,
2482 &msg,
2483 intf,
2484 NULL,
2485 NULL,
2486 0,
2487 intf->channels[0].address,
2488 intf->channels[0].lun,
2489 -1, 0);
2490}
2491
2492static void
2493guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2494{
2495 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2496 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2497 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2498 /* Not for me */
2499 return;
2500
2501 if (msg->msg.data[0] != 0) {
2502 /* Error from getting the GUID, the BMC doesn't have one. */
2503 intf->bmc->guid_set = 0;
2504 goto out;
2505 }
2506
2507 if (msg->msg.data_len < 17) {
2508 intf->bmc->guid_set = 0;
2509 printk(KERN_WARNING PFX
2510 "guid_handler: The GUID response from the BMC was too"
2511 " short, it was %d but should have been 17. Assuming"
2512 " GUID is not available.\n",
2513 msg->msg.data_len);
2514 goto out;
2515 }
2516
2517 memcpy(intf->bmc->guid, msg->msg.data, 16);
2518 intf->bmc->guid_set = 1;
2519 out:
2520 wake_up(&intf->waitq);
2521}
2522
2523static void
2524get_guid(ipmi_smi_t intf)
2525{
2526 int rv;
2527
2528 intf->bmc->guid_set = 0x2;
2529 intf->null_user_handler = guid_handler;
2530 rv = send_guid_cmd(intf, 0);
2531 if (rv)
2532 /* Send failed, no GUID available. */
2533 intf->bmc->guid_set = 0;
2534 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2535 intf->null_user_handler = NULL;
2536}
2537
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538static int
2539send_channel_info_cmd(ipmi_smi_t intf, int chan)
2540{
2541 struct kernel_ipmi_msg msg;
2542 unsigned char data[1];
2543 struct ipmi_system_interface_addr si;
2544
2545 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2546 si.channel = IPMI_BMC_CHANNEL;
2547 si.lun = 0;
2548
2549 msg.netfn = IPMI_NETFN_APP_REQUEST;
2550 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2551 msg.data = data;
2552 msg.data_len = 1;
2553 data[0] = chan;
2554 return i_ipmi_request(NULL,
2555 intf,
2556 (struct ipmi_addr *) &si,
2557 0,
2558 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002559 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 NULL,
2561 NULL,
2562 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002563 intf->channels[0].address,
2564 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 -1, 0);
2566}
2567
2568static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002569channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570{
2571 int rv = 0;
2572 int chan;
2573
Corey Minyard56a55ec2005-09-06 15:18:42 -07002574 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2575 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2576 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 {
2578 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002579 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 /* Got an error from the channel, just go on. */
2581
Corey Minyard56a55ec2005-09-06 15:18:42 -07002582 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 /* If the MC does not support this
2584 command, that is legal. We just
2585 assume it has one IPMB at channel
2586 zero. */
2587 intf->channels[0].medium
2588 = IPMI_CHANNEL_MEDIUM_IPMB;
2589 intf->channels[0].protocol
2590 = IPMI_CHANNEL_PROTOCOL_IPMB;
2591 rv = -ENOSYS;
2592
2593 intf->curr_channel = IPMI_MAX_CHANNELS;
2594 wake_up(&intf->waitq);
2595 goto out;
2596 }
2597 goto next_channel;
2598 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002599 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 /* Message not big enough, just go on. */
2601 goto next_channel;
2602 }
2603 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002604 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2605 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
2607 next_channel:
2608 intf->curr_channel++;
2609 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2610 wake_up(&intf->waitq);
2611 else
2612 rv = send_channel_info_cmd(intf, intf->curr_channel);
2613
2614 if (rv) {
2615 /* Got an error somehow, just give up. */
2616 intf->curr_channel = IPMI_MAX_CHANNELS;
2617 wake_up(&intf->waitq);
2618
2619 printk(KERN_WARNING PFX
2620 "Error sending channel information: %d\n",
2621 rv);
2622 }
2623 }
2624 out:
2625 return;
2626}
2627
2628int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2629 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002630 struct ipmi_device_id *device_id,
2631 struct device *si_dev,
Corey Minyard759643b2006-12-06 20:40:59 -08002632 const char *sysfs_name,
Corey Minyard453823b2006-03-31 02:30:39 -08002633 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634{
2635 int i, j;
2636 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002637 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -08002638 ipmi_smi_t tintf;
Corey Minyardbca03242006-12-06 20:40:57 -08002639 struct list_head *link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 /* Make sure the driver is actually initialized, this handles
2642 problems with initialization order. */
2643 if (!initialized) {
2644 rv = ipmi_init_msghandler();
2645 if (rv)
2646 return rv;
2647 /* The init code doesn't return an error if it was turned
2648 off, but it won't initialize. Check that. */
2649 if (!initialized)
2650 return -ENODEV;
2651 }
2652
Corey Minyard393d2cc2005-11-07 00:59:54 -08002653 intf = kmalloc(sizeof(*intf), GFP_KERNEL);
2654 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002656 memset(intf, 0, sizeof(*intf));
Corey Minyardb2c03942006-12-06 20:41:00 -08002657
2658 intf->ipmi_version_major = ipmi_version_major(device_id);
2659 intf->ipmi_version_minor = ipmi_version_minor(device_id);
2660
Corey Minyard50c812b2006-03-26 01:37:21 -08002661 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2662 if (!intf->bmc) {
2663 kfree(intf);
2664 return -ENOMEM;
2665 }
Corey Minyardbca03242006-12-06 20:40:57 -08002666 intf->intf_num = -1; /* Mark it invalid for now. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002667 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002668 intf->bmc->id = *device_id;
2669 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002670 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2671 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2672 intf->channels[j].lun = 2;
2673 }
2674 if (slave_addr != 0)
2675 intf->channels[0].address = slave_addr;
2676 INIT_LIST_HEAD(&intf->users);
2677 intf->handlers = handlers;
2678 intf->send_info = send_info;
2679 spin_lock_init(&intf->seq_lock);
2680 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2681 intf->seq_table[j].inuse = 0;
2682 intf->seq_table[j].seqid = 0;
2683 }
2684 intf->curr_seq = 0;
2685#ifdef CONFIG_PROC_FS
2686 spin_lock_init(&intf->proc_entry_lock);
2687#endif
2688 spin_lock_init(&intf->waiting_msgs_lock);
2689 INIT_LIST_HEAD(&intf->waiting_msgs);
2690 spin_lock_init(&intf->events_lock);
2691 INIT_LIST_HEAD(&intf->waiting_events);
2692 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002693 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyardb9675132006-12-06 20:41:02 -08002694 spin_lock_init(&intf->maintenance_mode_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002695 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2696 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
Corey Minyard393d2cc2005-11-07 00:59:54 -08002698 spin_lock_init(&intf->counter_lock);
2699 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Corey Minyardb2c03942006-12-06 20:41:00 -08002701 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002702 mutex_lock(&ipmi_interfaces_mutex);
2703 /* Look for a hole in the numbers. */
2704 i = 0;
2705 link = &ipmi_interfaces;
2706 list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) {
2707 if (tintf->intf_num != i) {
2708 link = &tintf->link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 break;
2710 }
Corey Minyardbca03242006-12-06 20:40:57 -08002711 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 }
Corey Minyardbca03242006-12-06 20:40:57 -08002713 /* Add the new interface in numeric order. */
2714 if (i == 0)
2715 list_add_rcu(&intf->link, &ipmi_interfaces);
2716 else
2717 list_add_tail_rcu(&intf->link, link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718
Corey Minyard453823b2006-03-31 02:30:39 -08002719 rv = handlers->start_processing(send_info, intf);
2720 if (rv)
2721 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002722
Corey Minyard50c812b2006-03-26 01:37:21 -08002723 get_guid(intf);
2724
Corey Minyardb2c03942006-12-06 20:41:00 -08002725 if ((intf->ipmi_version_major > 1)
2726 || ((intf->ipmi_version_major == 1)
2727 && (intf->ipmi_version_minor >= 5)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08002728 {
2729 /* Start scanning the channels to see what is
2730 available. */
2731 intf->null_user_handler = channel_handler;
2732 intf->curr_channel = 0;
2733 rv = send_channel_info_cmd(intf, 0);
2734 if (rv)
2735 goto out;
2736
2737 /* Wait for the channel info to be read. */
2738 wait_event(intf->waitq,
2739 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002740 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002741 } else {
2742 /* Assume a single IPMB channel at zero. */
2743 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2744 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
2747 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002748 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749
Corey Minyard759643b2006-12-06 20:40:59 -08002750 rv = ipmi_bmc_register(intf, i, sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002751
Corey Minyard393d2cc2005-11-07 00:59:54 -08002752 out:
2753 if (rv) {
2754 if (intf->proc_dir)
2755 remove_proc_entries(intf);
Corey Minyardb2c03942006-12-06 20:41:00 -08002756 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002757 list_del_rcu(&intf->link);
2758 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002759 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002760 synchronize_rcu();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002761 kref_put(&intf->refcount, intf_free);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002762 } else {
Corey Minyardbca03242006-12-06 20:40:57 -08002763 /* After this point the interface is legal to use. */
2764 intf->intf_num = i;
2765 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard50c812b2006-03-26 01:37:21 -08002766 call_smi_watchers(i, intf->si_dev);
Corey Minyardb2c03942006-12-06 20:41:00 -08002767 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 }
2769
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 return rv;
2771}
2772
Corey Minyardb2c03942006-12-06 20:41:00 -08002773static void cleanup_smi_msgs(ipmi_smi_t intf)
2774{
2775 int i;
2776 struct seq_table *ent;
2777
2778 /* No need for locks, the interface is down. */
2779 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
2780 ent = &(intf->seq_table[i]);
2781 if (!ent->inuse)
2782 continue;
2783 deliver_err_response(ent->recv_msg, IPMI_ERR_UNSPECIFIED);
2784 }
2785}
2786
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787int ipmi_unregister_smi(ipmi_smi_t intf)
2788{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 struct ipmi_smi_watcher *w;
Corey Minyardb2c03942006-12-06 20:41:00 -08002790 int intf_num = intf->intf_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791
Corey Minyard50c812b2006-03-26 01:37:21 -08002792 ipmi_bmc_unregister(intf);
2793
Corey Minyardb2c03942006-12-06 20:41:00 -08002794 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002795 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002796 intf->intf_num = -1;
2797 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002798 list_del_rcu(&intf->link);
2799 mutex_unlock(&ipmi_interfaces_mutex);
2800 synchronize_rcu();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
Corey Minyardb2c03942006-12-06 20:41:00 -08002802 cleanup_smi_msgs(intf);
2803
Corey Minyard393d2cc2005-11-07 00:59:54 -08002804 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805
2806 /* Call all the watcher interfaces to tell them that
2807 an interface is gone. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002808 list_for_each_entry(w, &smi_watchers, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08002809 w->smi_gone(intf_num);
2810 mutex_unlock(&smi_watchers_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002811
Corey Minyard393d2cc2005-11-07 00:59:54 -08002812 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 return 0;
2814}
2815
2816static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2817 struct ipmi_smi_msg *msg)
2818{
2819 struct ipmi_ipmb_addr ipmb_addr;
2820 struct ipmi_recv_msg *recv_msg;
2821 unsigned long flags;
2822
2823
2824 /* This is 11, not 10, because the response must contain a
2825 * completion code. */
2826 if (msg->rsp_size < 11) {
2827 /* Message not big enough, just ignore it. */
2828 spin_lock_irqsave(&intf->counter_lock, flags);
2829 intf->invalid_ipmb_responses++;
2830 spin_unlock_irqrestore(&intf->counter_lock, flags);
2831 return 0;
2832 }
2833
2834 if (msg->rsp[2] != 0) {
2835 /* An error getting the response, just ignore it. */
2836 return 0;
2837 }
2838
2839 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
2840 ipmb_addr.slave_addr = msg->rsp[6];
2841 ipmb_addr.channel = msg->rsp[3] & 0x0f;
2842 ipmb_addr.lun = msg->rsp[7] & 3;
2843
2844 /* It's a response from a remote entity. Look up the sequence
2845 number and handle the response. */
2846 if (intf_find_seq(intf,
2847 msg->rsp[7] >> 2,
2848 msg->rsp[3] & 0x0f,
2849 msg->rsp[8],
2850 (msg->rsp[4] >> 2) & (~1),
2851 (struct ipmi_addr *) &(ipmb_addr),
2852 &recv_msg))
2853 {
2854 /* We were unable to find the sequence number,
2855 so just nuke the message. */
2856 spin_lock_irqsave(&intf->counter_lock, flags);
2857 intf->unhandled_ipmb_responses++;
2858 spin_unlock_irqrestore(&intf->counter_lock, flags);
2859 return 0;
2860 }
2861
2862 memcpy(recv_msg->msg_data,
2863 &(msg->rsp[9]),
2864 msg->rsp_size - 9);
2865 /* THe other fields matched, so no need to set them, except
2866 for netfn, which needs to be the response that was
2867 returned, not the request value. */
2868 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2869 recv_msg->msg.data = recv_msg->msg_data;
2870 recv_msg->msg.data_len = msg->rsp_size - 10;
2871 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2872 spin_lock_irqsave(&intf->counter_lock, flags);
2873 intf->handled_ipmb_responses++;
2874 spin_unlock_irqrestore(&intf->counter_lock, flags);
2875 deliver_response(recv_msg);
2876
2877 return 0;
2878}
2879
2880static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2881 struct ipmi_smi_msg *msg)
2882{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002883 struct cmd_rcvr *rcvr;
2884 int rv = 0;
2885 unsigned char netfn;
2886 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002887 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002888 ipmi_user_t user = NULL;
2889 struct ipmi_ipmb_addr *ipmb_addr;
2890 struct ipmi_recv_msg *recv_msg;
2891 unsigned long flags;
Corey Minyardb2c03942006-12-06 20:41:00 -08002892 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893
2894 if (msg->rsp_size < 10) {
2895 /* Message not big enough, just ignore it. */
2896 spin_lock_irqsave(&intf->counter_lock, flags);
2897 intf->invalid_commands++;
2898 spin_unlock_irqrestore(&intf->counter_lock, flags);
2899 return 0;
2900 }
2901
2902 if (msg->rsp[2] != 0) {
2903 /* An error getting the response, just ignore it. */
2904 return 0;
2905 }
2906
2907 netfn = msg->rsp[4] >> 2;
2908 cmd = msg->rsp[8];
Corey Minyardc69c3122006-09-30 23:27:56 -07002909 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002911 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002912 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002913 if (rcvr) {
2914 user = rcvr->user;
2915 kref_get(&user->refcount);
2916 } else
2917 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002918 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
2920 if (user == NULL) {
2921 /* We didn't find a user, deliver an error response. */
2922 spin_lock_irqsave(&intf->counter_lock, flags);
2923 intf->unhandled_commands++;
2924 spin_unlock_irqrestore(&intf->counter_lock, flags);
2925
2926 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2927 msg->data[1] = IPMI_SEND_MSG_CMD;
2928 msg->data[2] = msg->rsp[3];
2929 msg->data[3] = msg->rsp[6];
2930 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2931 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002932 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 /* rqseq/lun */
2934 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2935 msg->data[8] = msg->rsp[8]; /* cmd */
2936 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2937 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2938 msg->data_size = 11;
2939
2940#ifdef DEBUG_MSGING
2941 {
2942 int m;
2943 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002944 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 printk(" %2.2x", msg->data[m]);
2946 printk("\n");
2947 }
2948#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08002949 rcu_read_lock();
2950 handlers = intf->handlers;
2951 if (handlers) {
2952 handlers->sender(intf->send_info, msg, 0);
2953 /* We used the message, so return the value
2954 that causes it to not be freed or
2955 queued. */
2956 rv = -1;
2957 }
2958 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 } else {
2960 /* Deliver the message to the user. */
2961 spin_lock_irqsave(&intf->counter_lock, flags);
2962 intf->handled_commands++;
2963 spin_unlock_irqrestore(&intf->counter_lock, flags);
2964
2965 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002966 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 /* We couldn't allocate memory for the
2968 message, so requeue it for handling
2969 later. */
2970 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002971 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 } else {
2973 /* Extract the source address from the data. */
2974 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2975 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2976 ipmb_addr->slave_addr = msg->rsp[6];
2977 ipmb_addr->lun = msg->rsp[7] & 3;
2978 ipmb_addr->channel = msg->rsp[3] & 0xf;
2979
2980 /* Extract the rest of the message information
2981 from the IPMB header.*/
2982 recv_msg->user = user;
2983 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2984 recv_msg->msgid = msg->rsp[7] >> 2;
2985 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2986 recv_msg->msg.cmd = msg->rsp[8];
2987 recv_msg->msg.data = recv_msg->msg_data;
2988
2989 /* We chop off 10, not 9 bytes because the checksum
2990 at the end also needs to be removed. */
2991 recv_msg->msg.data_len = msg->rsp_size - 10;
2992 memcpy(recv_msg->msg_data,
2993 &(msg->rsp[9]),
2994 msg->rsp_size - 10);
2995 deliver_response(recv_msg);
2996 }
2997 }
2998
2999 return rv;
3000}
3001
3002static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
3003 struct ipmi_smi_msg *msg)
3004{
3005 struct ipmi_lan_addr lan_addr;
3006 struct ipmi_recv_msg *recv_msg;
3007 unsigned long flags;
3008
3009
3010 /* This is 13, not 12, because the response must contain a
3011 * completion code. */
3012 if (msg->rsp_size < 13) {
3013 /* Message not big enough, just ignore it. */
3014 spin_lock_irqsave(&intf->counter_lock, flags);
3015 intf->invalid_lan_responses++;
3016 spin_unlock_irqrestore(&intf->counter_lock, flags);
3017 return 0;
3018 }
3019
3020 if (msg->rsp[2] != 0) {
3021 /* An error getting the response, just ignore it. */
3022 return 0;
3023 }
3024
3025 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
3026 lan_addr.session_handle = msg->rsp[4];
3027 lan_addr.remote_SWID = msg->rsp[8];
3028 lan_addr.local_SWID = msg->rsp[5];
3029 lan_addr.channel = msg->rsp[3] & 0x0f;
3030 lan_addr.privilege = msg->rsp[3] >> 4;
3031 lan_addr.lun = msg->rsp[9] & 3;
3032
3033 /* It's a response from a remote entity. Look up the sequence
3034 number and handle the response. */
3035 if (intf_find_seq(intf,
3036 msg->rsp[9] >> 2,
3037 msg->rsp[3] & 0x0f,
3038 msg->rsp[10],
3039 (msg->rsp[6] >> 2) & (~1),
3040 (struct ipmi_addr *) &(lan_addr),
3041 &recv_msg))
3042 {
3043 /* We were unable to find the sequence number,
3044 so just nuke the message. */
3045 spin_lock_irqsave(&intf->counter_lock, flags);
3046 intf->unhandled_lan_responses++;
3047 spin_unlock_irqrestore(&intf->counter_lock, flags);
3048 return 0;
3049 }
3050
3051 memcpy(recv_msg->msg_data,
3052 &(msg->rsp[11]),
3053 msg->rsp_size - 11);
3054 /* The other fields matched, so no need to set them, except
3055 for netfn, which needs to be the response that was
3056 returned, not the request value. */
3057 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3058 recv_msg->msg.data = recv_msg->msg_data;
3059 recv_msg->msg.data_len = msg->rsp_size - 12;
3060 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3061 spin_lock_irqsave(&intf->counter_lock, flags);
3062 intf->handled_lan_responses++;
3063 spin_unlock_irqrestore(&intf->counter_lock, flags);
3064 deliver_response(recv_msg);
3065
3066 return 0;
3067}
3068
3069static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
3070 struct ipmi_smi_msg *msg)
3071{
Corey Minyard393d2cc2005-11-07 00:59:54 -08003072 struct cmd_rcvr *rcvr;
3073 int rv = 0;
3074 unsigned char netfn;
3075 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07003076 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003077 ipmi_user_t user = NULL;
3078 struct ipmi_lan_addr *lan_addr;
3079 struct ipmi_recv_msg *recv_msg;
3080 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081
3082 if (msg->rsp_size < 12) {
3083 /* Message not big enough, just ignore it. */
3084 spin_lock_irqsave(&intf->counter_lock, flags);
3085 intf->invalid_commands++;
3086 spin_unlock_irqrestore(&intf->counter_lock, flags);
3087 return 0;
3088 }
3089
3090 if (msg->rsp[2] != 0) {
3091 /* An error getting the response, just ignore it. */
3092 return 0;
3093 }
3094
3095 netfn = msg->rsp[6] >> 2;
3096 cmd = msg->rsp[10];
Corey Minyardc69c3122006-09-30 23:27:56 -07003097 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003099 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07003100 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003101 if (rcvr) {
3102 user = rcvr->user;
3103 kref_get(&user->refcount);
3104 } else
3105 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003106 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
3108 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003109 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 spin_lock_irqsave(&intf->counter_lock, flags);
3111 intf->unhandled_commands++;
3112 spin_unlock_irqrestore(&intf->counter_lock, flags);
3113
3114 rv = 0; /* Don't do anything with these messages, just
3115 allow them to be freed. */
3116 } else {
3117 /* Deliver the message to the user. */
3118 spin_lock_irqsave(&intf->counter_lock, flags);
3119 intf->handled_commands++;
3120 spin_unlock_irqrestore(&intf->counter_lock, flags);
3121
3122 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003123 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 /* We couldn't allocate memory for the
3125 message, so requeue it for handling
3126 later. */
3127 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003128 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 } else {
3130 /* Extract the source address from the data. */
3131 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
3132 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
3133 lan_addr->session_handle = msg->rsp[4];
3134 lan_addr->remote_SWID = msg->rsp[8];
3135 lan_addr->local_SWID = msg->rsp[5];
3136 lan_addr->lun = msg->rsp[9] & 3;
3137 lan_addr->channel = msg->rsp[3] & 0xf;
3138 lan_addr->privilege = msg->rsp[3] >> 4;
3139
3140 /* Extract the rest of the message information
3141 from the IPMB header.*/
3142 recv_msg->user = user;
3143 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
3144 recv_msg->msgid = msg->rsp[9] >> 2;
3145 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3146 recv_msg->msg.cmd = msg->rsp[10];
3147 recv_msg->msg.data = recv_msg->msg_data;
3148
3149 /* We chop off 12, not 11 bytes because the checksum
3150 at the end also needs to be removed. */
3151 recv_msg->msg.data_len = msg->rsp_size - 12;
3152 memcpy(recv_msg->msg_data,
3153 &(msg->rsp[11]),
3154 msg->rsp_size - 12);
3155 deliver_response(recv_msg);
3156 }
3157 }
3158
3159 return rv;
3160}
3161
3162static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
3163 struct ipmi_smi_msg *msg)
3164{
3165 struct ipmi_system_interface_addr *smi_addr;
3166
3167 recv_msg->msgid = 0;
3168 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
3169 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3170 smi_addr->channel = IPMI_BMC_CHANNEL;
3171 smi_addr->lun = msg->rsp[0] & 3;
3172 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
3173 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3174 recv_msg->msg.cmd = msg->rsp[1];
3175 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
3176 recv_msg->msg.data = recv_msg->msg_data;
3177 recv_msg->msg.data_len = msg->rsp_size - 3;
3178}
3179
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180static int handle_read_event_rsp(ipmi_smi_t intf,
3181 struct ipmi_smi_msg *msg)
3182{
3183 struct ipmi_recv_msg *recv_msg, *recv_msg2;
3184 struct list_head msgs;
3185 ipmi_user_t user;
3186 int rv = 0;
3187 int deliver_count = 0;
3188 unsigned long flags;
3189
3190 if (msg->rsp_size < 19) {
3191 /* Message is too small to be an IPMB event. */
3192 spin_lock_irqsave(&intf->counter_lock, flags);
3193 intf->invalid_events++;
3194 spin_unlock_irqrestore(&intf->counter_lock, flags);
3195 return 0;
3196 }
3197
3198 if (msg->rsp[2] != 0) {
3199 /* An error getting the event, just ignore it. */
3200 return 0;
3201 }
3202
3203 INIT_LIST_HEAD(&msgs);
3204
Corey Minyard393d2cc2005-11-07 00:59:54 -08003205 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206
3207 spin_lock(&intf->counter_lock);
3208 intf->events++;
3209 spin_unlock(&intf->counter_lock);
3210
3211 /* Allocate and fill in one message for every user that is getting
3212 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003213 rcu_read_lock();
3214 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003215 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 continue;
3217
3218 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003219 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003220 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003221 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
3222 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 list_del(&recv_msg->link);
3224 ipmi_free_recv_msg(recv_msg);
3225 }
3226 /* We couldn't allocate memory for the
3227 message, so requeue it for handling
3228 later. */
3229 rv = 1;
3230 goto out;
3231 }
3232
3233 deliver_count++;
3234
3235 copy_event_into_recv_msg(recv_msg, msg);
3236 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003237 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 list_add_tail(&(recv_msg->link), &msgs);
3239 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003240 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
3242 if (deliver_count) {
3243 /* Now deliver all the messages. */
3244 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
3245 list_del(&recv_msg->link);
3246 deliver_response(recv_msg);
3247 }
3248 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
3249 /* No one to receive the message, put it in queue if there's
3250 not already too many things in the queue. */
3251 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003252 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 /* We couldn't allocate memory for the
3254 message, so requeue it for handling
3255 later. */
3256 rv = 1;
3257 goto out;
3258 }
3259
3260 copy_event_into_recv_msg(recv_msg, msg);
3261 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
Corey Minyard4791c032006-04-10 22:54:31 -07003262 intf->waiting_events_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 } else {
3264 /* There's too many things in the queue, discard this
3265 message. */
3266 printk(KERN_WARNING PFX "Event queue full, discarding an"
3267 " incoming event\n");
3268 }
3269
3270 out:
3271 spin_unlock_irqrestore(&(intf->events_lock), flags);
3272
3273 return rv;
3274}
3275
3276static int handle_bmc_rsp(ipmi_smi_t intf,
3277 struct ipmi_smi_msg *msg)
3278{
3279 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003281 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
3283 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07003284 if (recv_msg == NULL)
3285 {
3286 printk(KERN_WARNING"IPMI message received with no owner. This\n"
3287 "could be because of a malformed message, or\n"
3288 "because of a hardware error. Contact your\n"
3289 "hardware vender for assistance\n");
3290 return 0;
3291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
Corey Minyard393d2cc2005-11-07 00:59:54 -08003293 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003295 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07003296 /* The user for the message went away, so give up. */
3297 spin_lock_irqsave(&intf->counter_lock, flags);
3298 intf->unhandled_local_responses++;
3299 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 ipmi_free_recv_msg(recv_msg);
3301 } else {
3302 struct ipmi_system_interface_addr *smi_addr;
3303
3304 spin_lock_irqsave(&intf->counter_lock, flags);
3305 intf->handled_local_responses++;
3306 spin_unlock_irqrestore(&intf->counter_lock, flags);
3307 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3308 recv_msg->msgid = msg->msgid;
3309 smi_addr = ((struct ipmi_system_interface_addr *)
3310 &(recv_msg->addr));
3311 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3312 smi_addr->channel = IPMI_BMC_CHANNEL;
3313 smi_addr->lun = msg->rsp[0] & 3;
3314 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3315 recv_msg->msg.cmd = msg->rsp[1];
3316 memcpy(recv_msg->msg_data,
3317 &(msg->rsp[2]),
3318 msg->rsp_size - 2);
3319 recv_msg->msg.data = recv_msg->msg_data;
3320 recv_msg->msg.data_len = msg->rsp_size - 2;
3321 deliver_response(recv_msg);
3322 }
3323
3324 return 0;
3325}
3326
3327/* Handle a new message. Return 1 if the message should be requeued,
3328 0 if the message should be freed, or -1 if the message should not
3329 be freed or requeued. */
3330static int handle_new_recv_msg(ipmi_smi_t intf,
3331 struct ipmi_smi_msg *msg)
3332{
3333 int requeue;
3334 int chan;
3335
3336#ifdef DEBUG_MSGING
3337 int m;
3338 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07003339 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 printk(" %2.2x", msg->rsp[m]);
3341 printk("\n");
3342#endif
3343 if (msg->rsp_size < 2) {
3344 /* Message is too small to be correct. */
3345 printk(KERN_WARNING PFX "BMC returned to small a message"
3346 " for netfn %x cmd %x, got %d bytes\n",
3347 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3348
3349 /* Generate an error response for the message. */
3350 msg->rsp[0] = msg->data[0] | (1 << 2);
3351 msg->rsp[1] = msg->data[1];
3352 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3353 msg->rsp_size = 3;
3354 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3355 || (msg->rsp[1] != msg->data[1])) /* Command */
3356 {
3357 /* The response is not even marginally correct. */
3358 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3359 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3360 (msg->data[0] >> 2) | 1, msg->data[1],
3361 msg->rsp[0] >> 2, msg->rsp[1]);
3362
3363 /* Generate an error response for the message. */
3364 msg->rsp[0] = msg->data[0] | (1 << 2);
3365 msg->rsp[1] = msg->data[1];
3366 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3367 msg->rsp_size = 3;
3368 }
3369
3370 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3371 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3372 && (msg->user_data != NULL))
3373 {
3374 /* It's a response to a response we sent. For this we
3375 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003376 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377
3378 requeue = 0;
3379 if (msg->rsp_size < 2)
3380 /* Message is too small to be correct. */
3381 goto out;
3382
3383 chan = msg->data[2] & 0x0f;
3384 if (chan >= IPMI_MAX_CHANNELS)
3385 /* Invalid channel number */
3386 goto out;
3387
Corey Minyard393d2cc2005-11-07 00:59:54 -08003388 if (!recv_msg)
3389 goto out;
3390
3391 /* Make sure the user still exists. */
3392 if (!recv_msg->user || !recv_msg->user->valid)
3393 goto out;
3394
3395 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3396 recv_msg->msg.data = recv_msg->msg_data;
3397 recv_msg->msg.data_len = 1;
3398 recv_msg->msg_data[0] = msg->rsp[2];
3399 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3401 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3402 {
3403 /* It's from the receive queue. */
3404 chan = msg->rsp[3] & 0xf;
3405 if (chan >= IPMI_MAX_CHANNELS) {
3406 /* Invalid channel number */
3407 requeue = 0;
3408 goto out;
3409 }
3410
3411 switch (intf->channels[chan].medium) {
3412 case IPMI_CHANNEL_MEDIUM_IPMB:
3413 if (msg->rsp[4] & 0x04) {
3414 /* It's a response, so find the
3415 requesting message and send it up. */
3416 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3417 } else {
3418 /* It's a command to the SMS from some other
3419 entity. Handle that. */
3420 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3421 }
3422 break;
3423
3424 case IPMI_CHANNEL_MEDIUM_8023LAN:
3425 case IPMI_CHANNEL_MEDIUM_ASYNC:
3426 if (msg->rsp[6] & 0x04) {
3427 /* It's a response, so find the
3428 requesting message and send it up. */
3429 requeue = handle_lan_get_msg_rsp(intf, msg);
3430 } else {
3431 /* It's a command to the SMS from some other
3432 entity. Handle that. */
3433 requeue = handle_lan_get_msg_cmd(intf, msg);
3434 }
3435 break;
3436
3437 default:
3438 /* We don't handle the channel type, so just
3439 * free the message. */
3440 requeue = 0;
3441 }
3442
3443 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3444 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3445 {
3446 /* It's an asyncronous event. */
3447 requeue = handle_read_event_rsp(intf, msg);
3448 } else {
3449 /* It's a response from the local BMC. */
3450 requeue = handle_bmc_rsp(intf, msg);
3451 }
3452
3453 out:
3454 return requeue;
3455}
3456
3457/* Handle a new message from the lower layer. */
3458void ipmi_smi_msg_received(ipmi_smi_t intf,
3459 struct ipmi_smi_msg *msg)
3460{
3461 unsigned long flags;
3462 int rv;
3463
3464
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 if ((msg->data_size >= 2)
3466 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3467 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003468 && (msg->user_data == NULL))
3469 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 /* This is the local response to a command send, start
3471 the timer for these. The user_data will not be
3472 NULL if this is a response send, and we will let
3473 response sends just go through. */
3474
3475 /* Check for errors, if we get certain errors (ones
3476 that mean basically we can try again later), we
3477 ignore them and start the timer. Otherwise we
3478 report the error immediately. */
3479 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3480 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
Corey Minyard46d52b02006-11-08 17:44:55 -08003481 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
3482 && (msg->rsp[2] != IPMI_BUS_ERR)
3483 && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 {
3485 int chan = msg->rsp[3] & 0xf;
3486
3487 /* Got an error sending the message, handle it. */
3488 spin_lock_irqsave(&intf->counter_lock, flags);
3489 if (chan >= IPMI_MAX_CHANNELS)
3490 ; /* This shouldn't happen */
3491 else if ((intf->channels[chan].medium
3492 == IPMI_CHANNEL_MEDIUM_8023LAN)
3493 || (intf->channels[chan].medium
3494 == IPMI_CHANNEL_MEDIUM_ASYNC))
3495 intf->sent_lan_command_errs++;
3496 else
3497 intf->sent_ipmb_command_errs++;
3498 spin_unlock_irqrestore(&intf->counter_lock, flags);
3499 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3500 } else {
3501 /* The message was sent, start the timer. */
3502 intf_start_seq_timer(intf, msg->msgid);
3503 }
3504
3505 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003506 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 }
3508
3509 /* To preserve message order, if the list is not empty, we
3510 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003511 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
3512 if (!list_empty(&intf->waiting_msgs)) {
3513 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003514 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003515 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003517 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
3519 rv = handle_new_recv_msg(intf, msg);
3520 if (rv > 0) {
3521 /* Could not handle the message now, just add it to a
3522 list to handle later. */
Hironobu Ishii177294d2005-11-11 08:12:21 -06003523 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003524 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003525 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 } else if (rv == 0) {
3527 ipmi_free_smi_msg(msg);
3528 }
3529
Corey Minyard393d2cc2005-11-07 00:59:54 -08003530 out:
3531 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532}
3533
3534void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3535{
3536 ipmi_user_t user;
3537
Corey Minyard393d2cc2005-11-07 00:59:54 -08003538 rcu_read_lock();
3539 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003540 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 continue;
3542
3543 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3544 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003545 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546}
3547
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548
Corey Minyard882fe012005-05-01 08:59:12 -07003549static struct ipmi_smi_msg *
3550smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3551 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552{
Corey Minyard882fe012005-05-01 08:59:12 -07003553 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 if (!smi_msg)
3555 /* If we can't allocate the message, then just return, we
3556 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003557 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
3559 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3560 smi_msg->data_size = recv_msg->msg.data_len;
3561 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3562
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563#ifdef DEBUG_MSGING
3564 {
3565 int m;
3566 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003567 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 printk(" %2.2x", smi_msg->data[m]);
3569 printk("\n");
3570 }
3571#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003572 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573}
3574
Corey Minyard393d2cc2005-11-07 00:59:54 -08003575static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3576 struct list_head *timeouts, long timeout_period,
3577 int slot, unsigned long *flags)
3578{
Corey Minyardb2c03942006-12-06 20:41:00 -08003579 struct ipmi_recv_msg *msg;
3580 struct ipmi_smi_handlers *handlers;
3581
3582 if (intf->intf_num == -1)
3583 return;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003584
3585 if (!ent->inuse)
3586 return;
3587
3588 ent->timeout -= timeout_period;
3589 if (ent->timeout > 0)
3590 return;
3591
3592 if (ent->retries_left == 0) {
3593 /* The message has used all its retries. */
3594 ent->inuse = 0;
3595 msg = ent->recv_msg;
3596 list_add_tail(&msg->link, timeouts);
3597 spin_lock(&intf->counter_lock);
3598 if (ent->broadcast)
3599 intf->timed_out_ipmb_broadcasts++;
3600 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3601 intf->timed_out_lan_commands++;
3602 else
3603 intf->timed_out_ipmb_commands++;
3604 spin_unlock(&intf->counter_lock);
3605 } else {
3606 struct ipmi_smi_msg *smi_msg;
3607 /* More retries, send again. */
3608
3609 /* Start with the max timer, set to normal
3610 timer after the message is sent. */
3611 ent->timeout = MAX_MSG_TIMEOUT;
3612 ent->retries_left--;
3613 spin_lock(&intf->counter_lock);
3614 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3615 intf->retransmitted_lan_commands++;
3616 else
3617 intf->retransmitted_ipmb_commands++;
3618 spin_unlock(&intf->counter_lock);
3619
3620 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3621 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003622 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003623 return;
3624
3625 spin_unlock_irqrestore(&intf->seq_lock, *flags);
Corey Minyardb2c03942006-12-06 20:41:00 -08003626
Corey Minyard393d2cc2005-11-07 00:59:54 -08003627 /* Send the new message. We send with a zero
3628 * priority. It timed out, I doubt time is
3629 * that critical now, and high priority
3630 * messages are really only for messages to the
3631 * local MC, which don't get resent. */
Corey Minyardb2c03942006-12-06 20:41:00 -08003632 handlers = intf->handlers;
3633 if (handlers)
3634 intf->handlers->sender(intf->send_info,
3635 smi_msg, 0);
3636 else
3637 ipmi_free_smi_msg(smi_msg);
3638
Corey Minyard393d2cc2005-11-07 00:59:54 -08003639 spin_lock_irqsave(&intf->seq_lock, *flags);
3640 }
3641}
3642
3643static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644{
3645 ipmi_smi_t intf;
3646 struct list_head timeouts;
3647 struct ipmi_recv_msg *msg, *msg2;
3648 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3649 unsigned long flags;
Corey Minyardbca03242006-12-06 20:40:57 -08003650 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651
3652 INIT_LIST_HEAD(&timeouts);
3653
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. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003674 spin_lock_irqsave(&intf->seq_lock, flags);
Corey Minyardbca03242006-12-06 20:40:57 -08003675 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
3676 check_msg_timeout(intf, &(intf->seq_table[i]),
3677 &timeouts, timeout_period, i,
Corey Minyard393d2cc2005-11-07 00:59:54 -08003678 &flags);
3679 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680
Corey Minyard393d2cc2005-11-07 00:59:54 -08003681 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08003682 deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE);
Corey Minyardb9675132006-12-06 20:41:02 -08003683
3684 /*
3685 * Maintenance mode handling. Check the timeout
3686 * optimistically before we claim the lock. It may
3687 * mean a timeout gets missed occasionally, but that
3688 * only means the timeout gets extended by one period
3689 * in that case. No big deal, and it avoids the lock
3690 * most of the time.
3691 */
3692 if (intf->auto_maintenance_timeout > 0) {
3693 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
3694 if (intf->auto_maintenance_timeout > 0) {
3695 intf->auto_maintenance_timeout
3696 -= timeout_period;
3697 if (!intf->maintenance_mode
3698 && (intf->auto_maintenance_timeout <= 0))
3699 {
3700 intf->maintenance_mode_enable = 0;
3701 maintenance_mode_update(intf);
3702 }
3703 }
3704 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
3705 flags);
3706 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 }
Corey Minyardbca03242006-12-06 20:40:57 -08003708 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709}
3710
3711static void ipmi_request_event(void)
3712{
Corey Minyardb2c03942006-12-06 20:41:00 -08003713 ipmi_smi_t intf;
3714 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715
Corey Minyardbca03242006-12-06 20:40:57 -08003716 rcu_read_lock();
Corey Minyardb2c03942006-12-06 20:41:00 -08003717 /* Called from the timer, no need to check if handlers is
3718 * valid. */
3719 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb9675132006-12-06 20:41:02 -08003720 /* No event requests when in maintenance mode. */
3721 if (intf->maintenance_mode_enable)
3722 continue;
3723
Corey Minyardb2c03942006-12-06 20:41:00 -08003724 handlers = intf->handlers;
3725 if (handlers)
3726 handlers->request_events(intf->send_info);
3727 }
Corey Minyardbca03242006-12-06 20:40:57 -08003728 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729}
3730
3731static struct timer_list ipmi_timer;
3732
3733/* Call every ~100 ms. */
3734#define IPMI_TIMEOUT_TIME 100
3735
3736/* How many jiffies does it take to get to the timeout time. */
3737#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3738
3739/* Request events from the queue every second (this is the number of
3740 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3741 future, IPMI will add a way to know immediately if an event is in
3742 the queue and this silliness can go away. */
3743#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3744
Corey Minyard8f43f842005-06-23 22:01:40 -07003745static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3747
3748static void ipmi_timeout(unsigned long data)
3749{
Corey Minyard8f43f842005-06-23 22:01:40 -07003750 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752
3753 ticks_to_req_ev--;
3754 if (ticks_to_req_ev == 0) {
3755 ipmi_request_event();
3756 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3757 }
3758
3759 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3760
Corey Minyard8f43f842005-06-23 22:01:40 -07003761 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762}
3763
3764
3765static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3766static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3767
3768/* FIXME - convert these to slabs. */
3769static void free_smi_msg(struct ipmi_smi_msg *msg)
3770{
3771 atomic_dec(&smi_msg_inuse_count);
3772 kfree(msg);
3773}
3774
3775struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3776{
3777 struct ipmi_smi_msg *rv;
3778 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3779 if (rv) {
3780 rv->done = free_smi_msg;
3781 rv->user_data = NULL;
3782 atomic_inc(&smi_msg_inuse_count);
3783 }
3784 return rv;
3785}
3786
3787static void free_recv_msg(struct ipmi_recv_msg *msg)
3788{
3789 atomic_dec(&recv_msg_inuse_count);
3790 kfree(msg);
3791}
3792
3793struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3794{
3795 struct ipmi_recv_msg *rv;
3796
3797 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3798 if (rv) {
Corey Minyarda9eec552006-08-31 21:27:45 -07003799 rv->user = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 rv->done = free_recv_msg;
3801 atomic_inc(&recv_msg_inuse_count);
3802 }
3803 return rv;
3804}
3805
Corey Minyard393d2cc2005-11-07 00:59:54 -08003806void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3807{
3808 if (msg->user)
3809 kref_put(&msg->user->refcount, free_user);
3810 msg->done(msg);
3811}
3812
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813#ifdef CONFIG_IPMI_PANIC_EVENT
3814
3815static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3816{
3817}
3818
3819static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3820{
3821}
3822
3823#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003824static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003826 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3827 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3828 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3829 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830 {
3831 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003832 intf->event_receiver = msg->msg.data[1];
3833 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 }
3835}
3836
Corey Minyard56a55ec2005-09-06 15:18:42 -07003837static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003839 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3840 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3841 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3842 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 {
3844 /* A get device id command, save if we are an event
3845 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003846 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3847 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 }
3849}
3850#endif
3851
3852static void send_panic_events(char *str)
3853{
3854 struct kernel_ipmi_msg msg;
3855 ipmi_smi_t intf;
3856 unsigned char data[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 struct ipmi_system_interface_addr *si;
3858 struct ipmi_addr addr;
3859 struct ipmi_smi_msg smi_msg;
3860 struct ipmi_recv_msg recv_msg;
3861
3862 si = (struct ipmi_system_interface_addr *) &addr;
3863 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3864 si->channel = IPMI_BMC_CHANNEL;
3865 si->lun = 0;
3866
3867 /* Fill in an event telling that we have failed. */
3868 msg.netfn = 0x04; /* Sensor or Event. */
3869 msg.cmd = 2; /* Platform event command. */
3870 msg.data = data;
3871 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003872 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 data[1] = 0x03; /* This is for IPMI 1.0. */
3874 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3875 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3876 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3877
3878 /* Put a few breadcrumbs in. Hopefully later we can add more things
3879 to make the panic events more useful. */
3880 if (str) {
3881 data[3] = str[0];
3882 data[6] = str[1];
3883 data[7] = str[2];
3884 }
3885
3886 smi_msg.done = dummy_smi_done_handler;
3887 recv_msg.done = dummy_recv_done_handler;
3888
3889 /* For every registered interface, send the event. */
Corey Minyardbca03242006-12-06 20:40:57 -08003890 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08003891 if (!intf->handlers)
3892 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 continue;
3894
3895 /* Send the event announcing the panic. */
3896 intf->handlers->set_run_to_completion(intf->send_info, 1);
3897 i_ipmi_request(NULL,
3898 intf,
3899 &addr,
3900 0,
3901 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003902 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 &smi_msg,
3904 &recv_msg,
3905 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003906 intf->channels[0].address,
3907 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 0, 1); /* Don't retry, and don't wait. */
3909 }
3910
3911#ifdef CONFIG_IPMI_PANIC_STRING
3912 /* On every interface, dump a bunch of OEM event holding the
3913 string. */
3914 if (!str)
3915 return;
3916
Corey Minyardbca03242006-12-06 20:40:57 -08003917 /* For every registered interface, send the event. */
3918 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 char *p = str;
3920 struct ipmi_ipmb_addr *ipmb;
3921 int j;
3922
Corey Minyardbca03242006-12-06 20:40:57 -08003923 if (intf->intf_num == -1)
3924 /* Interface was not ready yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 continue;
3926
3927 /* First job here is to figure out where to send the
3928 OEM events. There's no way in IPMI to send OEM
3929 events using an event send command, so we have to
3930 find the SEL to put them in and stick them in
3931 there. */
3932
3933 /* Get capabilities from the get device id. */
3934 intf->local_sel_device = 0;
3935 intf->local_event_generator = 0;
3936 intf->event_receiver = 0;
3937
3938 /* Request the device info from the local MC. */
3939 msg.netfn = IPMI_NETFN_APP_REQUEST;
3940 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3941 msg.data = NULL;
3942 msg.data_len = 0;
3943 intf->null_user_handler = device_id_fetcher;
3944 i_ipmi_request(NULL,
3945 intf,
3946 &addr,
3947 0,
3948 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003949 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 &smi_msg,
3951 &recv_msg,
3952 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003953 intf->channels[0].address,
3954 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 0, 1); /* Don't retry, and don't wait. */
3956
3957 if (intf->local_event_generator) {
3958 /* Request the event receiver from the local MC. */
3959 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3960 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3961 msg.data = NULL;
3962 msg.data_len = 0;
3963 intf->null_user_handler = event_receiver_fetcher;
3964 i_ipmi_request(NULL,
3965 intf,
3966 &addr,
3967 0,
3968 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003969 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 &smi_msg,
3971 &recv_msg,
3972 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003973 intf->channels[0].address,
3974 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 0, 1); /* no retry, and no wait. */
3976 }
3977 intf->null_user_handler = NULL;
3978
3979 /* Validate the event receiver. The low bit must not
3980 be 1 (it must be a valid IPMB address), it cannot
3981 be zero, and it must not be my address. */
3982 if (((intf->event_receiver & 1) == 0)
3983 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003984 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 {
3986 /* The event receiver is valid, send an IPMB
3987 message. */
3988 ipmb = (struct ipmi_ipmb_addr *) &addr;
3989 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3990 ipmb->channel = 0; /* FIXME - is this right? */
3991 ipmb->lun = intf->event_receiver_lun;
3992 ipmb->slave_addr = intf->event_receiver;
3993 } else if (intf->local_sel_device) {
3994 /* The event receiver was not valid (or was
3995 me), but I am an SEL device, just dump it
3996 in my SEL. */
3997 si = (struct ipmi_system_interface_addr *) &addr;
3998 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3999 si->channel = IPMI_BMC_CHANNEL;
4000 si->lun = 0;
4001 } else
4002 continue; /* No where to send the event. */
4003
4004
4005 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
4006 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
4007 msg.data = data;
4008 msg.data_len = 16;
4009
4010 j = 0;
4011 while (*p) {
4012 int size = strlen(p);
4013
4014 if (size > 11)
4015 size = 11;
4016 data[0] = 0;
4017 data[1] = 0;
4018 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07004019 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 data[4] = j++; /* sequence # */
4021 /* Always give 11 bytes, so strncpy will fill
4022 it with zeroes for me. */
4023 strncpy(data+5, p, 11);
4024 p += size;
4025
4026 i_ipmi_request(NULL,
4027 intf,
4028 &addr,
4029 0,
4030 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07004031 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 &smi_msg,
4033 &recv_msg,
4034 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07004035 intf->channels[0].address,
4036 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 0, 1); /* no retry, and no wait. */
4038 }
4039 }
4040#endif /* CONFIG_IPMI_PANIC_STRING */
4041}
4042#endif /* CONFIG_IPMI_PANIC_EVENT */
4043
Lee Revellf18190b2006-06-26 18:30:00 +02004044static int has_panicked = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045
4046static int panic_event(struct notifier_block *this,
4047 unsigned long event,
4048 void *ptr)
4049{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 ipmi_smi_t intf;
4051
Lee Revellf18190b2006-06-26 18:30:00 +02004052 if (has_panicked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 return NOTIFY_DONE;
Lee Revellf18190b2006-06-26 18:30:00 +02004054 has_panicked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055
4056 /* For every registered interface, set it to run to completion. */
Corey Minyardbca03242006-12-06 20:40:57 -08004057 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08004058 if (!intf->handlers)
4059 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 continue;
4061
4062 intf->handlers->set_run_to_completion(intf->send_info, 1);
4063 }
4064
4065#ifdef CONFIG_IPMI_PANIC_EVENT
4066 send_panic_events(ptr);
4067#endif
4068
4069 return NOTIFY_DONE;
4070}
4071
4072static struct notifier_block panic_block = {
4073 .notifier_call = panic_event,
4074 .next = NULL,
4075 .priority = 200 /* priority: INT_MAX >= x >= 0 */
4076};
4077
4078static int ipmi_init_msghandler(void)
4079{
Corey Minyard50c812b2006-03-26 01:37:21 -08004080 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081
4082 if (initialized)
4083 return 0;
4084
Corey Minyard50c812b2006-03-26 01:37:21 -08004085 rv = driver_register(&ipmidriver);
4086 if (rv) {
4087 printk(KERN_ERR PFX "Could not register IPMI driver\n");
4088 return rv;
4089 }
4090
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004092 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093
Corey Minyard3b625942005-06-23 22:01:42 -07004094#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 proc_ipmi_root = proc_mkdir("ipmi", NULL);
4096 if (!proc_ipmi_root) {
4097 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
4098 return -ENOMEM;
4099 }
4100
4101 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07004102#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103
Corey Minyard409035e2006-06-28 04:26:53 -07004104 setup_timer(&ipmi_timer, ipmi_timeout, 0);
4105 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106
Alan Sterne041c682006-03-27 01:16:30 -08004107 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108
4109 initialized = 1;
4110
4111 return 0;
4112}
4113
4114static __init int ipmi_init_msghandler_mod(void)
4115{
4116 ipmi_init_msghandler();
4117 return 0;
4118}
4119
4120static __exit void cleanup_ipmi(void)
4121{
4122 int count;
4123
4124 if (!initialized)
4125 return;
4126
Alan Sterne041c682006-03-27 01:16:30 -08004127 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128
4129 /* This can't be called if any interfaces exist, so no worry about
4130 shutting down the interfaces. */
4131
4132 /* Tell the timer to stop, then wait for it to stop. This avoids
4133 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07004134 atomic_inc(&stop_operation);
4135 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136
Corey Minyard3b625942005-06-23 22:01:42 -07004137#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 remove_proc_entry(proc_ipmi_root->name, &proc_root);
Corey Minyard3b625942005-06-23 22:01:42 -07004139#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140
Corey Minyard50c812b2006-03-26 01:37:21 -08004141 driver_unregister(&ipmidriver);
4142
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 initialized = 0;
4144
4145 /* Check for buffer leaks. */
4146 count = atomic_read(&smi_msg_inuse_count);
4147 if (count != 0)
4148 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
4149 count);
4150 count = atomic_read(&recv_msg_inuse_count);
4151 if (count != 0)
4152 printk(KERN_WARNING PFX "recv message count %d at exit\n",
4153 count);
4154}
4155module_exit(cleanup_ipmi);
4156
4157module_init(ipmi_init_msghandler_mod);
4158MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004159MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
4160MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
4161MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162
4163EXPORT_SYMBOL(ipmi_create_user);
4164EXPORT_SYMBOL(ipmi_destroy_user);
4165EXPORT_SYMBOL(ipmi_get_version);
4166EXPORT_SYMBOL(ipmi_request_settime);
4167EXPORT_SYMBOL(ipmi_request_supply_msgs);
4168EXPORT_SYMBOL(ipmi_register_smi);
4169EXPORT_SYMBOL(ipmi_unregister_smi);
4170EXPORT_SYMBOL(ipmi_register_for_cmd);
4171EXPORT_SYMBOL(ipmi_unregister_for_cmd);
4172EXPORT_SYMBOL(ipmi_smi_msg_received);
4173EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
4174EXPORT_SYMBOL(ipmi_alloc_smi_msg);
4175EXPORT_SYMBOL(ipmi_addr_length);
4176EXPORT_SYMBOL(ipmi_validate_addr);
4177EXPORT_SYMBOL(ipmi_set_gets_events);
4178EXPORT_SYMBOL(ipmi_smi_watcher_register);
4179EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
4180EXPORT_SYMBOL(ipmi_set_my_address);
4181EXPORT_SYMBOL(ipmi_get_my_address);
4182EXPORT_SYMBOL(ipmi_set_my_LUN);
4183EXPORT_SYMBOL(ipmi_get_my_LUN);
4184EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08004186EXPORT_SYMBOL(ipmi_free_recv_msg);