blob: 0ded046d5aa80011e5e267a0d1b8ca72fec69475 [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>
Corey Minyardd6dfd132006-03-31 02:30:41 -080041#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/slab.h>
43#include <linux/ipmi.h>
44#include <linux/ipmi_smi.h>
45#include <linux/notifier.h>
46#include <linux/init.h>
47#include <linux/proc_fs.h>
Corey Minyard393d2cc2005-11-07 00:59:54 -080048#include <linux/rcupdate.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50#define PFX "IPMI message handler: "
Corey Minyard1fdd75b2005-09-06 15:18:42 -070051
Corey Minyarda23f9a32006-03-26 01:37:22 -080052#define IPMI_DRIVER_VERSION "39.0"
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
55static int ipmi_init_msghandler(void);
56
57static int initialized = 0;
58
Corey Minyard3b625942005-06-23 22:01:42 -070059#ifdef CONFIG_PROC_FS
60struct proc_dir_entry *proc_ipmi_root = NULL;
Adrian Bunkbe4f1bb2006-01-09 20:51:36 -080061EXPORT_SYMBOL(proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -070062#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64#define MAX_EVENTS_IN_QUEUE 25
65
66/* Don't let a message sit in a queue forever, always time it with at lest
67 the max message timer. This is in milliseconds. */
68#define MAX_MSG_TIMEOUT 60000
69
Corey Minyard393d2cc2005-11-07 00:59:54 -080070
71/*
72 * The main "user" data structure.
73 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070074struct ipmi_user
75{
76 struct list_head link;
77
Corey Minyard393d2cc2005-11-07 00:59:54 -080078 /* Set to "0" when the user is destroyed. */
79 int valid;
80
81 struct kref refcount;
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 /* The upper layer that handles receive messages. */
84 struct ipmi_user_hndl *handler;
85 void *handler_data;
86
87 /* The interface this user is bound to. */
88 ipmi_smi_t intf;
89
90 /* Does this interface receive IPMI events? */
91 int gets_events;
92};
93
94struct cmd_rcvr
95{
96 struct list_head link;
97
98 ipmi_user_t user;
99 unsigned char netfn;
100 unsigned char cmd;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800101
102 /*
103 * This is used to form a linked lised during mass deletion.
104 * Since this is in an RCU list, we cannot use the link above
105 * or change any data until the RCU period completes. So we
106 * use this next variable during mass deletion so we can have
107 * a list and don't have to wait and restart the search on
108 * every individual deletion of a command. */
109 struct cmd_rcvr *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110};
111
112struct seq_table
113{
114 unsigned int inuse : 1;
115 unsigned int broadcast : 1;
116
117 unsigned long timeout;
118 unsigned long orig_timeout;
119 unsigned int retries_left;
120
121 /* To verify on an incoming send message response that this is
122 the message that the response is for, we keep a sequence id
123 and increment it every time we send a message. */
124 long seqid;
125
126 /* This is held so we can properly respond to the message on a
127 timeout, and it is used to hold the temporary data for
128 retransmission, too. */
129 struct ipmi_recv_msg *recv_msg;
130};
131
132/* Store the information in a msgid (long) to allow us to find a
133 sequence table entry from the msgid. */
134#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
135
136#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
137 do { \
138 seq = ((msgid >> 26) & 0x3f); \
139 seqid = (msgid & 0x3fffff); \
Corey Minyarde8b33612005-09-06 15:18:45 -0700140 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
143
144struct ipmi_channel
145{
146 unsigned char medium;
147 unsigned char protocol;
Corey Minyardc14979b2005-09-06 15:18:38 -0700148
149 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
150 but may be changed by the user. */
151 unsigned char address;
152
153 /* My LUN. This should generally stay the SMS LUN, but just in
154 case... */
155 unsigned char lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156};
157
Corey Minyard3b625942005-06-23 22:01:42 -0700158#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159struct ipmi_proc_entry
160{
161 char *name;
162 struct ipmi_proc_entry *next;
163};
Corey Minyard3b625942005-06-23 22:01:42 -0700164#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
Corey Minyard50c812b2006-03-26 01:37:21 -0800166struct bmc_device
167{
168 struct platform_device *dev;
169 struct ipmi_device_id id;
170 unsigned char guid[16];
171 int guid_set;
172
173 struct kref refcount;
174
175 /* bmc device attributes */
176 struct device_attribute device_id_attr;
177 struct device_attribute provides_dev_sdrs_attr;
178 struct device_attribute revision_attr;
179 struct device_attribute firmware_rev_attr;
180 struct device_attribute version_attr;
181 struct device_attribute add_dev_support_attr;
182 struct device_attribute manufacturer_id_attr;
183 struct device_attribute product_id_attr;
184 struct device_attribute guid_attr;
185 struct device_attribute aux_firmware_rev_attr;
186};
187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188#define IPMI_IPMB_NUM_SEQ 64
Corey Minyardc14979b2005-09-06 15:18:38 -0700189#define IPMI_MAX_CHANNELS 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190struct ipmi_smi
191{
192 /* What interface number are we? */
193 int intf_num;
194
Corey Minyard393d2cc2005-11-07 00:59:54 -0800195 struct kref refcount;
196
197 /* The list of upper layers that are using me. seq_lock
198 * protects this. */
199 struct list_head users;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
201 /* Used for wake ups at startup. */
202 wait_queue_head_t waitq;
203
Corey Minyard50c812b2006-03-26 01:37:21 -0800204 struct bmc_device *bmc;
205 char *my_dev_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
207 /* This is the lower-layer's sender routine. */
208 struct ipmi_smi_handlers *handlers;
209 void *send_info;
210
Corey Minyard3b625942005-06-23 22:01:42 -0700211#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 /* A list of proc entries for this interface. This does not
213 need a lock, only one thread creates it and only one thread
214 destroys it. */
Corey Minyard3b625942005-06-23 22:01:42 -0700215 spinlock_t proc_entry_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 struct ipmi_proc_entry *proc_entries;
Corey Minyard3b625942005-06-23 22:01:42 -0700217#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Corey Minyard50c812b2006-03-26 01:37:21 -0800219 /* Driver-model device for the system interface. */
220 struct device *si_dev;
221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 /* A table of sequence numbers for this interface. We use the
223 sequence numbers for IPMB messages that go out of the
224 interface to match them up with their responses. A routine
225 is called periodically to time the items in this list. */
226 spinlock_t seq_lock;
227 struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
228 int curr_seq;
229
230 /* Messages that were delayed for some reason (out of memory,
231 for instance), will go in here to be processed later in a
232 periodic timer interrupt. */
233 spinlock_t waiting_msgs_lock;
234 struct list_head waiting_msgs;
235
236 /* The list of command receivers that are registered for commands
237 on this interface. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800238 struct mutex cmd_rcvrs_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 struct list_head cmd_rcvrs;
240
241 /* Events that were queues because no one was there to receive
242 them. */
243 spinlock_t events_lock; /* For dealing with event stuff. */
244 struct list_head waiting_events;
245 unsigned int waiting_events_count; /* How many events in queue? */
246
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 /* The event receiver for my BMC, only really used at panic
248 shutdown as a place to store this. */
249 unsigned char event_receiver;
250 unsigned char event_receiver_lun;
251 unsigned char local_sel_device;
252 unsigned char local_event_generator;
253
254 /* A cheap hack, if this is non-null and a message to an
255 interface comes in with a NULL user, call this routine with
256 it. Note that the message will still be freed by the
257 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700258 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260 /* When we are scanning the channels for an SMI, this will
261 tell which channel we are scanning. */
262 int curr_channel;
263
264 /* Channel information */
265 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
266
267 /* Proc FS stuff. */
268 struct proc_dir_entry *proc_dir;
269 char proc_dir_name[10];
270
271 spinlock_t counter_lock; /* For making counters atomic. */
272
273 /* Commands we got that were invalid. */
274 unsigned int sent_invalid_commands;
275
276 /* Commands we sent to the MC. */
277 unsigned int sent_local_commands;
278 /* Responses from the MC that were delivered to a user. */
279 unsigned int handled_local_responses;
280 /* Responses from the MC that were not delivered to a user. */
281 unsigned int unhandled_local_responses;
282
283 /* Commands we sent out to the IPMB bus. */
284 unsigned int sent_ipmb_commands;
285 /* Commands sent on the IPMB that had errors on the SEND CMD */
286 unsigned int sent_ipmb_command_errs;
287 /* Each retransmit increments this count. */
288 unsigned int retransmitted_ipmb_commands;
289 /* When a message times out (runs out of retransmits) this is
290 incremented. */
291 unsigned int timed_out_ipmb_commands;
292
293 /* This is like above, but for broadcasts. Broadcasts are
294 *not* included in the above count (they are expected to
295 time out). */
296 unsigned int timed_out_ipmb_broadcasts;
297
298 /* Responses I have sent to the IPMB bus. */
299 unsigned int sent_ipmb_responses;
300
301 /* The response was delivered to the user. */
302 unsigned int handled_ipmb_responses;
303 /* The response had invalid data in it. */
304 unsigned int invalid_ipmb_responses;
305 /* The response didn't have anyone waiting for it. */
306 unsigned int unhandled_ipmb_responses;
307
308 /* Commands we sent out to the IPMB bus. */
309 unsigned int sent_lan_commands;
310 /* Commands sent on the IPMB that had errors on the SEND CMD */
311 unsigned int sent_lan_command_errs;
312 /* Each retransmit increments this count. */
313 unsigned int retransmitted_lan_commands;
314 /* When a message times out (runs out of retransmits) this is
315 incremented. */
316 unsigned int timed_out_lan_commands;
317
318 /* Responses I have sent to the IPMB bus. */
319 unsigned int sent_lan_responses;
320
321 /* The response was delivered to the user. */
322 unsigned int handled_lan_responses;
323 /* The response had invalid data in it. */
324 unsigned int invalid_lan_responses;
325 /* The response didn't have anyone waiting for it. */
326 unsigned int unhandled_lan_responses;
327
328 /* The command was delivered to the user. */
329 unsigned int handled_commands;
330 /* The command had invalid data in it. */
331 unsigned int invalid_commands;
332 /* The command didn't have anyone waiting for it. */
333 unsigned int unhandled_commands;
334
335 /* Invalid data in an event. */
336 unsigned int invalid_events;
337 /* Events that were received with the proper format. */
338 unsigned int events;
339};
Corey Minyard50c812b2006-03-26 01:37:21 -0800340#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Corey Minyard393d2cc2005-11-07 00:59:54 -0800342/* Used to mark an interface entry that cannot be used but is not a
343 * free entry, either, primarily used at creation and deletion time so
344 * a slot doesn't get reused too quickly. */
345#define IPMI_INVALID_INTERFACE_ENTRY ((ipmi_smi_t) ((long) 1))
346#define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \
347 || (i == IPMI_INVALID_INTERFACE_ENTRY))
348
Corey Minyard50c812b2006-03-26 01:37:21 -0800349/**
350 * The driver model view of the IPMI messaging driver.
351 */
352static struct device_driver ipmidriver = {
353 .name = "ipmi",
354 .bus = &platform_bus_type
355};
356static DEFINE_MUTEX(ipmidriver_mutex);
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358#define MAX_IPMI_INTERFACES 4
359static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
360
Corey Minyard393d2cc2005-11-07 00:59:54 -0800361/* Directly protects the ipmi_interfaces data structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362static DEFINE_SPINLOCK(interfaces_lock);
363
364/* List of watchers that want to know when smi's are added and
365 deleted. */
366static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
367static DECLARE_RWSEM(smi_watchers_sem);
368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Corey Minyard393d2cc2005-11-07 00:59:54 -0800370static void free_recv_msg_list(struct list_head *q)
371{
372 struct ipmi_recv_msg *msg, *msg2;
373
374 list_for_each_entry_safe(msg, msg2, q, link) {
375 list_del(&msg->link);
376 ipmi_free_recv_msg(msg);
377 }
378}
379
380static void clean_up_interface_data(ipmi_smi_t intf)
381{
382 int i;
383 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800384 struct list_head list;
385
386 free_recv_msg_list(&intf->waiting_msgs);
387 free_recv_msg_list(&intf->waiting_events);
388
389 /* Wholesale remove all the entries from the list in the
390 * interface and wait for RCU to know that none are in use. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800391 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800392 list_add_rcu(&list, &intf->cmd_rcvrs);
393 list_del_rcu(&intf->cmd_rcvrs);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800394 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800395 synchronize_rcu();
396
397 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
398 kfree(rcvr);
399
400 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
401 if ((intf->seq_table[i].inuse)
402 && (intf->seq_table[i].recv_msg))
403 {
404 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 }
406 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800407}
408
409static void intf_free(struct kref *ref)
410{
411 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
412
413 clean_up_interface_data(intf);
414 kfree(intf);
415}
416
417int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
418{
419 int i;
420 unsigned long flags;
421
422 down_write(&smi_watchers_sem);
423 list_add(&(watcher->link), &smi_watchers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 up_write(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800425 spin_lock_irqsave(&interfaces_lock, flags);
426 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
427 ipmi_smi_t intf = ipmi_interfaces[i];
428 if (IPMI_INVALID_INTERFACE(intf))
429 continue;
430 spin_unlock_irqrestore(&interfaces_lock, flags);
Corey Minyard50c812b2006-03-26 01:37:21 -0800431 watcher->new_smi(i, intf->si_dev);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800432 spin_lock_irqsave(&interfaces_lock, flags);
433 }
434 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 return 0;
436}
437
438int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
439{
440 down_write(&smi_watchers_sem);
441 list_del(&(watcher->link));
442 up_write(&smi_watchers_sem);
443 return 0;
444}
445
446static void
Corey Minyard50c812b2006-03-26 01:37:21 -0800447call_smi_watchers(int i, struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
449 struct ipmi_smi_watcher *w;
450
451 down_read(&smi_watchers_sem);
452 list_for_each_entry(w, &smi_watchers, link) {
453 if (try_module_get(w->owner)) {
Corey Minyard50c812b2006-03-26 01:37:21 -0800454 w->new_smi(i, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 module_put(w->owner);
456 }
457 }
458 up_read(&smi_watchers_sem);
459}
460
461static int
462ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
463{
464 if (addr1->addr_type != addr2->addr_type)
465 return 0;
466
467 if (addr1->channel != addr2->channel)
468 return 0;
469
470 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
471 struct ipmi_system_interface_addr *smi_addr1
472 = (struct ipmi_system_interface_addr *) addr1;
473 struct ipmi_system_interface_addr *smi_addr2
474 = (struct ipmi_system_interface_addr *) addr2;
475 return (smi_addr1->lun == smi_addr2->lun);
476 }
477
478 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
479 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
480 {
481 struct ipmi_ipmb_addr *ipmb_addr1
482 = (struct ipmi_ipmb_addr *) addr1;
483 struct ipmi_ipmb_addr *ipmb_addr2
484 = (struct ipmi_ipmb_addr *) addr2;
485
486 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
487 && (ipmb_addr1->lun == ipmb_addr2->lun));
488 }
489
490 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
491 struct ipmi_lan_addr *lan_addr1
492 = (struct ipmi_lan_addr *) addr1;
493 struct ipmi_lan_addr *lan_addr2
494 = (struct ipmi_lan_addr *) addr2;
495
496 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
497 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
498 && (lan_addr1->session_handle
499 == lan_addr2->session_handle)
500 && (lan_addr1->lun == lan_addr2->lun));
501 }
502
503 return 1;
504}
505
506int ipmi_validate_addr(struct ipmi_addr *addr, int len)
507{
508 if (len < sizeof(struct ipmi_system_interface_addr)) {
509 return -EINVAL;
510 }
511
512 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
513 if (addr->channel != IPMI_BMC_CHANNEL)
514 return -EINVAL;
515 return 0;
516 }
517
518 if ((addr->channel == IPMI_BMC_CHANNEL)
Jayachandran C12fc1d72006-02-03 03:04:51 -0800519 || (addr->channel >= IPMI_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 || (addr->channel < 0))
521 return -EINVAL;
522
523 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
524 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
525 {
526 if (len < sizeof(struct ipmi_ipmb_addr)) {
527 return -EINVAL;
528 }
529 return 0;
530 }
531
532 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
533 if (len < sizeof(struct ipmi_lan_addr)) {
534 return -EINVAL;
535 }
536 return 0;
537 }
538
539 return -EINVAL;
540}
541
542unsigned int ipmi_addr_length(int addr_type)
543{
544 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
545 return sizeof(struct ipmi_system_interface_addr);
546
547 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
548 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
549 {
550 return sizeof(struct ipmi_ipmb_addr);
551 }
552
553 if (addr_type == IPMI_LAN_ADDR_TYPE)
554 return sizeof(struct ipmi_lan_addr);
555
556 return 0;
557}
558
559static void deliver_response(struct ipmi_recv_msg *msg)
560{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800561 if (!msg->user) {
Corey Minyard56a55ec2005-09-06 15:18:42 -0700562 ipmi_smi_t intf = msg->user_msg_data;
563 unsigned long flags;
564
565 /* Special handling for NULL users. */
566 if (intf->null_user_handler) {
567 intf->null_user_handler(intf, msg);
568 spin_lock_irqsave(&intf->counter_lock, flags);
569 intf->handled_local_responses++;
570 spin_unlock_irqrestore(&intf->counter_lock, flags);
571 } else {
572 /* No handler, so give up. */
573 spin_lock_irqsave(&intf->counter_lock, flags);
574 intf->unhandled_local_responses++;
575 spin_unlock_irqrestore(&intf->counter_lock, flags);
576 }
577 ipmi_free_recv_msg(msg);
578 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800579 ipmi_user_t user = msg->user;
580 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582}
583
584/* Find the next sequence number not being used and add the given
585 message with the given timeout to the sequence table. This must be
586 called with the interface's seq_lock held. */
587static int intf_next_seq(ipmi_smi_t intf,
588 struct ipmi_recv_msg *recv_msg,
589 unsigned long timeout,
590 int retries,
591 int broadcast,
592 unsigned char *seq,
593 long *seqid)
594{
595 int rv = 0;
596 unsigned int i;
597
Corey Minyarde8b33612005-09-06 15:18:45 -0700598 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700600 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800602 if (!intf->seq_table[i].inuse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 break;
604 }
605
Corey Minyard8a3628d2006-03-31 02:30:40 -0800606 if (!intf->seq_table[i].inuse) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 intf->seq_table[i].recv_msg = recv_msg;
608
609 /* Start with the maximum timeout, when the send response
610 comes in we will start the real timer. */
611 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
612 intf->seq_table[i].orig_timeout = timeout;
613 intf->seq_table[i].retries_left = retries;
614 intf->seq_table[i].broadcast = broadcast;
615 intf->seq_table[i].inuse = 1;
616 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
617 *seq = i;
618 *seqid = intf->seq_table[i].seqid;
619 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
620 } else {
621 rv = -EAGAIN;
622 }
623
624 return rv;
625}
626
627/* Return the receive message for the given sequence number and
628 release the sequence number so it can be reused. Some other data
629 is passed in to be sure the message matches up correctly (to help
630 guard against message coming in after their timeout and the
631 sequence number being reused). */
632static int intf_find_seq(ipmi_smi_t intf,
633 unsigned char seq,
634 short channel,
635 unsigned char cmd,
636 unsigned char netfn,
637 struct ipmi_addr *addr,
638 struct ipmi_recv_msg **recv_msg)
639{
640 int rv = -ENODEV;
641 unsigned long flags;
642
643 if (seq >= IPMI_IPMB_NUM_SEQ)
644 return -EINVAL;
645
646 spin_lock_irqsave(&(intf->seq_lock), flags);
647 if (intf->seq_table[seq].inuse) {
648 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
649
650 if ((msg->addr.channel == channel)
651 && (msg->msg.cmd == cmd)
652 && (msg->msg.netfn == netfn)
653 && (ipmi_addr_equal(addr, &(msg->addr))))
654 {
655 *recv_msg = msg;
656 intf->seq_table[seq].inuse = 0;
657 rv = 0;
658 }
659 }
660 spin_unlock_irqrestore(&(intf->seq_lock), flags);
661
662 return rv;
663}
664
665
666/* Start the timer for a specific sequence table entry. */
667static int intf_start_seq_timer(ipmi_smi_t intf,
668 long msgid)
669{
670 int rv = -ENODEV;
671 unsigned long flags;
672 unsigned char seq;
673 unsigned long seqid;
674
675
676 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
677
678 spin_lock_irqsave(&(intf->seq_lock), flags);
679 /* We do this verification because the user can be deleted
680 while a message is outstanding. */
681 if ((intf->seq_table[seq].inuse)
682 && (intf->seq_table[seq].seqid == seqid))
683 {
684 struct seq_table *ent = &(intf->seq_table[seq]);
685 ent->timeout = ent->orig_timeout;
686 rv = 0;
687 }
688 spin_unlock_irqrestore(&(intf->seq_lock), flags);
689
690 return rv;
691}
692
693/* Got an error for the send message for a specific sequence number. */
694static int intf_err_seq(ipmi_smi_t intf,
695 long msgid,
696 unsigned int err)
697{
698 int rv = -ENODEV;
699 unsigned long flags;
700 unsigned char seq;
701 unsigned long seqid;
702 struct ipmi_recv_msg *msg = NULL;
703
704
705 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
706
707 spin_lock_irqsave(&(intf->seq_lock), flags);
708 /* We do this verification because the user can be deleted
709 while a message is outstanding. */
710 if ((intf->seq_table[seq].inuse)
711 && (intf->seq_table[seq].seqid == seqid))
712 {
713 struct seq_table *ent = &(intf->seq_table[seq]);
714
715 ent->inuse = 0;
716 msg = ent->recv_msg;
717 rv = 0;
718 }
719 spin_unlock_irqrestore(&(intf->seq_lock), flags);
720
721 if (msg) {
722 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
723 msg->msg_data[0] = err;
724 msg->msg.netfn |= 1; /* Convert to a response. */
725 msg->msg.data_len = 1;
726 msg->msg.data = msg->msg_data;
727 deliver_response(msg);
728 }
729
730 return rv;
731}
732
733
734int ipmi_create_user(unsigned int if_num,
735 struct ipmi_user_hndl *handler,
736 void *handler_data,
737 ipmi_user_t *user)
738{
739 unsigned long flags;
740 ipmi_user_t new_user;
741 int rv = 0;
742 ipmi_smi_t intf;
743
744 /* There is no module usecount here, because it's not
745 required. Since this can only be used by and called from
746 other modules, they will implicitly use this module, and
747 thus this can't be removed unless the other modules are
748 removed. */
749
750 if (handler == NULL)
751 return -EINVAL;
752
753 /* Make sure the driver is actually initialized, this handles
754 problems with initialization order. */
755 if (!initialized) {
756 rv = ipmi_init_msghandler();
757 if (rv)
758 return rv;
759
760 /* The init code doesn't return an error if it was turned
761 off, but it won't initialize. Check that. */
762 if (!initialized)
763 return -ENODEV;
764 }
765
766 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800767 if (!new_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 return -ENOMEM;
769
Corey Minyard393d2cc2005-11-07 00:59:54 -0800770 spin_lock_irqsave(&interfaces_lock, flags);
771 intf = ipmi_interfaces[if_num];
772 if ((if_num >= MAX_IPMI_INTERFACES) || IPMI_INVALID_INTERFACE(intf)) {
773 spin_unlock_irqrestore(&interfaces_lock, flags);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800774 rv = -EINVAL;
775 goto out_kfree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 }
777
Corey Minyard393d2cc2005-11-07 00:59:54 -0800778 /* Note that each existing user holds a refcount to the interface. */
779 kref_get(&intf->refcount);
780 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Corey Minyard393d2cc2005-11-07 00:59:54 -0800782 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 new_user->handler = handler;
784 new_user->handler_data = handler_data;
785 new_user->intf = intf;
786 new_user->gets_events = 0;
787
788 if (!try_module_get(intf->handlers->owner)) {
789 rv = -ENODEV;
Adrian Bunk5c98d292006-03-25 03:07:52 -0800790 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
792
793 if (intf->handlers->inc_usecount) {
794 rv = intf->handlers->inc_usecount(intf->send_info);
795 if (rv) {
796 module_put(intf->handlers->owner);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800797 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 }
799 }
800
Corey Minyard393d2cc2005-11-07 00:59:54 -0800801 new_user->valid = 1;
802 spin_lock_irqsave(&intf->seq_lock, flags);
803 list_add_rcu(&new_user->link, &intf->users);
804 spin_unlock_irqrestore(&intf->seq_lock, flags);
805 *user = new_user;
806 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Adrian Bunk5c98d292006-03-25 03:07:52 -0800808out_kref:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800809 kref_put(&intf->refcount, intf_free);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800810out_kfree:
811 kfree(new_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 return rv;
813}
814
Corey Minyard393d2cc2005-11-07 00:59:54 -0800815static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800817 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819}
820
821int ipmi_destroy_user(ipmi_user_t user)
822{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800823 ipmi_smi_t intf = user->intf;
824 int i;
825 unsigned long flags;
826 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800827 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
Corey Minyard8a3628d2006-03-31 02:30:40 -0800829 user->valid = 0;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800830
831 /* Remove the user from the interface's sequence table. */
832 spin_lock_irqsave(&intf->seq_lock, flags);
833 list_del_rcu(&user->link);
834
835 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
836 if (intf->seq_table[i].inuse
837 && (intf->seq_table[i].recv_msg->user == user))
838 {
839 intf->seq_table[i].inuse = 0;
840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800842 spin_unlock_irqrestore(&intf->seq_lock, flags);
843
844 /*
845 * Remove the user from the command receiver's table. First
846 * we build a list of everything (not using the standard link,
847 * since other things may be using it till we do
848 * synchronize_rcu()) then free everything in that list.
849 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800850 mutex_lock(&intf->cmd_rcvrs_mutex);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800851 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800852 if (rcvr->user == user) {
853 list_del_rcu(&rcvr->link);
854 rcvr->next = rcvrs;
855 rcvrs = rcvr;
856 }
857 }
Corey Minyardd6dfd132006-03-31 02:30:41 -0800858 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800859 synchronize_rcu();
860 while (rcvrs) {
861 rcvr = rcvrs;
862 rcvrs = rcvr->next;
863 kfree(rcvr);
864 }
865
866 module_put(intf->handlers->owner);
867 if (intf->handlers->dec_usecount)
868 intf->handlers->dec_usecount(intf->send_info);
869
870 kref_put(&intf->refcount, intf_free);
871
872 kref_put(&user->refcount, free_user);
873
Corey Minyard8a3628d2006-03-31 02:30:40 -0800874 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875}
876
877void ipmi_get_version(ipmi_user_t user,
878 unsigned char *major,
879 unsigned char *minor)
880{
Corey Minyard50c812b2006-03-26 01:37:21 -0800881 *major = ipmi_version_major(&user->intf->bmc->id);
882 *minor = ipmi_version_minor(&user->intf->bmc->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883}
884
Corey Minyardc14979b2005-09-06 15:18:38 -0700885int ipmi_set_my_address(ipmi_user_t user,
886 unsigned int channel,
887 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
Corey Minyardc14979b2005-09-06 15:18:38 -0700889 if (channel >= IPMI_MAX_CHANNELS)
890 return -EINVAL;
891 user->intf->channels[channel].address = address;
892 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893}
894
Corey Minyardc14979b2005-09-06 15:18:38 -0700895int ipmi_get_my_address(ipmi_user_t user,
896 unsigned int channel,
897 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898{
Corey Minyardc14979b2005-09-06 15:18:38 -0700899 if (channel >= IPMI_MAX_CHANNELS)
900 return -EINVAL;
901 *address = user->intf->channels[channel].address;
902 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903}
904
Corey Minyardc14979b2005-09-06 15:18:38 -0700905int ipmi_set_my_LUN(ipmi_user_t user,
906 unsigned int channel,
907 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908{
Corey Minyardc14979b2005-09-06 15:18:38 -0700909 if (channel >= IPMI_MAX_CHANNELS)
910 return -EINVAL;
911 user->intf->channels[channel].lun = LUN & 0x3;
912 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913}
914
Corey Minyardc14979b2005-09-06 15:18:38 -0700915int ipmi_get_my_LUN(ipmi_user_t user,
916 unsigned int channel,
917 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918{
Corey Minyardc14979b2005-09-06 15:18:38 -0700919 if (channel >= IPMI_MAX_CHANNELS)
920 return -EINVAL;
921 *address = user->intf->channels[channel].lun;
922 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923}
924
925int ipmi_set_gets_events(ipmi_user_t user, int val)
926{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800927 unsigned long flags;
928 ipmi_smi_t intf = user->intf;
929 struct ipmi_recv_msg *msg, *msg2;
930 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Corey Minyard393d2cc2005-11-07 00:59:54 -0800932 INIT_LIST_HEAD(&msgs);
933
934 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 user->gets_events = val;
936
937 if (val) {
938 /* Deliver any queued events. */
Corey Minyard8a3628d2006-03-31 02:30:40 -0800939 list_for_each_entry_safe(msg, msg2, &intf->waiting_events,
940 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 list_del(&msg->link);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800942 list_add_tail(&msg->link, &msgs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 }
944 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800945
946 /* Hold the events lock while doing this to preserve order. */
947 list_for_each_entry_safe(msg, msg2, &msgs, link) {
948 msg->user = user;
949 kref_get(&user->refcount);
950 deliver_response(msg);
951 }
952
953 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
955 return 0;
956}
957
Corey Minyard393d2cc2005-11-07 00:59:54 -0800958static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
959 unsigned char netfn,
960 unsigned char cmd)
961{
962 struct cmd_rcvr *rcvr;
963
964 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
965 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd))
966 return rcvr;
967 }
968 return NULL;
969}
970
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971int ipmi_register_for_cmd(ipmi_user_t user,
972 unsigned char netfn,
973 unsigned char cmd)
974{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800975 ipmi_smi_t intf = user->intf;
976 struct cmd_rcvr *rcvr;
977 struct cmd_rcvr *entry;
978 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980
981 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800982 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800984 rcvr->cmd = cmd;
985 rcvr->netfn = netfn;
986 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Corey Minyardd6dfd132006-03-31 02:30:41 -0800988 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 /* Make sure the command/netfn is not already registered. */
Corey Minyard393d2cc2005-11-07 00:59:54 -0800990 entry = find_cmd_rcvr(intf, netfn, cmd);
991 if (entry) {
992 rv = -EBUSY;
993 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 }
995
Corey Minyard393d2cc2005-11-07 00:59:54 -0800996 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -0700997
Corey Minyard393d2cc2005-11-07 00:59:54 -0800998 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -0800999 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (rv)
1001 kfree(rcvr);
1002
1003 return rv;
1004}
1005
1006int ipmi_unregister_for_cmd(ipmi_user_t user,
1007 unsigned char netfn,
1008 unsigned char cmd)
1009{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001010 ipmi_smi_t intf = user->intf;
1011 struct cmd_rcvr *rcvr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
Corey Minyardd6dfd132006-03-31 02:30:41 -08001013 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 /* Make sure the command/netfn is not already registered. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001015 rcvr = find_cmd_rcvr(intf, netfn, cmd);
1016 if ((rcvr) && (rcvr->user == user)) {
1017 list_del_rcu(&rcvr->link);
Corey Minyardd6dfd132006-03-31 02:30:41 -08001018 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001019 synchronize_rcu();
1020 kfree(rcvr);
1021 return 0;
1022 } else {
Corey Minyardd6dfd132006-03-31 02:30:41 -08001023 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001024 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026}
1027
1028void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
1029{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001030 ipmi_smi_t intf = user->intf;
1031 intf->handlers->set_run_to_completion(intf->send_info, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032}
1033
1034static unsigned char
1035ipmb_checksum(unsigned char *data, int size)
1036{
1037 unsigned char csum = 0;
1038
1039 for (; size > 0; size--, data++)
1040 csum += *data;
1041
1042 return -csum;
1043}
1044
1045static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1046 struct kernel_ipmi_msg *msg,
1047 struct ipmi_ipmb_addr *ipmb_addr,
1048 long msgid,
1049 unsigned char ipmb_seq,
1050 int broadcast,
1051 unsigned char source_address,
1052 unsigned char source_lun)
1053{
1054 int i = broadcast;
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] = ipmb_addr->channel;
1060 if (broadcast)
1061 smi_msg->data[3] = 0;
1062 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1063 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1064 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1065 smi_msg->data[i+6] = source_address;
1066 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1067 smi_msg->data[i+8] = msg->cmd;
1068
1069 /* Now tack on the data to the message. */
1070 if (msg->data_len > 0)
1071 memcpy(&(smi_msg->data[i+9]), msg->data,
1072 msg->data_len);
1073 smi_msg->data_size = msg->data_len + 9;
1074
1075 /* Now calculate the checksum and tack it on. */
1076 smi_msg->data[i+smi_msg->data_size]
1077 = ipmb_checksum(&(smi_msg->data[i+6]),
1078 smi_msg->data_size-6);
1079
1080 /* Add on the checksum size and the offset from the
1081 broadcast. */
1082 smi_msg->data_size += 1 + i;
1083
1084 smi_msg->msgid = msgid;
1085}
1086
1087static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1088 struct kernel_ipmi_msg *msg,
1089 struct ipmi_lan_addr *lan_addr,
1090 long msgid,
1091 unsigned char ipmb_seq,
1092 unsigned char source_lun)
1093{
1094 /* Format the IPMB header data. */
1095 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1096 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1097 smi_msg->data[2] = lan_addr->channel;
1098 smi_msg->data[3] = lan_addr->session_handle;
1099 smi_msg->data[4] = lan_addr->remote_SWID;
1100 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1101 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1102 smi_msg->data[7] = lan_addr->local_SWID;
1103 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1104 smi_msg->data[9] = msg->cmd;
1105
1106 /* Now tack on the data to the message. */
1107 if (msg->data_len > 0)
1108 memcpy(&(smi_msg->data[10]), msg->data,
1109 msg->data_len);
1110 smi_msg->data_size = msg->data_len + 10;
1111
1112 /* Now calculate the checksum and tack it on. */
1113 smi_msg->data[smi_msg->data_size]
1114 = ipmb_checksum(&(smi_msg->data[7]),
1115 smi_msg->data_size-7);
1116
1117 /* Add on the checksum size and the offset from the
1118 broadcast. */
1119 smi_msg->data_size += 1;
1120
1121 smi_msg->msgid = msgid;
1122}
1123
1124/* Separate from ipmi_request so that the user does not have to be
1125 supplied in certain circumstances (mainly at panic time). If
1126 messages are supplied, they will be freed, even if an error
1127 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001128static int i_ipmi_request(ipmi_user_t user,
1129 ipmi_smi_t intf,
1130 struct ipmi_addr *addr,
1131 long msgid,
1132 struct kernel_ipmi_msg *msg,
1133 void *user_msg_data,
1134 void *supplied_smi,
1135 struct ipmi_recv_msg *supplied_recv,
1136 int priority,
1137 unsigned char source_address,
1138 unsigned char source_lun,
1139 int retries,
1140 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141{
1142 int rv = 0;
1143 struct ipmi_smi_msg *smi_msg;
1144 struct ipmi_recv_msg *recv_msg;
1145 unsigned long flags;
1146
1147
1148 if (supplied_recv) {
1149 recv_msg = supplied_recv;
1150 } else {
1151 recv_msg = ipmi_alloc_recv_msg();
1152 if (recv_msg == NULL) {
1153 return -ENOMEM;
1154 }
1155 }
1156 recv_msg->user_msg_data = user_msg_data;
1157
1158 if (supplied_smi) {
1159 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1160 } else {
1161 smi_msg = ipmi_alloc_smi_msg();
1162 if (smi_msg == NULL) {
1163 ipmi_free_recv_msg(recv_msg);
1164 return -ENOMEM;
1165 }
1166 }
1167
1168 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001169 if (user)
1170 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 recv_msg->msgid = msgid;
1172 /* Store the message to send in the receive message so timeout
1173 responses can get the proper response data. */
1174 recv_msg->msg = *msg;
1175
1176 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1177 struct ipmi_system_interface_addr *smi_addr;
1178
1179 if (msg->netfn & 1) {
1180 /* Responses are not allowed to the SMI. */
1181 rv = -EINVAL;
1182 goto out_err;
1183 }
1184
1185 smi_addr = (struct ipmi_system_interface_addr *) addr;
1186 if (smi_addr->lun > 3) {
1187 spin_lock_irqsave(&intf->counter_lock, flags);
1188 intf->sent_invalid_commands++;
1189 spin_unlock_irqrestore(&intf->counter_lock, flags);
1190 rv = -EINVAL;
1191 goto out_err;
1192 }
1193
1194 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1195
1196 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1197 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1198 || (msg->cmd == IPMI_GET_MSG_CMD)
1199 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1200 {
1201 /* We don't let the user do these, since we manage
1202 the sequence numbers. */
1203 spin_lock_irqsave(&intf->counter_lock, flags);
1204 intf->sent_invalid_commands++;
1205 spin_unlock_irqrestore(&intf->counter_lock, flags);
1206 rv = -EINVAL;
1207 goto out_err;
1208 }
1209
1210 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1211 spin_lock_irqsave(&intf->counter_lock, flags);
1212 intf->sent_invalid_commands++;
1213 spin_unlock_irqrestore(&intf->counter_lock, flags);
1214 rv = -EMSGSIZE;
1215 goto out_err;
1216 }
1217
1218 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1219 smi_msg->data[1] = msg->cmd;
1220 smi_msg->msgid = msgid;
1221 smi_msg->user_data = recv_msg;
1222 if (msg->data_len > 0)
1223 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1224 smi_msg->data_size = msg->data_len + 2;
1225 spin_lock_irqsave(&intf->counter_lock, flags);
1226 intf->sent_local_commands++;
1227 spin_unlock_irqrestore(&intf->counter_lock, flags);
1228 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1229 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1230 {
1231 struct ipmi_ipmb_addr *ipmb_addr;
1232 unsigned char ipmb_seq;
1233 long seqid;
1234 int broadcast = 0;
1235
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001236 if (addr->channel >= IPMI_MAX_CHANNELS) {
1237 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 intf->sent_invalid_commands++;
1239 spin_unlock_irqrestore(&intf->counter_lock, flags);
1240 rv = -EINVAL;
1241 goto out_err;
1242 }
1243
1244 if (intf->channels[addr->channel].medium
1245 != IPMI_CHANNEL_MEDIUM_IPMB)
1246 {
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 if (retries < 0) {
1255 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1256 retries = 0; /* Don't retry broadcasts. */
1257 else
1258 retries = 4;
1259 }
1260 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1261 /* Broadcasts add a zero at the beginning of the
1262 message, but otherwise is the same as an IPMB
1263 address. */
1264 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1265 broadcast = 1;
1266 }
1267
1268
1269 /* Default to 1 second retries. */
1270 if (retry_time_ms == 0)
1271 retry_time_ms = 1000;
1272
1273 /* 9 for the header and 1 for the checksum, plus
1274 possibly one for the broadcast. */
1275 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1276 spin_lock_irqsave(&intf->counter_lock, flags);
1277 intf->sent_invalid_commands++;
1278 spin_unlock_irqrestore(&intf->counter_lock, flags);
1279 rv = -EMSGSIZE;
1280 goto out_err;
1281 }
1282
1283 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1284 if (ipmb_addr->lun > 3) {
1285 spin_lock_irqsave(&intf->counter_lock, flags);
1286 intf->sent_invalid_commands++;
1287 spin_unlock_irqrestore(&intf->counter_lock, flags);
1288 rv = -EINVAL;
1289 goto out_err;
1290 }
1291
1292 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1293
1294 if (recv_msg->msg.netfn & 0x1) {
1295 /* It's a response, so use the user's sequence
1296 from msgid. */
1297 spin_lock_irqsave(&intf->counter_lock, flags);
1298 intf->sent_ipmb_responses++;
1299 spin_unlock_irqrestore(&intf->counter_lock, flags);
1300 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1301 msgid, broadcast,
1302 source_address, source_lun);
1303
1304 /* Save the receive message so we can use it
1305 to deliver the response. */
1306 smi_msg->user_data = recv_msg;
1307 } else {
1308 /* It's a command, so get a sequence for it. */
1309
1310 spin_lock_irqsave(&(intf->seq_lock), flags);
1311
1312 spin_lock(&intf->counter_lock);
1313 intf->sent_ipmb_commands++;
1314 spin_unlock(&intf->counter_lock);
1315
1316 /* Create a sequence number with a 1 second
1317 timeout and 4 retries. */
1318 rv = intf_next_seq(intf,
1319 recv_msg,
1320 retry_time_ms,
1321 retries,
1322 broadcast,
1323 &ipmb_seq,
1324 &seqid);
1325 if (rv) {
1326 /* We have used up all the sequence numbers,
1327 probably, so abort. */
1328 spin_unlock_irqrestore(&(intf->seq_lock),
1329 flags);
1330 goto out_err;
1331 }
1332
1333 /* Store the sequence number in the message,
1334 so that when the send message response
1335 comes back we can start the timer. */
1336 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1337 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1338 ipmb_seq, broadcast,
1339 source_address, source_lun);
1340
1341 /* Copy the message into the recv message data, so we
1342 can retransmit it later if necessary. */
1343 memcpy(recv_msg->msg_data, smi_msg->data,
1344 smi_msg->data_size);
1345 recv_msg->msg.data = recv_msg->msg_data;
1346 recv_msg->msg.data_len = smi_msg->data_size;
1347
1348 /* We don't unlock until here, because we need
1349 to copy the completed message into the
1350 recv_msg before we release the lock.
1351 Otherwise, race conditions may bite us. I
1352 know that's pretty paranoid, but I prefer
1353 to be correct. */
1354 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1355 }
1356 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1357 struct ipmi_lan_addr *lan_addr;
1358 unsigned char ipmb_seq;
1359 long seqid;
1360
Jayachandran C12fc1d72006-02-03 03:04:51 -08001361 if (addr->channel >= IPMI_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 spin_lock_irqsave(&intf->counter_lock, flags);
1363 intf->sent_invalid_commands++;
1364 spin_unlock_irqrestore(&intf->counter_lock, flags);
1365 rv = -EINVAL;
1366 goto out_err;
1367 }
1368
1369 if ((intf->channels[addr->channel].medium
1370 != IPMI_CHANNEL_MEDIUM_8023LAN)
1371 && (intf->channels[addr->channel].medium
1372 != IPMI_CHANNEL_MEDIUM_ASYNC))
1373 {
1374 spin_lock_irqsave(&intf->counter_lock, flags);
1375 intf->sent_invalid_commands++;
1376 spin_unlock_irqrestore(&intf->counter_lock, flags);
1377 rv = -EINVAL;
1378 goto out_err;
1379 }
1380
1381 retries = 4;
1382
1383 /* Default to 1 second retries. */
1384 if (retry_time_ms == 0)
1385 retry_time_ms = 1000;
1386
1387 /* 11 for the header and 1 for the checksum. */
1388 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1389 spin_lock_irqsave(&intf->counter_lock, flags);
1390 intf->sent_invalid_commands++;
1391 spin_unlock_irqrestore(&intf->counter_lock, flags);
1392 rv = -EMSGSIZE;
1393 goto out_err;
1394 }
1395
1396 lan_addr = (struct ipmi_lan_addr *) addr;
1397 if (lan_addr->lun > 3) {
1398 spin_lock_irqsave(&intf->counter_lock, flags);
1399 intf->sent_invalid_commands++;
1400 spin_unlock_irqrestore(&intf->counter_lock, flags);
1401 rv = -EINVAL;
1402 goto out_err;
1403 }
1404
1405 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1406
1407 if (recv_msg->msg.netfn & 0x1) {
1408 /* It's a response, so use the user's sequence
1409 from msgid. */
1410 spin_lock_irqsave(&intf->counter_lock, flags);
1411 intf->sent_lan_responses++;
1412 spin_unlock_irqrestore(&intf->counter_lock, flags);
1413 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1414 msgid, source_lun);
1415
1416 /* Save the receive message so we can use it
1417 to deliver the response. */
1418 smi_msg->user_data = recv_msg;
1419 } else {
1420 /* It's a command, so get a sequence for it. */
1421
1422 spin_lock_irqsave(&(intf->seq_lock), flags);
1423
1424 spin_lock(&intf->counter_lock);
1425 intf->sent_lan_commands++;
1426 spin_unlock(&intf->counter_lock);
1427
1428 /* Create a sequence number with a 1 second
1429 timeout and 4 retries. */
1430 rv = intf_next_seq(intf,
1431 recv_msg,
1432 retry_time_ms,
1433 retries,
1434 0,
1435 &ipmb_seq,
1436 &seqid);
1437 if (rv) {
1438 /* We have used up all the sequence numbers,
1439 probably, so abort. */
1440 spin_unlock_irqrestore(&(intf->seq_lock),
1441 flags);
1442 goto out_err;
1443 }
1444
1445 /* Store the sequence number in the message,
1446 so that when the send message response
1447 comes back we can start the timer. */
1448 format_lan_msg(smi_msg, msg, lan_addr,
1449 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1450 ipmb_seq, source_lun);
1451
1452 /* Copy the message into the recv message data, so we
1453 can retransmit it later if necessary. */
1454 memcpy(recv_msg->msg_data, smi_msg->data,
1455 smi_msg->data_size);
1456 recv_msg->msg.data = recv_msg->msg_data;
1457 recv_msg->msg.data_len = smi_msg->data_size;
1458
1459 /* We don't unlock until here, because we need
1460 to copy the completed message into the
1461 recv_msg before we release the lock.
1462 Otherwise, race conditions may bite us. I
1463 know that's pretty paranoid, but I prefer
1464 to be correct. */
1465 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1466 }
1467 } else {
1468 /* Unknown address type. */
1469 spin_lock_irqsave(&intf->counter_lock, flags);
1470 intf->sent_invalid_commands++;
1471 spin_unlock_irqrestore(&intf->counter_lock, flags);
1472 rv = -EINVAL;
1473 goto out_err;
1474 }
1475
1476#ifdef DEBUG_MSGING
1477 {
1478 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001479 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 printk(" %2.2x", smi_msg->data[m]);
1481 printk("\n");
1482 }
1483#endif
1484 intf->handlers->sender(intf->send_info, smi_msg, priority);
1485
1486 return 0;
1487
1488 out_err:
1489 ipmi_free_smi_msg(smi_msg);
1490 ipmi_free_recv_msg(recv_msg);
1491 return rv;
1492}
1493
Corey Minyardc14979b2005-09-06 15:18:38 -07001494static int check_addr(ipmi_smi_t intf,
1495 struct ipmi_addr *addr,
1496 unsigned char *saddr,
1497 unsigned char *lun)
1498{
1499 if (addr->channel >= IPMI_MAX_CHANNELS)
1500 return -EINVAL;
1501 *lun = intf->channels[addr->channel].lun;
1502 *saddr = intf->channels[addr->channel].address;
1503 return 0;
1504}
1505
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506int ipmi_request_settime(ipmi_user_t user,
1507 struct ipmi_addr *addr,
1508 long msgid,
1509 struct kernel_ipmi_msg *msg,
1510 void *user_msg_data,
1511 int priority,
1512 int retries,
1513 unsigned int retry_time_ms)
1514{
Corey Minyardc14979b2005-09-06 15:18:38 -07001515 unsigned char saddr, lun;
1516 int rv;
1517
Corey Minyard8a3628d2006-03-31 02:30:40 -08001518 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001519 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001520 rv = check_addr(user->intf, addr, &saddr, &lun);
1521 if (rv)
1522 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 return i_ipmi_request(user,
1524 user->intf,
1525 addr,
1526 msgid,
1527 msg,
1528 user_msg_data,
1529 NULL, NULL,
1530 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001531 saddr,
1532 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 retries,
1534 retry_time_ms);
1535}
1536
1537int ipmi_request_supply_msgs(ipmi_user_t user,
1538 struct ipmi_addr *addr,
1539 long msgid,
1540 struct kernel_ipmi_msg *msg,
1541 void *user_msg_data,
1542 void *supplied_smi,
1543 struct ipmi_recv_msg *supplied_recv,
1544 int priority)
1545{
Corey Minyardc14979b2005-09-06 15:18:38 -07001546 unsigned char saddr, lun;
1547 int rv;
1548
Corey Minyard8a3628d2006-03-31 02:30:40 -08001549 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001550 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001551 rv = check_addr(user->intf, addr, &saddr, &lun);
1552 if (rv)
1553 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 return i_ipmi_request(user,
1555 user->intf,
1556 addr,
1557 msgid,
1558 msg,
1559 user_msg_data,
1560 supplied_smi,
1561 supplied_recv,
1562 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001563 saddr,
1564 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 -1, 0);
1566}
1567
1568static int ipmb_file_read_proc(char *page, char **start, off_t off,
1569 int count, int *eof, void *data)
1570{
1571 char *out = (char *) page;
1572 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001573 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001574 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
Corey Minyarde8b33612005-09-06 15:18:45 -07001576 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001577 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1578 out[rv-1] = '\n'; /* Replace the final space with a newline */
1579 out[rv] = '\0';
1580 rv++;
1581 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582}
1583
1584static int version_file_read_proc(char *page, char **start, off_t off,
1585 int count, int *eof, void *data)
1586{
1587 char *out = (char *) page;
1588 ipmi_smi_t intf = data;
1589
1590 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001591 ipmi_version_major(&intf->bmc->id),
1592 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593}
1594
1595static int stat_file_read_proc(char *page, char **start, off_t off,
1596 int count, int *eof, void *data)
1597{
1598 char *out = (char *) page;
1599 ipmi_smi_t intf = data;
1600
1601 out += sprintf(out, "sent_invalid_commands: %d\n",
1602 intf->sent_invalid_commands);
1603 out += sprintf(out, "sent_local_commands: %d\n",
1604 intf->sent_local_commands);
1605 out += sprintf(out, "handled_local_responses: %d\n",
1606 intf->handled_local_responses);
1607 out += sprintf(out, "unhandled_local_responses: %d\n",
1608 intf->unhandled_local_responses);
1609 out += sprintf(out, "sent_ipmb_commands: %d\n",
1610 intf->sent_ipmb_commands);
1611 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1612 intf->sent_ipmb_command_errs);
1613 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1614 intf->retransmitted_ipmb_commands);
1615 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1616 intf->timed_out_ipmb_commands);
1617 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1618 intf->timed_out_ipmb_broadcasts);
1619 out += sprintf(out, "sent_ipmb_responses: %d\n",
1620 intf->sent_ipmb_responses);
1621 out += sprintf(out, "handled_ipmb_responses: %d\n",
1622 intf->handled_ipmb_responses);
1623 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1624 intf->invalid_ipmb_responses);
1625 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1626 intf->unhandled_ipmb_responses);
1627 out += sprintf(out, "sent_lan_commands: %d\n",
1628 intf->sent_lan_commands);
1629 out += sprintf(out, "sent_lan_command_errs: %d\n",
1630 intf->sent_lan_command_errs);
1631 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1632 intf->retransmitted_lan_commands);
1633 out += sprintf(out, "timed_out_lan_commands: %d\n",
1634 intf->timed_out_lan_commands);
1635 out += sprintf(out, "sent_lan_responses: %d\n",
1636 intf->sent_lan_responses);
1637 out += sprintf(out, "handled_lan_responses: %d\n",
1638 intf->handled_lan_responses);
1639 out += sprintf(out, "invalid_lan_responses: %d\n",
1640 intf->invalid_lan_responses);
1641 out += sprintf(out, "unhandled_lan_responses: %d\n",
1642 intf->unhandled_lan_responses);
1643 out += sprintf(out, "handled_commands: %d\n",
1644 intf->handled_commands);
1645 out += sprintf(out, "invalid_commands: %d\n",
1646 intf->invalid_commands);
1647 out += sprintf(out, "unhandled_commands: %d\n",
1648 intf->unhandled_commands);
1649 out += sprintf(out, "invalid_events: %d\n",
1650 intf->invalid_events);
1651 out += sprintf(out, "events: %d\n",
1652 intf->events);
1653
1654 return (out - ((char *) page));
1655}
1656
1657int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1658 read_proc_t *read_proc, write_proc_t *write_proc,
1659 void *data, struct module *owner)
1660{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001662#ifdef CONFIG_PROC_FS
1663 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 struct ipmi_proc_entry *entry;
1665
1666 /* Create a list element. */
1667 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1668 if (!entry)
1669 return -ENOMEM;
1670 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1671 if (!entry->name) {
1672 kfree(entry);
1673 return -ENOMEM;
1674 }
1675 strcpy(entry->name, name);
1676
1677 file = create_proc_entry(name, 0, smi->proc_dir);
1678 if (!file) {
1679 kfree(entry->name);
1680 kfree(entry);
1681 rv = -ENOMEM;
1682 } else {
1683 file->nlink = 1;
1684 file->data = data;
1685 file->read_proc = read_proc;
1686 file->write_proc = write_proc;
1687 file->owner = owner;
1688
Corey Minyard3b625942005-06-23 22:01:42 -07001689 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 /* Stick it on the list. */
1691 entry->next = smi->proc_entries;
1692 smi->proc_entries = entry;
Corey Minyard3b625942005-06-23 22:01:42 -07001693 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 }
Corey Minyard3b625942005-06-23 22:01:42 -07001695#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 return rv;
1698}
1699
1700static int add_proc_entries(ipmi_smi_t smi, int num)
1701{
1702 int rv = 0;
1703
Corey Minyard3b625942005-06-23 22:01:42 -07001704#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 sprintf(smi->proc_dir_name, "%d", num);
1706 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1707 if (!smi->proc_dir)
1708 rv = -ENOMEM;
1709 else {
1710 smi->proc_dir->owner = THIS_MODULE;
1711 }
1712
1713 if (rv == 0)
1714 rv = ipmi_smi_add_proc_entry(smi, "stats",
1715 stat_file_read_proc, NULL,
1716 smi, THIS_MODULE);
1717
1718 if (rv == 0)
1719 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1720 ipmb_file_read_proc, NULL,
1721 smi, THIS_MODULE);
1722
1723 if (rv == 0)
1724 rv = ipmi_smi_add_proc_entry(smi, "version",
1725 version_file_read_proc, NULL,
1726 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001727#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
1729 return rv;
1730}
1731
1732static void remove_proc_entries(ipmi_smi_t smi)
1733{
Corey Minyard3b625942005-06-23 22:01:42 -07001734#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 struct ipmi_proc_entry *entry;
1736
Corey Minyard3b625942005-06-23 22:01:42 -07001737 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 while (smi->proc_entries) {
1739 entry = smi->proc_entries;
1740 smi->proc_entries = entry->next;
1741
1742 remove_proc_entry(entry->name, smi->proc_dir);
1743 kfree(entry->name);
1744 kfree(entry);
1745 }
Corey Minyard3b625942005-06-23 22:01:42 -07001746 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001748#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749}
1750
Corey Minyard50c812b2006-03-26 01:37:21 -08001751static int __find_bmc_guid(struct device *dev, void *data)
1752{
1753 unsigned char *id = data;
1754 struct bmc_device *bmc = dev_get_drvdata(dev);
1755 return memcmp(bmc->guid, id, 16) == 0;
1756}
1757
1758static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1759 unsigned char *guid)
1760{
1761 struct device *dev;
1762
1763 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1764 if (dev)
1765 return dev_get_drvdata(dev);
1766 else
1767 return NULL;
1768}
1769
1770struct prod_dev_id {
1771 unsigned int product_id;
1772 unsigned char device_id;
1773};
1774
1775static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1776{
1777 struct prod_dev_id *id = data;
1778 struct bmc_device *bmc = dev_get_drvdata(dev);
1779
1780 return (bmc->id.product_id == id->product_id
1781 && bmc->id.product_id == id->product_id
1782 && bmc->id.device_id == id->device_id);
1783}
1784
1785static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1786 struct device_driver *drv,
1787 unsigned char product_id, unsigned char device_id)
1788{
1789 struct prod_dev_id id = {
1790 .product_id = product_id,
1791 .device_id = device_id,
1792 };
1793 struct device *dev;
1794
1795 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
1796 if (dev)
1797 return dev_get_drvdata(dev);
1798 else
1799 return NULL;
1800}
1801
1802static ssize_t device_id_show(struct device *dev,
1803 struct device_attribute *attr,
1804 char *buf)
1805{
1806 struct bmc_device *bmc = dev_get_drvdata(dev);
1807
1808 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
1809}
1810
1811static ssize_t provides_dev_sdrs_show(struct device *dev,
1812 struct device_attribute *attr,
1813 char *buf)
1814{
1815 struct bmc_device *bmc = dev_get_drvdata(dev);
1816
1817 return snprintf(buf, 10, "%u\n",
1818 bmc->id.device_revision && 0x80 >> 7);
1819}
1820
1821static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
1822 char *buf)
1823{
1824 struct bmc_device *bmc = dev_get_drvdata(dev);
1825
1826 return snprintf(buf, 20, "%u\n",
1827 bmc->id.device_revision && 0x0F);
1828}
1829
1830static ssize_t firmware_rev_show(struct device *dev,
1831 struct device_attribute *attr,
1832 char *buf)
1833{
1834 struct bmc_device *bmc = dev_get_drvdata(dev);
1835
1836 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
1837 bmc->id.firmware_revision_2);
1838}
1839
1840static ssize_t ipmi_version_show(struct device *dev,
1841 struct device_attribute *attr,
1842 char *buf)
1843{
1844 struct bmc_device *bmc = dev_get_drvdata(dev);
1845
1846 return snprintf(buf, 20, "%u.%u\n",
1847 ipmi_version_major(&bmc->id),
1848 ipmi_version_minor(&bmc->id));
1849}
1850
1851static ssize_t add_dev_support_show(struct device *dev,
1852 struct device_attribute *attr,
1853 char *buf)
1854{
1855 struct bmc_device *bmc = dev_get_drvdata(dev);
1856
1857 return snprintf(buf, 10, "0x%02x\n",
1858 bmc->id.additional_device_support);
1859}
1860
1861static ssize_t manufacturer_id_show(struct device *dev,
1862 struct device_attribute *attr,
1863 char *buf)
1864{
1865 struct bmc_device *bmc = dev_get_drvdata(dev);
1866
1867 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
1868}
1869
1870static ssize_t product_id_show(struct device *dev,
1871 struct device_attribute *attr,
1872 char *buf)
1873{
1874 struct bmc_device *bmc = dev_get_drvdata(dev);
1875
1876 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
1877}
1878
1879static ssize_t aux_firmware_rev_show(struct device *dev,
1880 struct device_attribute *attr,
1881 char *buf)
1882{
1883 struct bmc_device *bmc = dev_get_drvdata(dev);
1884
1885 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
1886 bmc->id.aux_firmware_revision[3],
1887 bmc->id.aux_firmware_revision[2],
1888 bmc->id.aux_firmware_revision[1],
1889 bmc->id.aux_firmware_revision[0]);
1890}
1891
1892static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
1893 char *buf)
1894{
1895 struct bmc_device *bmc = dev_get_drvdata(dev);
1896
1897 return snprintf(buf, 100, "%Lx%Lx\n",
1898 (long long) bmc->guid[0],
1899 (long long) bmc->guid[8]);
1900}
1901
1902static void
1903cleanup_bmc_device(struct kref *ref)
1904{
1905 struct bmc_device *bmc;
1906
1907 bmc = container_of(ref, struct bmc_device, refcount);
1908
1909 device_remove_file(&bmc->dev->dev,
1910 &bmc->device_id_attr);
1911 device_remove_file(&bmc->dev->dev,
1912 &bmc->provides_dev_sdrs_attr);
1913 device_remove_file(&bmc->dev->dev,
1914 &bmc->revision_attr);
1915 device_remove_file(&bmc->dev->dev,
1916 &bmc->firmware_rev_attr);
1917 device_remove_file(&bmc->dev->dev,
1918 &bmc->version_attr);
1919 device_remove_file(&bmc->dev->dev,
1920 &bmc->add_dev_support_attr);
1921 device_remove_file(&bmc->dev->dev,
1922 &bmc->manufacturer_id_attr);
1923 device_remove_file(&bmc->dev->dev,
1924 &bmc->product_id_attr);
1925 if (bmc->id.aux_firmware_revision_set)
1926 device_remove_file(&bmc->dev->dev,
1927 &bmc->aux_firmware_rev_attr);
1928 if (bmc->guid_set)
1929 device_remove_file(&bmc->dev->dev,
1930 &bmc->guid_attr);
1931 platform_device_unregister(bmc->dev);
1932 kfree(bmc);
1933}
1934
1935static void ipmi_bmc_unregister(ipmi_smi_t intf)
1936{
1937 struct bmc_device *bmc = intf->bmc;
1938
1939 sysfs_remove_link(&intf->si_dev->kobj, "bmc");
1940 if (intf->my_dev_name) {
1941 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
1942 kfree(intf->my_dev_name);
1943 intf->my_dev_name = NULL;
1944 }
1945
1946 mutex_lock(&ipmidriver_mutex);
1947 kref_put(&bmc->refcount, cleanup_bmc_device);
1948 mutex_unlock(&ipmidriver_mutex);
1949}
1950
1951static int ipmi_bmc_register(ipmi_smi_t intf)
1952{
1953 int rv;
1954 struct bmc_device *bmc = intf->bmc;
1955 struct bmc_device *old_bmc;
1956 int size;
1957 char dummy[1];
1958
1959 mutex_lock(&ipmidriver_mutex);
1960
1961 /*
1962 * Try to find if there is an bmc_device struct
1963 * representing the interfaced BMC already
1964 */
1965 if (bmc->guid_set)
1966 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
1967 else
1968 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
1969 bmc->id.product_id,
1970 bmc->id.device_id);
1971
1972 /*
1973 * If there is already an bmc_device, free the new one,
1974 * otherwise register the new BMC device
1975 */
1976 if (old_bmc) {
1977 kfree(bmc);
1978 intf->bmc = old_bmc;
1979 bmc = old_bmc;
1980
1981 kref_get(&bmc->refcount);
1982 mutex_unlock(&ipmidriver_mutex);
1983
1984 printk(KERN_INFO
1985 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
1986 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
1987 bmc->id.manufacturer_id,
1988 bmc->id.product_id,
1989 bmc->id.device_id);
1990 } else {
1991 bmc->dev = platform_device_alloc("ipmi_bmc",
1992 bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08001993 if (!bmc->dev) {
Corey Minyard50c812b2006-03-26 01:37:21 -08001994 printk(KERN_ERR
1995 "ipmi_msghandler:"
1996 " Unable to allocate platform device\n");
1997 return -ENOMEM;
1998 }
1999 bmc->dev->dev.driver = &ipmidriver;
2000 dev_set_drvdata(&bmc->dev->dev, bmc);
2001 kref_init(&bmc->refcount);
2002
2003 rv = platform_device_register(bmc->dev);
2004 mutex_unlock(&ipmidriver_mutex);
2005 if (rv) {
2006 printk(KERN_ERR
2007 "ipmi_msghandler:"
2008 " Unable to register bmc device: %d\n",
2009 rv);
2010 /* Don't go to out_err, you can only do that if
2011 the device is registered already. */
2012 return rv;
2013 }
2014
2015 bmc->device_id_attr.attr.name = "device_id";
2016 bmc->device_id_attr.attr.owner = THIS_MODULE;
2017 bmc->device_id_attr.attr.mode = S_IRUGO;
2018 bmc->device_id_attr.show = device_id_show;
2019
2020 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
2021 bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
2022 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2023 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2024
2025
2026 bmc->revision_attr.attr.name = "revision";
2027 bmc->revision_attr.attr.owner = THIS_MODULE;
2028 bmc->revision_attr.attr.mode = S_IRUGO;
2029 bmc->revision_attr.show = revision_show;
2030
2031 bmc->firmware_rev_attr.attr.name = "firmware_revision";
2032 bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
2033 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2034 bmc->firmware_rev_attr.show = firmware_rev_show;
2035
2036 bmc->version_attr.attr.name = "ipmi_version";
2037 bmc->version_attr.attr.owner = THIS_MODULE;
2038 bmc->version_attr.attr.mode = S_IRUGO;
2039 bmc->version_attr.show = ipmi_version_show;
2040
2041 bmc->add_dev_support_attr.attr.name
2042 = "additional_device_support";
2043 bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
2044 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2045 bmc->add_dev_support_attr.show = add_dev_support_show;
2046
2047 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
2048 bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
2049 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2050 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2051
2052 bmc->product_id_attr.attr.name = "product_id";
2053 bmc->product_id_attr.attr.owner = THIS_MODULE;
2054 bmc->product_id_attr.attr.mode = S_IRUGO;
2055 bmc->product_id_attr.show = product_id_show;
2056
2057 bmc->guid_attr.attr.name = "guid";
2058 bmc->guid_attr.attr.owner = THIS_MODULE;
2059 bmc->guid_attr.attr.mode = S_IRUGO;
2060 bmc->guid_attr.show = guid_show;
2061
2062 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
2063 bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
2064 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2065 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2066
2067 device_create_file(&bmc->dev->dev,
2068 &bmc->device_id_attr);
2069 device_create_file(&bmc->dev->dev,
2070 &bmc->provides_dev_sdrs_attr);
2071 device_create_file(&bmc->dev->dev,
2072 &bmc->revision_attr);
2073 device_create_file(&bmc->dev->dev,
2074 &bmc->firmware_rev_attr);
2075 device_create_file(&bmc->dev->dev,
2076 &bmc->version_attr);
2077 device_create_file(&bmc->dev->dev,
2078 &bmc->add_dev_support_attr);
2079 device_create_file(&bmc->dev->dev,
2080 &bmc->manufacturer_id_attr);
2081 device_create_file(&bmc->dev->dev,
2082 &bmc->product_id_attr);
2083 if (bmc->id.aux_firmware_revision_set)
2084 device_create_file(&bmc->dev->dev,
2085 &bmc->aux_firmware_rev_attr);
2086 if (bmc->guid_set)
2087 device_create_file(&bmc->dev->dev,
2088 &bmc->guid_attr);
2089
2090 printk(KERN_INFO
2091 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2092 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2093 bmc->id.manufacturer_id,
2094 bmc->id.product_id,
2095 bmc->id.device_id);
2096 }
2097
2098 /*
2099 * create symlink from system interface device to bmc device
2100 * and back.
2101 */
2102 rv = sysfs_create_link(&intf->si_dev->kobj,
2103 &bmc->dev->dev.kobj, "bmc");
2104 if (rv) {
2105 printk(KERN_ERR
2106 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2107 rv);
2108 goto out_err;
2109 }
2110
2111 size = snprintf(dummy, 0, "ipmi%d", intf->intf_num);
2112 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2113 if (!intf->my_dev_name) {
2114 rv = -ENOMEM;
2115 printk(KERN_ERR
2116 "ipmi_msghandler: allocate link from BMC: %d\n",
2117 rv);
2118 goto out_err;
2119 }
2120 snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num);
2121
2122 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2123 intf->my_dev_name);
2124 if (rv) {
2125 kfree(intf->my_dev_name);
2126 intf->my_dev_name = NULL;
2127 printk(KERN_ERR
2128 "ipmi_msghandler:"
2129 " Unable to create symlink to bmc: %d\n",
2130 rv);
2131 goto out_err;
2132 }
2133
2134 return 0;
2135
2136out_err:
2137 ipmi_bmc_unregister(intf);
2138 return rv;
2139}
2140
2141static int
2142send_guid_cmd(ipmi_smi_t intf, int chan)
2143{
2144 struct kernel_ipmi_msg msg;
2145 struct ipmi_system_interface_addr si;
2146
2147 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2148 si.channel = IPMI_BMC_CHANNEL;
2149 si.lun = 0;
2150
2151 msg.netfn = IPMI_NETFN_APP_REQUEST;
2152 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2153 msg.data = NULL;
2154 msg.data_len = 0;
2155 return i_ipmi_request(NULL,
2156 intf,
2157 (struct ipmi_addr *) &si,
2158 0,
2159 &msg,
2160 intf,
2161 NULL,
2162 NULL,
2163 0,
2164 intf->channels[0].address,
2165 intf->channels[0].lun,
2166 -1, 0);
2167}
2168
2169static void
2170guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2171{
2172 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2173 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2174 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2175 /* Not for me */
2176 return;
2177
2178 if (msg->msg.data[0] != 0) {
2179 /* Error from getting the GUID, the BMC doesn't have one. */
2180 intf->bmc->guid_set = 0;
2181 goto out;
2182 }
2183
2184 if (msg->msg.data_len < 17) {
2185 intf->bmc->guid_set = 0;
2186 printk(KERN_WARNING PFX
2187 "guid_handler: The GUID response from the BMC was too"
2188 " short, it was %d but should have been 17. Assuming"
2189 " GUID is not available.\n",
2190 msg->msg.data_len);
2191 goto out;
2192 }
2193
2194 memcpy(intf->bmc->guid, msg->msg.data, 16);
2195 intf->bmc->guid_set = 1;
2196 out:
2197 wake_up(&intf->waitq);
2198}
2199
2200static void
2201get_guid(ipmi_smi_t intf)
2202{
2203 int rv;
2204
2205 intf->bmc->guid_set = 0x2;
2206 intf->null_user_handler = guid_handler;
2207 rv = send_guid_cmd(intf, 0);
2208 if (rv)
2209 /* Send failed, no GUID available. */
2210 intf->bmc->guid_set = 0;
2211 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2212 intf->null_user_handler = NULL;
2213}
2214
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215static int
2216send_channel_info_cmd(ipmi_smi_t intf, int chan)
2217{
2218 struct kernel_ipmi_msg msg;
2219 unsigned char data[1];
2220 struct ipmi_system_interface_addr si;
2221
2222 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2223 si.channel = IPMI_BMC_CHANNEL;
2224 si.lun = 0;
2225
2226 msg.netfn = IPMI_NETFN_APP_REQUEST;
2227 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2228 msg.data = data;
2229 msg.data_len = 1;
2230 data[0] = chan;
2231 return i_ipmi_request(NULL,
2232 intf,
2233 (struct ipmi_addr *) &si,
2234 0,
2235 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002236 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 NULL,
2238 NULL,
2239 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002240 intf->channels[0].address,
2241 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 -1, 0);
2243}
2244
2245static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002246channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247{
2248 int rv = 0;
2249 int chan;
2250
Corey Minyard56a55ec2005-09-06 15:18:42 -07002251 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2252 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2253 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 {
2255 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002256 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 /* Got an error from the channel, just go on. */
2258
Corey Minyard56a55ec2005-09-06 15:18:42 -07002259 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 /* If the MC does not support this
2261 command, that is legal. We just
2262 assume it has one IPMB at channel
2263 zero. */
2264 intf->channels[0].medium
2265 = IPMI_CHANNEL_MEDIUM_IPMB;
2266 intf->channels[0].protocol
2267 = IPMI_CHANNEL_PROTOCOL_IPMB;
2268 rv = -ENOSYS;
2269
2270 intf->curr_channel = IPMI_MAX_CHANNELS;
2271 wake_up(&intf->waitq);
2272 goto out;
2273 }
2274 goto next_channel;
2275 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002276 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 /* Message not big enough, just go on. */
2278 goto next_channel;
2279 }
2280 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002281 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2282 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283
2284 next_channel:
2285 intf->curr_channel++;
2286 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2287 wake_up(&intf->waitq);
2288 else
2289 rv = send_channel_info_cmd(intf, intf->curr_channel);
2290
2291 if (rv) {
2292 /* Got an error somehow, just give up. */
2293 intf->curr_channel = IPMI_MAX_CHANNELS;
2294 wake_up(&intf->waitq);
2295
2296 printk(KERN_WARNING PFX
2297 "Error sending channel information: %d\n",
2298 rv);
2299 }
2300 }
2301 out:
2302 return;
2303}
2304
2305int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2306 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002307 struct ipmi_device_id *device_id,
2308 struct device *si_dev,
Corey Minyard453823b2006-03-31 02:30:39 -08002309 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310{
2311 int i, j;
2312 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002313 ipmi_smi_t intf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 unsigned long flags;
Corey Minyard50c812b2006-03-26 01:37:21 -08002315 int version_major;
2316 int version_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
Corey Minyard50c812b2006-03-26 01:37:21 -08002318 version_major = ipmi_version_major(device_id);
2319 version_minor = ipmi_version_minor(device_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
2321 /* Make sure the driver is actually initialized, this handles
2322 problems with initialization order. */
2323 if (!initialized) {
2324 rv = ipmi_init_msghandler();
2325 if (rv)
2326 return rv;
2327 /* The init code doesn't return an error if it was turned
2328 off, but it won't initialize. Check that. */
2329 if (!initialized)
2330 return -ENODEV;
2331 }
2332
Corey Minyard393d2cc2005-11-07 00:59:54 -08002333 intf = kmalloc(sizeof(*intf), GFP_KERNEL);
2334 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002336 memset(intf, 0, sizeof(*intf));
Corey Minyard50c812b2006-03-26 01:37:21 -08002337 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2338 if (!intf->bmc) {
2339 kfree(intf);
2340 return -ENOMEM;
2341 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002342 intf->intf_num = -1;
2343 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002344 intf->bmc->id = *device_id;
2345 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002346 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2347 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2348 intf->channels[j].lun = 2;
2349 }
2350 if (slave_addr != 0)
2351 intf->channels[0].address = slave_addr;
2352 INIT_LIST_HEAD(&intf->users);
2353 intf->handlers = handlers;
2354 intf->send_info = send_info;
2355 spin_lock_init(&intf->seq_lock);
2356 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2357 intf->seq_table[j].inuse = 0;
2358 intf->seq_table[j].seqid = 0;
2359 }
2360 intf->curr_seq = 0;
2361#ifdef CONFIG_PROC_FS
2362 spin_lock_init(&intf->proc_entry_lock);
2363#endif
2364 spin_lock_init(&intf->waiting_msgs_lock);
2365 INIT_LIST_HEAD(&intf->waiting_msgs);
2366 spin_lock_init(&intf->events_lock);
2367 INIT_LIST_HEAD(&intf->waiting_events);
2368 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002369 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002370 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2371 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372
Corey Minyard393d2cc2005-11-07 00:59:54 -08002373 spin_lock_init(&intf->counter_lock);
2374 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375
2376 rv = -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002377 spin_lock_irqsave(&interfaces_lock, flags);
Corey Minyarde8b33612005-09-06 15:18:45 -07002378 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 if (ipmi_interfaces[i] == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002380 intf->intf_num = i;
2381 /* Reserve the entry till we are done. */
2382 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 break;
2385 }
2386 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002387 spin_unlock_irqrestore(&interfaces_lock, flags);
2388 if (rv)
2389 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390
Corey Minyard453823b2006-03-31 02:30:39 -08002391 rv = handlers->start_processing(send_info, intf);
2392 if (rv)
2393 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002394
Corey Minyard50c812b2006-03-26 01:37:21 -08002395 get_guid(intf);
2396
Corey Minyard393d2cc2005-11-07 00:59:54 -08002397 if ((version_major > 1)
2398 || ((version_major == 1) && (version_minor >= 5)))
2399 {
2400 /* Start scanning the channels to see what is
2401 available. */
2402 intf->null_user_handler = channel_handler;
2403 intf->curr_channel = 0;
2404 rv = send_channel_info_cmd(intf, 0);
2405 if (rv)
2406 goto out;
2407
2408 /* Wait for the channel info to be read. */
2409 wait_event(intf->waitq,
2410 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002411 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002412 } else {
2413 /* Assume a single IPMB channel at zero. */
2414 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2415 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417
2418 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002419 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Corey Minyard50c812b2006-03-26 01:37:21 -08002421 rv = ipmi_bmc_register(intf);
2422
Corey Minyard393d2cc2005-11-07 00:59:54 -08002423 out:
2424 if (rv) {
2425 if (intf->proc_dir)
2426 remove_proc_entries(intf);
2427 kref_put(&intf->refcount, intf_free);
2428 if (i < MAX_IPMI_INTERFACES) {
2429 spin_lock_irqsave(&interfaces_lock, flags);
2430 ipmi_interfaces[i] = NULL;
2431 spin_unlock_irqrestore(&interfaces_lock, flags);
2432 }
2433 } else {
2434 spin_lock_irqsave(&interfaces_lock, flags);
2435 ipmi_interfaces[i] = intf;
2436 spin_unlock_irqrestore(&interfaces_lock, flags);
Corey Minyard50c812b2006-03-26 01:37:21 -08002437 call_smi_watchers(i, intf->si_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 }
2439
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 return rv;
2441}
2442
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443int ipmi_unregister_smi(ipmi_smi_t intf)
2444{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 int i;
2446 struct ipmi_smi_watcher *w;
2447 unsigned long flags;
2448
Corey Minyard50c812b2006-03-26 01:37:21 -08002449 ipmi_bmc_unregister(intf);
2450
Corey Minyard393d2cc2005-11-07 00:59:54 -08002451 spin_lock_irqsave(&interfaces_lock, flags);
2452 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
2453 if (ipmi_interfaces[i] == intf) {
2454 /* Set the interface number reserved until we
2455 * are done. */
2456 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
2457 intf->intf_num = -1;
2458 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002461 spin_unlock_irqrestore(&interfaces_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462
Corey Minyard393d2cc2005-11-07 00:59:54 -08002463 if (i == MAX_IPMI_INTERFACES)
2464 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
Corey Minyard393d2cc2005-11-07 00:59:54 -08002466 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
2468 /* Call all the watcher interfaces to tell them that
2469 an interface is gone. */
2470 down_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002471 list_for_each_entry(w, &smi_watchers, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 w->smi_gone(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 up_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002474
2475 /* Allow the entry to be reused now. */
2476 spin_lock_irqsave(&interfaces_lock, flags);
2477 ipmi_interfaces[i] = NULL;
2478 spin_unlock_irqrestore(&interfaces_lock,flags);
2479
2480 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 return 0;
2482}
2483
2484static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2485 struct ipmi_smi_msg *msg)
2486{
2487 struct ipmi_ipmb_addr ipmb_addr;
2488 struct ipmi_recv_msg *recv_msg;
2489 unsigned long flags;
2490
2491
2492 /* This is 11, not 10, because the response must contain a
2493 * completion code. */
2494 if (msg->rsp_size < 11) {
2495 /* Message not big enough, just ignore it. */
2496 spin_lock_irqsave(&intf->counter_lock, flags);
2497 intf->invalid_ipmb_responses++;
2498 spin_unlock_irqrestore(&intf->counter_lock, flags);
2499 return 0;
2500 }
2501
2502 if (msg->rsp[2] != 0) {
2503 /* An error getting the response, just ignore it. */
2504 return 0;
2505 }
2506
2507 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
2508 ipmb_addr.slave_addr = msg->rsp[6];
2509 ipmb_addr.channel = msg->rsp[3] & 0x0f;
2510 ipmb_addr.lun = msg->rsp[7] & 3;
2511
2512 /* It's a response from a remote entity. Look up the sequence
2513 number and handle the response. */
2514 if (intf_find_seq(intf,
2515 msg->rsp[7] >> 2,
2516 msg->rsp[3] & 0x0f,
2517 msg->rsp[8],
2518 (msg->rsp[4] >> 2) & (~1),
2519 (struct ipmi_addr *) &(ipmb_addr),
2520 &recv_msg))
2521 {
2522 /* We were unable to find the sequence number,
2523 so just nuke the message. */
2524 spin_lock_irqsave(&intf->counter_lock, flags);
2525 intf->unhandled_ipmb_responses++;
2526 spin_unlock_irqrestore(&intf->counter_lock, flags);
2527 return 0;
2528 }
2529
2530 memcpy(recv_msg->msg_data,
2531 &(msg->rsp[9]),
2532 msg->rsp_size - 9);
2533 /* THe other fields matched, so no need to set them, except
2534 for netfn, which needs to be the response that was
2535 returned, not the request value. */
2536 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2537 recv_msg->msg.data = recv_msg->msg_data;
2538 recv_msg->msg.data_len = msg->rsp_size - 10;
2539 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2540 spin_lock_irqsave(&intf->counter_lock, flags);
2541 intf->handled_ipmb_responses++;
2542 spin_unlock_irqrestore(&intf->counter_lock, flags);
2543 deliver_response(recv_msg);
2544
2545 return 0;
2546}
2547
2548static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2549 struct ipmi_smi_msg *msg)
2550{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002551 struct cmd_rcvr *rcvr;
2552 int rv = 0;
2553 unsigned char netfn;
2554 unsigned char cmd;
2555 ipmi_user_t user = NULL;
2556 struct ipmi_ipmb_addr *ipmb_addr;
2557 struct ipmi_recv_msg *recv_msg;
2558 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559
2560 if (msg->rsp_size < 10) {
2561 /* Message not big enough, just ignore it. */
2562 spin_lock_irqsave(&intf->counter_lock, flags);
2563 intf->invalid_commands++;
2564 spin_unlock_irqrestore(&intf->counter_lock, flags);
2565 return 0;
2566 }
2567
2568 if (msg->rsp[2] != 0) {
2569 /* An error getting the response, just ignore it. */
2570 return 0;
2571 }
2572
2573 netfn = msg->rsp[4] >> 2;
2574 cmd = msg->rsp[8];
2575
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002576 rcu_read_lock();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002577 rcvr = find_cmd_rcvr(intf, netfn, cmd);
2578 if (rcvr) {
2579 user = rcvr->user;
2580 kref_get(&user->refcount);
2581 } else
2582 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002583 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584
2585 if (user == NULL) {
2586 /* We didn't find a user, deliver an error response. */
2587 spin_lock_irqsave(&intf->counter_lock, flags);
2588 intf->unhandled_commands++;
2589 spin_unlock_irqrestore(&intf->counter_lock, flags);
2590
2591 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2592 msg->data[1] = IPMI_SEND_MSG_CMD;
2593 msg->data[2] = msg->rsp[3];
2594 msg->data[3] = msg->rsp[6];
2595 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2596 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002597 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 /* rqseq/lun */
2599 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2600 msg->data[8] = msg->rsp[8]; /* cmd */
2601 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2602 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2603 msg->data_size = 11;
2604
2605#ifdef DEBUG_MSGING
2606 {
2607 int m;
2608 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002609 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 printk(" %2.2x", msg->data[m]);
2611 printk("\n");
2612 }
2613#endif
2614 intf->handlers->sender(intf->send_info, msg, 0);
2615
2616 rv = -1; /* We used the message, so return the value that
2617 causes it to not be freed or queued. */
2618 } else {
2619 /* Deliver the message to the user. */
2620 spin_lock_irqsave(&intf->counter_lock, flags);
2621 intf->handled_commands++;
2622 spin_unlock_irqrestore(&intf->counter_lock, flags);
2623
2624 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002625 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 /* We couldn't allocate memory for the
2627 message, so requeue it for handling
2628 later. */
2629 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002630 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 } else {
2632 /* Extract the source address from the data. */
2633 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2634 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2635 ipmb_addr->slave_addr = msg->rsp[6];
2636 ipmb_addr->lun = msg->rsp[7] & 3;
2637 ipmb_addr->channel = msg->rsp[3] & 0xf;
2638
2639 /* Extract the rest of the message information
2640 from the IPMB header.*/
2641 recv_msg->user = user;
2642 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2643 recv_msg->msgid = msg->rsp[7] >> 2;
2644 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2645 recv_msg->msg.cmd = msg->rsp[8];
2646 recv_msg->msg.data = recv_msg->msg_data;
2647
2648 /* We chop off 10, not 9 bytes because the checksum
2649 at the end also needs to be removed. */
2650 recv_msg->msg.data_len = msg->rsp_size - 10;
2651 memcpy(recv_msg->msg_data,
2652 &(msg->rsp[9]),
2653 msg->rsp_size - 10);
2654 deliver_response(recv_msg);
2655 }
2656 }
2657
2658 return rv;
2659}
2660
2661static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
2662 struct ipmi_smi_msg *msg)
2663{
2664 struct ipmi_lan_addr lan_addr;
2665 struct ipmi_recv_msg *recv_msg;
2666 unsigned long flags;
2667
2668
2669 /* This is 13, not 12, because the response must contain a
2670 * completion code. */
2671 if (msg->rsp_size < 13) {
2672 /* Message not big enough, just ignore it. */
2673 spin_lock_irqsave(&intf->counter_lock, flags);
2674 intf->invalid_lan_responses++;
2675 spin_unlock_irqrestore(&intf->counter_lock, flags);
2676 return 0;
2677 }
2678
2679 if (msg->rsp[2] != 0) {
2680 /* An error getting the response, just ignore it. */
2681 return 0;
2682 }
2683
2684 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
2685 lan_addr.session_handle = msg->rsp[4];
2686 lan_addr.remote_SWID = msg->rsp[8];
2687 lan_addr.local_SWID = msg->rsp[5];
2688 lan_addr.channel = msg->rsp[3] & 0x0f;
2689 lan_addr.privilege = msg->rsp[3] >> 4;
2690 lan_addr.lun = msg->rsp[9] & 3;
2691
2692 /* It's a response from a remote entity. Look up the sequence
2693 number and handle the response. */
2694 if (intf_find_seq(intf,
2695 msg->rsp[9] >> 2,
2696 msg->rsp[3] & 0x0f,
2697 msg->rsp[10],
2698 (msg->rsp[6] >> 2) & (~1),
2699 (struct ipmi_addr *) &(lan_addr),
2700 &recv_msg))
2701 {
2702 /* We were unable to find the sequence number,
2703 so just nuke the message. */
2704 spin_lock_irqsave(&intf->counter_lock, flags);
2705 intf->unhandled_lan_responses++;
2706 spin_unlock_irqrestore(&intf->counter_lock, flags);
2707 return 0;
2708 }
2709
2710 memcpy(recv_msg->msg_data,
2711 &(msg->rsp[11]),
2712 msg->rsp_size - 11);
2713 /* The other fields matched, so no need to set them, except
2714 for netfn, which needs to be the response that was
2715 returned, not the request value. */
2716 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2717 recv_msg->msg.data = recv_msg->msg_data;
2718 recv_msg->msg.data_len = msg->rsp_size - 12;
2719 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2720 spin_lock_irqsave(&intf->counter_lock, flags);
2721 intf->handled_lan_responses++;
2722 spin_unlock_irqrestore(&intf->counter_lock, flags);
2723 deliver_response(recv_msg);
2724
2725 return 0;
2726}
2727
2728static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2729 struct ipmi_smi_msg *msg)
2730{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002731 struct cmd_rcvr *rcvr;
2732 int rv = 0;
2733 unsigned char netfn;
2734 unsigned char cmd;
2735 ipmi_user_t user = NULL;
2736 struct ipmi_lan_addr *lan_addr;
2737 struct ipmi_recv_msg *recv_msg;
2738 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
2740 if (msg->rsp_size < 12) {
2741 /* Message not big enough, just ignore it. */
2742 spin_lock_irqsave(&intf->counter_lock, flags);
2743 intf->invalid_commands++;
2744 spin_unlock_irqrestore(&intf->counter_lock, flags);
2745 return 0;
2746 }
2747
2748 if (msg->rsp[2] != 0) {
2749 /* An error getting the response, just ignore it. */
2750 return 0;
2751 }
2752
2753 netfn = msg->rsp[6] >> 2;
2754 cmd = msg->rsp[10];
2755
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002756 rcu_read_lock();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002757 rcvr = find_cmd_rcvr(intf, netfn, cmd);
2758 if (rcvr) {
2759 user = rcvr->user;
2760 kref_get(&user->refcount);
2761 } else
2762 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002763 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764
2765 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002766 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 spin_lock_irqsave(&intf->counter_lock, flags);
2768 intf->unhandled_commands++;
2769 spin_unlock_irqrestore(&intf->counter_lock, flags);
2770
2771 rv = 0; /* Don't do anything with these messages, just
2772 allow them to be freed. */
2773 } else {
2774 /* Deliver the message to the user. */
2775 spin_lock_irqsave(&intf->counter_lock, flags);
2776 intf->handled_commands++;
2777 spin_unlock_irqrestore(&intf->counter_lock, flags);
2778
2779 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002780 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 /* We couldn't allocate memory for the
2782 message, so requeue it for handling
2783 later. */
2784 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002785 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 } else {
2787 /* Extract the source address from the data. */
2788 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
2789 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
2790 lan_addr->session_handle = msg->rsp[4];
2791 lan_addr->remote_SWID = msg->rsp[8];
2792 lan_addr->local_SWID = msg->rsp[5];
2793 lan_addr->lun = msg->rsp[9] & 3;
2794 lan_addr->channel = msg->rsp[3] & 0xf;
2795 lan_addr->privilege = msg->rsp[3] >> 4;
2796
2797 /* Extract the rest of the message information
2798 from the IPMB header.*/
2799 recv_msg->user = user;
2800 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2801 recv_msg->msgid = msg->rsp[9] >> 2;
2802 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2803 recv_msg->msg.cmd = msg->rsp[10];
2804 recv_msg->msg.data = recv_msg->msg_data;
2805
2806 /* We chop off 12, not 11 bytes because the checksum
2807 at the end also needs to be removed. */
2808 recv_msg->msg.data_len = msg->rsp_size - 12;
2809 memcpy(recv_msg->msg_data,
2810 &(msg->rsp[11]),
2811 msg->rsp_size - 12);
2812 deliver_response(recv_msg);
2813 }
2814 }
2815
2816 return rv;
2817}
2818
2819static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
2820 struct ipmi_smi_msg *msg)
2821{
2822 struct ipmi_system_interface_addr *smi_addr;
2823
2824 recv_msg->msgid = 0;
2825 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
2826 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2827 smi_addr->channel = IPMI_BMC_CHANNEL;
2828 smi_addr->lun = msg->rsp[0] & 3;
2829 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
2830 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2831 recv_msg->msg.cmd = msg->rsp[1];
2832 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
2833 recv_msg->msg.data = recv_msg->msg_data;
2834 recv_msg->msg.data_len = msg->rsp_size - 3;
2835}
2836
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837static int handle_read_event_rsp(ipmi_smi_t intf,
2838 struct ipmi_smi_msg *msg)
2839{
2840 struct ipmi_recv_msg *recv_msg, *recv_msg2;
2841 struct list_head msgs;
2842 ipmi_user_t user;
2843 int rv = 0;
2844 int deliver_count = 0;
2845 unsigned long flags;
2846
2847 if (msg->rsp_size < 19) {
2848 /* Message is too small to be an IPMB event. */
2849 spin_lock_irqsave(&intf->counter_lock, flags);
2850 intf->invalid_events++;
2851 spin_unlock_irqrestore(&intf->counter_lock, flags);
2852 return 0;
2853 }
2854
2855 if (msg->rsp[2] != 0) {
2856 /* An error getting the event, just ignore it. */
2857 return 0;
2858 }
2859
2860 INIT_LIST_HEAD(&msgs);
2861
Corey Minyard393d2cc2005-11-07 00:59:54 -08002862 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863
2864 spin_lock(&intf->counter_lock);
2865 intf->events++;
2866 spin_unlock(&intf->counter_lock);
2867
2868 /* Allocate and fill in one message for every user that is getting
2869 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002870 rcu_read_lock();
2871 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08002872 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 continue;
2874
2875 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002876 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002877 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002878 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
2879 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 list_del(&recv_msg->link);
2881 ipmi_free_recv_msg(recv_msg);
2882 }
2883 /* We couldn't allocate memory for the
2884 message, so requeue it for handling
2885 later. */
2886 rv = 1;
2887 goto out;
2888 }
2889
2890 deliver_count++;
2891
2892 copy_event_into_recv_msg(recv_msg, msg);
2893 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002894 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 list_add_tail(&(recv_msg->link), &msgs);
2896 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002897 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898
2899 if (deliver_count) {
2900 /* Now deliver all the messages. */
2901 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
2902 list_del(&recv_msg->link);
2903 deliver_response(recv_msg);
2904 }
2905 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
2906 /* No one to receive the message, put it in queue if there's
2907 not already too many things in the queue. */
2908 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002909 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 /* We couldn't allocate memory for the
2911 message, so requeue it for handling
2912 later. */
2913 rv = 1;
2914 goto out;
2915 }
2916
2917 copy_event_into_recv_msg(recv_msg, msg);
2918 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
2919 } else {
2920 /* There's too many things in the queue, discard this
2921 message. */
2922 printk(KERN_WARNING PFX "Event queue full, discarding an"
2923 " incoming event\n");
2924 }
2925
2926 out:
2927 spin_unlock_irqrestore(&(intf->events_lock), flags);
2928
2929 return rv;
2930}
2931
2932static int handle_bmc_rsp(ipmi_smi_t intf,
2933 struct ipmi_smi_msg *msg)
2934{
2935 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002937 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938
2939 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002940 if (recv_msg == NULL)
2941 {
2942 printk(KERN_WARNING"IPMI message received with no owner. This\n"
2943 "could be because of a malformed message, or\n"
2944 "because of a hardware error. Contact your\n"
2945 "hardware vender for assistance\n");
2946 return 0;
2947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948
Corey Minyard393d2cc2005-11-07 00:59:54 -08002949 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002951 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07002952 /* The user for the message went away, so give up. */
2953 spin_lock_irqsave(&intf->counter_lock, flags);
2954 intf->unhandled_local_responses++;
2955 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 ipmi_free_recv_msg(recv_msg);
2957 } else {
2958 struct ipmi_system_interface_addr *smi_addr;
2959
2960 spin_lock_irqsave(&intf->counter_lock, flags);
2961 intf->handled_local_responses++;
2962 spin_unlock_irqrestore(&intf->counter_lock, flags);
2963 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2964 recv_msg->msgid = msg->msgid;
2965 smi_addr = ((struct ipmi_system_interface_addr *)
2966 &(recv_msg->addr));
2967 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2968 smi_addr->channel = IPMI_BMC_CHANNEL;
2969 smi_addr->lun = msg->rsp[0] & 3;
2970 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2971 recv_msg->msg.cmd = msg->rsp[1];
2972 memcpy(recv_msg->msg_data,
2973 &(msg->rsp[2]),
2974 msg->rsp_size - 2);
2975 recv_msg->msg.data = recv_msg->msg_data;
2976 recv_msg->msg.data_len = msg->rsp_size - 2;
2977 deliver_response(recv_msg);
2978 }
2979
2980 return 0;
2981}
2982
2983/* Handle a new message. Return 1 if the message should be requeued,
2984 0 if the message should be freed, or -1 if the message should not
2985 be freed or requeued. */
2986static int handle_new_recv_msg(ipmi_smi_t intf,
2987 struct ipmi_smi_msg *msg)
2988{
2989 int requeue;
2990 int chan;
2991
2992#ifdef DEBUG_MSGING
2993 int m;
2994 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002995 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 printk(" %2.2x", msg->rsp[m]);
2997 printk("\n");
2998#endif
2999 if (msg->rsp_size < 2) {
3000 /* Message is too small to be correct. */
3001 printk(KERN_WARNING PFX "BMC returned to small a message"
3002 " for netfn %x cmd %x, got %d bytes\n",
3003 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3004
3005 /* Generate an error response for the message. */
3006 msg->rsp[0] = msg->data[0] | (1 << 2);
3007 msg->rsp[1] = msg->data[1];
3008 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3009 msg->rsp_size = 3;
3010 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3011 || (msg->rsp[1] != msg->data[1])) /* Command */
3012 {
3013 /* The response is not even marginally correct. */
3014 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3015 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3016 (msg->data[0] >> 2) | 1, msg->data[1],
3017 msg->rsp[0] >> 2, msg->rsp[1]);
3018
3019 /* Generate an error response for the message. */
3020 msg->rsp[0] = msg->data[0] | (1 << 2);
3021 msg->rsp[1] = msg->data[1];
3022 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3023 msg->rsp_size = 3;
3024 }
3025
3026 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3027 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3028 && (msg->user_data != NULL))
3029 {
3030 /* It's a response to a response we sent. For this we
3031 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003032 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033
3034 requeue = 0;
3035 if (msg->rsp_size < 2)
3036 /* Message is too small to be correct. */
3037 goto out;
3038
3039 chan = msg->data[2] & 0x0f;
3040 if (chan >= IPMI_MAX_CHANNELS)
3041 /* Invalid channel number */
3042 goto out;
3043
Corey Minyard393d2cc2005-11-07 00:59:54 -08003044 if (!recv_msg)
3045 goto out;
3046
3047 /* Make sure the user still exists. */
3048 if (!recv_msg->user || !recv_msg->user->valid)
3049 goto out;
3050
3051 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3052 recv_msg->msg.data = recv_msg->msg_data;
3053 recv_msg->msg.data_len = 1;
3054 recv_msg->msg_data[0] = msg->rsp[2];
3055 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3057 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3058 {
3059 /* It's from the receive queue. */
3060 chan = msg->rsp[3] & 0xf;
3061 if (chan >= IPMI_MAX_CHANNELS) {
3062 /* Invalid channel number */
3063 requeue = 0;
3064 goto out;
3065 }
3066
3067 switch (intf->channels[chan].medium) {
3068 case IPMI_CHANNEL_MEDIUM_IPMB:
3069 if (msg->rsp[4] & 0x04) {
3070 /* It's a response, so find the
3071 requesting message and send it up. */
3072 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3073 } else {
3074 /* It's a command to the SMS from some other
3075 entity. Handle that. */
3076 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3077 }
3078 break;
3079
3080 case IPMI_CHANNEL_MEDIUM_8023LAN:
3081 case IPMI_CHANNEL_MEDIUM_ASYNC:
3082 if (msg->rsp[6] & 0x04) {
3083 /* It's a response, so find the
3084 requesting message and send it up. */
3085 requeue = handle_lan_get_msg_rsp(intf, msg);
3086 } else {
3087 /* It's a command to the SMS from some other
3088 entity. Handle that. */
3089 requeue = handle_lan_get_msg_cmd(intf, msg);
3090 }
3091 break;
3092
3093 default:
3094 /* We don't handle the channel type, so just
3095 * free the message. */
3096 requeue = 0;
3097 }
3098
3099 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3100 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3101 {
3102 /* It's an asyncronous event. */
3103 requeue = handle_read_event_rsp(intf, msg);
3104 } else {
3105 /* It's a response from the local BMC. */
3106 requeue = handle_bmc_rsp(intf, msg);
3107 }
3108
3109 out:
3110 return requeue;
3111}
3112
3113/* Handle a new message from the lower layer. */
3114void ipmi_smi_msg_received(ipmi_smi_t intf,
3115 struct ipmi_smi_msg *msg)
3116{
3117 unsigned long flags;
3118 int rv;
3119
3120
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 if ((msg->data_size >= 2)
3122 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3123 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003124 && (msg->user_data == NULL))
3125 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 /* This is the local response to a command send, start
3127 the timer for these. The user_data will not be
3128 NULL if this is a response send, and we will let
3129 response sends just go through. */
3130
3131 /* Check for errors, if we get certain errors (ones
3132 that mean basically we can try again later), we
3133 ignore them and start the timer. Otherwise we
3134 report the error immediately. */
3135 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3136 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
3137 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR))
3138 {
3139 int chan = msg->rsp[3] & 0xf;
3140
3141 /* Got an error sending the message, handle it. */
3142 spin_lock_irqsave(&intf->counter_lock, flags);
3143 if (chan >= IPMI_MAX_CHANNELS)
3144 ; /* This shouldn't happen */
3145 else if ((intf->channels[chan].medium
3146 == IPMI_CHANNEL_MEDIUM_8023LAN)
3147 || (intf->channels[chan].medium
3148 == IPMI_CHANNEL_MEDIUM_ASYNC))
3149 intf->sent_lan_command_errs++;
3150 else
3151 intf->sent_ipmb_command_errs++;
3152 spin_unlock_irqrestore(&intf->counter_lock, flags);
3153 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3154 } else {
3155 /* The message was sent, start the timer. */
3156 intf_start_seq_timer(intf, msg->msgid);
3157 }
3158
3159 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003160 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 }
3162
3163 /* To preserve message order, if the list is not empty, we
3164 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003165 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
3166 if (!list_empty(&intf->waiting_msgs)) {
3167 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003168 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003169 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003171 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172
3173 rv = handle_new_recv_msg(intf, msg);
3174 if (rv > 0) {
3175 /* Could not handle the message now, just add it to a
3176 list to handle later. */
Hironobu Ishii177294d2005-11-11 08:12:21 -06003177 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003178 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003179 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 } else if (rv == 0) {
3181 ipmi_free_smi_msg(msg);
3182 }
3183
Corey Minyard393d2cc2005-11-07 00:59:54 -08003184 out:
3185 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186}
3187
3188void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3189{
3190 ipmi_user_t user;
3191
Corey Minyard393d2cc2005-11-07 00:59:54 -08003192 rcu_read_lock();
3193 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003194 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 continue;
3196
3197 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3198 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003199 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200}
3201
3202static void
3203handle_msg_timeout(struct ipmi_recv_msg *msg)
3204{
3205 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3206 msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;
3207 msg->msg.netfn |= 1; /* Convert to a response. */
3208 msg->msg.data_len = 1;
3209 msg->msg.data = msg->msg_data;
3210 deliver_response(msg);
3211}
3212
Corey Minyard882fe012005-05-01 08:59:12 -07003213static struct ipmi_smi_msg *
3214smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3215 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216{
Corey Minyard882fe012005-05-01 08:59:12 -07003217 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 if (!smi_msg)
3219 /* If we can't allocate the message, then just return, we
3220 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003221 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
3223 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3224 smi_msg->data_size = recv_msg->msg.data_len;
3225 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3226
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227#ifdef DEBUG_MSGING
3228 {
3229 int m;
3230 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003231 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 printk(" %2.2x", smi_msg->data[m]);
3233 printk("\n");
3234 }
3235#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003236 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237}
3238
Corey Minyard393d2cc2005-11-07 00:59:54 -08003239static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3240 struct list_head *timeouts, long timeout_period,
3241 int slot, unsigned long *flags)
3242{
3243 struct ipmi_recv_msg *msg;
3244
3245 if (!ent->inuse)
3246 return;
3247
3248 ent->timeout -= timeout_period;
3249 if (ent->timeout > 0)
3250 return;
3251
3252 if (ent->retries_left == 0) {
3253 /* The message has used all its retries. */
3254 ent->inuse = 0;
3255 msg = ent->recv_msg;
3256 list_add_tail(&msg->link, timeouts);
3257 spin_lock(&intf->counter_lock);
3258 if (ent->broadcast)
3259 intf->timed_out_ipmb_broadcasts++;
3260 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3261 intf->timed_out_lan_commands++;
3262 else
3263 intf->timed_out_ipmb_commands++;
3264 spin_unlock(&intf->counter_lock);
3265 } else {
3266 struct ipmi_smi_msg *smi_msg;
3267 /* More retries, send again. */
3268
3269 /* Start with the max timer, set to normal
3270 timer after the message is sent. */
3271 ent->timeout = MAX_MSG_TIMEOUT;
3272 ent->retries_left--;
3273 spin_lock(&intf->counter_lock);
3274 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3275 intf->retransmitted_lan_commands++;
3276 else
3277 intf->retransmitted_ipmb_commands++;
3278 spin_unlock(&intf->counter_lock);
3279
3280 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3281 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003282 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003283 return;
3284
3285 spin_unlock_irqrestore(&intf->seq_lock, *flags);
3286 /* Send the new message. We send with a zero
3287 * priority. It timed out, I doubt time is
3288 * that critical now, and high priority
3289 * messages are really only for messages to the
3290 * local MC, which don't get resent. */
3291 intf->handlers->sender(intf->send_info,
3292 smi_msg, 0);
3293 spin_lock_irqsave(&intf->seq_lock, *flags);
3294 }
3295}
3296
3297static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298{
3299 ipmi_smi_t intf;
3300 struct list_head timeouts;
3301 struct ipmi_recv_msg *msg, *msg2;
3302 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3303 unsigned long flags;
3304 int i, j;
3305
3306 INIT_LIST_HEAD(&timeouts);
3307
3308 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07003309 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003311 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 continue;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003313 kref_get(&intf->refcount);
3314 spin_unlock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315
3316 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003317 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003318 list_for_each_entry_safe(smi_msg, smi_msg2,
3319 &intf->waiting_msgs, link) {
3320 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 list_del(&smi_msg->link);
3322 ipmi_free_smi_msg(smi_msg);
3323 } else {
3324 /* To preserve message order, quit if we
3325 can't handle a message. */
3326 break;
3327 }
3328 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003329 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330
3331 /* Go through the seq table and find any messages that
3332 have timed out, putting them in the timeouts
3333 list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003334 spin_lock_irqsave(&intf->seq_lock, flags);
3335 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++)
3336 check_msg_timeout(intf, &(intf->seq_table[j]),
3337 &timeouts, timeout_period, j,
3338 &flags);
3339 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340
Corey Minyard393d2cc2005-11-07 00:59:54 -08003341 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 handle_msg_timeout(msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343
Corey Minyard393d2cc2005-11-07 00:59:54 -08003344 kref_put(&intf->refcount, intf_free);
3345 spin_lock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 }
3347 spin_unlock(&interfaces_lock);
3348}
3349
3350static void ipmi_request_event(void)
3351{
3352 ipmi_smi_t intf;
3353 int i;
3354
3355 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07003356 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003358 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 continue;
3360
3361 intf->handlers->request_events(intf->send_info);
3362 }
3363 spin_unlock(&interfaces_lock);
3364}
3365
3366static struct timer_list ipmi_timer;
3367
3368/* Call every ~100 ms. */
3369#define IPMI_TIMEOUT_TIME 100
3370
3371/* How many jiffies does it take to get to the timeout time. */
3372#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3373
3374/* Request events from the queue every second (this is the number of
3375 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3376 future, IPMI will add a way to know immediately if an event is in
3377 the queue and this silliness can go away. */
3378#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3379
Corey Minyard8f43f842005-06-23 22:01:40 -07003380static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3382
3383static void ipmi_timeout(unsigned long data)
3384{
Corey Minyard8f43f842005-06-23 22:01:40 -07003385 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387
3388 ticks_to_req_ev--;
3389 if (ticks_to_req_ev == 0) {
3390 ipmi_request_event();
3391 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3392 }
3393
3394 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3395
Corey Minyard8f43f842005-06-23 22:01:40 -07003396 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397}
3398
3399
3400static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3401static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3402
3403/* FIXME - convert these to slabs. */
3404static void free_smi_msg(struct ipmi_smi_msg *msg)
3405{
3406 atomic_dec(&smi_msg_inuse_count);
3407 kfree(msg);
3408}
3409
3410struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3411{
3412 struct ipmi_smi_msg *rv;
3413 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3414 if (rv) {
3415 rv->done = free_smi_msg;
3416 rv->user_data = NULL;
3417 atomic_inc(&smi_msg_inuse_count);
3418 }
3419 return rv;
3420}
3421
3422static void free_recv_msg(struct ipmi_recv_msg *msg)
3423{
3424 atomic_dec(&recv_msg_inuse_count);
3425 kfree(msg);
3426}
3427
3428struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3429{
3430 struct ipmi_recv_msg *rv;
3431
3432 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3433 if (rv) {
3434 rv->done = free_recv_msg;
3435 atomic_inc(&recv_msg_inuse_count);
3436 }
3437 return rv;
3438}
3439
Corey Minyard393d2cc2005-11-07 00:59:54 -08003440void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3441{
3442 if (msg->user)
3443 kref_put(&msg->user->refcount, free_user);
3444 msg->done(msg);
3445}
3446
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447#ifdef CONFIG_IPMI_PANIC_EVENT
3448
3449static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3450{
3451}
3452
3453static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3454{
3455}
3456
3457#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003458static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003460 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3461 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3462 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3463 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 {
3465 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003466 intf->event_receiver = msg->msg.data[1];
3467 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 }
3469}
3470
Corey Minyard56a55ec2005-09-06 15:18:42 -07003471static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003473 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3474 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3475 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3476 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 {
3478 /* A get device id command, save if we are an event
3479 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003480 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3481 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 }
3483}
3484#endif
3485
3486static void send_panic_events(char *str)
3487{
3488 struct kernel_ipmi_msg msg;
3489 ipmi_smi_t intf;
3490 unsigned char data[16];
3491 int i;
3492 struct ipmi_system_interface_addr *si;
3493 struct ipmi_addr addr;
3494 struct ipmi_smi_msg smi_msg;
3495 struct ipmi_recv_msg recv_msg;
3496
3497 si = (struct ipmi_system_interface_addr *) &addr;
3498 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3499 si->channel = IPMI_BMC_CHANNEL;
3500 si->lun = 0;
3501
3502 /* Fill in an event telling that we have failed. */
3503 msg.netfn = 0x04; /* Sensor or Event. */
3504 msg.cmd = 2; /* Platform event command. */
3505 msg.data = data;
3506 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003507 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 data[1] = 0x03; /* This is for IPMI 1.0. */
3509 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3510 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3511 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3512
3513 /* Put a few breadcrumbs in. Hopefully later we can add more things
3514 to make the panic events more useful. */
3515 if (str) {
3516 data[3] = str[0];
3517 data[6] = str[1];
3518 data[7] = str[2];
3519 }
3520
3521 smi_msg.done = dummy_smi_done_handler;
3522 recv_msg.done = dummy_recv_done_handler;
3523
3524 /* For every registered interface, send the event. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003525 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003527 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 continue;
3529
3530 /* Send the event announcing the panic. */
3531 intf->handlers->set_run_to_completion(intf->send_info, 1);
3532 i_ipmi_request(NULL,
3533 intf,
3534 &addr,
3535 0,
3536 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003537 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 &smi_msg,
3539 &recv_msg,
3540 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003541 intf->channels[0].address,
3542 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 0, 1); /* Don't retry, and don't wait. */
3544 }
3545
3546#ifdef CONFIG_IPMI_PANIC_STRING
3547 /* On every interface, dump a bunch of OEM event holding the
3548 string. */
3549 if (!str)
3550 return;
3551
Corey Minyarde8b33612005-09-06 15:18:45 -07003552 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 char *p = str;
3554 struct ipmi_ipmb_addr *ipmb;
3555 int j;
3556
3557 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003558 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 continue;
3560
3561 /* First job here is to figure out where to send the
3562 OEM events. There's no way in IPMI to send OEM
3563 events using an event send command, so we have to
3564 find the SEL to put them in and stick them in
3565 there. */
3566
3567 /* Get capabilities from the get device id. */
3568 intf->local_sel_device = 0;
3569 intf->local_event_generator = 0;
3570 intf->event_receiver = 0;
3571
3572 /* Request the device info from the local MC. */
3573 msg.netfn = IPMI_NETFN_APP_REQUEST;
3574 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3575 msg.data = NULL;
3576 msg.data_len = 0;
3577 intf->null_user_handler = device_id_fetcher;
3578 i_ipmi_request(NULL,
3579 intf,
3580 &addr,
3581 0,
3582 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003583 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 &smi_msg,
3585 &recv_msg,
3586 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003587 intf->channels[0].address,
3588 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 0, 1); /* Don't retry, and don't wait. */
3590
3591 if (intf->local_event_generator) {
3592 /* Request the event receiver from the local MC. */
3593 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3594 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3595 msg.data = NULL;
3596 msg.data_len = 0;
3597 intf->null_user_handler = event_receiver_fetcher;
3598 i_ipmi_request(NULL,
3599 intf,
3600 &addr,
3601 0,
3602 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003603 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 &smi_msg,
3605 &recv_msg,
3606 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003607 intf->channels[0].address,
3608 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 0, 1); /* no retry, and no wait. */
3610 }
3611 intf->null_user_handler = NULL;
3612
3613 /* Validate the event receiver. The low bit must not
3614 be 1 (it must be a valid IPMB address), it cannot
3615 be zero, and it must not be my address. */
3616 if (((intf->event_receiver & 1) == 0)
3617 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003618 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 {
3620 /* The event receiver is valid, send an IPMB
3621 message. */
3622 ipmb = (struct ipmi_ipmb_addr *) &addr;
3623 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3624 ipmb->channel = 0; /* FIXME - is this right? */
3625 ipmb->lun = intf->event_receiver_lun;
3626 ipmb->slave_addr = intf->event_receiver;
3627 } else if (intf->local_sel_device) {
3628 /* The event receiver was not valid (or was
3629 me), but I am an SEL device, just dump it
3630 in my SEL. */
3631 si = (struct ipmi_system_interface_addr *) &addr;
3632 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3633 si->channel = IPMI_BMC_CHANNEL;
3634 si->lun = 0;
3635 } else
3636 continue; /* No where to send the event. */
3637
3638
3639 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
3640 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
3641 msg.data = data;
3642 msg.data_len = 16;
3643
3644 j = 0;
3645 while (*p) {
3646 int size = strlen(p);
3647
3648 if (size > 11)
3649 size = 11;
3650 data[0] = 0;
3651 data[1] = 0;
3652 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07003653 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 data[4] = j++; /* sequence # */
3655 /* Always give 11 bytes, so strncpy will fill
3656 it with zeroes for me. */
3657 strncpy(data+5, p, 11);
3658 p += size;
3659
3660 i_ipmi_request(NULL,
3661 intf,
3662 &addr,
3663 0,
3664 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003665 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 &smi_msg,
3667 &recv_msg,
3668 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003669 intf->channels[0].address,
3670 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 0, 1); /* no retry, and no wait. */
3672 }
3673 }
3674#endif /* CONFIG_IPMI_PANIC_STRING */
3675}
3676#endif /* CONFIG_IPMI_PANIC_EVENT */
3677
3678static int has_paniced = 0;
3679
3680static int panic_event(struct notifier_block *this,
3681 unsigned long event,
3682 void *ptr)
3683{
3684 int i;
3685 ipmi_smi_t intf;
3686
3687 if (has_paniced)
3688 return NOTIFY_DONE;
3689 has_paniced = 1;
3690
3691 /* For every registered interface, set it to run to completion. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003692 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003694 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 continue;
3696
3697 intf->handlers->set_run_to_completion(intf->send_info, 1);
3698 }
3699
3700#ifdef CONFIG_IPMI_PANIC_EVENT
3701 send_panic_events(ptr);
3702#endif
3703
3704 return NOTIFY_DONE;
3705}
3706
3707static struct notifier_block panic_block = {
3708 .notifier_call = panic_event,
3709 .next = NULL,
3710 .priority = 200 /* priority: INT_MAX >= x >= 0 */
3711};
3712
3713static int ipmi_init_msghandler(void)
3714{
3715 int i;
Corey Minyard50c812b2006-03-26 01:37:21 -08003716 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717
3718 if (initialized)
3719 return 0;
3720
Corey Minyard50c812b2006-03-26 01:37:21 -08003721 rv = driver_register(&ipmidriver);
3722 if (rv) {
3723 printk(KERN_ERR PFX "Could not register IPMI driver\n");
3724 return rv;
3725 }
3726
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003728 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729
Corey Minyard393d2cc2005-11-07 00:59:54 -08003730 for (i = 0; i < MAX_IPMI_INTERFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 ipmi_interfaces[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
Corey Minyard3b625942005-06-23 22:01:42 -07003733#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 proc_ipmi_root = proc_mkdir("ipmi", NULL);
3735 if (!proc_ipmi_root) {
3736 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
3737 return -ENOMEM;
3738 }
3739
3740 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07003741#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742
3743 init_timer(&ipmi_timer);
3744 ipmi_timer.data = 0;
3745 ipmi_timer.function = ipmi_timeout;
3746 ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
3747 add_timer(&ipmi_timer);
3748
Alan Sterne041c682006-03-27 01:16:30 -08003749 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750
3751 initialized = 1;
3752
3753 return 0;
3754}
3755
3756static __init int ipmi_init_msghandler_mod(void)
3757{
3758 ipmi_init_msghandler();
3759 return 0;
3760}
3761
3762static __exit void cleanup_ipmi(void)
3763{
3764 int count;
3765
3766 if (!initialized)
3767 return;
3768
Alan Sterne041c682006-03-27 01:16:30 -08003769 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770
3771 /* This can't be called if any interfaces exist, so no worry about
3772 shutting down the interfaces. */
3773
3774 /* Tell the timer to stop, then wait for it to stop. This avoids
3775 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07003776 atomic_inc(&stop_operation);
3777 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778
Corey Minyard3b625942005-06-23 22:01:42 -07003779#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 remove_proc_entry(proc_ipmi_root->name, &proc_root);
Corey Minyard3b625942005-06-23 22:01:42 -07003781#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
Corey Minyard50c812b2006-03-26 01:37:21 -08003783 driver_unregister(&ipmidriver);
3784
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 initialized = 0;
3786
3787 /* Check for buffer leaks. */
3788 count = atomic_read(&smi_msg_inuse_count);
3789 if (count != 0)
3790 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
3791 count);
3792 count = atomic_read(&recv_msg_inuse_count);
3793 if (count != 0)
3794 printk(KERN_WARNING PFX "recv message count %d at exit\n",
3795 count);
3796}
3797module_exit(cleanup_ipmi);
3798
3799module_init(ipmi_init_msghandler_mod);
3800MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003801MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
3802MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
3803MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804
3805EXPORT_SYMBOL(ipmi_create_user);
3806EXPORT_SYMBOL(ipmi_destroy_user);
3807EXPORT_SYMBOL(ipmi_get_version);
3808EXPORT_SYMBOL(ipmi_request_settime);
3809EXPORT_SYMBOL(ipmi_request_supply_msgs);
3810EXPORT_SYMBOL(ipmi_register_smi);
3811EXPORT_SYMBOL(ipmi_unregister_smi);
3812EXPORT_SYMBOL(ipmi_register_for_cmd);
3813EXPORT_SYMBOL(ipmi_unregister_for_cmd);
3814EXPORT_SYMBOL(ipmi_smi_msg_received);
3815EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
3816EXPORT_SYMBOL(ipmi_alloc_smi_msg);
3817EXPORT_SYMBOL(ipmi_addr_length);
3818EXPORT_SYMBOL(ipmi_validate_addr);
3819EXPORT_SYMBOL(ipmi_set_gets_events);
3820EXPORT_SYMBOL(ipmi_smi_watcher_register);
3821EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
3822EXPORT_SYMBOL(ipmi_set_my_address);
3823EXPORT_SYMBOL(ipmi_get_my_address);
3824EXPORT_SYMBOL(ipmi_set_my_LUN);
3825EXPORT_SYMBOL(ipmi_get_my_LUN);
3826EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003828EXPORT_SYMBOL(ipmi_free_recv_msg);