blob: 561430ed94af789d6beb67764660a91222f98c42 [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
Corey Minyard3225e1d2005-11-15 00:09:07 -080051#define IPMI_DRIVER_VERSION "38.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;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800790 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Corey Minyard393d2cc2005-11-07 00:59:54 -0800792 user->valid = 1;
793
794 /* Remove the user from the interface's sequence table. */
795 spin_lock_irqsave(&intf->seq_lock, flags);
796 list_del_rcu(&user->link);
797
798 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
799 if (intf->seq_table[i].inuse
800 && (intf->seq_table[i].recv_msg->user == user))
801 {
802 intf->seq_table[i].inuse = 0;
803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800805 spin_unlock_irqrestore(&intf->seq_lock, flags);
806
807 /*
808 * Remove the user from the command receiver's table. First
809 * we build a list of everything (not using the standard link,
810 * since other things may be using it till we do
811 * synchronize_rcu()) then free everything in that list.
812 */
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800813 down(&intf->cmd_rcvrs_lock);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800814 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800815 if (rcvr->user == user) {
816 list_del_rcu(&rcvr->link);
817 rcvr->next = rcvrs;
818 rcvrs = rcvr;
819 }
820 }
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800821 up(&intf->cmd_rcvrs_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800822 synchronize_rcu();
823 while (rcvrs) {
824 rcvr = rcvrs;
825 rcvrs = rcvr->next;
826 kfree(rcvr);
827 }
828
829 module_put(intf->handlers->owner);
830 if (intf->handlers->dec_usecount)
831 intf->handlers->dec_usecount(intf->send_info);
832
833 kref_put(&intf->refcount, intf_free);
834
835 kref_put(&user->refcount, free_user);
836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 return rv;
838}
839
840void ipmi_get_version(ipmi_user_t user,
841 unsigned char *major,
842 unsigned char *minor)
843{
844 *major = user->intf->version_major;
845 *minor = user->intf->version_minor;
846}
847
Corey Minyardc14979b2005-09-06 15:18:38 -0700848int ipmi_set_my_address(ipmi_user_t user,
849 unsigned int channel,
850 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851{
Corey Minyardc14979b2005-09-06 15:18:38 -0700852 if (channel >= IPMI_MAX_CHANNELS)
853 return -EINVAL;
854 user->intf->channels[channel].address = address;
855 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856}
857
Corey Minyardc14979b2005-09-06 15:18:38 -0700858int ipmi_get_my_address(ipmi_user_t user,
859 unsigned int channel,
860 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
Corey Minyardc14979b2005-09-06 15:18:38 -0700862 if (channel >= IPMI_MAX_CHANNELS)
863 return -EINVAL;
864 *address = user->intf->channels[channel].address;
865 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866}
867
Corey Minyardc14979b2005-09-06 15:18:38 -0700868int ipmi_set_my_LUN(ipmi_user_t user,
869 unsigned int channel,
870 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871{
Corey Minyardc14979b2005-09-06 15:18:38 -0700872 if (channel >= IPMI_MAX_CHANNELS)
873 return -EINVAL;
874 user->intf->channels[channel].lun = LUN & 0x3;
875 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
Corey Minyardc14979b2005-09-06 15:18:38 -0700878int ipmi_get_my_LUN(ipmi_user_t user,
879 unsigned int channel,
880 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
Corey Minyardc14979b2005-09-06 15:18:38 -0700882 if (channel >= IPMI_MAX_CHANNELS)
883 return -EINVAL;
884 *address = user->intf->channels[channel].lun;
885 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886}
887
888int ipmi_set_gets_events(ipmi_user_t user, int val)
889{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800890 unsigned long flags;
891 ipmi_smi_t intf = user->intf;
892 struct ipmi_recv_msg *msg, *msg2;
893 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
Corey Minyard393d2cc2005-11-07 00:59:54 -0800895 INIT_LIST_HEAD(&msgs);
896
897 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 user->gets_events = val;
899
900 if (val) {
901 /* Deliver any queued events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -0800902 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 list_del(&msg->link);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800904 list_add_tail(&msg->link, &msgs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
906 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800907
908 /* Hold the events lock while doing this to preserve order. */
909 list_for_each_entry_safe(msg, msg2, &msgs, link) {
910 msg->user = user;
911 kref_get(&user->refcount);
912 deliver_response(msg);
913 }
914
915 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917 return 0;
918}
919
Corey Minyard393d2cc2005-11-07 00:59:54 -0800920static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
921 unsigned char netfn,
922 unsigned char cmd)
923{
924 struct cmd_rcvr *rcvr;
925
926 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
927 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd))
928 return rcvr;
929 }
930 return NULL;
931}
932
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933int ipmi_register_for_cmd(ipmi_user_t user,
934 unsigned char netfn,
935 unsigned char cmd)
936{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800937 ipmi_smi_t intf = user->intf;
938 struct cmd_rcvr *rcvr;
939 struct cmd_rcvr *entry;
940 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942
943 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
944 if (! rcvr)
945 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800946 rcvr->cmd = cmd;
947 rcvr->netfn = netfn;
948 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800950 down(&intf->cmd_rcvrs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 /* Make sure the command/netfn is not already registered. */
Corey Minyard393d2cc2005-11-07 00:59:54 -0800952 entry = find_cmd_rcvr(intf, netfn, cmd);
953 if (entry) {
954 rv = -EBUSY;
955 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 }
957
Corey Minyard393d2cc2005-11-07 00:59:54 -0800958 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -0700959
Corey Minyard393d2cc2005-11-07 00:59:54 -0800960 out_unlock:
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800961 up(&intf->cmd_rcvrs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 if (rv)
963 kfree(rcvr);
964
965 return rv;
966}
967
968int ipmi_unregister_for_cmd(ipmi_user_t user,
969 unsigned char netfn,
970 unsigned char cmd)
971{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800972 ipmi_smi_t intf = user->intf;
973 struct cmd_rcvr *rcvr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800975 down(&intf->cmd_rcvrs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 /* Make sure the command/netfn is not already registered. */
Corey Minyard393d2cc2005-11-07 00:59:54 -0800977 rcvr = find_cmd_rcvr(intf, netfn, cmd);
978 if ((rcvr) && (rcvr->user == user)) {
979 list_del_rcu(&rcvr->link);
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800980 up(&intf->cmd_rcvrs_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800981 synchronize_rcu();
982 kfree(rcvr);
983 return 0;
984 } else {
Corey Minyarde61fb5b2005-11-07 01:00:05 -0800985 up(&intf->cmd_rcvrs_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800986 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988}
989
990void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
991{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800992 ipmi_smi_t intf = user->intf;
993 intf->handlers->set_run_to_completion(intf->send_info, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994}
995
996static unsigned char
997ipmb_checksum(unsigned char *data, int size)
998{
999 unsigned char csum = 0;
1000
1001 for (; size > 0; size--, data++)
1002 csum += *data;
1003
1004 return -csum;
1005}
1006
1007static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1008 struct kernel_ipmi_msg *msg,
1009 struct ipmi_ipmb_addr *ipmb_addr,
1010 long msgid,
1011 unsigned char ipmb_seq,
1012 int broadcast,
1013 unsigned char source_address,
1014 unsigned char source_lun)
1015{
1016 int i = broadcast;
1017
1018 /* Format the IPMB header data. */
1019 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1020 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1021 smi_msg->data[2] = ipmb_addr->channel;
1022 if (broadcast)
1023 smi_msg->data[3] = 0;
1024 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1025 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1026 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1027 smi_msg->data[i+6] = source_address;
1028 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1029 smi_msg->data[i+8] = msg->cmd;
1030
1031 /* Now tack on the data to the message. */
1032 if (msg->data_len > 0)
1033 memcpy(&(smi_msg->data[i+9]), msg->data,
1034 msg->data_len);
1035 smi_msg->data_size = msg->data_len + 9;
1036
1037 /* Now calculate the checksum and tack it on. */
1038 smi_msg->data[i+smi_msg->data_size]
1039 = ipmb_checksum(&(smi_msg->data[i+6]),
1040 smi_msg->data_size-6);
1041
1042 /* Add on the checksum size and the offset from the
1043 broadcast. */
1044 smi_msg->data_size += 1 + i;
1045
1046 smi_msg->msgid = msgid;
1047}
1048
1049static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1050 struct kernel_ipmi_msg *msg,
1051 struct ipmi_lan_addr *lan_addr,
1052 long msgid,
1053 unsigned char ipmb_seq,
1054 unsigned char source_lun)
1055{
1056 /* Format the IPMB header data. */
1057 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1058 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1059 smi_msg->data[2] = lan_addr->channel;
1060 smi_msg->data[3] = lan_addr->session_handle;
1061 smi_msg->data[4] = lan_addr->remote_SWID;
1062 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1063 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1064 smi_msg->data[7] = lan_addr->local_SWID;
1065 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1066 smi_msg->data[9] = msg->cmd;
1067
1068 /* Now tack on the data to the message. */
1069 if (msg->data_len > 0)
1070 memcpy(&(smi_msg->data[10]), msg->data,
1071 msg->data_len);
1072 smi_msg->data_size = msg->data_len + 10;
1073
1074 /* Now calculate the checksum and tack it on. */
1075 smi_msg->data[smi_msg->data_size]
1076 = ipmb_checksum(&(smi_msg->data[7]),
1077 smi_msg->data_size-7);
1078
1079 /* Add on the checksum size and the offset from the
1080 broadcast. */
1081 smi_msg->data_size += 1;
1082
1083 smi_msg->msgid = msgid;
1084}
1085
1086/* Separate from ipmi_request so that the user does not have to be
1087 supplied in certain circumstances (mainly at panic time). If
1088 messages are supplied, they will be freed, even if an error
1089 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001090static int i_ipmi_request(ipmi_user_t user,
1091 ipmi_smi_t intf,
1092 struct ipmi_addr *addr,
1093 long msgid,
1094 struct kernel_ipmi_msg *msg,
1095 void *user_msg_data,
1096 void *supplied_smi,
1097 struct ipmi_recv_msg *supplied_recv,
1098 int priority,
1099 unsigned char source_address,
1100 unsigned char source_lun,
1101 int retries,
1102 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103{
1104 int rv = 0;
1105 struct ipmi_smi_msg *smi_msg;
1106 struct ipmi_recv_msg *recv_msg;
1107 unsigned long flags;
1108
1109
1110 if (supplied_recv) {
1111 recv_msg = supplied_recv;
1112 } else {
1113 recv_msg = ipmi_alloc_recv_msg();
1114 if (recv_msg == NULL) {
1115 return -ENOMEM;
1116 }
1117 }
1118 recv_msg->user_msg_data = user_msg_data;
1119
1120 if (supplied_smi) {
1121 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1122 } else {
1123 smi_msg = ipmi_alloc_smi_msg();
1124 if (smi_msg == NULL) {
1125 ipmi_free_recv_msg(recv_msg);
1126 return -ENOMEM;
1127 }
1128 }
1129
1130 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001131 if (user)
1132 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 recv_msg->msgid = msgid;
1134 /* Store the message to send in the receive message so timeout
1135 responses can get the proper response data. */
1136 recv_msg->msg = *msg;
1137
1138 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1139 struct ipmi_system_interface_addr *smi_addr;
1140
1141 if (msg->netfn & 1) {
1142 /* Responses are not allowed to the SMI. */
1143 rv = -EINVAL;
1144 goto out_err;
1145 }
1146
1147 smi_addr = (struct ipmi_system_interface_addr *) addr;
1148 if (smi_addr->lun > 3) {
1149 spin_lock_irqsave(&intf->counter_lock, flags);
1150 intf->sent_invalid_commands++;
1151 spin_unlock_irqrestore(&intf->counter_lock, flags);
1152 rv = -EINVAL;
1153 goto out_err;
1154 }
1155
1156 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1157
1158 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1159 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1160 || (msg->cmd == IPMI_GET_MSG_CMD)
1161 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1162 {
1163 /* We don't let the user do these, since we manage
1164 the sequence numbers. */
1165 spin_lock_irqsave(&intf->counter_lock, flags);
1166 intf->sent_invalid_commands++;
1167 spin_unlock_irqrestore(&intf->counter_lock, flags);
1168 rv = -EINVAL;
1169 goto out_err;
1170 }
1171
1172 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1173 spin_lock_irqsave(&intf->counter_lock, flags);
1174 intf->sent_invalid_commands++;
1175 spin_unlock_irqrestore(&intf->counter_lock, flags);
1176 rv = -EMSGSIZE;
1177 goto out_err;
1178 }
1179
1180 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1181 smi_msg->data[1] = msg->cmd;
1182 smi_msg->msgid = msgid;
1183 smi_msg->user_data = recv_msg;
1184 if (msg->data_len > 0)
1185 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1186 smi_msg->data_size = msg->data_len + 2;
1187 spin_lock_irqsave(&intf->counter_lock, flags);
1188 intf->sent_local_commands++;
1189 spin_unlock_irqrestore(&intf->counter_lock, flags);
1190 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1191 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1192 {
1193 struct ipmi_ipmb_addr *ipmb_addr;
1194 unsigned char ipmb_seq;
1195 long seqid;
1196 int broadcast = 0;
1197
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001198 if (addr->channel >= IPMI_MAX_CHANNELS) {
1199 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 intf->sent_invalid_commands++;
1201 spin_unlock_irqrestore(&intf->counter_lock, flags);
1202 rv = -EINVAL;
1203 goto out_err;
1204 }
1205
1206 if (intf->channels[addr->channel].medium
1207 != IPMI_CHANNEL_MEDIUM_IPMB)
1208 {
1209 spin_lock_irqsave(&intf->counter_lock, flags);
1210 intf->sent_invalid_commands++;
1211 spin_unlock_irqrestore(&intf->counter_lock, flags);
1212 rv = -EINVAL;
1213 goto out_err;
1214 }
1215
1216 if (retries < 0) {
1217 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1218 retries = 0; /* Don't retry broadcasts. */
1219 else
1220 retries = 4;
1221 }
1222 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1223 /* Broadcasts add a zero at the beginning of the
1224 message, but otherwise is the same as an IPMB
1225 address. */
1226 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1227 broadcast = 1;
1228 }
1229
1230
1231 /* Default to 1 second retries. */
1232 if (retry_time_ms == 0)
1233 retry_time_ms = 1000;
1234
1235 /* 9 for the header and 1 for the checksum, plus
1236 possibly one for the broadcast. */
1237 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1238 spin_lock_irqsave(&intf->counter_lock, flags);
1239 intf->sent_invalid_commands++;
1240 spin_unlock_irqrestore(&intf->counter_lock, flags);
1241 rv = -EMSGSIZE;
1242 goto out_err;
1243 }
1244
1245 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1246 if (ipmb_addr->lun > 3) {
1247 spin_lock_irqsave(&intf->counter_lock, flags);
1248 intf->sent_invalid_commands++;
1249 spin_unlock_irqrestore(&intf->counter_lock, flags);
1250 rv = -EINVAL;
1251 goto out_err;
1252 }
1253
1254 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1255
1256 if (recv_msg->msg.netfn & 0x1) {
1257 /* It's a response, so use the user's sequence
1258 from msgid. */
1259 spin_lock_irqsave(&intf->counter_lock, flags);
1260 intf->sent_ipmb_responses++;
1261 spin_unlock_irqrestore(&intf->counter_lock, flags);
1262 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1263 msgid, broadcast,
1264 source_address, source_lun);
1265
1266 /* Save the receive message so we can use it
1267 to deliver the response. */
1268 smi_msg->user_data = recv_msg;
1269 } else {
1270 /* It's a command, so get a sequence for it. */
1271
1272 spin_lock_irqsave(&(intf->seq_lock), flags);
1273
1274 spin_lock(&intf->counter_lock);
1275 intf->sent_ipmb_commands++;
1276 spin_unlock(&intf->counter_lock);
1277
1278 /* Create a sequence number with a 1 second
1279 timeout and 4 retries. */
1280 rv = intf_next_seq(intf,
1281 recv_msg,
1282 retry_time_ms,
1283 retries,
1284 broadcast,
1285 &ipmb_seq,
1286 &seqid);
1287 if (rv) {
1288 /* We have used up all the sequence numbers,
1289 probably, so abort. */
1290 spin_unlock_irqrestore(&(intf->seq_lock),
1291 flags);
1292 goto out_err;
1293 }
1294
1295 /* Store the sequence number in the message,
1296 so that when the send message response
1297 comes back we can start the timer. */
1298 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1299 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1300 ipmb_seq, broadcast,
1301 source_address, source_lun);
1302
1303 /* Copy the message into the recv message data, so we
1304 can retransmit it later if necessary. */
1305 memcpy(recv_msg->msg_data, smi_msg->data,
1306 smi_msg->data_size);
1307 recv_msg->msg.data = recv_msg->msg_data;
1308 recv_msg->msg.data_len = smi_msg->data_size;
1309
1310 /* We don't unlock until here, because we need
1311 to copy the completed message into the
1312 recv_msg before we release the lock.
1313 Otherwise, race conditions may bite us. I
1314 know that's pretty paranoid, but I prefer
1315 to be correct. */
1316 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1317 }
1318 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1319 struct ipmi_lan_addr *lan_addr;
1320 unsigned char ipmb_seq;
1321 long seqid;
1322
Corey Minyardc14979b2005-09-06 15:18:38 -07001323 if (addr->channel >= IPMI_NUM_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 spin_lock_irqsave(&intf->counter_lock, flags);
1325 intf->sent_invalid_commands++;
1326 spin_unlock_irqrestore(&intf->counter_lock, flags);
1327 rv = -EINVAL;
1328 goto out_err;
1329 }
1330
1331 if ((intf->channels[addr->channel].medium
1332 != IPMI_CHANNEL_MEDIUM_8023LAN)
1333 && (intf->channels[addr->channel].medium
1334 != IPMI_CHANNEL_MEDIUM_ASYNC))
1335 {
1336 spin_lock_irqsave(&intf->counter_lock, flags);
1337 intf->sent_invalid_commands++;
1338 spin_unlock_irqrestore(&intf->counter_lock, flags);
1339 rv = -EINVAL;
1340 goto out_err;
1341 }
1342
1343 retries = 4;
1344
1345 /* Default to 1 second retries. */
1346 if (retry_time_ms == 0)
1347 retry_time_ms = 1000;
1348
1349 /* 11 for the header and 1 for the checksum. */
1350 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1351 spin_lock_irqsave(&intf->counter_lock, flags);
1352 intf->sent_invalid_commands++;
1353 spin_unlock_irqrestore(&intf->counter_lock, flags);
1354 rv = -EMSGSIZE;
1355 goto out_err;
1356 }
1357
1358 lan_addr = (struct ipmi_lan_addr *) addr;
1359 if (lan_addr->lun > 3) {
1360 spin_lock_irqsave(&intf->counter_lock, flags);
1361 intf->sent_invalid_commands++;
1362 spin_unlock_irqrestore(&intf->counter_lock, flags);
1363 rv = -EINVAL;
1364 goto out_err;
1365 }
1366
1367 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1368
1369 if (recv_msg->msg.netfn & 0x1) {
1370 /* It's a response, so use the user's sequence
1371 from msgid. */
1372 spin_lock_irqsave(&intf->counter_lock, flags);
1373 intf->sent_lan_responses++;
1374 spin_unlock_irqrestore(&intf->counter_lock, flags);
1375 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1376 msgid, source_lun);
1377
1378 /* Save the receive message so we can use it
1379 to deliver the response. */
1380 smi_msg->user_data = recv_msg;
1381 } else {
1382 /* It's a command, so get a sequence for it. */
1383
1384 spin_lock_irqsave(&(intf->seq_lock), flags);
1385
1386 spin_lock(&intf->counter_lock);
1387 intf->sent_lan_commands++;
1388 spin_unlock(&intf->counter_lock);
1389
1390 /* Create a sequence number with a 1 second
1391 timeout and 4 retries. */
1392 rv = intf_next_seq(intf,
1393 recv_msg,
1394 retry_time_ms,
1395 retries,
1396 0,
1397 &ipmb_seq,
1398 &seqid);
1399 if (rv) {
1400 /* We have used up all the sequence numbers,
1401 probably, so abort. */
1402 spin_unlock_irqrestore(&(intf->seq_lock),
1403 flags);
1404 goto out_err;
1405 }
1406
1407 /* Store the sequence number in the message,
1408 so that when the send message response
1409 comes back we can start the timer. */
1410 format_lan_msg(smi_msg, msg, lan_addr,
1411 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1412 ipmb_seq, source_lun);
1413
1414 /* Copy the message into the recv message data, so we
1415 can retransmit it later if necessary. */
1416 memcpy(recv_msg->msg_data, smi_msg->data,
1417 smi_msg->data_size);
1418 recv_msg->msg.data = recv_msg->msg_data;
1419 recv_msg->msg.data_len = smi_msg->data_size;
1420
1421 /* We don't unlock until here, because we need
1422 to copy the completed message into the
1423 recv_msg before we release the lock.
1424 Otherwise, race conditions may bite us. I
1425 know that's pretty paranoid, but I prefer
1426 to be correct. */
1427 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1428 }
1429 } else {
1430 /* Unknown address type. */
1431 spin_lock_irqsave(&intf->counter_lock, flags);
1432 intf->sent_invalid_commands++;
1433 spin_unlock_irqrestore(&intf->counter_lock, flags);
1434 rv = -EINVAL;
1435 goto out_err;
1436 }
1437
1438#ifdef DEBUG_MSGING
1439 {
1440 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001441 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 printk(" %2.2x", smi_msg->data[m]);
1443 printk("\n");
1444 }
1445#endif
1446 intf->handlers->sender(intf->send_info, smi_msg, priority);
1447
1448 return 0;
1449
1450 out_err:
1451 ipmi_free_smi_msg(smi_msg);
1452 ipmi_free_recv_msg(recv_msg);
1453 return rv;
1454}
1455
Corey Minyardc14979b2005-09-06 15:18:38 -07001456static int check_addr(ipmi_smi_t intf,
1457 struct ipmi_addr *addr,
1458 unsigned char *saddr,
1459 unsigned char *lun)
1460{
1461 if (addr->channel >= IPMI_MAX_CHANNELS)
1462 return -EINVAL;
1463 *lun = intf->channels[addr->channel].lun;
1464 *saddr = intf->channels[addr->channel].address;
1465 return 0;
1466}
1467
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468int ipmi_request_settime(ipmi_user_t user,
1469 struct ipmi_addr *addr,
1470 long msgid,
1471 struct kernel_ipmi_msg *msg,
1472 void *user_msg_data,
1473 int priority,
1474 int retries,
1475 unsigned int retry_time_ms)
1476{
Corey Minyardc14979b2005-09-06 15:18:38 -07001477 unsigned char saddr, lun;
1478 int rv;
1479
Corey Minyard56a55ec2005-09-06 15:18:42 -07001480 if (! user)
1481 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001482 rv = check_addr(user->intf, addr, &saddr, &lun);
1483 if (rv)
1484 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 return i_ipmi_request(user,
1486 user->intf,
1487 addr,
1488 msgid,
1489 msg,
1490 user_msg_data,
1491 NULL, NULL,
1492 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001493 saddr,
1494 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 retries,
1496 retry_time_ms);
1497}
1498
1499int ipmi_request_supply_msgs(ipmi_user_t user,
1500 struct ipmi_addr *addr,
1501 long msgid,
1502 struct kernel_ipmi_msg *msg,
1503 void *user_msg_data,
1504 void *supplied_smi,
1505 struct ipmi_recv_msg *supplied_recv,
1506 int priority)
1507{
Corey Minyardc14979b2005-09-06 15:18:38 -07001508 unsigned char saddr, lun;
1509 int rv;
1510
Corey Minyard56a55ec2005-09-06 15:18:42 -07001511 if (! user)
1512 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001513 rv = check_addr(user->intf, addr, &saddr, &lun);
1514 if (rv)
1515 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 return i_ipmi_request(user,
1517 user->intf,
1518 addr,
1519 msgid,
1520 msg,
1521 user_msg_data,
1522 supplied_smi,
1523 supplied_recv,
1524 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001525 saddr,
1526 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 -1, 0);
1528}
1529
1530static int ipmb_file_read_proc(char *page, char **start, off_t off,
1531 int count, int *eof, void *data)
1532{
1533 char *out = (char *) page;
1534 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001535 int i;
1536 int rv= 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
Corey Minyarde8b33612005-09-06 15:18:45 -07001538 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001539 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1540 out[rv-1] = '\n'; /* Replace the final space with a newline */
1541 out[rv] = '\0';
1542 rv++;
1543 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544}
1545
1546static int version_file_read_proc(char *page, char **start, off_t off,
1547 int count, int *eof, void *data)
1548{
1549 char *out = (char *) page;
1550 ipmi_smi_t intf = data;
1551
1552 return sprintf(out, "%d.%d\n",
1553 intf->version_major, intf->version_minor);
1554}
1555
1556static int stat_file_read_proc(char *page, char **start, off_t off,
1557 int count, int *eof, void *data)
1558{
1559 char *out = (char *) page;
1560 ipmi_smi_t intf = data;
1561
1562 out += sprintf(out, "sent_invalid_commands: %d\n",
1563 intf->sent_invalid_commands);
1564 out += sprintf(out, "sent_local_commands: %d\n",
1565 intf->sent_local_commands);
1566 out += sprintf(out, "handled_local_responses: %d\n",
1567 intf->handled_local_responses);
1568 out += sprintf(out, "unhandled_local_responses: %d\n",
1569 intf->unhandled_local_responses);
1570 out += sprintf(out, "sent_ipmb_commands: %d\n",
1571 intf->sent_ipmb_commands);
1572 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1573 intf->sent_ipmb_command_errs);
1574 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1575 intf->retransmitted_ipmb_commands);
1576 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1577 intf->timed_out_ipmb_commands);
1578 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1579 intf->timed_out_ipmb_broadcasts);
1580 out += sprintf(out, "sent_ipmb_responses: %d\n",
1581 intf->sent_ipmb_responses);
1582 out += sprintf(out, "handled_ipmb_responses: %d\n",
1583 intf->handled_ipmb_responses);
1584 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1585 intf->invalid_ipmb_responses);
1586 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1587 intf->unhandled_ipmb_responses);
1588 out += sprintf(out, "sent_lan_commands: %d\n",
1589 intf->sent_lan_commands);
1590 out += sprintf(out, "sent_lan_command_errs: %d\n",
1591 intf->sent_lan_command_errs);
1592 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1593 intf->retransmitted_lan_commands);
1594 out += sprintf(out, "timed_out_lan_commands: %d\n",
1595 intf->timed_out_lan_commands);
1596 out += sprintf(out, "sent_lan_responses: %d\n",
1597 intf->sent_lan_responses);
1598 out += sprintf(out, "handled_lan_responses: %d\n",
1599 intf->handled_lan_responses);
1600 out += sprintf(out, "invalid_lan_responses: %d\n",
1601 intf->invalid_lan_responses);
1602 out += sprintf(out, "unhandled_lan_responses: %d\n",
1603 intf->unhandled_lan_responses);
1604 out += sprintf(out, "handled_commands: %d\n",
1605 intf->handled_commands);
1606 out += sprintf(out, "invalid_commands: %d\n",
1607 intf->invalid_commands);
1608 out += sprintf(out, "unhandled_commands: %d\n",
1609 intf->unhandled_commands);
1610 out += sprintf(out, "invalid_events: %d\n",
1611 intf->invalid_events);
1612 out += sprintf(out, "events: %d\n",
1613 intf->events);
1614
1615 return (out - ((char *) page));
1616}
1617
1618int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1619 read_proc_t *read_proc, write_proc_t *write_proc,
1620 void *data, struct module *owner)
1621{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001623#ifdef CONFIG_PROC_FS
1624 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 struct ipmi_proc_entry *entry;
1626
1627 /* Create a list element. */
1628 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1629 if (!entry)
1630 return -ENOMEM;
1631 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1632 if (!entry->name) {
1633 kfree(entry);
1634 return -ENOMEM;
1635 }
1636 strcpy(entry->name, name);
1637
1638 file = create_proc_entry(name, 0, smi->proc_dir);
1639 if (!file) {
1640 kfree(entry->name);
1641 kfree(entry);
1642 rv = -ENOMEM;
1643 } else {
1644 file->nlink = 1;
1645 file->data = data;
1646 file->read_proc = read_proc;
1647 file->write_proc = write_proc;
1648 file->owner = owner;
1649
Corey Minyard3b625942005-06-23 22:01:42 -07001650 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 /* Stick it on the list. */
1652 entry->next = smi->proc_entries;
1653 smi->proc_entries = entry;
Corey Minyard3b625942005-06-23 22:01:42 -07001654 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 }
Corey Minyard3b625942005-06-23 22:01:42 -07001656#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657
1658 return rv;
1659}
1660
1661static int add_proc_entries(ipmi_smi_t smi, int num)
1662{
1663 int rv = 0;
1664
Corey Minyard3b625942005-06-23 22:01:42 -07001665#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 sprintf(smi->proc_dir_name, "%d", num);
1667 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1668 if (!smi->proc_dir)
1669 rv = -ENOMEM;
1670 else {
1671 smi->proc_dir->owner = THIS_MODULE;
1672 }
1673
1674 if (rv == 0)
1675 rv = ipmi_smi_add_proc_entry(smi, "stats",
1676 stat_file_read_proc, NULL,
1677 smi, THIS_MODULE);
1678
1679 if (rv == 0)
1680 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1681 ipmb_file_read_proc, NULL,
1682 smi, THIS_MODULE);
1683
1684 if (rv == 0)
1685 rv = ipmi_smi_add_proc_entry(smi, "version",
1686 version_file_read_proc, NULL,
1687 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001688#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
1690 return rv;
1691}
1692
1693static void remove_proc_entries(ipmi_smi_t smi)
1694{
Corey Minyard3b625942005-06-23 22:01:42 -07001695#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 struct ipmi_proc_entry *entry;
1697
Corey Minyard3b625942005-06-23 22:01:42 -07001698 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 while (smi->proc_entries) {
1700 entry = smi->proc_entries;
1701 smi->proc_entries = entry->next;
1702
1703 remove_proc_entry(entry->name, smi->proc_dir);
1704 kfree(entry->name);
1705 kfree(entry);
1706 }
Corey Minyard3b625942005-06-23 22:01:42 -07001707 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001709#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710}
1711
1712static int
1713send_channel_info_cmd(ipmi_smi_t intf, int chan)
1714{
1715 struct kernel_ipmi_msg msg;
1716 unsigned char data[1];
1717 struct ipmi_system_interface_addr si;
1718
1719 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
1720 si.channel = IPMI_BMC_CHANNEL;
1721 si.lun = 0;
1722
1723 msg.netfn = IPMI_NETFN_APP_REQUEST;
1724 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
1725 msg.data = data;
1726 msg.data_len = 1;
1727 data[0] = chan;
1728 return i_ipmi_request(NULL,
1729 intf,
1730 (struct ipmi_addr *) &si,
1731 0,
1732 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07001733 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 NULL,
1735 NULL,
1736 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07001737 intf->channels[0].address,
1738 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 -1, 0);
1740}
1741
1742static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07001743channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744{
1745 int rv = 0;
1746 int chan;
1747
Corey Minyard56a55ec2005-09-06 15:18:42 -07001748 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
1749 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
1750 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 {
1752 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07001753 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 /* Got an error from the channel, just go on. */
1755
Corey Minyard56a55ec2005-09-06 15:18:42 -07001756 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 /* If the MC does not support this
1758 command, that is legal. We just
1759 assume it has one IPMB at channel
1760 zero. */
1761 intf->channels[0].medium
1762 = IPMI_CHANNEL_MEDIUM_IPMB;
1763 intf->channels[0].protocol
1764 = IPMI_CHANNEL_PROTOCOL_IPMB;
1765 rv = -ENOSYS;
1766
1767 intf->curr_channel = IPMI_MAX_CHANNELS;
1768 wake_up(&intf->waitq);
1769 goto out;
1770 }
1771 goto next_channel;
1772 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07001773 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 /* Message not big enough, just go on. */
1775 goto next_channel;
1776 }
1777 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07001778 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
1779 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
1781 next_channel:
1782 intf->curr_channel++;
1783 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
1784 wake_up(&intf->waitq);
1785 else
1786 rv = send_channel_info_cmd(intf, intf->curr_channel);
1787
1788 if (rv) {
1789 /* Got an error somehow, just give up. */
1790 intf->curr_channel = IPMI_MAX_CHANNELS;
1791 wake_up(&intf->waitq);
1792
1793 printk(KERN_WARNING PFX
1794 "Error sending channel information: %d\n",
1795 rv);
1796 }
1797 }
1798 out:
1799 return;
1800}
1801
1802int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
1803 void *send_info,
1804 unsigned char version_major,
1805 unsigned char version_minor,
1806 unsigned char slave_addr,
Corey Minyard393d2cc2005-11-07 00:59:54 -08001807 ipmi_smi_t *new_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808{
1809 int i, j;
1810 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001811 ipmi_smi_t intf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 unsigned long flags;
1813
1814
1815 /* Make sure the driver is actually initialized, this handles
1816 problems with initialization order. */
1817 if (!initialized) {
1818 rv = ipmi_init_msghandler();
1819 if (rv)
1820 return rv;
1821 /* The init code doesn't return an error if it was turned
1822 off, but it won't initialize. Check that. */
1823 if (!initialized)
1824 return -ENODEV;
1825 }
1826
Corey Minyard393d2cc2005-11-07 00:59:54 -08001827 intf = kmalloc(sizeof(*intf), GFP_KERNEL);
1828 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001830 memset(intf, 0, sizeof(*intf));
1831 intf->intf_num = -1;
1832 kref_init(&intf->refcount);
1833 intf->version_major = version_major;
1834 intf->version_minor = version_minor;
1835 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
1836 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
1837 intf->channels[j].lun = 2;
1838 }
1839 if (slave_addr != 0)
1840 intf->channels[0].address = slave_addr;
1841 INIT_LIST_HEAD(&intf->users);
1842 intf->handlers = handlers;
1843 intf->send_info = send_info;
1844 spin_lock_init(&intf->seq_lock);
1845 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
1846 intf->seq_table[j].inuse = 0;
1847 intf->seq_table[j].seqid = 0;
1848 }
1849 intf->curr_seq = 0;
1850#ifdef CONFIG_PROC_FS
1851 spin_lock_init(&intf->proc_entry_lock);
1852#endif
1853 spin_lock_init(&intf->waiting_msgs_lock);
1854 INIT_LIST_HEAD(&intf->waiting_msgs);
1855 spin_lock_init(&intf->events_lock);
1856 INIT_LIST_HEAD(&intf->waiting_events);
1857 intf->waiting_events_count = 0;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08001858 init_MUTEX(&intf->cmd_rcvrs_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001859 INIT_LIST_HEAD(&intf->cmd_rcvrs);
1860 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
Corey Minyard393d2cc2005-11-07 00:59:54 -08001862 spin_lock_init(&intf->counter_lock);
1863 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
1865 rv = -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001866 spin_lock_irqsave(&interfaces_lock, flags);
Corey Minyarde8b33612005-09-06 15:18:45 -07001867 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 if (ipmi_interfaces[i] == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08001869 intf->intf_num = i;
1870 /* Reserve the entry till we are done. */
1871 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 break;
1874 }
1875 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08001876 spin_unlock_irqrestore(&interfaces_lock, flags);
1877 if (rv)
1878 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Corey Minyard393d2cc2005-11-07 00:59:54 -08001880 /* FIXME - this is an ugly kludge, this sets the intf for the
1881 caller before sending any messages with it. */
1882 *new_intf = intf;
1883
1884 if ((version_major > 1)
1885 || ((version_major == 1) && (version_minor >= 5)))
1886 {
1887 /* Start scanning the channels to see what is
1888 available. */
1889 intf->null_user_handler = channel_handler;
1890 intf->curr_channel = 0;
1891 rv = send_channel_info_cmd(intf, 0);
1892 if (rv)
1893 goto out;
1894
1895 /* Wait for the channel info to be read. */
1896 wait_event(intf->waitq,
1897 intf->curr_channel >= IPMI_MAX_CHANNELS);
1898 } else {
1899 /* Assume a single IPMB channel at zero. */
1900 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
1901 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
1902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
1904 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08001905 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906
Corey Minyard393d2cc2005-11-07 00:59:54 -08001907 out:
1908 if (rv) {
1909 if (intf->proc_dir)
1910 remove_proc_entries(intf);
1911 kref_put(&intf->refcount, intf_free);
1912 if (i < MAX_IPMI_INTERFACES) {
1913 spin_lock_irqsave(&interfaces_lock, flags);
1914 ipmi_interfaces[i] = NULL;
1915 spin_unlock_irqrestore(&interfaces_lock, flags);
1916 }
1917 } else {
1918 spin_lock_irqsave(&interfaces_lock, flags);
1919 ipmi_interfaces[i] = intf;
1920 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 call_smi_watchers(i);
1922 }
1923
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 return rv;
1925}
1926
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927int ipmi_unregister_smi(ipmi_smi_t intf)
1928{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 int i;
1930 struct ipmi_smi_watcher *w;
1931 unsigned long flags;
1932
Corey Minyard393d2cc2005-11-07 00:59:54 -08001933 spin_lock_irqsave(&interfaces_lock, flags);
1934 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
1935 if (ipmi_interfaces[i] == intf) {
1936 /* Set the interface number reserved until we
1937 * are done. */
1938 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
1939 intf->intf_num = -1;
1940 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08001943 spin_unlock_irqrestore(&interfaces_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944
Corey Minyard393d2cc2005-11-07 00:59:54 -08001945 if (i == MAX_IPMI_INTERFACES)
1946 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947
Corey Minyard393d2cc2005-11-07 00:59:54 -08001948 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949
1950 /* Call all the watcher interfaces to tell them that
1951 an interface is gone. */
1952 down_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001953 list_for_each_entry(w, &smi_watchers, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 w->smi_gone(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 up_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001956
1957 /* Allow the entry to be reused now. */
1958 spin_lock_irqsave(&interfaces_lock, flags);
1959 ipmi_interfaces[i] = NULL;
1960 spin_unlock_irqrestore(&interfaces_lock,flags);
1961
1962 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 return 0;
1964}
1965
1966static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
1967 struct ipmi_smi_msg *msg)
1968{
1969 struct ipmi_ipmb_addr ipmb_addr;
1970 struct ipmi_recv_msg *recv_msg;
1971 unsigned long flags;
1972
1973
1974 /* This is 11, not 10, because the response must contain a
1975 * completion code. */
1976 if (msg->rsp_size < 11) {
1977 /* Message not big enough, just ignore it. */
1978 spin_lock_irqsave(&intf->counter_lock, flags);
1979 intf->invalid_ipmb_responses++;
1980 spin_unlock_irqrestore(&intf->counter_lock, flags);
1981 return 0;
1982 }
1983
1984 if (msg->rsp[2] != 0) {
1985 /* An error getting the response, just ignore it. */
1986 return 0;
1987 }
1988
1989 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
1990 ipmb_addr.slave_addr = msg->rsp[6];
1991 ipmb_addr.channel = msg->rsp[3] & 0x0f;
1992 ipmb_addr.lun = msg->rsp[7] & 3;
1993
1994 /* It's a response from a remote entity. Look up the sequence
1995 number and handle the response. */
1996 if (intf_find_seq(intf,
1997 msg->rsp[7] >> 2,
1998 msg->rsp[3] & 0x0f,
1999 msg->rsp[8],
2000 (msg->rsp[4] >> 2) & (~1),
2001 (struct ipmi_addr *) &(ipmb_addr),
2002 &recv_msg))
2003 {
2004 /* We were unable to find the sequence number,
2005 so just nuke the message. */
2006 spin_lock_irqsave(&intf->counter_lock, flags);
2007 intf->unhandled_ipmb_responses++;
2008 spin_unlock_irqrestore(&intf->counter_lock, flags);
2009 return 0;
2010 }
2011
2012 memcpy(recv_msg->msg_data,
2013 &(msg->rsp[9]),
2014 msg->rsp_size - 9);
2015 /* THe other fields matched, so no need to set them, except
2016 for netfn, which needs to be the response that was
2017 returned, not the request value. */
2018 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2019 recv_msg->msg.data = recv_msg->msg_data;
2020 recv_msg->msg.data_len = msg->rsp_size - 10;
2021 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2022 spin_lock_irqsave(&intf->counter_lock, flags);
2023 intf->handled_ipmb_responses++;
2024 spin_unlock_irqrestore(&intf->counter_lock, flags);
2025 deliver_response(recv_msg);
2026
2027 return 0;
2028}
2029
2030static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2031 struct ipmi_smi_msg *msg)
2032{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002033 struct cmd_rcvr *rcvr;
2034 int rv = 0;
2035 unsigned char netfn;
2036 unsigned char cmd;
2037 ipmi_user_t user = NULL;
2038 struct ipmi_ipmb_addr *ipmb_addr;
2039 struct ipmi_recv_msg *recv_msg;
2040 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041
2042 if (msg->rsp_size < 10) {
2043 /* Message not big enough, just ignore it. */
2044 spin_lock_irqsave(&intf->counter_lock, flags);
2045 intf->invalid_commands++;
2046 spin_unlock_irqrestore(&intf->counter_lock, flags);
2047 return 0;
2048 }
2049
2050 if (msg->rsp[2] != 0) {
2051 /* An error getting the response, just ignore it. */
2052 return 0;
2053 }
2054
2055 netfn = msg->rsp[4] >> 2;
2056 cmd = msg->rsp[8];
2057
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002058 rcu_read_lock();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002059 rcvr = find_cmd_rcvr(intf, netfn, cmd);
2060 if (rcvr) {
2061 user = rcvr->user;
2062 kref_get(&user->refcount);
2063 } else
2064 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002065 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
2067 if (user == NULL) {
2068 /* We didn't find a user, deliver an error response. */
2069 spin_lock_irqsave(&intf->counter_lock, flags);
2070 intf->unhandled_commands++;
2071 spin_unlock_irqrestore(&intf->counter_lock, flags);
2072
2073 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2074 msg->data[1] = IPMI_SEND_MSG_CMD;
2075 msg->data[2] = msg->rsp[3];
2076 msg->data[3] = msg->rsp[6];
2077 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2078 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002079 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 /* rqseq/lun */
2081 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2082 msg->data[8] = msg->rsp[8]; /* cmd */
2083 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2084 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2085 msg->data_size = 11;
2086
2087#ifdef DEBUG_MSGING
2088 {
2089 int m;
2090 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002091 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 printk(" %2.2x", msg->data[m]);
2093 printk("\n");
2094 }
2095#endif
2096 intf->handlers->sender(intf->send_info, msg, 0);
2097
2098 rv = -1; /* We used the message, so return the value that
2099 causes it to not be freed or queued. */
2100 } else {
2101 /* Deliver the message to the user. */
2102 spin_lock_irqsave(&intf->counter_lock, flags);
2103 intf->handled_commands++;
2104 spin_unlock_irqrestore(&intf->counter_lock, flags);
2105
2106 recv_msg = ipmi_alloc_recv_msg();
2107 if (! recv_msg) {
2108 /* We couldn't allocate memory for the
2109 message, so requeue it for handling
2110 later. */
2111 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002112 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 } else {
2114 /* Extract the source address from the data. */
2115 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2116 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2117 ipmb_addr->slave_addr = msg->rsp[6];
2118 ipmb_addr->lun = msg->rsp[7] & 3;
2119 ipmb_addr->channel = msg->rsp[3] & 0xf;
2120
2121 /* Extract the rest of the message information
2122 from the IPMB header.*/
2123 recv_msg->user = user;
2124 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2125 recv_msg->msgid = msg->rsp[7] >> 2;
2126 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2127 recv_msg->msg.cmd = msg->rsp[8];
2128 recv_msg->msg.data = recv_msg->msg_data;
2129
2130 /* We chop off 10, not 9 bytes because the checksum
2131 at the end also needs to be removed. */
2132 recv_msg->msg.data_len = msg->rsp_size - 10;
2133 memcpy(recv_msg->msg_data,
2134 &(msg->rsp[9]),
2135 msg->rsp_size - 10);
2136 deliver_response(recv_msg);
2137 }
2138 }
2139
2140 return rv;
2141}
2142
2143static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
2144 struct ipmi_smi_msg *msg)
2145{
2146 struct ipmi_lan_addr lan_addr;
2147 struct ipmi_recv_msg *recv_msg;
2148 unsigned long flags;
2149
2150
2151 /* This is 13, not 12, because the response must contain a
2152 * completion code. */
2153 if (msg->rsp_size < 13) {
2154 /* Message not big enough, just ignore it. */
2155 spin_lock_irqsave(&intf->counter_lock, flags);
2156 intf->invalid_lan_responses++;
2157 spin_unlock_irqrestore(&intf->counter_lock, flags);
2158 return 0;
2159 }
2160
2161 if (msg->rsp[2] != 0) {
2162 /* An error getting the response, just ignore it. */
2163 return 0;
2164 }
2165
2166 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
2167 lan_addr.session_handle = msg->rsp[4];
2168 lan_addr.remote_SWID = msg->rsp[8];
2169 lan_addr.local_SWID = msg->rsp[5];
2170 lan_addr.channel = msg->rsp[3] & 0x0f;
2171 lan_addr.privilege = msg->rsp[3] >> 4;
2172 lan_addr.lun = msg->rsp[9] & 3;
2173
2174 /* It's a response from a remote entity. Look up the sequence
2175 number and handle the response. */
2176 if (intf_find_seq(intf,
2177 msg->rsp[9] >> 2,
2178 msg->rsp[3] & 0x0f,
2179 msg->rsp[10],
2180 (msg->rsp[6] >> 2) & (~1),
2181 (struct ipmi_addr *) &(lan_addr),
2182 &recv_msg))
2183 {
2184 /* We were unable to find the sequence number,
2185 so just nuke the message. */
2186 spin_lock_irqsave(&intf->counter_lock, flags);
2187 intf->unhandled_lan_responses++;
2188 spin_unlock_irqrestore(&intf->counter_lock, flags);
2189 return 0;
2190 }
2191
2192 memcpy(recv_msg->msg_data,
2193 &(msg->rsp[11]),
2194 msg->rsp_size - 11);
2195 /* The other fields matched, so no need to set them, except
2196 for netfn, which needs to be the response that was
2197 returned, not the request value. */
2198 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2199 recv_msg->msg.data = recv_msg->msg_data;
2200 recv_msg->msg.data_len = msg->rsp_size - 12;
2201 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2202 spin_lock_irqsave(&intf->counter_lock, flags);
2203 intf->handled_lan_responses++;
2204 spin_unlock_irqrestore(&intf->counter_lock, flags);
2205 deliver_response(recv_msg);
2206
2207 return 0;
2208}
2209
2210static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2211 struct ipmi_smi_msg *msg)
2212{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002213 struct cmd_rcvr *rcvr;
2214 int rv = 0;
2215 unsigned char netfn;
2216 unsigned char cmd;
2217 ipmi_user_t user = NULL;
2218 struct ipmi_lan_addr *lan_addr;
2219 struct ipmi_recv_msg *recv_msg;
2220 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222 if (msg->rsp_size < 12) {
2223 /* Message not big enough, just ignore it. */
2224 spin_lock_irqsave(&intf->counter_lock, flags);
2225 intf->invalid_commands++;
2226 spin_unlock_irqrestore(&intf->counter_lock, flags);
2227 return 0;
2228 }
2229
2230 if (msg->rsp[2] != 0) {
2231 /* An error getting the response, just ignore it. */
2232 return 0;
2233 }
2234
2235 netfn = msg->rsp[6] >> 2;
2236 cmd = msg->rsp[10];
2237
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002238 rcu_read_lock();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002239 rcvr = find_cmd_rcvr(intf, netfn, cmd);
2240 if (rcvr) {
2241 user = rcvr->user;
2242 kref_get(&user->refcount);
2243 } else
2244 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002245 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
2247 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002248 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 spin_lock_irqsave(&intf->counter_lock, flags);
2250 intf->unhandled_commands++;
2251 spin_unlock_irqrestore(&intf->counter_lock, flags);
2252
2253 rv = 0; /* Don't do anything with these messages, just
2254 allow them to be freed. */
2255 } else {
2256 /* Deliver the message to the user. */
2257 spin_lock_irqsave(&intf->counter_lock, flags);
2258 intf->handled_commands++;
2259 spin_unlock_irqrestore(&intf->counter_lock, flags);
2260
2261 recv_msg = ipmi_alloc_recv_msg();
2262 if (! recv_msg) {
2263 /* We couldn't allocate memory for the
2264 message, so requeue it for handling
2265 later. */
2266 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002267 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 } else {
2269 /* Extract the source address from the data. */
2270 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
2271 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
2272 lan_addr->session_handle = msg->rsp[4];
2273 lan_addr->remote_SWID = msg->rsp[8];
2274 lan_addr->local_SWID = msg->rsp[5];
2275 lan_addr->lun = msg->rsp[9] & 3;
2276 lan_addr->channel = msg->rsp[3] & 0xf;
2277 lan_addr->privilege = msg->rsp[3] >> 4;
2278
2279 /* Extract the rest of the message information
2280 from the IPMB header.*/
2281 recv_msg->user = user;
2282 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2283 recv_msg->msgid = msg->rsp[9] >> 2;
2284 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2285 recv_msg->msg.cmd = msg->rsp[10];
2286 recv_msg->msg.data = recv_msg->msg_data;
2287
2288 /* We chop off 12, not 11 bytes because the checksum
2289 at the end also needs to be removed. */
2290 recv_msg->msg.data_len = msg->rsp_size - 12;
2291 memcpy(recv_msg->msg_data,
2292 &(msg->rsp[11]),
2293 msg->rsp_size - 12);
2294 deliver_response(recv_msg);
2295 }
2296 }
2297
2298 return rv;
2299}
2300
2301static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
2302 struct ipmi_smi_msg *msg)
2303{
2304 struct ipmi_system_interface_addr *smi_addr;
2305
2306 recv_msg->msgid = 0;
2307 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
2308 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2309 smi_addr->channel = IPMI_BMC_CHANNEL;
2310 smi_addr->lun = msg->rsp[0] & 3;
2311 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
2312 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2313 recv_msg->msg.cmd = msg->rsp[1];
2314 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
2315 recv_msg->msg.data = recv_msg->msg_data;
2316 recv_msg->msg.data_len = msg->rsp_size - 3;
2317}
2318
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319static int handle_read_event_rsp(ipmi_smi_t intf,
2320 struct ipmi_smi_msg *msg)
2321{
2322 struct ipmi_recv_msg *recv_msg, *recv_msg2;
2323 struct list_head msgs;
2324 ipmi_user_t user;
2325 int rv = 0;
2326 int deliver_count = 0;
2327 unsigned long flags;
2328
2329 if (msg->rsp_size < 19) {
2330 /* Message is too small to be an IPMB event. */
2331 spin_lock_irqsave(&intf->counter_lock, flags);
2332 intf->invalid_events++;
2333 spin_unlock_irqrestore(&intf->counter_lock, flags);
2334 return 0;
2335 }
2336
2337 if (msg->rsp[2] != 0) {
2338 /* An error getting the event, just ignore it. */
2339 return 0;
2340 }
2341
2342 INIT_LIST_HEAD(&msgs);
2343
Corey Minyard393d2cc2005-11-07 00:59:54 -08002344 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
2346 spin_lock(&intf->counter_lock);
2347 intf->events++;
2348 spin_unlock(&intf->counter_lock);
2349
2350 /* Allocate and fill in one message for every user that is getting
2351 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002352 rcu_read_lock();
2353 list_for_each_entry_rcu(user, &intf->users, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 if (! user->gets_events)
2355 continue;
2356
2357 recv_msg = ipmi_alloc_recv_msg();
2358 if (! recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002359 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
2361 list_del(&recv_msg->link);
2362 ipmi_free_recv_msg(recv_msg);
2363 }
2364 /* We couldn't allocate memory for the
2365 message, so requeue it for handling
2366 later. */
2367 rv = 1;
2368 goto out;
2369 }
2370
2371 deliver_count++;
2372
2373 copy_event_into_recv_msg(recv_msg, msg);
2374 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002375 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 list_add_tail(&(recv_msg->link), &msgs);
2377 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002378 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379
2380 if (deliver_count) {
2381 /* Now deliver all the messages. */
2382 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
2383 list_del(&recv_msg->link);
2384 deliver_response(recv_msg);
2385 }
2386 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
2387 /* No one to receive the message, put it in queue if there's
2388 not already too many things in the queue. */
2389 recv_msg = ipmi_alloc_recv_msg();
2390 if (! recv_msg) {
2391 /* We couldn't allocate memory for the
2392 message, so requeue it for handling
2393 later. */
2394 rv = 1;
2395 goto out;
2396 }
2397
2398 copy_event_into_recv_msg(recv_msg, msg);
2399 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
2400 } else {
2401 /* There's too many things in the queue, discard this
2402 message. */
2403 printk(KERN_WARNING PFX "Event queue full, discarding an"
2404 " incoming event\n");
2405 }
2406
2407 out:
2408 spin_unlock_irqrestore(&(intf->events_lock), flags);
2409
2410 return rv;
2411}
2412
2413static int handle_bmc_rsp(ipmi_smi_t intf,
2414 struct ipmi_smi_msg *msg)
2415{
2416 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002418 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
2420 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002421 if (recv_msg == NULL)
2422 {
2423 printk(KERN_WARNING"IPMI message received with no owner. This\n"
2424 "could be because of a malformed message, or\n"
2425 "because of a hardware error. Contact your\n"
2426 "hardware vender for assistance\n");
2427 return 0;
2428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
Corey Minyard393d2cc2005-11-07 00:59:54 -08002430 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002432 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07002433 /* The user for the message went away, so give up. */
2434 spin_lock_irqsave(&intf->counter_lock, flags);
2435 intf->unhandled_local_responses++;
2436 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 ipmi_free_recv_msg(recv_msg);
2438 } else {
2439 struct ipmi_system_interface_addr *smi_addr;
2440
2441 spin_lock_irqsave(&intf->counter_lock, flags);
2442 intf->handled_local_responses++;
2443 spin_unlock_irqrestore(&intf->counter_lock, flags);
2444 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2445 recv_msg->msgid = msg->msgid;
2446 smi_addr = ((struct ipmi_system_interface_addr *)
2447 &(recv_msg->addr));
2448 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2449 smi_addr->channel = IPMI_BMC_CHANNEL;
2450 smi_addr->lun = msg->rsp[0] & 3;
2451 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2452 recv_msg->msg.cmd = msg->rsp[1];
2453 memcpy(recv_msg->msg_data,
2454 &(msg->rsp[2]),
2455 msg->rsp_size - 2);
2456 recv_msg->msg.data = recv_msg->msg_data;
2457 recv_msg->msg.data_len = msg->rsp_size - 2;
2458 deliver_response(recv_msg);
2459 }
2460
2461 return 0;
2462}
2463
2464/* Handle a new message. Return 1 if the message should be requeued,
2465 0 if the message should be freed, or -1 if the message should not
2466 be freed or requeued. */
2467static int handle_new_recv_msg(ipmi_smi_t intf,
2468 struct ipmi_smi_msg *msg)
2469{
2470 int requeue;
2471 int chan;
2472
2473#ifdef DEBUG_MSGING
2474 int m;
2475 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002476 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 printk(" %2.2x", msg->rsp[m]);
2478 printk("\n");
2479#endif
2480 if (msg->rsp_size < 2) {
2481 /* Message is too small to be correct. */
2482 printk(KERN_WARNING PFX "BMC returned to small a message"
2483 " for netfn %x cmd %x, got %d bytes\n",
2484 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
2485
2486 /* Generate an error response for the message. */
2487 msg->rsp[0] = msg->data[0] | (1 << 2);
2488 msg->rsp[1] = msg->data[1];
2489 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
2490 msg->rsp_size = 3;
2491 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
2492 || (msg->rsp[1] != msg->data[1])) /* Command */
2493 {
2494 /* The response is not even marginally correct. */
2495 printk(KERN_WARNING PFX "BMC returned incorrect response,"
2496 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
2497 (msg->data[0] >> 2) | 1, msg->data[1],
2498 msg->rsp[0] >> 2, msg->rsp[1]);
2499
2500 /* Generate an error response for the message. */
2501 msg->rsp[0] = msg->data[0] | (1 << 2);
2502 msg->rsp[1] = msg->data[1];
2503 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
2504 msg->rsp_size = 3;
2505 }
2506
2507 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
2508 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
2509 && (msg->user_data != NULL))
2510 {
2511 /* It's a response to a response we sent. For this we
2512 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002513 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514
2515 requeue = 0;
2516 if (msg->rsp_size < 2)
2517 /* Message is too small to be correct. */
2518 goto out;
2519
2520 chan = msg->data[2] & 0x0f;
2521 if (chan >= IPMI_MAX_CHANNELS)
2522 /* Invalid channel number */
2523 goto out;
2524
Corey Minyard393d2cc2005-11-07 00:59:54 -08002525 if (!recv_msg)
2526 goto out;
2527
2528 /* Make sure the user still exists. */
2529 if (!recv_msg->user || !recv_msg->user->valid)
2530 goto out;
2531
2532 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
2533 recv_msg->msg.data = recv_msg->msg_data;
2534 recv_msg->msg.data_len = 1;
2535 recv_msg->msg_data[0] = msg->rsp[2];
2536 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
2538 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
2539 {
2540 /* It's from the receive queue. */
2541 chan = msg->rsp[3] & 0xf;
2542 if (chan >= IPMI_MAX_CHANNELS) {
2543 /* Invalid channel number */
2544 requeue = 0;
2545 goto out;
2546 }
2547
2548 switch (intf->channels[chan].medium) {
2549 case IPMI_CHANNEL_MEDIUM_IPMB:
2550 if (msg->rsp[4] & 0x04) {
2551 /* It's a response, so find the
2552 requesting message and send it up. */
2553 requeue = handle_ipmb_get_msg_rsp(intf, msg);
2554 } else {
2555 /* It's a command to the SMS from some other
2556 entity. Handle that. */
2557 requeue = handle_ipmb_get_msg_cmd(intf, msg);
2558 }
2559 break;
2560
2561 case IPMI_CHANNEL_MEDIUM_8023LAN:
2562 case IPMI_CHANNEL_MEDIUM_ASYNC:
2563 if (msg->rsp[6] & 0x04) {
2564 /* It's a response, so find the
2565 requesting message and send it up. */
2566 requeue = handle_lan_get_msg_rsp(intf, msg);
2567 } else {
2568 /* It's a command to the SMS from some other
2569 entity. Handle that. */
2570 requeue = handle_lan_get_msg_cmd(intf, msg);
2571 }
2572 break;
2573
2574 default:
2575 /* We don't handle the channel type, so just
2576 * free the message. */
2577 requeue = 0;
2578 }
2579
2580 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
2581 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
2582 {
2583 /* It's an asyncronous event. */
2584 requeue = handle_read_event_rsp(intf, msg);
2585 } else {
2586 /* It's a response from the local BMC. */
2587 requeue = handle_bmc_rsp(intf, msg);
2588 }
2589
2590 out:
2591 return requeue;
2592}
2593
2594/* Handle a new message from the lower layer. */
2595void ipmi_smi_msg_received(ipmi_smi_t intf,
2596 struct ipmi_smi_msg *msg)
2597{
2598 unsigned long flags;
2599 int rv;
2600
2601
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 if ((msg->data_size >= 2)
2603 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
2604 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002605 && (msg->user_data == NULL))
2606 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 /* This is the local response to a command send, start
2608 the timer for these. The user_data will not be
2609 NULL if this is a response send, and we will let
2610 response sends just go through. */
2611
2612 /* Check for errors, if we get certain errors (ones
2613 that mean basically we can try again later), we
2614 ignore them and start the timer. Otherwise we
2615 report the error immediately. */
2616 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
2617 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
2618 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR))
2619 {
2620 int chan = msg->rsp[3] & 0xf;
2621
2622 /* Got an error sending the message, handle it. */
2623 spin_lock_irqsave(&intf->counter_lock, flags);
2624 if (chan >= IPMI_MAX_CHANNELS)
2625 ; /* This shouldn't happen */
2626 else if ((intf->channels[chan].medium
2627 == IPMI_CHANNEL_MEDIUM_8023LAN)
2628 || (intf->channels[chan].medium
2629 == IPMI_CHANNEL_MEDIUM_ASYNC))
2630 intf->sent_lan_command_errs++;
2631 else
2632 intf->sent_ipmb_command_errs++;
2633 spin_unlock_irqrestore(&intf->counter_lock, flags);
2634 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
2635 } else {
2636 /* The message was sent, start the timer. */
2637 intf_start_seq_timer(intf, msg->msgid);
2638 }
2639
2640 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002641 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 }
2643
2644 /* To preserve message order, if the list is not empty, we
2645 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002646 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
2647 if (!list_empty(&intf->waiting_msgs)) {
2648 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06002649 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002650 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002652 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653
2654 rv = handle_new_recv_msg(intf, msg);
2655 if (rv > 0) {
2656 /* Could not handle the message now, just add it to a
2657 list to handle later. */
Hironobu Ishii177294d2005-11-11 08:12:21 -06002658 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002659 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06002660 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 } else if (rv == 0) {
2662 ipmi_free_smi_msg(msg);
2663 }
2664
Corey Minyard393d2cc2005-11-07 00:59:54 -08002665 out:
2666 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667}
2668
2669void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
2670{
2671 ipmi_user_t user;
2672
Corey Minyard393d2cc2005-11-07 00:59:54 -08002673 rcu_read_lock();
2674 list_for_each_entry_rcu(user, &intf->users, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 if (! user->handler->ipmi_watchdog_pretimeout)
2676 continue;
2677
2678 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
2679 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002680 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681}
2682
2683static void
2684handle_msg_timeout(struct ipmi_recv_msg *msg)
2685{
2686 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2687 msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;
2688 msg->msg.netfn |= 1; /* Convert to a response. */
2689 msg->msg.data_len = 1;
2690 msg->msg.data = msg->msg_data;
2691 deliver_response(msg);
2692}
2693
Corey Minyard882fe012005-05-01 08:59:12 -07002694static struct ipmi_smi_msg *
2695smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
2696 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697{
Corey Minyard882fe012005-05-01 08:59:12 -07002698 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 if (!smi_msg)
2700 /* If we can't allocate the message, then just return, we
2701 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07002702 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
2704 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
2705 smi_msg->data_size = recv_msg->msg.data_len;
2706 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
2707
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708#ifdef DEBUG_MSGING
2709 {
2710 int m;
2711 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07002712 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 printk(" %2.2x", smi_msg->data[m]);
2714 printk("\n");
2715 }
2716#endif
Corey Minyard882fe012005-05-01 08:59:12 -07002717 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718}
2719
Corey Minyard393d2cc2005-11-07 00:59:54 -08002720static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
2721 struct list_head *timeouts, long timeout_period,
2722 int slot, unsigned long *flags)
2723{
2724 struct ipmi_recv_msg *msg;
2725
2726 if (!ent->inuse)
2727 return;
2728
2729 ent->timeout -= timeout_period;
2730 if (ent->timeout > 0)
2731 return;
2732
2733 if (ent->retries_left == 0) {
2734 /* The message has used all its retries. */
2735 ent->inuse = 0;
2736 msg = ent->recv_msg;
2737 list_add_tail(&msg->link, timeouts);
2738 spin_lock(&intf->counter_lock);
2739 if (ent->broadcast)
2740 intf->timed_out_ipmb_broadcasts++;
2741 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
2742 intf->timed_out_lan_commands++;
2743 else
2744 intf->timed_out_ipmb_commands++;
2745 spin_unlock(&intf->counter_lock);
2746 } else {
2747 struct ipmi_smi_msg *smi_msg;
2748 /* More retries, send again. */
2749
2750 /* Start with the max timer, set to normal
2751 timer after the message is sent. */
2752 ent->timeout = MAX_MSG_TIMEOUT;
2753 ent->retries_left--;
2754 spin_lock(&intf->counter_lock);
2755 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
2756 intf->retransmitted_lan_commands++;
2757 else
2758 intf->retransmitted_ipmb_commands++;
2759 spin_unlock(&intf->counter_lock);
2760
2761 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
2762 ent->seqid);
2763 if (! smi_msg)
2764 return;
2765
2766 spin_unlock_irqrestore(&intf->seq_lock, *flags);
2767 /* Send the new message. We send with a zero
2768 * priority. It timed out, I doubt time is
2769 * that critical now, and high priority
2770 * messages are really only for messages to the
2771 * local MC, which don't get resent. */
2772 intf->handlers->sender(intf->send_info,
2773 smi_msg, 0);
2774 spin_lock_irqsave(&intf->seq_lock, *flags);
2775 }
2776}
2777
2778static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779{
2780 ipmi_smi_t intf;
2781 struct list_head timeouts;
2782 struct ipmi_recv_msg *msg, *msg2;
2783 struct ipmi_smi_msg *smi_msg, *smi_msg2;
2784 unsigned long flags;
2785 int i, j;
2786
2787 INIT_LIST_HEAD(&timeouts);
2788
2789 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07002790 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08002792 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 continue;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002794 kref_get(&intf->refcount);
2795 spin_unlock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
2797 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002798 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
2799 list_for_each_entry_safe(smi_msg, smi_msg2, &intf->waiting_msgs, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 if (! handle_new_recv_msg(intf, smi_msg)) {
2801 list_del(&smi_msg->link);
2802 ipmi_free_smi_msg(smi_msg);
2803 } else {
2804 /* To preserve message order, quit if we
2805 can't handle a message. */
2806 break;
2807 }
2808 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002809 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810
2811 /* Go through the seq table and find any messages that
2812 have timed out, putting them in the timeouts
2813 list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002814 spin_lock_irqsave(&intf->seq_lock, flags);
2815 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++)
2816 check_msg_timeout(intf, &(intf->seq_table[j]),
2817 &timeouts, timeout_period, j,
2818 &flags);
2819 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820
Corey Minyard393d2cc2005-11-07 00:59:54 -08002821 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 handle_msg_timeout(msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823
Corey Minyard393d2cc2005-11-07 00:59:54 -08002824 kref_put(&intf->refcount, intf_free);
2825 spin_lock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 }
2827 spin_unlock(&interfaces_lock);
2828}
2829
2830static void ipmi_request_event(void)
2831{
2832 ipmi_smi_t intf;
2833 int i;
2834
2835 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07002836 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08002838 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 continue;
2840
2841 intf->handlers->request_events(intf->send_info);
2842 }
2843 spin_unlock(&interfaces_lock);
2844}
2845
2846static struct timer_list ipmi_timer;
2847
2848/* Call every ~100 ms. */
2849#define IPMI_TIMEOUT_TIME 100
2850
2851/* How many jiffies does it take to get to the timeout time. */
2852#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
2853
2854/* Request events from the queue every second (this is the number of
2855 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
2856 future, IPMI will add a way to know immediately if an event is in
2857 the queue and this silliness can go away. */
2858#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
2859
Corey Minyard8f43f842005-06-23 22:01:40 -07002860static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
2862
2863static void ipmi_timeout(unsigned long data)
2864{
Corey Minyard8f43f842005-06-23 22:01:40 -07002865 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867
2868 ticks_to_req_ev--;
2869 if (ticks_to_req_ev == 0) {
2870 ipmi_request_event();
2871 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
2872 }
2873
2874 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
2875
Corey Minyard8f43f842005-06-23 22:01:40 -07002876 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877}
2878
2879
2880static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
2881static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
2882
2883/* FIXME - convert these to slabs. */
2884static void free_smi_msg(struct ipmi_smi_msg *msg)
2885{
2886 atomic_dec(&smi_msg_inuse_count);
2887 kfree(msg);
2888}
2889
2890struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
2891{
2892 struct ipmi_smi_msg *rv;
2893 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
2894 if (rv) {
2895 rv->done = free_smi_msg;
2896 rv->user_data = NULL;
2897 atomic_inc(&smi_msg_inuse_count);
2898 }
2899 return rv;
2900}
2901
2902static void free_recv_msg(struct ipmi_recv_msg *msg)
2903{
2904 atomic_dec(&recv_msg_inuse_count);
2905 kfree(msg);
2906}
2907
2908struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
2909{
2910 struct ipmi_recv_msg *rv;
2911
2912 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
2913 if (rv) {
2914 rv->done = free_recv_msg;
2915 atomic_inc(&recv_msg_inuse_count);
2916 }
2917 return rv;
2918}
2919
Corey Minyard393d2cc2005-11-07 00:59:54 -08002920void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
2921{
2922 if (msg->user)
2923 kref_put(&msg->user->refcount, free_user);
2924 msg->done(msg);
2925}
2926
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927#ifdef CONFIG_IPMI_PANIC_EVENT
2928
2929static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
2930{
2931}
2932
2933static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
2934{
2935}
2936
2937#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07002938static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939{
Corey Minyard56a55ec2005-09-06 15:18:42 -07002940 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2941 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
2942 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
2943 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 {
2945 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002946 intf->event_receiver = msg->msg.data[1];
2947 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 }
2949}
2950
Corey Minyard56a55ec2005-09-06 15:18:42 -07002951static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952{
Corey Minyard56a55ec2005-09-06 15:18:42 -07002953 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2954 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2955 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
2956 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 {
2958 /* A get device id command, save if we are an event
2959 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002960 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
2961 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 }
2963}
2964#endif
2965
2966static void send_panic_events(char *str)
2967{
2968 struct kernel_ipmi_msg msg;
2969 ipmi_smi_t intf;
2970 unsigned char data[16];
2971 int i;
2972 struct ipmi_system_interface_addr *si;
2973 struct ipmi_addr addr;
2974 struct ipmi_smi_msg smi_msg;
2975 struct ipmi_recv_msg recv_msg;
2976
2977 si = (struct ipmi_system_interface_addr *) &addr;
2978 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2979 si->channel = IPMI_BMC_CHANNEL;
2980 si->lun = 0;
2981
2982 /* Fill in an event telling that we have failed. */
2983 msg.netfn = 0x04; /* Sensor or Event. */
2984 msg.cmd = 2; /* Platform event command. */
2985 msg.data = data;
2986 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08002987 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 data[1] = 0x03; /* This is for IPMI 1.0. */
2989 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
2990 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
2991 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
2992
2993 /* Put a few breadcrumbs in. Hopefully later we can add more things
2994 to make the panic events more useful. */
2995 if (str) {
2996 data[3] = str[0];
2997 data[6] = str[1];
2998 data[7] = str[2];
2999 }
3000
3001 smi_msg.done = dummy_smi_done_handler;
3002 recv_msg.done = dummy_recv_done_handler;
3003
3004 /* For every registered interface, send the event. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003005 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003007 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 continue;
3009
3010 /* Send the event announcing the panic. */
3011 intf->handlers->set_run_to_completion(intf->send_info, 1);
3012 i_ipmi_request(NULL,
3013 intf,
3014 &addr,
3015 0,
3016 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003017 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 &smi_msg,
3019 &recv_msg,
3020 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003021 intf->channels[0].address,
3022 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 0, 1); /* Don't retry, and don't wait. */
3024 }
3025
3026#ifdef CONFIG_IPMI_PANIC_STRING
3027 /* On every interface, dump a bunch of OEM event holding the
3028 string. */
3029 if (!str)
3030 return;
3031
Corey Minyarde8b33612005-09-06 15:18:45 -07003032 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 char *p = str;
3034 struct ipmi_ipmb_addr *ipmb;
3035 int j;
3036
3037 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003038 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 continue;
3040
3041 /* First job here is to figure out where to send the
3042 OEM events. There's no way in IPMI to send OEM
3043 events using an event send command, so we have to
3044 find the SEL to put them in and stick them in
3045 there. */
3046
3047 /* Get capabilities from the get device id. */
3048 intf->local_sel_device = 0;
3049 intf->local_event_generator = 0;
3050 intf->event_receiver = 0;
3051
3052 /* Request the device info from the local MC. */
3053 msg.netfn = IPMI_NETFN_APP_REQUEST;
3054 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3055 msg.data = NULL;
3056 msg.data_len = 0;
3057 intf->null_user_handler = device_id_fetcher;
3058 i_ipmi_request(NULL,
3059 intf,
3060 &addr,
3061 0,
3062 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003063 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 &smi_msg,
3065 &recv_msg,
3066 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003067 intf->channels[0].address,
3068 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 0, 1); /* Don't retry, and don't wait. */
3070
3071 if (intf->local_event_generator) {
3072 /* Request the event receiver from the local MC. */
3073 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3074 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3075 msg.data = NULL;
3076 msg.data_len = 0;
3077 intf->null_user_handler = event_receiver_fetcher;
3078 i_ipmi_request(NULL,
3079 intf,
3080 &addr,
3081 0,
3082 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003083 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 &smi_msg,
3085 &recv_msg,
3086 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003087 intf->channels[0].address,
3088 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 0, 1); /* no retry, and no wait. */
3090 }
3091 intf->null_user_handler = NULL;
3092
3093 /* Validate the event receiver. The low bit must not
3094 be 1 (it must be a valid IPMB address), it cannot
3095 be zero, and it must not be my address. */
3096 if (((intf->event_receiver & 1) == 0)
3097 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003098 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 {
3100 /* The event receiver is valid, send an IPMB
3101 message. */
3102 ipmb = (struct ipmi_ipmb_addr *) &addr;
3103 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3104 ipmb->channel = 0; /* FIXME - is this right? */
3105 ipmb->lun = intf->event_receiver_lun;
3106 ipmb->slave_addr = intf->event_receiver;
3107 } else if (intf->local_sel_device) {
3108 /* The event receiver was not valid (or was
3109 me), but I am an SEL device, just dump it
3110 in my SEL. */
3111 si = (struct ipmi_system_interface_addr *) &addr;
3112 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3113 si->channel = IPMI_BMC_CHANNEL;
3114 si->lun = 0;
3115 } else
3116 continue; /* No where to send the event. */
3117
3118
3119 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
3120 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
3121 msg.data = data;
3122 msg.data_len = 16;
3123
3124 j = 0;
3125 while (*p) {
3126 int size = strlen(p);
3127
3128 if (size > 11)
3129 size = 11;
3130 data[0] = 0;
3131 data[1] = 0;
3132 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07003133 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 data[4] = j++; /* sequence # */
3135 /* Always give 11 bytes, so strncpy will fill
3136 it with zeroes for me. */
3137 strncpy(data+5, p, 11);
3138 p += size;
3139
3140 i_ipmi_request(NULL,
3141 intf,
3142 &addr,
3143 0,
3144 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003145 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 &smi_msg,
3147 &recv_msg,
3148 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003149 intf->channels[0].address,
3150 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 0, 1); /* no retry, and no wait. */
3152 }
3153 }
3154#endif /* CONFIG_IPMI_PANIC_STRING */
3155}
3156#endif /* CONFIG_IPMI_PANIC_EVENT */
3157
3158static int has_paniced = 0;
3159
3160static int panic_event(struct notifier_block *this,
3161 unsigned long event,
3162 void *ptr)
3163{
3164 int i;
3165 ipmi_smi_t intf;
3166
3167 if (has_paniced)
3168 return NOTIFY_DONE;
3169 has_paniced = 1;
3170
3171 /* For every registered interface, set it to run to completion. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003172 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003174 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 continue;
3176
3177 intf->handlers->set_run_to_completion(intf->send_info, 1);
3178 }
3179
3180#ifdef CONFIG_IPMI_PANIC_EVENT
3181 send_panic_events(ptr);
3182#endif
3183
3184 return NOTIFY_DONE;
3185}
3186
3187static struct notifier_block panic_block = {
3188 .notifier_call = panic_event,
3189 .next = NULL,
3190 .priority = 200 /* priority: INT_MAX >= x >= 0 */
3191};
3192
3193static int ipmi_init_msghandler(void)
3194{
3195 int i;
3196
3197 if (initialized)
3198 return 0;
3199
3200 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003201 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202
Corey Minyard393d2cc2005-11-07 00:59:54 -08003203 for (i = 0; i < MAX_IPMI_INTERFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 ipmi_interfaces[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
Corey Minyard3b625942005-06-23 22:01:42 -07003206#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 proc_ipmi_root = proc_mkdir("ipmi", NULL);
3208 if (!proc_ipmi_root) {
3209 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
3210 return -ENOMEM;
3211 }
3212
3213 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07003214#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215
3216 init_timer(&ipmi_timer);
3217 ipmi_timer.data = 0;
3218 ipmi_timer.function = ipmi_timeout;
3219 ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
3220 add_timer(&ipmi_timer);
3221
3222 notifier_chain_register(&panic_notifier_list, &panic_block);
3223
3224 initialized = 1;
3225
3226 return 0;
3227}
3228
3229static __init int ipmi_init_msghandler_mod(void)
3230{
3231 ipmi_init_msghandler();
3232 return 0;
3233}
3234
3235static __exit void cleanup_ipmi(void)
3236{
3237 int count;
3238
3239 if (!initialized)
3240 return;
3241
3242 notifier_chain_unregister(&panic_notifier_list, &panic_block);
3243
3244 /* This can't be called if any interfaces exist, so no worry about
3245 shutting down the interfaces. */
3246
3247 /* Tell the timer to stop, then wait for it to stop. This avoids
3248 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07003249 atomic_inc(&stop_operation);
3250 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251
Corey Minyard3b625942005-06-23 22:01:42 -07003252#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 remove_proc_entry(proc_ipmi_root->name, &proc_root);
Corey Minyard3b625942005-06-23 22:01:42 -07003254#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255
3256 initialized = 0;
3257
3258 /* Check for buffer leaks. */
3259 count = atomic_read(&smi_msg_inuse_count);
3260 if (count != 0)
3261 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
3262 count);
3263 count = atomic_read(&recv_msg_inuse_count);
3264 if (count != 0)
3265 printk(KERN_WARNING PFX "recv message count %d at exit\n",
3266 count);
3267}
3268module_exit(cleanup_ipmi);
3269
3270module_init(ipmi_init_msghandler_mod);
3271MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003272MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
3273MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
3274MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275
3276EXPORT_SYMBOL(ipmi_create_user);
3277EXPORT_SYMBOL(ipmi_destroy_user);
3278EXPORT_SYMBOL(ipmi_get_version);
3279EXPORT_SYMBOL(ipmi_request_settime);
3280EXPORT_SYMBOL(ipmi_request_supply_msgs);
3281EXPORT_SYMBOL(ipmi_register_smi);
3282EXPORT_SYMBOL(ipmi_unregister_smi);
3283EXPORT_SYMBOL(ipmi_register_for_cmd);
3284EXPORT_SYMBOL(ipmi_unregister_for_cmd);
3285EXPORT_SYMBOL(ipmi_smi_msg_received);
3286EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
3287EXPORT_SYMBOL(ipmi_alloc_smi_msg);
3288EXPORT_SYMBOL(ipmi_addr_length);
3289EXPORT_SYMBOL(ipmi_validate_addr);
3290EXPORT_SYMBOL(ipmi_set_gets_events);
3291EXPORT_SYMBOL(ipmi_smi_watcher_register);
3292EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
3293EXPORT_SYMBOL(ipmi_set_my_address);
3294EXPORT_SYMBOL(ipmi_get_my_address);
3295EXPORT_SYMBOL(ipmi_set_my_LUN);
3296EXPORT_SYMBOL(ipmi_get_my_LUN);
3297EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Corey Minyard3b625942005-06-23 22:01:42 -07003298EXPORT_SYMBOL(proc_ipmi_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003300EXPORT_SYMBOL(ipmi_free_recv_msg);