blob: c1d06ba449b60455fcffdeb908fca20f4952df8d [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
34#include <linux/config.h>
35#include <linux/module.h>
36#include <linux/errno.h>
37#include <asm/system.h>
38#include <linux/sched.h>
39#include <linux/poll.h>
40#include <linux/spinlock.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
51#define IPMI_DRIVER_VERSION "36.0"
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
59struct proc_dir_entry *proc_ipmi_root = NULL;
60#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62#define MAX_EVENTS_IN_QUEUE 25
63
64/* Don't let a message sit in a queue forever, always time it with at lest
65 the max message timer. This is in milliseconds. */
66#define MAX_MSG_TIMEOUT 60000
67
Corey Minyard393d2cc2005-11-07 00:59:54 -080068
69/*
70 * The main "user" data structure.
71 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070072struct ipmi_user
73{
74 struct list_head link;
75
Corey Minyard393d2cc2005-11-07 00:59:54 -080076 /* Set to "0" when the user is destroyed. */
77 int valid;
78
79 struct kref refcount;
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 /* The upper layer that handles receive messages. */
82 struct ipmi_user_hndl *handler;
83 void *handler_data;
84
85 /* The interface this user is bound to. */
86 ipmi_smi_t intf;
87
88 /* Does this interface receive IPMI events? */
89 int gets_events;
90};
91
92struct cmd_rcvr
93{
94 struct list_head link;
95
96 ipmi_user_t user;
97 unsigned char netfn;
98 unsigned char cmd;
Corey Minyard393d2cc2005-11-07 00:59:54 -080099
100 /*
101 * This is used to form a linked lised during mass deletion.
102 * Since this is in an RCU list, we cannot use the link above
103 * or change any data until the RCU period completes. So we
104 * use this next variable during mass deletion so we can have
105 * a list and don't have to wait and restart the search on
106 * every individual deletion of a command. */
107 struct cmd_rcvr *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
110struct seq_table
111{
112 unsigned int inuse : 1;
113 unsigned int broadcast : 1;
114
115 unsigned long timeout;
116 unsigned long orig_timeout;
117 unsigned int retries_left;
118
119 /* To verify on an incoming send message response that this is
120 the message that the response is for, we keep a sequence id
121 and increment it every time we send a message. */
122 long seqid;
123
124 /* This is held so we can properly respond to the message on a
125 timeout, and it is used to hold the temporary data for
126 retransmission, too. */
127 struct ipmi_recv_msg *recv_msg;
128};
129
130/* Store the information in a msgid (long) to allow us to find a
131 sequence table entry from the msgid. */
132#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
133
134#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
135 do { \
136 seq = ((msgid >> 26) & 0x3f); \
137 seqid = (msgid & 0x3fffff); \
Corey Minyarde8b33612005-09-06 15:18:45 -0700138 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
141
142struct ipmi_channel
143{
144 unsigned char medium;
145 unsigned char protocol;
Corey Minyardc14979b2005-09-06 15:18:38 -0700146
147 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
148 but may be changed by the user. */
149 unsigned char address;
150
151 /* My LUN. This should generally stay the SMS LUN, but just in
152 case... */
153 unsigned char lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154};
155
Corey Minyard3b625942005-06-23 22:01:42 -0700156#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157struct ipmi_proc_entry
158{
159 char *name;
160 struct ipmi_proc_entry *next;
161};
Corey Minyard3b625942005-06-23 22:01:42 -0700162#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164#define IPMI_IPMB_NUM_SEQ 64
Corey Minyardc14979b2005-09-06 15:18:38 -0700165#define IPMI_MAX_CHANNELS 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166struct ipmi_smi
167{
168 /* What interface number are we? */
169 int intf_num;
170
Corey Minyard393d2cc2005-11-07 00:59:54 -0800171 struct kref refcount;
172
173 /* The list of upper layers that are using me. seq_lock
174 * protects this. */
175 struct list_head users;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177 /* Used for wake ups at startup. */
178 wait_queue_head_t waitq;
179
180 /* The IPMI version of the BMC on the other end. */
181 unsigned char version_major;
182 unsigned char version_minor;
183
184 /* This is the lower-layer's sender routine. */
185 struct ipmi_smi_handlers *handlers;
186 void *send_info;
187
Corey Minyard3b625942005-06-23 22:01:42 -0700188#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 /* A list of proc entries for this interface. This does not
190 need a lock, only one thread creates it and only one thread
191 destroys it. */
Corey Minyard3b625942005-06-23 22:01:42 -0700192 spinlock_t proc_entry_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 struct ipmi_proc_entry *proc_entries;
Corey Minyard3b625942005-06-23 22:01:42 -0700194#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196 /* A table of sequence numbers for this interface. We use the
197 sequence numbers for IPMB messages that go out of the
198 interface to match them up with their responses. A routine
199 is called periodically to time the items in this list. */
200 spinlock_t seq_lock;
201 struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
202 int curr_seq;
203
204 /* Messages that were delayed for some reason (out of memory,
205 for instance), will go in here to be processed later in a
206 periodic timer interrupt. */
207 spinlock_t waiting_msgs_lock;
208 struct list_head waiting_msgs;
209
210 /* The list of command receivers that are registered for commands
211 on this interface. */
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800212 struct semaphore cmd_rcvrs_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 struct list_head cmd_rcvrs;
214
215 /* Events that were queues because no one was there to receive
216 them. */
217 spinlock_t events_lock; /* For dealing with event stuff. */
218 struct list_head waiting_events;
219 unsigned int waiting_events_count; /* How many events in queue? */
220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 /* The event receiver for my BMC, only really used at panic
222 shutdown as a place to store this. */
223 unsigned char event_receiver;
224 unsigned char event_receiver_lun;
225 unsigned char local_sel_device;
226 unsigned char local_event_generator;
227
228 /* A cheap hack, if this is non-null and a message to an
229 interface comes in with a NULL user, call this routine with
230 it. Note that the message will still be freed by the
231 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700232 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
234 /* When we are scanning the channels for an SMI, this will
235 tell which channel we are scanning. */
236 int curr_channel;
237
238 /* Channel information */
239 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
240
241 /* Proc FS stuff. */
242 struct proc_dir_entry *proc_dir;
243 char proc_dir_name[10];
244
245 spinlock_t counter_lock; /* For making counters atomic. */
246
247 /* Commands we got that were invalid. */
248 unsigned int sent_invalid_commands;
249
250 /* Commands we sent to the MC. */
251 unsigned int sent_local_commands;
252 /* Responses from the MC that were delivered to a user. */
253 unsigned int handled_local_responses;
254 /* Responses from the MC that were not delivered to a user. */
255 unsigned int unhandled_local_responses;
256
257 /* Commands we sent out to the IPMB bus. */
258 unsigned int sent_ipmb_commands;
259 /* Commands sent on the IPMB that had errors on the SEND CMD */
260 unsigned int sent_ipmb_command_errs;
261 /* Each retransmit increments this count. */
262 unsigned int retransmitted_ipmb_commands;
263 /* When a message times out (runs out of retransmits) this is
264 incremented. */
265 unsigned int timed_out_ipmb_commands;
266
267 /* This is like above, but for broadcasts. Broadcasts are
268 *not* included in the above count (they are expected to
269 time out). */
270 unsigned int timed_out_ipmb_broadcasts;
271
272 /* Responses I have sent to the IPMB bus. */
273 unsigned int sent_ipmb_responses;
274
275 /* The response was delivered to the user. */
276 unsigned int handled_ipmb_responses;
277 /* The response had invalid data in it. */
278 unsigned int invalid_ipmb_responses;
279 /* The response didn't have anyone waiting for it. */
280 unsigned int unhandled_ipmb_responses;
281
282 /* Commands we sent out to the IPMB bus. */
283 unsigned int sent_lan_commands;
284 /* Commands sent on the IPMB that had errors on the SEND CMD */
285 unsigned int sent_lan_command_errs;
286 /* Each retransmit increments this count. */
287 unsigned int retransmitted_lan_commands;
288 /* When a message times out (runs out of retransmits) this is
289 incremented. */
290 unsigned int timed_out_lan_commands;
291
292 /* Responses I have sent to the IPMB bus. */
293 unsigned int sent_lan_responses;
294
295 /* The response was delivered to the user. */
296 unsigned int handled_lan_responses;
297 /* The response had invalid data in it. */
298 unsigned int invalid_lan_responses;
299 /* The response didn't have anyone waiting for it. */
300 unsigned int unhandled_lan_responses;
301
302 /* The command was delivered to the user. */
303 unsigned int handled_commands;
304 /* The command had invalid data in it. */
305 unsigned int invalid_commands;
306 /* The command didn't have anyone waiting for it. */
307 unsigned int unhandled_commands;
308
309 /* Invalid data in an event. */
310 unsigned int invalid_events;
311 /* Events that were received with the proper format. */
312 unsigned int events;
313};
314
Corey Minyard393d2cc2005-11-07 00:59:54 -0800315/* Used to mark an interface entry that cannot be used but is not a
316 * free entry, either, primarily used at creation and deletion time so
317 * a slot doesn't get reused too quickly. */
318#define IPMI_INVALID_INTERFACE_ENTRY ((ipmi_smi_t) ((long) 1))
319#define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \
320 || (i == IPMI_INVALID_INTERFACE_ENTRY))
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322#define MAX_IPMI_INTERFACES 4
323static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
324
Corey Minyard393d2cc2005-11-07 00:59:54 -0800325/* Directly protects the ipmi_interfaces data structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326static DEFINE_SPINLOCK(interfaces_lock);
327
328/* List of watchers that want to know when smi's are added and
329 deleted. */
330static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
331static DECLARE_RWSEM(smi_watchers_sem);
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Corey Minyard393d2cc2005-11-07 00:59:54 -0800334static void free_recv_msg_list(struct list_head *q)
335{
336 struct ipmi_recv_msg *msg, *msg2;
337
338 list_for_each_entry_safe(msg, msg2, q, link) {
339 list_del(&msg->link);
340 ipmi_free_recv_msg(msg);
341 }
342}
343
344static void clean_up_interface_data(ipmi_smi_t intf)
345{
346 int i;
347 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800348 struct list_head list;
349
350 free_recv_msg_list(&intf->waiting_msgs);
351 free_recv_msg_list(&intf->waiting_events);
352
353 /* Wholesale remove all the entries from the list in the
354 * interface and wait for RCU to know that none are in use. */
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800355 down(&intf->cmd_rcvrs_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800356 list_add_rcu(&list, &intf->cmd_rcvrs);
357 list_del_rcu(&intf->cmd_rcvrs);
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800358 up(&intf->cmd_rcvrs_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800359 synchronize_rcu();
360
361 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
362 kfree(rcvr);
363
364 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
365 if ((intf->seq_table[i].inuse)
366 && (intf->seq_table[i].recv_msg))
367 {
368 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 }
370 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800371}
372
373static void intf_free(struct kref *ref)
374{
375 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
376
377 clean_up_interface_data(intf);
378 kfree(intf);
379}
380
381int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
382{
383 int i;
384 unsigned long flags;
385
386 down_write(&smi_watchers_sem);
387 list_add(&(watcher->link), &smi_watchers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 up_write(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800389 spin_lock_irqsave(&interfaces_lock, flags);
390 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
391 ipmi_smi_t intf = ipmi_interfaces[i];
392 if (IPMI_INVALID_INTERFACE(intf))
393 continue;
394 spin_unlock_irqrestore(&interfaces_lock, flags);
395 watcher->new_smi(i);
396 spin_lock_irqsave(&interfaces_lock, flags);
397 }
398 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 return 0;
400}
401
402int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
403{
404 down_write(&smi_watchers_sem);
405 list_del(&(watcher->link));
406 up_write(&smi_watchers_sem);
407 return 0;
408}
409
410static void
411call_smi_watchers(int i)
412{
413 struct ipmi_smi_watcher *w;
414
415 down_read(&smi_watchers_sem);
416 list_for_each_entry(w, &smi_watchers, link) {
417 if (try_module_get(w->owner)) {
418 w->new_smi(i);
419 module_put(w->owner);
420 }
421 }
422 up_read(&smi_watchers_sem);
423}
424
425static int
426ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
427{
428 if (addr1->addr_type != addr2->addr_type)
429 return 0;
430
431 if (addr1->channel != addr2->channel)
432 return 0;
433
434 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
435 struct ipmi_system_interface_addr *smi_addr1
436 = (struct ipmi_system_interface_addr *) addr1;
437 struct ipmi_system_interface_addr *smi_addr2
438 = (struct ipmi_system_interface_addr *) addr2;
439 return (smi_addr1->lun == smi_addr2->lun);
440 }
441
442 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
443 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
444 {
445 struct ipmi_ipmb_addr *ipmb_addr1
446 = (struct ipmi_ipmb_addr *) addr1;
447 struct ipmi_ipmb_addr *ipmb_addr2
448 = (struct ipmi_ipmb_addr *) addr2;
449
450 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
451 && (ipmb_addr1->lun == ipmb_addr2->lun));
452 }
453
454 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
455 struct ipmi_lan_addr *lan_addr1
456 = (struct ipmi_lan_addr *) addr1;
457 struct ipmi_lan_addr *lan_addr2
458 = (struct ipmi_lan_addr *) addr2;
459
460 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
461 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
462 && (lan_addr1->session_handle
463 == lan_addr2->session_handle)
464 && (lan_addr1->lun == lan_addr2->lun));
465 }
466
467 return 1;
468}
469
470int ipmi_validate_addr(struct ipmi_addr *addr, int len)
471{
472 if (len < sizeof(struct ipmi_system_interface_addr)) {
473 return -EINVAL;
474 }
475
476 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
477 if (addr->channel != IPMI_BMC_CHANNEL)
478 return -EINVAL;
479 return 0;
480 }
481
482 if ((addr->channel == IPMI_BMC_CHANNEL)
483 || (addr->channel >= IPMI_NUM_CHANNELS)
484 || (addr->channel < 0))
485 return -EINVAL;
486
487 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
488 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
489 {
490 if (len < sizeof(struct ipmi_ipmb_addr)) {
491 return -EINVAL;
492 }
493 return 0;
494 }
495
496 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
497 if (len < sizeof(struct ipmi_lan_addr)) {
498 return -EINVAL;
499 }
500 return 0;
501 }
502
503 return -EINVAL;
504}
505
506unsigned int ipmi_addr_length(int addr_type)
507{
508 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
509 return sizeof(struct ipmi_system_interface_addr);
510
511 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
512 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
513 {
514 return sizeof(struct ipmi_ipmb_addr);
515 }
516
517 if (addr_type == IPMI_LAN_ADDR_TYPE)
518 return sizeof(struct ipmi_lan_addr);
519
520 return 0;
521}
522
523static void deliver_response(struct ipmi_recv_msg *msg)
524{
Corey Minyard56a55ec2005-09-06 15:18:42 -0700525 if (! msg->user) {
526 ipmi_smi_t intf = msg->user_msg_data;
527 unsigned long flags;
528
529 /* Special handling for NULL users. */
530 if (intf->null_user_handler) {
531 intf->null_user_handler(intf, msg);
532 spin_lock_irqsave(&intf->counter_lock, flags);
533 intf->handled_local_responses++;
534 spin_unlock_irqrestore(&intf->counter_lock, flags);
535 } else {
536 /* No handler, so give up. */
537 spin_lock_irqsave(&intf->counter_lock, flags);
538 intf->unhandled_local_responses++;
539 spin_unlock_irqrestore(&intf->counter_lock, flags);
540 }
541 ipmi_free_recv_msg(msg);
542 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800543 ipmi_user_t user = msg->user;
544 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546}
547
548/* Find the next sequence number not being used and add the given
549 message with the given timeout to the sequence table. This must be
550 called with the interface's seq_lock held. */
551static int intf_next_seq(ipmi_smi_t intf,
552 struct ipmi_recv_msg *recv_msg,
553 unsigned long timeout,
554 int retries,
555 int broadcast,
556 unsigned char *seq,
557 long *seqid)
558{
559 int rv = 0;
560 unsigned int i;
561
Corey Minyarde8b33612005-09-06 15:18:45 -0700562 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700564 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 {
566 if (! intf->seq_table[i].inuse)
567 break;
568 }
569
570 if (! intf->seq_table[i].inuse) {
571 intf->seq_table[i].recv_msg = recv_msg;
572
573 /* Start with the maximum timeout, when the send response
574 comes in we will start the real timer. */
575 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
576 intf->seq_table[i].orig_timeout = timeout;
577 intf->seq_table[i].retries_left = retries;
578 intf->seq_table[i].broadcast = broadcast;
579 intf->seq_table[i].inuse = 1;
580 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
581 *seq = i;
582 *seqid = intf->seq_table[i].seqid;
583 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
584 } else {
585 rv = -EAGAIN;
586 }
587
588 return rv;
589}
590
591/* Return the receive message for the given sequence number and
592 release the sequence number so it can be reused. Some other data
593 is passed in to be sure the message matches up correctly (to help
594 guard against message coming in after their timeout and the
595 sequence number being reused). */
596static int intf_find_seq(ipmi_smi_t intf,
597 unsigned char seq,
598 short channel,
599 unsigned char cmd,
600 unsigned char netfn,
601 struct ipmi_addr *addr,
602 struct ipmi_recv_msg **recv_msg)
603{
604 int rv = -ENODEV;
605 unsigned long flags;
606
607 if (seq >= IPMI_IPMB_NUM_SEQ)
608 return -EINVAL;
609
610 spin_lock_irqsave(&(intf->seq_lock), flags);
611 if (intf->seq_table[seq].inuse) {
612 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
613
614 if ((msg->addr.channel == channel)
615 && (msg->msg.cmd == cmd)
616 && (msg->msg.netfn == netfn)
617 && (ipmi_addr_equal(addr, &(msg->addr))))
618 {
619 *recv_msg = msg;
620 intf->seq_table[seq].inuse = 0;
621 rv = 0;
622 }
623 }
624 spin_unlock_irqrestore(&(intf->seq_lock), flags);
625
626 return rv;
627}
628
629
630/* Start the timer for a specific sequence table entry. */
631static int intf_start_seq_timer(ipmi_smi_t intf,
632 long msgid)
633{
634 int rv = -ENODEV;
635 unsigned long flags;
636 unsigned char seq;
637 unsigned long seqid;
638
639
640 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
641
642 spin_lock_irqsave(&(intf->seq_lock), flags);
643 /* We do this verification because the user can be deleted
644 while a message is outstanding. */
645 if ((intf->seq_table[seq].inuse)
646 && (intf->seq_table[seq].seqid == seqid))
647 {
648 struct seq_table *ent = &(intf->seq_table[seq]);
649 ent->timeout = ent->orig_timeout;
650 rv = 0;
651 }
652 spin_unlock_irqrestore(&(intf->seq_lock), flags);
653
654 return rv;
655}
656
657/* Got an error for the send message for a specific sequence number. */
658static int intf_err_seq(ipmi_smi_t intf,
659 long msgid,
660 unsigned int err)
661{
662 int rv = -ENODEV;
663 unsigned long flags;
664 unsigned char seq;
665 unsigned long seqid;
666 struct ipmi_recv_msg *msg = NULL;
667
668
669 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
670
671 spin_lock_irqsave(&(intf->seq_lock), flags);
672 /* We do this verification because the user can be deleted
673 while a message is outstanding. */
674 if ((intf->seq_table[seq].inuse)
675 && (intf->seq_table[seq].seqid == seqid))
676 {
677 struct seq_table *ent = &(intf->seq_table[seq]);
678
679 ent->inuse = 0;
680 msg = ent->recv_msg;
681 rv = 0;
682 }
683 spin_unlock_irqrestore(&(intf->seq_lock), flags);
684
685 if (msg) {
686 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
687 msg->msg_data[0] = err;
688 msg->msg.netfn |= 1; /* Convert to a response. */
689 msg->msg.data_len = 1;
690 msg->msg.data = msg->msg_data;
691 deliver_response(msg);
692 }
693
694 return rv;
695}
696
697
698int ipmi_create_user(unsigned int if_num,
699 struct ipmi_user_hndl *handler,
700 void *handler_data,
701 ipmi_user_t *user)
702{
703 unsigned long flags;
704 ipmi_user_t new_user;
705 int rv = 0;
706 ipmi_smi_t intf;
707
708 /* There is no module usecount here, because it's not
709 required. Since this can only be used by and called from
710 other modules, they will implicitly use this module, and
711 thus this can't be removed unless the other modules are
712 removed. */
713
714 if (handler == NULL)
715 return -EINVAL;
716
717 /* Make sure the driver is actually initialized, this handles
718 problems with initialization order. */
719 if (!initialized) {
720 rv = ipmi_init_msghandler();
721 if (rv)
722 return rv;
723
724 /* The init code doesn't return an error if it was turned
725 off, but it won't initialize. Check that. */
726 if (!initialized)
727 return -ENODEV;
728 }
729
730 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
731 if (! new_user)
732 return -ENOMEM;
733
Corey Minyard393d2cc2005-11-07 00:59:54 -0800734 spin_lock_irqsave(&interfaces_lock, flags);
735 intf = ipmi_interfaces[if_num];
736 if ((if_num >= MAX_IPMI_INTERFACES) || IPMI_INVALID_INTERFACE(intf)) {
737 spin_unlock_irqrestore(&interfaces_lock, flags);
738 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 }
740
Corey Minyard393d2cc2005-11-07 00:59:54 -0800741 /* Note that each existing user holds a refcount to the interface. */
742 kref_get(&intf->refcount);
743 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
Corey Minyard393d2cc2005-11-07 00:59:54 -0800745 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 new_user->handler = handler;
747 new_user->handler_data = handler_data;
748 new_user->intf = intf;
749 new_user->gets_events = 0;
750
751 if (!try_module_get(intf->handlers->owner)) {
752 rv = -ENODEV;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800753 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 }
755
756 if (intf->handlers->inc_usecount) {
757 rv = intf->handlers->inc_usecount(intf->send_info);
758 if (rv) {
759 module_put(intf->handlers->owner);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800760 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 }
762 }
763
Corey Minyard393d2cc2005-11-07 00:59:54 -0800764 new_user->valid = 1;
765 spin_lock_irqsave(&intf->seq_lock, flags);
766 list_add_rcu(&new_user->link, &intf->users);
767 spin_unlock_irqrestore(&intf->seq_lock, flags);
768 *user = new_user;
769 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Corey Minyard393d2cc2005-11-07 00:59:54 -0800771 out_err:
772 kfree(new_user);
773 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 return rv;
775}
776
Corey Minyard393d2cc2005-11-07 00:59:54 -0800777static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800779 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781}
782
783int ipmi_destroy_user(ipmi_user_t user)
784{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800785 int rv = -ENODEV;
786 ipmi_smi_t intf = user->intf;
787 int i;
788 unsigned long flags;
789 struct cmd_rcvr *rcvr;
790 struct list_head *entry1, *entry2;
791 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
Corey Minyard393d2cc2005-11-07 00:59:54 -0800793 user->valid = 1;
794
795 /* Remove the user from the interface's sequence table. */
796 spin_lock_irqsave(&intf->seq_lock, flags);
797 list_del_rcu(&user->link);
798
799 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
800 if (intf->seq_table[i].inuse
801 && (intf->seq_table[i].recv_msg->user == user))
802 {
803 intf->seq_table[i].inuse = 0;
804 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800806 spin_unlock_irqrestore(&intf->seq_lock, flags);
807
808 /*
809 * Remove the user from the command receiver's table. First
810 * we build a list of everything (not using the standard link,
811 * since other things may be using it till we do
812 * synchronize_rcu()) then free everything in that list.
813 */
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800814 down(&intf->cmd_rcvrs_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800815 list_for_each_safe_rcu(entry1, entry2, &intf->cmd_rcvrs) {
816 rcvr = list_entry(entry1, struct cmd_rcvr, link);
817 if (rcvr->user == user) {
818 list_del_rcu(&rcvr->link);
819 rcvr->next = rcvrs;
820 rcvrs = rcvr;
821 }
822 }
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800823 up(&intf->cmd_rcvrs_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800824 synchronize_rcu();
825 while (rcvrs) {
826 rcvr = rcvrs;
827 rcvrs = rcvr->next;
828 kfree(rcvr);
829 }
830
831 module_put(intf->handlers->owner);
832 if (intf->handlers->dec_usecount)
833 intf->handlers->dec_usecount(intf->send_info);
834
835 kref_put(&intf->refcount, intf_free);
836
837 kref_put(&user->refcount, free_user);
838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 return rv;
840}
841
842void ipmi_get_version(ipmi_user_t user,
843 unsigned char *major,
844 unsigned char *minor)
845{
846 *major = user->intf->version_major;
847 *minor = user->intf->version_minor;
848}
849
Corey Minyardc14979b2005-09-06 15:18:38 -0700850int ipmi_set_my_address(ipmi_user_t user,
851 unsigned int channel,
852 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853{
Corey Minyardc14979b2005-09-06 15:18:38 -0700854 if (channel >= IPMI_MAX_CHANNELS)
855 return -EINVAL;
856 user->intf->channels[channel].address = address;
857 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858}
859
Corey Minyardc14979b2005-09-06 15:18:38 -0700860int ipmi_get_my_address(ipmi_user_t user,
861 unsigned int channel,
862 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
Corey Minyardc14979b2005-09-06 15:18:38 -0700864 if (channel >= IPMI_MAX_CHANNELS)
865 return -EINVAL;
866 *address = user->intf->channels[channel].address;
867 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868}
869
Corey Minyardc14979b2005-09-06 15:18:38 -0700870int ipmi_set_my_LUN(ipmi_user_t user,
871 unsigned int channel,
872 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873{
Corey Minyardc14979b2005-09-06 15:18:38 -0700874 if (channel >= IPMI_MAX_CHANNELS)
875 return -EINVAL;
876 user->intf->channels[channel].lun = LUN & 0x3;
877 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878}
879
Corey Minyardc14979b2005-09-06 15:18:38 -0700880int ipmi_get_my_LUN(ipmi_user_t user,
881 unsigned int channel,
882 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
Corey Minyardc14979b2005-09-06 15:18:38 -0700884 if (channel >= IPMI_MAX_CHANNELS)
885 return -EINVAL;
886 *address = user->intf->channels[channel].lun;
887 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888}
889
890int ipmi_set_gets_events(ipmi_user_t user, int val)
891{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800892 unsigned long flags;
893 ipmi_smi_t intf = user->intf;
894 struct ipmi_recv_msg *msg, *msg2;
895 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
Corey Minyard393d2cc2005-11-07 00:59:54 -0800897 INIT_LIST_HEAD(&msgs);
898
899 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 user->gets_events = val;
901
902 if (val) {
903 /* Deliver any queued events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -0800904 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 list_del(&msg->link);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800906 list_add_tail(&msg->link, &msgs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
908 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800909
910 /* Hold the events lock while doing this to preserve order. */
911 list_for_each_entry_safe(msg, msg2, &msgs, link) {
912 msg->user = user;
913 kref_get(&user->refcount);
914 deliver_response(msg);
915 }
916
917 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919 return 0;
920}
921
Corey Minyard393d2cc2005-11-07 00:59:54 -0800922static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
923 unsigned char netfn,
924 unsigned char cmd)
925{
926 struct cmd_rcvr *rcvr;
927
928 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
929 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd))
930 return rcvr;
931 }
932 return NULL;
933}
934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935int ipmi_register_for_cmd(ipmi_user_t user,
936 unsigned char netfn,
937 unsigned char cmd)
938{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800939 ipmi_smi_t intf = user->intf;
940 struct cmd_rcvr *rcvr;
941 struct cmd_rcvr *entry;
942 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
944
945 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
946 if (! rcvr)
947 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800948 rcvr->cmd = cmd;
949 rcvr->netfn = netfn;
950 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800952 down(&intf->cmd_rcvrs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 /* Make sure the command/netfn is not already registered. */
Corey Minyard393d2cc2005-11-07 00:59:54 -0800954 entry = find_cmd_rcvr(intf, netfn, cmd);
955 if (entry) {
956 rv = -EBUSY;
957 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 }
959
Corey Minyard393d2cc2005-11-07 00:59:54 -0800960 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -0700961
Corey Minyard393d2cc2005-11-07 00:59:54 -0800962 out_unlock:
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800963 up(&intf->cmd_rcvrs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 if (rv)
965 kfree(rcvr);
966
967 return rv;
968}
969
970int ipmi_unregister_for_cmd(ipmi_user_t user,
971 unsigned char netfn,
972 unsigned char cmd)
973{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800974 ipmi_smi_t intf = user->intf;
975 struct cmd_rcvr *rcvr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800977 down(&intf->cmd_rcvrs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 /* Make sure the command/netfn is not already registered. */
Corey Minyard393d2cc2005-11-07 00:59:54 -0800979 rcvr = find_cmd_rcvr(intf, netfn, cmd);
980 if ((rcvr) && (rcvr->user == user)) {
981 list_del_rcu(&rcvr->link);
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800982 up(&intf->cmd_rcvrs_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800983 synchronize_rcu();
984 kfree(rcvr);
985 return 0;
986 } else {
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800987 up(&intf->cmd_rcvrs_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800988 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990}
991
992void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
993{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800994 ipmi_smi_t intf = user->intf;
995 intf->handlers->set_run_to_completion(intf->send_info, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996}
997
998static unsigned char
999ipmb_checksum(unsigned char *data, int size)
1000{
1001 unsigned char csum = 0;
1002
1003 for (; size > 0; size--, data++)
1004 csum += *data;
1005
1006 return -csum;
1007}
1008
1009static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1010 struct kernel_ipmi_msg *msg,
1011 struct ipmi_ipmb_addr *ipmb_addr,
1012 long msgid,
1013 unsigned char ipmb_seq,
1014 int broadcast,
1015 unsigned char source_address,
1016 unsigned char source_lun)
1017{
1018 int i = broadcast;
1019
1020 /* Format the IPMB header data. */
1021 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1022 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1023 smi_msg->data[2] = ipmb_addr->channel;
1024 if (broadcast)
1025 smi_msg->data[3] = 0;
1026 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1027 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1028 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1029 smi_msg->data[i+6] = source_address;
1030 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1031 smi_msg->data[i+8] = msg->cmd;
1032
1033 /* Now tack on the data to the message. */
1034 if (msg->data_len > 0)
1035 memcpy(&(smi_msg->data[i+9]), msg->data,
1036 msg->data_len);
1037 smi_msg->data_size = msg->data_len + 9;
1038
1039 /* Now calculate the checksum and tack it on. */
1040 smi_msg->data[i+smi_msg->data_size]
1041 = ipmb_checksum(&(smi_msg->data[i+6]),
1042 smi_msg->data_size-6);
1043
1044 /* Add on the checksum size and the offset from the
1045 broadcast. */
1046 smi_msg->data_size += 1 + i;
1047
1048 smi_msg->msgid = msgid;
1049}
1050
1051static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1052 struct kernel_ipmi_msg *msg,
1053 struct ipmi_lan_addr *lan_addr,
1054 long msgid,
1055 unsigned char ipmb_seq,
1056 unsigned char source_lun)
1057{
1058 /* Format the IPMB header data. */
1059 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1060 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1061 smi_msg->data[2] = lan_addr->channel;
1062 smi_msg->data[3] = lan_addr->session_handle;
1063 smi_msg->data[4] = lan_addr->remote_SWID;
1064 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1065 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1066 smi_msg->data[7] = lan_addr->local_SWID;
1067 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1068 smi_msg->data[9] = msg->cmd;
1069
1070 /* Now tack on the data to the message. */
1071 if (msg->data_len > 0)
1072 memcpy(&(smi_msg->data[10]), msg->data,
1073 msg->data_len);
1074 smi_msg->data_size = msg->data_len + 10;
1075
1076 /* Now calculate the checksum and tack it on. */
1077 smi_msg->data[smi_msg->data_size]
1078 = ipmb_checksum(&(smi_msg->data[7]),
1079 smi_msg->data_size-7);
1080
1081 /* Add on the checksum size and the offset from the
1082 broadcast. */
1083 smi_msg->data_size += 1;
1084
1085 smi_msg->msgid = msgid;
1086}
1087
1088/* Separate from ipmi_request so that the user does not have to be
1089 supplied in certain circumstances (mainly at panic time). If
1090 messages are supplied, they will be freed, even if an error
1091 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001092static int i_ipmi_request(ipmi_user_t user,
1093 ipmi_smi_t intf,
1094 struct ipmi_addr *addr,
1095 long msgid,
1096 struct kernel_ipmi_msg *msg,
1097 void *user_msg_data,
1098 void *supplied_smi,
1099 struct ipmi_recv_msg *supplied_recv,
1100 int priority,
1101 unsigned char source_address,
1102 unsigned char source_lun,
1103 int retries,
1104 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105{
1106 int rv = 0;
1107 struct ipmi_smi_msg *smi_msg;
1108 struct ipmi_recv_msg *recv_msg;
1109 unsigned long flags;
1110
1111
1112 if (supplied_recv) {
1113 recv_msg = supplied_recv;
1114 } else {
1115 recv_msg = ipmi_alloc_recv_msg();
1116 if (recv_msg == NULL) {
1117 return -ENOMEM;
1118 }
1119 }
1120 recv_msg->user_msg_data = user_msg_data;
1121
1122 if (supplied_smi) {
1123 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1124 } else {
1125 smi_msg = ipmi_alloc_smi_msg();
1126 if (smi_msg == NULL) {
1127 ipmi_free_recv_msg(recv_msg);
1128 return -ENOMEM;
1129 }
1130 }
1131
1132 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001133 if (user)
1134 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 recv_msg->msgid = msgid;
1136 /* Store the message to send in the receive message so timeout
1137 responses can get the proper response data. */
1138 recv_msg->msg = *msg;
1139
1140 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1141 struct ipmi_system_interface_addr *smi_addr;
1142
1143 if (msg->netfn & 1) {
1144 /* Responses are not allowed to the SMI. */
1145 rv = -EINVAL;
1146 goto out_err;
1147 }
1148
1149 smi_addr = (struct ipmi_system_interface_addr *) addr;
1150 if (smi_addr->lun > 3) {
1151 spin_lock_irqsave(&intf->counter_lock, flags);
1152 intf->sent_invalid_commands++;
1153 spin_unlock_irqrestore(&intf->counter_lock, flags);
1154 rv = -EINVAL;
1155 goto out_err;
1156 }
1157
1158 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1159
1160 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1161 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1162 || (msg->cmd == IPMI_GET_MSG_CMD)
1163 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1164 {
1165 /* We don't let the user do these, since we manage
1166 the sequence numbers. */
1167 spin_lock_irqsave(&intf->counter_lock, flags);
1168 intf->sent_invalid_commands++;
1169 spin_unlock_irqrestore(&intf->counter_lock, flags);
1170 rv = -EINVAL;
1171 goto out_err;
1172 }
1173
1174 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1175 spin_lock_irqsave(&intf->counter_lock, flags);
1176 intf->sent_invalid_commands++;
1177 spin_unlock_irqrestore(&intf->counter_lock, flags);
1178 rv = -EMSGSIZE;
1179 goto out_err;
1180 }
1181
1182 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1183 smi_msg->data[1] = msg->cmd;
1184 smi_msg->msgid = msgid;
1185 smi_msg->user_data = recv_msg;
1186 if (msg->data_len > 0)
1187 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1188 smi_msg->data_size = msg->data_len + 2;
1189 spin_lock_irqsave(&intf->counter_lock, flags);
1190 intf->sent_local_commands++;
1191 spin_unlock_irqrestore(&intf->counter_lock, flags);
1192 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1193 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1194 {
1195 struct ipmi_ipmb_addr *ipmb_addr;
1196 unsigned char ipmb_seq;
1197 long seqid;
1198 int broadcast = 0;
1199
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001200 if (addr->channel >= IPMI_MAX_CHANNELS) {
1201 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 intf->sent_invalid_commands++;
1203 spin_unlock_irqrestore(&intf->counter_lock, flags);
1204 rv = -EINVAL;
1205 goto out_err;
1206 }
1207
1208 if (intf->channels[addr->channel].medium
1209 != IPMI_CHANNEL_MEDIUM_IPMB)
1210 {
1211 spin_lock_irqsave(&intf->counter_lock, flags);
1212 intf->sent_invalid_commands++;
1213 spin_unlock_irqrestore(&intf->counter_lock, flags);
1214 rv = -EINVAL;
1215 goto out_err;
1216 }
1217
1218 if (retries < 0) {
1219 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1220 retries = 0; /* Don't retry broadcasts. */
1221 else
1222 retries = 4;
1223 }
1224 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1225 /* Broadcasts add a zero at the beginning of the
1226 message, but otherwise is the same as an IPMB
1227 address. */
1228 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1229 broadcast = 1;
1230 }
1231
1232
1233 /* Default to 1 second retries. */
1234 if (retry_time_ms == 0)
1235 retry_time_ms = 1000;
1236
1237 /* 9 for the header and 1 for the checksum, plus
1238 possibly one for the broadcast. */
1239 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1240 spin_lock_irqsave(&intf->counter_lock, flags);
1241 intf->sent_invalid_commands++;
1242 spin_unlock_irqrestore(&intf->counter_lock, flags);
1243 rv = -EMSGSIZE;
1244 goto out_err;
1245 }
1246
1247 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1248 if (ipmb_addr->lun > 3) {
1249 spin_lock_irqsave(&intf->counter_lock, flags);
1250 intf->sent_invalid_commands++;
1251 spin_unlock_irqrestore(&intf->counter_lock, flags);
1252 rv = -EINVAL;
1253 goto out_err;
1254 }
1255
1256 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1257
1258 if (recv_msg->msg.netfn & 0x1) {
1259 /* It's a response, so use the user's sequence
1260 from msgid. */
1261 spin_lock_irqsave(&intf->counter_lock, flags);
1262 intf->sent_ipmb_responses++;
1263 spin_unlock_irqrestore(&intf->counter_lock, flags);
1264 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1265 msgid, broadcast,
1266 source_address, source_lun);
1267
1268 /* Save the receive message so we can use it
1269 to deliver the response. */
1270 smi_msg->user_data = recv_msg;
1271 } else {
1272 /* It's a command, so get a sequence for it. */
1273
1274 spin_lock_irqsave(&(intf->seq_lock), flags);
1275
1276 spin_lock(&intf->counter_lock);
1277 intf->sent_ipmb_commands++;
1278 spin_unlock(&intf->counter_lock);
1279
1280 /* Create a sequence number with a 1 second
1281 timeout and 4 retries. */
1282 rv = intf_next_seq(intf,
1283 recv_msg,
1284 retry_time_ms,
1285 retries,
1286 broadcast,
1287 &ipmb_seq,
1288 &seqid);
1289 if (rv) {
1290 /* We have used up all the sequence numbers,
1291 probably, so abort. */
1292 spin_unlock_irqrestore(&(intf->seq_lock),
1293 flags);
1294 goto out_err;
1295 }
1296
1297 /* Store the sequence number in the message,
1298 so that when the send message response
1299 comes back we can start the timer. */
1300 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1301 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1302 ipmb_seq, broadcast,
1303 source_address, source_lun);
1304
1305 /* Copy the message into the recv message data, so we
1306 can retransmit it later if necessary. */
1307 memcpy(recv_msg->msg_data, smi_msg->data,
1308 smi_msg->data_size);
1309 recv_msg->msg.data = recv_msg->msg_data;
1310 recv_msg->msg.data_len = smi_msg->data_size;
1311
1312 /* We don't unlock until here, because we need
1313 to copy the completed message into the
1314 recv_msg before we release the lock.
1315 Otherwise, race conditions may bite us. I
1316 know that's pretty paranoid, but I prefer
1317 to be correct. */
1318 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1319 }
1320 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1321 struct ipmi_lan_addr *lan_addr;
1322 unsigned char ipmb_seq;
1323 long seqid;
1324
Corey Minyardc14979b2005-09-06 15:18:38 -07001325 if (addr->channel >= IPMI_NUM_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 spin_lock_irqsave(&intf->counter_lock, flags);
1327 intf->sent_invalid_commands++;
1328 spin_unlock_irqrestore(&intf->counter_lock, flags);
1329 rv = -EINVAL;
1330 goto out_err;
1331 }
1332
1333 if ((intf->channels[addr->channel].medium
1334 != IPMI_CHANNEL_MEDIUM_8023LAN)
1335 && (intf->channels[addr->channel].medium
1336 != IPMI_CHANNEL_MEDIUM_ASYNC))
1337 {
1338 spin_lock_irqsave(&intf->counter_lock, flags);
1339 intf->sent_invalid_commands++;
1340 spin_unlock_irqrestore(&intf->counter_lock, flags);
1341 rv = -EINVAL;
1342 goto out_err;
1343 }
1344
1345 retries = 4;
1346
1347 /* Default to 1 second retries. */
1348 if (retry_time_ms == 0)
1349 retry_time_ms = 1000;
1350
1351 /* 11 for the header and 1 for the checksum. */
1352 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1353 spin_lock_irqsave(&intf->counter_lock, flags);
1354 intf->sent_invalid_commands++;
1355 spin_unlock_irqrestore(&intf->counter_lock, flags);
1356 rv = -EMSGSIZE;
1357 goto out_err;
1358 }
1359
1360 lan_addr = (struct ipmi_lan_addr *) addr;
1361 if (lan_addr->lun > 3) {
1362 spin_lock_irqsave(&intf->counter_lock, flags);
1363 intf->sent_invalid_commands++;
1364 spin_unlock_irqrestore(&intf->counter_lock, flags);
1365 rv = -EINVAL;
1366 goto out_err;
1367 }
1368
1369 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1370
1371 if (recv_msg->msg.netfn & 0x1) {
1372 /* It's a response, so use the user's sequence
1373 from msgid. */
1374 spin_lock_irqsave(&intf->counter_lock, flags);
1375 intf->sent_lan_responses++;
1376 spin_unlock_irqrestore(&intf->counter_lock, flags);
1377 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1378 msgid, source_lun);
1379
1380 /* Save the receive message so we can use it
1381 to deliver the response. */
1382 smi_msg->user_data = recv_msg;
1383 } else {
1384 /* It's a command, so get a sequence for it. */
1385
1386 spin_lock_irqsave(&(intf->seq_lock), flags);
1387
1388 spin_lock(&intf->counter_lock);
1389 intf->sent_lan_commands++;
1390 spin_unlock(&intf->counter_lock);
1391
1392 /* Create a sequence number with a 1 second
1393 timeout and 4 retries. */
1394 rv = intf_next_seq(intf,
1395 recv_msg,
1396 retry_time_ms,
1397 retries,
1398 0,
1399 &ipmb_seq,
1400 &seqid);
1401 if (rv) {
1402 /* We have used up all the sequence numbers,
1403 probably, so abort. */
1404 spin_unlock_irqrestore(&(intf->seq_lock),
1405 flags);
1406 goto out_err;
1407 }
1408
1409 /* Store the sequence number in the message,
1410 so that when the send message response
1411 comes back we can start the timer. */
1412 format_lan_msg(smi_msg, msg, lan_addr,
1413 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1414 ipmb_seq, source_lun);
1415
1416 /* Copy the message into the recv message data, so we
1417 can retransmit it later if necessary. */
1418 memcpy(recv_msg->msg_data, smi_msg->data,
1419 smi_msg->data_size);
1420 recv_msg->msg.data = recv_msg->msg_data;
1421 recv_msg->msg.data_len = smi_msg->data_size;
1422
1423 /* We don't unlock until here, because we need
1424 to copy the completed message into the
1425 recv_msg before we release the lock.
1426 Otherwise, race conditions may bite us. I
1427 know that's pretty paranoid, but I prefer
1428 to be correct. */
1429 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1430 }
1431 } else {
1432 /* Unknown address type. */
1433 spin_lock_irqsave(&intf->counter_lock, flags);
1434 intf->sent_invalid_commands++;
1435 spin_unlock_irqrestore(&intf->counter_lock, flags);
1436 rv = -EINVAL;
1437 goto out_err;
1438 }
1439
1440#ifdef DEBUG_MSGING
1441 {
1442 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001443 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 printk(" %2.2x", smi_msg->data[m]);
1445 printk("\n");
1446 }
1447#endif
1448 intf->handlers->sender(intf->send_info, smi_msg, priority);
1449
1450 return 0;
1451
1452 out_err:
1453 ipmi_free_smi_msg(smi_msg);
1454 ipmi_free_recv_msg(recv_msg);
1455 return rv;
1456}
1457
Corey Minyardc14979b2005-09-06 15:18:38 -07001458static int check_addr(ipmi_smi_t intf,
1459 struct ipmi_addr *addr,
1460 unsigned char *saddr,
1461 unsigned char *lun)
1462{
1463 if (addr->channel >= IPMI_MAX_CHANNELS)
1464 return -EINVAL;
1465 *lun = intf->channels[addr->channel].lun;
1466 *saddr = intf->channels[addr->channel].address;
1467 return 0;
1468}
1469
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470int ipmi_request_settime(ipmi_user_t user,
1471 struct ipmi_addr *addr,
1472 long msgid,
1473 struct kernel_ipmi_msg *msg,
1474 void *user_msg_data,
1475 int priority,
1476 int retries,
1477 unsigned int retry_time_ms)
1478{
Corey Minyardc14979b2005-09-06 15:18:38 -07001479 unsigned char saddr, lun;
1480 int rv;
1481
Corey Minyard56a55ec2005-09-06 15:18:42 -07001482 if (! user)
1483 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001484 rv = check_addr(user->intf, addr, &saddr, &lun);
1485 if (rv)
1486 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 return i_ipmi_request(user,
1488 user->intf,
1489 addr,
1490 msgid,
1491 msg,
1492 user_msg_data,
1493 NULL, NULL,
1494 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001495 saddr,
1496 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 retries,
1498 retry_time_ms);
1499}
1500
1501int ipmi_request_supply_msgs(ipmi_user_t user,
1502 struct ipmi_addr *addr,
1503 long msgid,
1504 struct kernel_ipmi_msg *msg,
1505 void *user_msg_data,
1506 void *supplied_smi,
1507 struct ipmi_recv_msg *supplied_recv,
1508 int priority)
1509{
Corey Minyardc14979b2005-09-06 15:18:38 -07001510 unsigned char saddr, lun;
1511 int rv;
1512
Corey Minyard56a55ec2005-09-06 15:18:42 -07001513 if (! user)
1514 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001515 rv = check_addr(user->intf, addr, &saddr, &lun);
1516 if (rv)
1517 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 return i_ipmi_request(user,
1519 user->intf,
1520 addr,
1521 msgid,
1522 msg,
1523 user_msg_data,
1524 supplied_smi,
1525 supplied_recv,
1526 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001527 saddr,
1528 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 -1, 0);
1530}
1531
1532static int ipmb_file_read_proc(char *page, char **start, off_t off,
1533 int count, int *eof, void *data)
1534{
1535 char *out = (char *) page;
1536 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001537 int i;
1538 int rv= 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Corey Minyarde8b33612005-09-06 15:18:45 -07001540 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001541 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1542 out[rv-1] = '\n'; /* Replace the final space with a newline */
1543 out[rv] = '\0';
1544 rv++;
1545 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546}
1547
1548static int version_file_read_proc(char *page, char **start, off_t off,
1549 int count, int *eof, void *data)
1550{
1551 char *out = (char *) page;
1552 ipmi_smi_t intf = data;
1553
1554 return sprintf(out, "%d.%d\n",
1555 intf->version_major, intf->version_minor);
1556}
1557
1558static int stat_file_read_proc(char *page, char **start, off_t off,
1559 int count, int *eof, void *data)
1560{
1561 char *out = (char *) page;
1562 ipmi_smi_t intf = data;
1563
1564 out += sprintf(out, "sent_invalid_commands: %d\n",
1565 intf->sent_invalid_commands);
1566 out += sprintf(out, "sent_local_commands: %d\n",
1567 intf->sent_local_commands);
1568 out += sprintf(out, "handled_local_responses: %d\n",
1569 intf->handled_local_responses);
1570 out += sprintf(out, "unhandled_local_responses: %d\n",
1571 intf->unhandled_local_responses);
1572 out += sprintf(out, "sent_ipmb_commands: %d\n",
1573 intf->sent_ipmb_commands);
1574 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1575 intf->sent_ipmb_command_errs);
1576 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1577 intf->retransmitted_ipmb_commands);
1578 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1579 intf->timed_out_ipmb_commands);
1580 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1581 intf->timed_out_ipmb_broadcasts);
1582 out += sprintf(out, "sent_ipmb_responses: %d\n",
1583 intf->sent_ipmb_responses);
1584 out += sprintf(out, "handled_ipmb_responses: %d\n",
1585 intf->handled_ipmb_responses);
1586 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1587 intf->invalid_ipmb_responses);
1588 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1589 intf->unhandled_ipmb_responses);
1590 out += sprintf(out, "sent_lan_commands: %d\n",
1591 intf->sent_lan_commands);
1592 out += sprintf(out, "sent_lan_command_errs: %d\n",
1593 intf->sent_lan_command_errs);
1594 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1595 intf->retransmitted_lan_commands);
1596 out += sprintf(out, "timed_out_lan_commands: %d\n",
1597 intf->timed_out_lan_commands);
1598 out += sprintf(out, "sent_lan_responses: %d\n",
1599 intf->sent_lan_responses);
1600 out += sprintf(out, "handled_lan_responses: %d\n",
1601 intf->handled_lan_responses);
1602 out += sprintf(out, "invalid_lan_responses: %d\n",
1603 intf->invalid_lan_responses);
1604 out += sprintf(out, "unhandled_lan_responses: %d\n",
1605 intf->unhandled_lan_responses);
1606 out += sprintf(out, "handled_commands: %d\n",
1607 intf->handled_commands);
1608 out += sprintf(out, "invalid_commands: %d\n",
1609 intf->invalid_commands);
1610 out += sprintf(out, "unhandled_commands: %d\n",
1611 intf->unhandled_commands);
1612 out += sprintf(out, "invalid_events: %d\n",
1613 intf->invalid_events);
1614 out += sprintf(out, "events: %d\n",
1615 intf->events);
1616
1617 return (out - ((char *) page));
1618}
1619
1620int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1621 read_proc_t *read_proc, write_proc_t *write_proc,
1622 void *data, struct module *owner)
1623{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001625#ifdef CONFIG_PROC_FS
1626 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 struct ipmi_proc_entry *entry;
1628
1629 /* Create a list element. */
1630 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1631 if (!entry)
1632 return -ENOMEM;
1633 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1634 if (!entry->name) {
1635 kfree(entry);
1636 return -ENOMEM;
1637 }
1638 strcpy(entry->name, name);
1639
1640 file = create_proc_entry(name, 0, smi->proc_dir);
1641 if (!file) {
1642 kfree(entry->name);
1643 kfree(entry);
1644 rv = -ENOMEM;
1645 } else {
1646 file->nlink = 1;
1647 file->data = data;
1648 file->read_proc = read_proc;
1649 file->write_proc = write_proc;
1650 file->owner = owner;
1651
Corey Minyard3b625942005-06-23 22:01:42 -07001652 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 /* Stick it on the list. */
1654 entry->next = smi->proc_entries;
1655 smi->proc_entries = entry;
Corey Minyard3b625942005-06-23 22:01:42 -07001656 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 }
Corey Minyard3b625942005-06-23 22:01:42 -07001658#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
1660 return rv;
1661}
1662
1663static int add_proc_entries(ipmi_smi_t smi, int num)
1664{
1665 int rv = 0;
1666
Corey Minyard3b625942005-06-23 22:01:42 -07001667#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 sprintf(smi->proc_dir_name, "%d", num);
1669 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1670 if (!smi->proc_dir)
1671 rv = -ENOMEM;
1672 else {
1673 smi->proc_dir->owner = THIS_MODULE;
1674 }
1675
1676 if (rv == 0)
1677 rv = ipmi_smi_add_proc_entry(smi, "stats",
1678 stat_file_read_proc, NULL,
1679 smi, THIS_MODULE);
1680
1681 if (rv == 0)
1682 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1683 ipmb_file_read_proc, NULL,
1684 smi, THIS_MODULE);
1685
1686 if (rv == 0)
1687 rv = ipmi_smi_add_proc_entry(smi, "version",
1688 version_file_read_proc, NULL,
1689 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001690#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
1692 return rv;
1693}
1694
1695static void remove_proc_entries(ipmi_smi_t smi)
1696{
Corey Minyard3b625942005-06-23 22:01:42 -07001697#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 struct ipmi_proc_entry *entry;
1699
Corey Minyard3b625942005-06-23 22:01:42 -07001700 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 while (smi->proc_entries) {
1702 entry = smi->proc_entries;
1703 smi->proc_entries = entry->next;
1704
1705 remove_proc_entry(entry->name, smi->proc_dir);
1706 kfree(entry->name);
1707 kfree(entry);
1708 }
Corey Minyard3b625942005-06-23 22:01:42 -07001709 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001711#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712}
1713
1714static int
1715send_channel_info_cmd(ipmi_smi_t intf, int chan)
1716{
1717 struct kernel_ipmi_msg msg;
1718 unsigned char data[1];
1719 struct ipmi_system_interface_addr si;
1720
1721 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
1722 si.channel = IPMI_BMC_CHANNEL;
1723 si.lun = 0;
1724
1725 msg.netfn = IPMI_NETFN_APP_REQUEST;
1726 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
1727 msg.data = data;
1728 msg.data_len = 1;
1729 data[0] = chan;
1730 return i_ipmi_request(NULL,
1731 intf,
1732 (struct ipmi_addr *) &si,
1733 0,
1734 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07001735 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 NULL,
1737 NULL,
1738 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07001739 intf->channels[0].address,
1740 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 -1, 0);
1742}
1743
1744static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07001745channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746{
1747 int rv = 0;
1748 int chan;
1749
Corey Minyard56a55ec2005-09-06 15:18:42 -07001750 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
1751 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
1752 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 {
1754 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07001755 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 /* Got an error from the channel, just go on. */
1757
Corey Minyard56a55ec2005-09-06 15:18:42 -07001758 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 /* If the MC does not support this
1760 command, that is legal. We just
1761 assume it has one IPMB at channel
1762 zero. */
1763 intf->channels[0].medium
1764 = IPMI_CHANNEL_MEDIUM_IPMB;
1765 intf->channels[0].protocol
1766 = IPMI_CHANNEL_PROTOCOL_IPMB;
1767 rv = -ENOSYS;
1768
1769 intf->curr_channel = IPMI_MAX_CHANNELS;
1770 wake_up(&intf->waitq);
1771 goto out;
1772 }
1773 goto next_channel;
1774 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07001775 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 /* Message not big enough, just go on. */
1777 goto next_channel;
1778 }
1779 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07001780 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
1781 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782
1783 next_channel:
1784 intf->curr_channel++;
1785 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
1786 wake_up(&intf->waitq);
1787 else
1788 rv = send_channel_info_cmd(intf, intf->curr_channel);
1789
1790 if (rv) {
1791 /* Got an error somehow, just give up. */
1792 intf->curr_channel = IPMI_MAX_CHANNELS;
1793 wake_up(&intf->waitq);
1794
1795 printk(KERN_WARNING PFX
1796 "Error sending channel information: %d\n",
1797 rv);
1798 }
1799 }
1800 out:
1801 return;
1802}
1803
1804int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
1805 void *send_info,
1806 unsigned char version_major,
1807 unsigned char version_minor,
1808 unsigned char slave_addr,
Corey Minyard393d2cc2005-11-07 00:59:54 -08001809 ipmi_smi_t *new_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810{
1811 int i, j;
1812 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001813 ipmi_smi_t intf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 unsigned long flags;
1815
1816
1817 /* Make sure the driver is actually initialized, this handles
1818 problems with initialization order. */
1819 if (!initialized) {
1820 rv = ipmi_init_msghandler();
1821 if (rv)
1822 return rv;
1823 /* The init code doesn't return an error if it was turned
1824 off, but it won't initialize. Check that. */
1825 if (!initialized)
1826 return -ENODEV;
1827 }
1828
Corey Minyard393d2cc2005-11-07 00:59:54 -08001829 intf = kmalloc(sizeof(*intf), GFP_KERNEL);
1830 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001832 memset(intf, 0, sizeof(*intf));
1833 intf->intf_num = -1;
1834 kref_init(&intf->refcount);
1835 intf->version_major = version_major;
1836 intf->version_minor = version_minor;
1837 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
1838 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
1839 intf->channels[j].lun = 2;
1840 }
1841 if (slave_addr != 0)
1842 intf->channels[0].address = slave_addr;
1843 INIT_LIST_HEAD(&intf->users);
1844 intf->handlers = handlers;
1845 intf->send_info = send_info;
1846 spin_lock_init(&intf->seq_lock);
1847 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
1848 intf->seq_table[j].inuse = 0;
1849 intf->seq_table[j].seqid = 0;
1850 }
1851 intf->curr_seq = 0;
1852#ifdef CONFIG_PROC_FS
1853 spin_lock_init(&intf->proc_entry_lock);
1854#endif
1855 spin_lock_init(&intf->waiting_msgs_lock);
1856 INIT_LIST_HEAD(&intf->waiting_msgs);
1857 spin_lock_init(&intf->events_lock);
1858 INIT_LIST_HEAD(&intf->waiting_events);
1859 intf->waiting_events_count = 0;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08001860 init_MUTEX(&intf->cmd_rcvrs_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001861 INIT_LIST_HEAD(&intf->cmd_rcvrs);
1862 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863
Corey Minyard393d2cc2005-11-07 00:59:54 -08001864 spin_lock_init(&intf->counter_lock);
1865 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
1867 rv = -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001868 spin_lock_irqsave(&interfaces_lock, flags);
Corey Minyarde8b33612005-09-06 15:18:45 -07001869 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 if (ipmi_interfaces[i] == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08001871 intf->intf_num = i;
1872 /* Reserve the entry till we are done. */
1873 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 break;
1876 }
1877 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08001878 spin_unlock_irqrestore(&interfaces_lock, flags);
1879 if (rv)
1880 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Corey Minyard393d2cc2005-11-07 00:59:54 -08001882 /* FIXME - this is an ugly kludge, this sets the intf for the
1883 caller before sending any messages with it. */
1884 *new_intf = intf;
1885
1886 if ((version_major > 1)
1887 || ((version_major == 1) && (version_minor >= 5)))
1888 {
1889 /* Start scanning the channels to see what is
1890 available. */
1891 intf->null_user_handler = channel_handler;
1892 intf->curr_channel = 0;
1893 rv = send_channel_info_cmd(intf, 0);
1894 if (rv)
1895 goto out;
1896
1897 /* Wait for the channel info to be read. */
1898 wait_event(intf->waitq,
1899 intf->curr_channel >= IPMI_MAX_CHANNELS);
1900 } else {
1901 /* Assume a single IPMB channel at zero. */
1902 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
1903 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
1904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
1906 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08001907 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
Corey Minyard393d2cc2005-11-07 00:59:54 -08001909 out:
1910 if (rv) {
1911 if (intf->proc_dir)
1912 remove_proc_entries(intf);
1913 kref_put(&intf->refcount, intf_free);
1914 if (i < MAX_IPMI_INTERFACES) {
1915 spin_lock_irqsave(&interfaces_lock, flags);
1916 ipmi_interfaces[i] = NULL;
1917 spin_unlock_irqrestore(&interfaces_lock, flags);
1918 }
1919 } else {
1920 spin_lock_irqsave(&interfaces_lock, flags);
1921 ipmi_interfaces[i] = intf;
1922 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 call_smi_watchers(i);
1924 }
1925
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 return rv;
1927}
1928
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929int ipmi_unregister_smi(ipmi_smi_t intf)
1930{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 int i;
1932 struct ipmi_smi_watcher *w;
1933 unsigned long flags;
1934
Corey Minyard393d2cc2005-11-07 00:59:54 -08001935 spin_lock_irqsave(&interfaces_lock, flags);
1936 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
1937 if (ipmi_interfaces[i] == intf) {
1938 /* Set the interface number reserved until we
1939 * are done. */
1940 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
1941 intf->intf_num = -1;
1942 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08001945 spin_unlock_irqrestore(&interfaces_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946
Corey Minyard393d2cc2005-11-07 00:59:54 -08001947 if (i == MAX_IPMI_INTERFACES)
1948 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949
Corey Minyard393d2cc2005-11-07 00:59:54 -08001950 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951
1952 /* Call all the watcher interfaces to tell them that
1953 an interface is gone. */
1954 down_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001955 list_for_each_entry(w, &smi_watchers, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 w->smi_gone(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 up_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001958
1959 /* Allow the entry to be reused now. */
1960 spin_lock_irqsave(&interfaces_lock, flags);
1961 ipmi_interfaces[i] = NULL;
1962 spin_unlock_irqrestore(&interfaces_lock,flags);
1963
1964 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 return 0;
1966}
1967
1968static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
1969 struct ipmi_smi_msg *msg)
1970{
1971 struct ipmi_ipmb_addr ipmb_addr;
1972 struct ipmi_recv_msg *recv_msg;
1973 unsigned long flags;
1974
1975
1976 /* This is 11, not 10, because the response must contain a
1977 * completion code. */
1978 if (msg->rsp_size < 11) {
1979 /* Message not big enough, just ignore it. */
1980 spin_lock_irqsave(&intf->counter_lock, flags);
1981 intf->invalid_ipmb_responses++;
1982 spin_unlock_irqrestore(&intf->counter_lock, flags);
1983 return 0;
1984 }
1985
1986 if (msg->rsp[2] != 0) {
1987 /* An error getting the response, just ignore it. */
1988 return 0;
1989 }
1990
1991 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
1992 ipmb_addr.slave_addr = msg->rsp[6];
1993 ipmb_addr.channel = msg->rsp[3] & 0x0f;
1994 ipmb_addr.lun = msg->rsp[7] & 3;
1995
1996 /* It's a response from a remote entity. Look up the sequence
1997 number and handle the response. */
1998 if (intf_find_seq(intf,
1999 msg->rsp[7] >> 2,
2000 msg->rsp[3] & 0x0f,
2001 msg->rsp[8],
2002 (msg->rsp[4] >> 2) & (~1),
2003 (struct ipmi_addr *) &(ipmb_addr),
2004 &recv_msg))
2005 {
2006 /* We were unable to find the sequence number,
2007 so just nuke the message. */
2008 spin_lock_irqsave(&intf->counter_lock, flags);
2009 intf->unhandled_ipmb_responses++;
2010 spin_unlock_irqrestore(&intf->counter_lock, flags);
2011 return 0;
2012 }
2013
2014 memcpy(recv_msg->msg_data,
2015 &(msg->rsp[9]),
2016 msg->rsp_size - 9);
2017 /* THe other fields matched, so no need to set them, except
2018 for netfn, which needs to be the response that was
2019 returned, not the request value. */
2020 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2021 recv_msg->msg.data = recv_msg->msg_data;
2022 recv_msg->msg.data_len = msg->rsp_size - 10;
2023 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2024 spin_lock_irqsave(&intf->counter_lock, flags);
2025 intf->handled_ipmb_responses++;
2026 spin_unlock_irqrestore(&intf->counter_lock, flags);
2027 deliver_response(recv_msg);
2028
2029 return 0;
2030}
2031
2032static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2033 struct ipmi_smi_msg *msg)
2034{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002035 struct cmd_rcvr *rcvr;
2036 int rv = 0;
2037 unsigned char netfn;
2038 unsigned char cmd;
2039 ipmi_user_t user = NULL;
2040 struct ipmi_ipmb_addr *ipmb_addr;
2041 struct ipmi_recv_msg *recv_msg;
2042 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043
2044 if (msg->rsp_size < 10) {
2045 /* Message not big enough, just ignore it. */
2046 spin_lock_irqsave(&intf->counter_lock, flags);
2047 intf->invalid_commands++;
2048 spin_unlock_irqrestore(&intf->counter_lock, flags);
2049 return 0;
2050 }
2051
2052 if (msg->rsp[2] != 0) {
2053 /* An error getting the response, just ignore it. */
2054 return 0;
2055 }
2056
2057 netfn = msg->rsp[4] >> 2;
2058 cmd = msg->rsp[8];
2059
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002060 rcu_read_lock();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002061 rcvr = find_cmd_rcvr(intf, netfn, cmd);
2062 if (rcvr) {
2063 user = rcvr->user;
2064 kref_get(&user->refcount);
2065 } else
2066 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002067 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
2069 if (user == NULL) {
2070 /* We didn't find a user, deliver an error response. */
2071 spin_lock_irqsave(&intf->counter_lock, flags);
2072 intf->unhandled_commands++;
2073 spin_unlock_irqrestore(&intf->counter_lock, flags);
2074
2075 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2076 msg->data[1] = IPMI_SEND_MSG_CMD;
2077 msg->data[2] = msg->rsp[3];
2078 msg->data[3] = msg->rsp[6];
2079 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2080 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002081 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 /* rqseq/lun */
2083 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2084 msg->data[8] = msg->rsp[8]; /* cmd */
2085 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2086 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2087 msg->data_size = 11;
2088
2089#ifdef DEBUG_MSGING
2090 {
2091 int m;
2092 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002093 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 printk(" %2.2x", msg->data[m]);
2095 printk("\n");
2096 }
2097#endif
2098 intf->handlers->sender(intf->send_info, msg, 0);
2099
2100 rv = -1; /* We used the message, so return the value that
2101 causes it to not be freed or queued. */
2102 } else {
2103 /* Deliver the message to the user. */
2104 spin_lock_irqsave(&intf->counter_lock, flags);
2105 intf->handled_commands++;
2106 spin_unlock_irqrestore(&intf->counter_lock, flags);
2107
2108 recv_msg = ipmi_alloc_recv_msg();
2109 if (! recv_msg) {
2110 /* We couldn't allocate memory for the
2111 message, so requeue it for handling
2112 later. */
2113 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002114 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 } else {
2116 /* Extract the source address from the data. */
2117 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2118 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2119 ipmb_addr->slave_addr = msg->rsp[6];
2120 ipmb_addr->lun = msg->rsp[7] & 3;
2121 ipmb_addr->channel = msg->rsp[3] & 0xf;
2122
2123 /* Extract the rest of the message information
2124 from the IPMB header.*/
2125 recv_msg->user = user;
2126 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2127 recv_msg->msgid = msg->rsp[7] >> 2;
2128 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2129 recv_msg->msg.cmd = msg->rsp[8];
2130 recv_msg->msg.data = recv_msg->msg_data;
2131
2132 /* We chop off 10, not 9 bytes because the checksum
2133 at the end also needs to be removed. */
2134 recv_msg->msg.data_len = msg->rsp_size - 10;
2135 memcpy(recv_msg->msg_data,
2136 &(msg->rsp[9]),
2137 msg->rsp_size - 10);
2138 deliver_response(recv_msg);
2139 }
2140 }
2141
2142 return rv;
2143}
2144
2145static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
2146 struct ipmi_smi_msg *msg)
2147{
2148 struct ipmi_lan_addr lan_addr;
2149 struct ipmi_recv_msg *recv_msg;
2150 unsigned long flags;
2151
2152
2153 /* This is 13, not 12, because the response must contain a
2154 * completion code. */
2155 if (msg->rsp_size < 13) {
2156 /* Message not big enough, just ignore it. */
2157 spin_lock_irqsave(&intf->counter_lock, flags);
2158 intf->invalid_lan_responses++;
2159 spin_unlock_irqrestore(&intf->counter_lock, flags);
2160 return 0;
2161 }
2162
2163 if (msg->rsp[2] != 0) {
2164 /* An error getting the response, just ignore it. */
2165 return 0;
2166 }
2167
2168 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
2169 lan_addr.session_handle = msg->rsp[4];
2170 lan_addr.remote_SWID = msg->rsp[8];
2171 lan_addr.local_SWID = msg->rsp[5];
2172 lan_addr.channel = msg->rsp[3] & 0x0f;
2173 lan_addr.privilege = msg->rsp[3] >> 4;
2174 lan_addr.lun = msg->rsp[9] & 3;
2175
2176 /* It's a response from a remote entity. Look up the sequence
2177 number and handle the response. */
2178 if (intf_find_seq(intf,
2179 msg->rsp[9] >> 2,
2180 msg->rsp[3] & 0x0f,
2181 msg->rsp[10],
2182 (msg->rsp[6] >> 2) & (~1),
2183 (struct ipmi_addr *) &(lan_addr),
2184 &recv_msg))
2185 {
2186 /* We were unable to find the sequence number,
2187 so just nuke the message. */
2188 spin_lock_irqsave(&intf->counter_lock, flags);
2189 intf->unhandled_lan_responses++;
2190 spin_unlock_irqrestore(&intf->counter_lock, flags);
2191 return 0;
2192 }
2193
2194 memcpy(recv_msg->msg_data,
2195 &(msg->rsp[11]),
2196 msg->rsp_size - 11);
2197 /* The other fields matched, so no need to set them, except
2198 for netfn, which needs to be the response that was
2199 returned, not the request value. */
2200 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2201 recv_msg->msg.data = recv_msg->msg_data;
2202 recv_msg->msg.data_len = msg->rsp_size - 12;
2203 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2204 spin_lock_irqsave(&intf->counter_lock, flags);
2205 intf->handled_lan_responses++;
2206 spin_unlock_irqrestore(&intf->counter_lock, flags);
2207 deliver_response(recv_msg);
2208
2209 return 0;
2210}
2211
2212static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2213 struct ipmi_smi_msg *msg)
2214{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002215 struct cmd_rcvr *rcvr;
2216 int rv = 0;
2217 unsigned char netfn;
2218 unsigned char cmd;
2219 ipmi_user_t user = NULL;
2220 struct ipmi_lan_addr *lan_addr;
2221 struct ipmi_recv_msg *recv_msg;
2222 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
2224 if (msg->rsp_size < 12) {
2225 /* Message not big enough, just ignore it. */
2226 spin_lock_irqsave(&intf->counter_lock, flags);
2227 intf->invalid_commands++;
2228 spin_unlock_irqrestore(&intf->counter_lock, flags);
2229 return 0;
2230 }
2231
2232 if (msg->rsp[2] != 0) {
2233 /* An error getting the response, just ignore it. */
2234 return 0;
2235 }
2236
2237 netfn = msg->rsp[6] >> 2;
2238 cmd = msg->rsp[10];
2239
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002240 rcu_read_lock();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002241 rcvr = find_cmd_rcvr(intf, netfn, cmd);
2242 if (rcvr) {
2243 user = rcvr->user;
2244 kref_get(&user->refcount);
2245 } else
2246 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002247 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248
2249 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002250 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 spin_lock_irqsave(&intf->counter_lock, flags);
2252 intf->unhandled_commands++;
2253 spin_unlock_irqrestore(&intf->counter_lock, flags);
2254
2255 rv = 0; /* Don't do anything with these messages, just
2256 allow them to be freed. */
2257 } else {
2258 /* Deliver the message to the user. */
2259 spin_lock_irqsave(&intf->counter_lock, flags);
2260 intf->handled_commands++;
2261 spin_unlock_irqrestore(&intf->counter_lock, flags);
2262
2263 recv_msg = ipmi_alloc_recv_msg();
2264 if (! recv_msg) {
2265 /* We couldn't allocate memory for the
2266 message, so requeue it for handling
2267 later. */
2268 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002269 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 } else {
2271 /* Extract the source address from the data. */
2272 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
2273 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
2274 lan_addr->session_handle = msg->rsp[4];
2275 lan_addr->remote_SWID = msg->rsp[8];
2276 lan_addr->local_SWID = msg->rsp[5];
2277 lan_addr->lun = msg->rsp[9] & 3;
2278 lan_addr->channel = msg->rsp[3] & 0xf;
2279 lan_addr->privilege = msg->rsp[3] >> 4;
2280
2281 /* Extract the rest of the message information
2282 from the IPMB header.*/
2283 recv_msg->user = user;
2284 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2285 recv_msg->msgid = msg->rsp[9] >> 2;
2286 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2287 recv_msg->msg.cmd = msg->rsp[10];
2288 recv_msg->msg.data = recv_msg->msg_data;
2289
2290 /* We chop off 12, not 11 bytes because the checksum
2291 at the end also needs to be removed. */
2292 recv_msg->msg.data_len = msg->rsp_size - 12;
2293 memcpy(recv_msg->msg_data,
2294 &(msg->rsp[11]),
2295 msg->rsp_size - 12);
2296 deliver_response(recv_msg);
2297 }
2298 }
2299
2300 return rv;
2301}
2302
2303static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
2304 struct ipmi_smi_msg *msg)
2305{
2306 struct ipmi_system_interface_addr *smi_addr;
2307
2308 recv_msg->msgid = 0;
2309 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
2310 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2311 smi_addr->channel = IPMI_BMC_CHANNEL;
2312 smi_addr->lun = msg->rsp[0] & 3;
2313 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
2314 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2315 recv_msg->msg.cmd = msg->rsp[1];
2316 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
2317 recv_msg->msg.data = recv_msg->msg_data;
2318 recv_msg->msg.data_len = msg->rsp_size - 3;
2319}
2320
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321static int handle_read_event_rsp(ipmi_smi_t intf,
2322 struct ipmi_smi_msg *msg)
2323{
2324 struct ipmi_recv_msg *recv_msg, *recv_msg2;
2325 struct list_head msgs;
2326 ipmi_user_t user;
2327 int rv = 0;
2328 int deliver_count = 0;
2329 unsigned long flags;
2330
2331 if (msg->rsp_size < 19) {
2332 /* Message is too small to be an IPMB event. */
2333 spin_lock_irqsave(&intf->counter_lock, flags);
2334 intf->invalid_events++;
2335 spin_unlock_irqrestore(&intf->counter_lock, flags);
2336 return 0;
2337 }
2338
2339 if (msg->rsp[2] != 0) {
2340 /* An error getting the event, just ignore it. */
2341 return 0;
2342 }
2343
2344 INIT_LIST_HEAD(&msgs);
2345
Corey Minyard393d2cc2005-11-07 00:59:54 -08002346 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
2348 spin_lock(&intf->counter_lock);
2349 intf->events++;
2350 spin_unlock(&intf->counter_lock);
2351
2352 /* Allocate and fill in one message for every user that is getting
2353 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002354 rcu_read_lock();
2355 list_for_each_entry_rcu(user, &intf->users, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 if (! user->gets_events)
2357 continue;
2358
2359 recv_msg = ipmi_alloc_recv_msg();
2360 if (! recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002361 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
2363 list_del(&recv_msg->link);
2364 ipmi_free_recv_msg(recv_msg);
2365 }
2366 /* We couldn't allocate memory for the
2367 message, so requeue it for handling
2368 later. */
2369 rv = 1;
2370 goto out;
2371 }
2372
2373 deliver_count++;
2374
2375 copy_event_into_recv_msg(recv_msg, msg);
2376 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002377 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 list_add_tail(&(recv_msg->link), &msgs);
2379 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002380 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
2382 if (deliver_count) {
2383 /* Now deliver all the messages. */
2384 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
2385 list_del(&recv_msg->link);
2386 deliver_response(recv_msg);
2387 }
2388 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
2389 /* No one to receive the message, put it in queue if there's
2390 not already too many things in the queue. */
2391 recv_msg = ipmi_alloc_recv_msg();
2392 if (! recv_msg) {
2393 /* We couldn't allocate memory for the
2394 message, so requeue it for handling
2395 later. */
2396 rv = 1;
2397 goto out;
2398 }
2399
2400 copy_event_into_recv_msg(recv_msg, msg);
2401 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
2402 } else {
2403 /* There's too many things in the queue, discard this
2404 message. */
2405 printk(KERN_WARNING PFX "Event queue full, discarding an"
2406 " incoming event\n");
2407 }
2408
2409 out:
2410 spin_unlock_irqrestore(&(intf->events_lock), flags);
2411
2412 return rv;
2413}
2414
2415static int handle_bmc_rsp(ipmi_smi_t intf,
2416 struct ipmi_smi_msg *msg)
2417{
2418 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002420 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421
2422 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002423 if (recv_msg == NULL)
2424 {
2425 printk(KERN_WARNING"IPMI message received with no owner. This\n"
2426 "could be because of a malformed message, or\n"
2427 "because of a hardware error. Contact your\n"
2428 "hardware vender for assistance\n");
2429 return 0;
2430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
Corey Minyard393d2cc2005-11-07 00:59:54 -08002432 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002434 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07002435 /* The user for the message went away, so give up. */
2436 spin_lock_irqsave(&intf->counter_lock, flags);
2437 intf->unhandled_local_responses++;
2438 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 ipmi_free_recv_msg(recv_msg);
2440 } else {
2441 struct ipmi_system_interface_addr *smi_addr;
2442
2443 spin_lock_irqsave(&intf->counter_lock, flags);
2444 intf->handled_local_responses++;
2445 spin_unlock_irqrestore(&intf->counter_lock, flags);
2446 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2447 recv_msg->msgid = msg->msgid;
2448 smi_addr = ((struct ipmi_system_interface_addr *)
2449 &(recv_msg->addr));
2450 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2451 smi_addr->channel = IPMI_BMC_CHANNEL;
2452 smi_addr->lun = msg->rsp[0] & 3;
2453 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2454 recv_msg->msg.cmd = msg->rsp[1];
2455 memcpy(recv_msg->msg_data,
2456 &(msg->rsp[2]),
2457 msg->rsp_size - 2);
2458 recv_msg->msg.data = recv_msg->msg_data;
2459 recv_msg->msg.data_len = msg->rsp_size - 2;
2460 deliver_response(recv_msg);
2461 }
2462
2463 return 0;
2464}
2465
2466/* Handle a new message. Return 1 if the message should be requeued,
2467 0 if the message should be freed, or -1 if the message should not
2468 be freed or requeued. */
2469static int handle_new_recv_msg(ipmi_smi_t intf,
2470 struct ipmi_smi_msg *msg)
2471{
2472 int requeue;
2473 int chan;
2474
2475#ifdef DEBUG_MSGING
2476 int m;
2477 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002478 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 printk(" %2.2x", msg->rsp[m]);
2480 printk("\n");
2481#endif
2482 if (msg->rsp_size < 2) {
2483 /* Message is too small to be correct. */
2484 printk(KERN_WARNING PFX "BMC returned to small a message"
2485 " for netfn %x cmd %x, got %d bytes\n",
2486 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
2487
2488 /* Generate an error response for the message. */
2489 msg->rsp[0] = msg->data[0] | (1 << 2);
2490 msg->rsp[1] = msg->data[1];
2491 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
2492 msg->rsp_size = 3;
2493 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
2494 || (msg->rsp[1] != msg->data[1])) /* Command */
2495 {
2496 /* The response is not even marginally correct. */
2497 printk(KERN_WARNING PFX "BMC returned incorrect response,"
2498 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
2499 (msg->data[0] >> 2) | 1, msg->data[1],
2500 msg->rsp[0] >> 2, msg->rsp[1]);
2501
2502 /* Generate an error response for the message. */
2503 msg->rsp[0] = msg->data[0] | (1 << 2);
2504 msg->rsp[1] = msg->data[1];
2505 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
2506 msg->rsp_size = 3;
2507 }
2508
2509 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
2510 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
2511 && (msg->user_data != NULL))
2512 {
2513 /* It's a response to a response we sent. For this we
2514 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002515 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516
2517 requeue = 0;
2518 if (msg->rsp_size < 2)
2519 /* Message is too small to be correct. */
2520 goto out;
2521
2522 chan = msg->data[2] & 0x0f;
2523 if (chan >= IPMI_MAX_CHANNELS)
2524 /* Invalid channel number */
2525 goto out;
2526
Corey Minyard393d2cc2005-11-07 00:59:54 -08002527 if (!recv_msg)
2528 goto out;
2529
2530 /* Make sure the user still exists. */
2531 if (!recv_msg->user || !recv_msg->user->valid)
2532 goto out;
2533
2534 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
2535 recv_msg->msg.data = recv_msg->msg_data;
2536 recv_msg->msg.data_len = 1;
2537 recv_msg->msg_data[0] = msg->rsp[2];
2538 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
2540 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
2541 {
2542 /* It's from the receive queue. */
2543 chan = msg->rsp[3] & 0xf;
2544 if (chan >= IPMI_MAX_CHANNELS) {
2545 /* Invalid channel number */
2546 requeue = 0;
2547 goto out;
2548 }
2549
2550 switch (intf->channels[chan].medium) {
2551 case IPMI_CHANNEL_MEDIUM_IPMB:
2552 if (msg->rsp[4] & 0x04) {
2553 /* It's a response, so find the
2554 requesting message and send it up. */
2555 requeue = handle_ipmb_get_msg_rsp(intf, msg);
2556 } else {
2557 /* It's a command to the SMS from some other
2558 entity. Handle that. */
2559 requeue = handle_ipmb_get_msg_cmd(intf, msg);
2560 }
2561 break;
2562
2563 case IPMI_CHANNEL_MEDIUM_8023LAN:
2564 case IPMI_CHANNEL_MEDIUM_ASYNC:
2565 if (msg->rsp[6] & 0x04) {
2566 /* It's a response, so find the
2567 requesting message and send it up. */
2568 requeue = handle_lan_get_msg_rsp(intf, msg);
2569 } else {
2570 /* It's a command to the SMS from some other
2571 entity. Handle that. */
2572 requeue = handle_lan_get_msg_cmd(intf, msg);
2573 }
2574 break;
2575
2576 default:
2577 /* We don't handle the channel type, so just
2578 * free the message. */
2579 requeue = 0;
2580 }
2581
2582 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
2583 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
2584 {
2585 /* It's an asyncronous event. */
2586 requeue = handle_read_event_rsp(intf, msg);
2587 } else {
2588 /* It's a response from the local BMC. */
2589 requeue = handle_bmc_rsp(intf, msg);
2590 }
2591
2592 out:
2593 return requeue;
2594}
2595
2596/* Handle a new message from the lower layer. */
2597void ipmi_smi_msg_received(ipmi_smi_t intf,
2598 struct ipmi_smi_msg *msg)
2599{
2600 unsigned long flags;
2601 int rv;
2602
2603
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 if ((msg->data_size >= 2)
2605 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
2606 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002607 && (msg->user_data == NULL))
2608 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 /* This is the local response to a command send, start
2610 the timer for these. The user_data will not be
2611 NULL if this is a response send, and we will let
2612 response sends just go through. */
2613
2614 /* Check for errors, if we get certain errors (ones
2615 that mean basically we can try again later), we
2616 ignore them and start the timer. Otherwise we
2617 report the error immediately. */
2618 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
2619 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
2620 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR))
2621 {
2622 int chan = msg->rsp[3] & 0xf;
2623
2624 /* Got an error sending the message, handle it. */
2625 spin_lock_irqsave(&intf->counter_lock, flags);
2626 if (chan >= IPMI_MAX_CHANNELS)
2627 ; /* This shouldn't happen */
2628 else if ((intf->channels[chan].medium
2629 == IPMI_CHANNEL_MEDIUM_8023LAN)
2630 || (intf->channels[chan].medium
2631 == IPMI_CHANNEL_MEDIUM_ASYNC))
2632 intf->sent_lan_command_errs++;
2633 else
2634 intf->sent_ipmb_command_errs++;
2635 spin_unlock_irqrestore(&intf->counter_lock, flags);
2636 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
2637 } else {
2638 /* The message was sent, start the timer. */
2639 intf_start_seq_timer(intf, msg->msgid);
2640 }
2641
2642 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002643 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 }
2645
2646 /* To preserve message order, if the list is not empty, we
2647 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002648 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
2649 if (!list_empty(&intf->waiting_msgs)) {
2650 list_add_tail(&msg->link, &intf->waiting_msgs);
2651 spin_unlock(&intf->waiting_msgs_lock);
2652 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002654 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
2656 rv = handle_new_recv_msg(intf, msg);
2657 if (rv > 0) {
2658 /* Could not handle the message now, just add it to a
2659 list to handle later. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002660 spin_lock(&intf->waiting_msgs_lock);
2661 list_add_tail(&msg->link, &intf->waiting_msgs);
2662 spin_unlock(&intf->waiting_msgs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 } else if (rv == 0) {
2664 ipmi_free_smi_msg(msg);
2665 }
2666
Corey Minyard393d2cc2005-11-07 00:59:54 -08002667 out:
2668 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669}
2670
2671void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
2672{
2673 ipmi_user_t user;
2674
Corey Minyard393d2cc2005-11-07 00:59:54 -08002675 rcu_read_lock();
2676 list_for_each_entry_rcu(user, &intf->users, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 if (! user->handler->ipmi_watchdog_pretimeout)
2678 continue;
2679
2680 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
2681 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002682 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683}
2684
2685static void
2686handle_msg_timeout(struct ipmi_recv_msg *msg)
2687{
2688 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2689 msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;
2690 msg->msg.netfn |= 1; /* Convert to a response. */
2691 msg->msg.data_len = 1;
2692 msg->msg.data = msg->msg_data;
2693 deliver_response(msg);
2694}
2695
Corey Minyard882fe012005-05-01 08:59:12 -07002696static struct ipmi_smi_msg *
2697smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
2698 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699{
Corey Minyard882fe012005-05-01 08:59:12 -07002700 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 if (!smi_msg)
2702 /* If we can't allocate the message, then just return, we
2703 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07002704 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
2706 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
2707 smi_msg->data_size = recv_msg->msg.data_len;
2708 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
2709
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710#ifdef DEBUG_MSGING
2711 {
2712 int m;
2713 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07002714 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 printk(" %2.2x", smi_msg->data[m]);
2716 printk("\n");
2717 }
2718#endif
Corey Minyard882fe012005-05-01 08:59:12 -07002719 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720}
2721
Corey Minyard393d2cc2005-11-07 00:59:54 -08002722static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
2723 struct list_head *timeouts, long timeout_period,
2724 int slot, unsigned long *flags)
2725{
2726 struct ipmi_recv_msg *msg;
2727
2728 if (!ent->inuse)
2729 return;
2730
2731 ent->timeout -= timeout_period;
2732 if (ent->timeout > 0)
2733 return;
2734
2735 if (ent->retries_left == 0) {
2736 /* The message has used all its retries. */
2737 ent->inuse = 0;
2738 msg = ent->recv_msg;
2739 list_add_tail(&msg->link, timeouts);
2740 spin_lock(&intf->counter_lock);
2741 if (ent->broadcast)
2742 intf->timed_out_ipmb_broadcasts++;
2743 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
2744 intf->timed_out_lan_commands++;
2745 else
2746 intf->timed_out_ipmb_commands++;
2747 spin_unlock(&intf->counter_lock);
2748 } else {
2749 struct ipmi_smi_msg *smi_msg;
2750 /* More retries, send again. */
2751
2752 /* Start with the max timer, set to normal
2753 timer after the message is sent. */
2754 ent->timeout = MAX_MSG_TIMEOUT;
2755 ent->retries_left--;
2756 spin_lock(&intf->counter_lock);
2757 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
2758 intf->retransmitted_lan_commands++;
2759 else
2760 intf->retransmitted_ipmb_commands++;
2761 spin_unlock(&intf->counter_lock);
2762
2763 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
2764 ent->seqid);
2765 if (! smi_msg)
2766 return;
2767
2768 spin_unlock_irqrestore(&intf->seq_lock, *flags);
2769 /* Send the new message. We send with a zero
2770 * priority. It timed out, I doubt time is
2771 * that critical now, and high priority
2772 * messages are really only for messages to the
2773 * local MC, which don't get resent. */
2774 intf->handlers->sender(intf->send_info,
2775 smi_msg, 0);
2776 spin_lock_irqsave(&intf->seq_lock, *flags);
2777 }
2778}
2779
2780static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781{
2782 ipmi_smi_t intf;
2783 struct list_head timeouts;
2784 struct ipmi_recv_msg *msg, *msg2;
2785 struct ipmi_smi_msg *smi_msg, *smi_msg2;
2786 unsigned long flags;
2787 int i, j;
2788
2789 INIT_LIST_HEAD(&timeouts);
2790
2791 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07002792 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08002794 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 continue;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002796 kref_get(&intf->refcount);
2797 spin_unlock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
2799 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002800 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
2801 list_for_each_entry_safe(smi_msg, smi_msg2, &intf->waiting_msgs, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 if (! handle_new_recv_msg(intf, smi_msg)) {
2803 list_del(&smi_msg->link);
2804 ipmi_free_smi_msg(smi_msg);
2805 } else {
2806 /* To preserve message order, quit if we
2807 can't handle a message. */
2808 break;
2809 }
2810 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002811 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812
2813 /* Go through the seq table and find any messages that
2814 have timed out, putting them in the timeouts
2815 list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002816 spin_lock_irqsave(&intf->seq_lock, flags);
2817 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++)
2818 check_msg_timeout(intf, &(intf->seq_table[j]),
2819 &timeouts, timeout_period, j,
2820 &flags);
2821 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822
Corey Minyard393d2cc2005-11-07 00:59:54 -08002823 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 handle_msg_timeout(msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825
Corey Minyard393d2cc2005-11-07 00:59:54 -08002826 kref_put(&intf->refcount, intf_free);
2827 spin_lock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 }
2829 spin_unlock(&interfaces_lock);
2830}
2831
2832static void ipmi_request_event(void)
2833{
2834 ipmi_smi_t intf;
2835 int i;
2836
2837 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07002838 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08002840 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 continue;
2842
2843 intf->handlers->request_events(intf->send_info);
2844 }
2845 spin_unlock(&interfaces_lock);
2846}
2847
2848static struct timer_list ipmi_timer;
2849
2850/* Call every ~100 ms. */
2851#define IPMI_TIMEOUT_TIME 100
2852
2853/* How many jiffies does it take to get to the timeout time. */
2854#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
2855
2856/* Request events from the queue every second (this is the number of
2857 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
2858 future, IPMI will add a way to know immediately if an event is in
2859 the queue and this silliness can go away. */
2860#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
2861
Corey Minyard8f43f842005-06-23 22:01:40 -07002862static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
2864
2865static void ipmi_timeout(unsigned long data)
2866{
Corey Minyard8f43f842005-06-23 22:01:40 -07002867 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869
2870 ticks_to_req_ev--;
2871 if (ticks_to_req_ev == 0) {
2872 ipmi_request_event();
2873 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
2874 }
2875
2876 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
2877
Corey Minyard8f43f842005-06-23 22:01:40 -07002878 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879}
2880
2881
2882static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
2883static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
2884
2885/* FIXME - convert these to slabs. */
2886static void free_smi_msg(struct ipmi_smi_msg *msg)
2887{
2888 atomic_dec(&smi_msg_inuse_count);
2889 kfree(msg);
2890}
2891
2892struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
2893{
2894 struct ipmi_smi_msg *rv;
2895 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
2896 if (rv) {
2897 rv->done = free_smi_msg;
2898 rv->user_data = NULL;
2899 atomic_inc(&smi_msg_inuse_count);
2900 }
2901 return rv;
2902}
2903
2904static void free_recv_msg(struct ipmi_recv_msg *msg)
2905{
2906 atomic_dec(&recv_msg_inuse_count);
2907 kfree(msg);
2908}
2909
2910struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
2911{
2912 struct ipmi_recv_msg *rv;
2913
2914 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
2915 if (rv) {
2916 rv->done = free_recv_msg;
2917 atomic_inc(&recv_msg_inuse_count);
2918 }
2919 return rv;
2920}
2921
Corey Minyard393d2cc2005-11-07 00:59:54 -08002922void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
2923{
2924 if (msg->user)
2925 kref_put(&msg->user->refcount, free_user);
2926 msg->done(msg);
2927}
2928
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929#ifdef CONFIG_IPMI_PANIC_EVENT
2930
2931static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
2932{
2933}
2934
2935static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
2936{
2937}
2938
2939#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07002940static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941{
Corey Minyard56a55ec2005-09-06 15:18:42 -07002942 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2943 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
2944 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
2945 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 {
2947 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002948 intf->event_receiver = msg->msg.data[1];
2949 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 }
2951}
2952
Corey Minyard56a55ec2005-09-06 15:18:42 -07002953static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954{
Corey Minyard56a55ec2005-09-06 15:18:42 -07002955 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2956 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2957 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
2958 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 {
2960 /* A get device id command, save if we are an event
2961 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002962 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
2963 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 }
2965}
2966#endif
2967
2968static void send_panic_events(char *str)
2969{
2970 struct kernel_ipmi_msg msg;
2971 ipmi_smi_t intf;
2972 unsigned char data[16];
2973 int i;
2974 struct ipmi_system_interface_addr *si;
2975 struct ipmi_addr addr;
2976 struct ipmi_smi_msg smi_msg;
2977 struct ipmi_recv_msg recv_msg;
2978
2979 si = (struct ipmi_system_interface_addr *) &addr;
2980 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2981 si->channel = IPMI_BMC_CHANNEL;
2982 si->lun = 0;
2983
2984 /* Fill in an event telling that we have failed. */
2985 msg.netfn = 0x04; /* Sensor or Event. */
2986 msg.cmd = 2; /* Platform event command. */
2987 msg.data = data;
2988 msg.data_len = 8;
2989 data[0] = 0x21; /* Kernel generator ID, IPMI table 5-4 */
2990 data[1] = 0x03; /* This is for IPMI 1.0. */
2991 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
2992 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
2993 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
2994
2995 /* Put a few breadcrumbs in. Hopefully later we can add more things
2996 to make the panic events more useful. */
2997 if (str) {
2998 data[3] = str[0];
2999 data[6] = str[1];
3000 data[7] = str[2];
3001 }
3002
3003 smi_msg.done = dummy_smi_done_handler;
3004 recv_msg.done = dummy_recv_done_handler;
3005
3006 /* For every registered interface, send the event. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003007 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003009 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 continue;
3011
3012 /* Send the event announcing the panic. */
3013 intf->handlers->set_run_to_completion(intf->send_info, 1);
3014 i_ipmi_request(NULL,
3015 intf,
3016 &addr,
3017 0,
3018 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003019 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 &smi_msg,
3021 &recv_msg,
3022 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003023 intf->channels[0].address,
3024 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 0, 1); /* Don't retry, and don't wait. */
3026 }
3027
3028#ifdef CONFIG_IPMI_PANIC_STRING
3029 /* On every interface, dump a bunch of OEM event holding the
3030 string. */
3031 if (!str)
3032 return;
3033
Corey Minyarde8b33612005-09-06 15:18:45 -07003034 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 char *p = str;
3036 struct ipmi_ipmb_addr *ipmb;
3037 int j;
3038
3039 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003040 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 continue;
3042
3043 /* First job here is to figure out where to send the
3044 OEM events. There's no way in IPMI to send OEM
3045 events using an event send command, so we have to
3046 find the SEL to put them in and stick them in
3047 there. */
3048
3049 /* Get capabilities from the get device id. */
3050 intf->local_sel_device = 0;
3051 intf->local_event_generator = 0;
3052 intf->event_receiver = 0;
3053
3054 /* Request the device info from the local MC. */
3055 msg.netfn = IPMI_NETFN_APP_REQUEST;
3056 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3057 msg.data = NULL;
3058 msg.data_len = 0;
3059 intf->null_user_handler = device_id_fetcher;
3060 i_ipmi_request(NULL,
3061 intf,
3062 &addr,
3063 0,
3064 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003065 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 &smi_msg,
3067 &recv_msg,
3068 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003069 intf->channels[0].address,
3070 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 0, 1); /* Don't retry, and don't wait. */
3072
3073 if (intf->local_event_generator) {
3074 /* Request the event receiver from the local MC. */
3075 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3076 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3077 msg.data = NULL;
3078 msg.data_len = 0;
3079 intf->null_user_handler = event_receiver_fetcher;
3080 i_ipmi_request(NULL,
3081 intf,
3082 &addr,
3083 0,
3084 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003085 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 &smi_msg,
3087 &recv_msg,
3088 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003089 intf->channels[0].address,
3090 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 0, 1); /* no retry, and no wait. */
3092 }
3093 intf->null_user_handler = NULL;
3094
3095 /* Validate the event receiver. The low bit must not
3096 be 1 (it must be a valid IPMB address), it cannot
3097 be zero, and it must not be my address. */
3098 if (((intf->event_receiver & 1) == 0)
3099 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003100 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 {
3102 /* The event receiver is valid, send an IPMB
3103 message. */
3104 ipmb = (struct ipmi_ipmb_addr *) &addr;
3105 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3106 ipmb->channel = 0; /* FIXME - is this right? */
3107 ipmb->lun = intf->event_receiver_lun;
3108 ipmb->slave_addr = intf->event_receiver;
3109 } else if (intf->local_sel_device) {
3110 /* The event receiver was not valid (or was
3111 me), but I am an SEL device, just dump it
3112 in my SEL. */
3113 si = (struct ipmi_system_interface_addr *) &addr;
3114 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3115 si->channel = IPMI_BMC_CHANNEL;
3116 si->lun = 0;
3117 } else
3118 continue; /* No where to send the event. */
3119
3120
3121 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
3122 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
3123 msg.data = data;
3124 msg.data_len = 16;
3125
3126 j = 0;
3127 while (*p) {
3128 int size = strlen(p);
3129
3130 if (size > 11)
3131 size = 11;
3132 data[0] = 0;
3133 data[1] = 0;
3134 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07003135 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 data[4] = j++; /* sequence # */
3137 /* Always give 11 bytes, so strncpy will fill
3138 it with zeroes for me. */
3139 strncpy(data+5, p, 11);
3140 p += size;
3141
3142 i_ipmi_request(NULL,
3143 intf,
3144 &addr,
3145 0,
3146 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003147 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 &smi_msg,
3149 &recv_msg,
3150 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003151 intf->channels[0].address,
3152 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 0, 1); /* no retry, and no wait. */
3154 }
3155 }
3156#endif /* CONFIG_IPMI_PANIC_STRING */
3157}
3158#endif /* CONFIG_IPMI_PANIC_EVENT */
3159
3160static int has_paniced = 0;
3161
3162static int panic_event(struct notifier_block *this,
3163 unsigned long event,
3164 void *ptr)
3165{
3166 int i;
3167 ipmi_smi_t intf;
3168
3169 if (has_paniced)
3170 return NOTIFY_DONE;
3171 has_paniced = 1;
3172
3173 /* For every registered interface, set it to run to completion. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003174 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003176 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 continue;
3178
3179 intf->handlers->set_run_to_completion(intf->send_info, 1);
3180 }
3181
3182#ifdef CONFIG_IPMI_PANIC_EVENT
3183 send_panic_events(ptr);
3184#endif
3185
3186 return NOTIFY_DONE;
3187}
3188
3189static struct notifier_block panic_block = {
3190 .notifier_call = panic_event,
3191 .next = NULL,
3192 .priority = 200 /* priority: INT_MAX >= x >= 0 */
3193};
3194
3195static int ipmi_init_msghandler(void)
3196{
3197 int i;
3198
3199 if (initialized)
3200 return 0;
3201
3202 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003203 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204
Corey Minyard393d2cc2005-11-07 00:59:54 -08003205 for (i = 0; i < MAX_IPMI_INTERFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 ipmi_interfaces[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
Corey Minyard3b625942005-06-23 22:01:42 -07003208#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 proc_ipmi_root = proc_mkdir("ipmi", NULL);
3210 if (!proc_ipmi_root) {
3211 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
3212 return -ENOMEM;
3213 }
3214
3215 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07003216#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
3218 init_timer(&ipmi_timer);
3219 ipmi_timer.data = 0;
3220 ipmi_timer.function = ipmi_timeout;
3221 ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
3222 add_timer(&ipmi_timer);
3223
3224 notifier_chain_register(&panic_notifier_list, &panic_block);
3225
3226 initialized = 1;
3227
3228 return 0;
3229}
3230
3231static __init int ipmi_init_msghandler_mod(void)
3232{
3233 ipmi_init_msghandler();
3234 return 0;
3235}
3236
3237static __exit void cleanup_ipmi(void)
3238{
3239 int count;
3240
3241 if (!initialized)
3242 return;
3243
3244 notifier_chain_unregister(&panic_notifier_list, &panic_block);
3245
3246 /* This can't be called if any interfaces exist, so no worry about
3247 shutting down the interfaces. */
3248
3249 /* Tell the timer to stop, then wait for it to stop. This avoids
3250 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07003251 atomic_inc(&stop_operation);
3252 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253
Corey Minyard3b625942005-06-23 22:01:42 -07003254#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 remove_proc_entry(proc_ipmi_root->name, &proc_root);
Corey Minyard3b625942005-06-23 22:01:42 -07003256#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257
3258 initialized = 0;
3259
3260 /* Check for buffer leaks. */
3261 count = atomic_read(&smi_msg_inuse_count);
3262 if (count != 0)
3263 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
3264 count);
3265 count = atomic_read(&recv_msg_inuse_count);
3266 if (count != 0)
3267 printk(KERN_WARNING PFX "recv message count %d at exit\n",
3268 count);
3269}
3270module_exit(cleanup_ipmi);
3271
3272module_init(ipmi_init_msghandler_mod);
3273MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003274MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
3275MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
3276MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277
3278EXPORT_SYMBOL(ipmi_create_user);
3279EXPORT_SYMBOL(ipmi_destroy_user);
3280EXPORT_SYMBOL(ipmi_get_version);
3281EXPORT_SYMBOL(ipmi_request_settime);
3282EXPORT_SYMBOL(ipmi_request_supply_msgs);
3283EXPORT_SYMBOL(ipmi_register_smi);
3284EXPORT_SYMBOL(ipmi_unregister_smi);
3285EXPORT_SYMBOL(ipmi_register_for_cmd);
3286EXPORT_SYMBOL(ipmi_unregister_for_cmd);
3287EXPORT_SYMBOL(ipmi_smi_msg_received);
3288EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
3289EXPORT_SYMBOL(ipmi_alloc_smi_msg);
3290EXPORT_SYMBOL(ipmi_addr_length);
3291EXPORT_SYMBOL(ipmi_validate_addr);
3292EXPORT_SYMBOL(ipmi_set_gets_events);
3293EXPORT_SYMBOL(ipmi_smi_watcher_register);
3294EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
3295EXPORT_SYMBOL(ipmi_set_my_address);
3296EXPORT_SYMBOL(ipmi_get_my_address);
3297EXPORT_SYMBOL(ipmi_set_my_LUN);
3298EXPORT_SYMBOL(ipmi_get_my_LUN);
3299EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Corey Minyard3b625942005-06-23 22:01:42 -07003300EXPORT_SYMBOL(proc_ipmi_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003302EXPORT_SYMBOL(ipmi_free_recv_msg);