blob: 23028559dbc48276293250f79af0fb81401ef9a8 [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. */
Akinobu Mita179e0912006-06-26 00:24:41 -0700939 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
940 list_move_tail(&msg->link, &msgs);
Corey Minyard4791c032006-04-10 22:54:31 -0700941 intf->waiting_events_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800943
944 /* Hold the events lock while doing this to preserve order. */
945 list_for_each_entry_safe(msg, msg2, &msgs, link) {
946 msg->user = user;
947 kref_get(&user->refcount);
948 deliver_response(msg);
949 }
950
951 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 return 0;
954}
955
Corey Minyard393d2cc2005-11-07 00:59:54 -0800956static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
957 unsigned char netfn,
958 unsigned char cmd)
959{
960 struct cmd_rcvr *rcvr;
961
962 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
963 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd))
964 return rcvr;
965 }
966 return NULL;
967}
968
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969int ipmi_register_for_cmd(ipmi_user_t user,
970 unsigned char netfn,
971 unsigned char cmd)
972{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800973 ipmi_smi_t intf = user->intf;
974 struct cmd_rcvr *rcvr;
975 struct cmd_rcvr *entry;
976 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978
979 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800980 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800982 rcvr->cmd = cmd;
983 rcvr->netfn = netfn;
984 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Corey Minyardd6dfd132006-03-31 02:30:41 -0800986 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 /* Make sure the command/netfn is not already registered. */
Corey Minyard393d2cc2005-11-07 00:59:54 -0800988 entry = find_cmd_rcvr(intf, netfn, cmd);
989 if (entry) {
990 rv = -EBUSY;
991 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 }
993
Corey Minyard393d2cc2005-11-07 00:59:54 -0800994 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -0700995
Corey Minyard393d2cc2005-11-07 00:59:54 -0800996 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -0800997 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (rv)
999 kfree(rcvr);
1000
1001 return rv;
1002}
1003
1004int ipmi_unregister_for_cmd(ipmi_user_t user,
1005 unsigned char netfn,
1006 unsigned char cmd)
1007{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001008 ipmi_smi_t intf = user->intf;
1009 struct cmd_rcvr *rcvr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
Corey Minyardd6dfd132006-03-31 02:30:41 -08001011 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 /* Make sure the command/netfn is not already registered. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001013 rcvr = find_cmd_rcvr(intf, netfn, cmd);
1014 if ((rcvr) && (rcvr->user == user)) {
1015 list_del_rcu(&rcvr->link);
Corey Minyardd6dfd132006-03-31 02:30:41 -08001016 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001017 synchronize_rcu();
1018 kfree(rcvr);
1019 return 0;
1020 } else {
Corey Minyardd6dfd132006-03-31 02:30:41 -08001021 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001022 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024}
1025
1026void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
1027{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001028 ipmi_smi_t intf = user->intf;
1029 intf->handlers->set_run_to_completion(intf->send_info, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030}
1031
1032static unsigned char
1033ipmb_checksum(unsigned char *data, int size)
1034{
1035 unsigned char csum = 0;
1036
1037 for (; size > 0; size--, data++)
1038 csum += *data;
1039
1040 return -csum;
1041}
1042
1043static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1044 struct kernel_ipmi_msg *msg,
1045 struct ipmi_ipmb_addr *ipmb_addr,
1046 long msgid,
1047 unsigned char ipmb_seq,
1048 int broadcast,
1049 unsigned char source_address,
1050 unsigned char source_lun)
1051{
1052 int i = broadcast;
1053
1054 /* Format the IPMB header data. */
1055 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1056 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1057 smi_msg->data[2] = ipmb_addr->channel;
1058 if (broadcast)
1059 smi_msg->data[3] = 0;
1060 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1061 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1062 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1063 smi_msg->data[i+6] = source_address;
1064 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1065 smi_msg->data[i+8] = msg->cmd;
1066
1067 /* Now tack on the data to the message. */
1068 if (msg->data_len > 0)
1069 memcpy(&(smi_msg->data[i+9]), msg->data,
1070 msg->data_len);
1071 smi_msg->data_size = msg->data_len + 9;
1072
1073 /* Now calculate the checksum and tack it on. */
1074 smi_msg->data[i+smi_msg->data_size]
1075 = ipmb_checksum(&(smi_msg->data[i+6]),
1076 smi_msg->data_size-6);
1077
1078 /* Add on the checksum size and the offset from the
1079 broadcast. */
1080 smi_msg->data_size += 1 + i;
1081
1082 smi_msg->msgid = msgid;
1083}
1084
1085static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1086 struct kernel_ipmi_msg *msg,
1087 struct ipmi_lan_addr *lan_addr,
1088 long msgid,
1089 unsigned char ipmb_seq,
1090 unsigned char source_lun)
1091{
1092 /* Format the IPMB header data. */
1093 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1094 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1095 smi_msg->data[2] = lan_addr->channel;
1096 smi_msg->data[3] = lan_addr->session_handle;
1097 smi_msg->data[4] = lan_addr->remote_SWID;
1098 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1099 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1100 smi_msg->data[7] = lan_addr->local_SWID;
1101 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1102 smi_msg->data[9] = msg->cmd;
1103
1104 /* Now tack on the data to the message. */
1105 if (msg->data_len > 0)
1106 memcpy(&(smi_msg->data[10]), msg->data,
1107 msg->data_len);
1108 smi_msg->data_size = msg->data_len + 10;
1109
1110 /* Now calculate the checksum and tack it on. */
1111 smi_msg->data[smi_msg->data_size]
1112 = ipmb_checksum(&(smi_msg->data[7]),
1113 smi_msg->data_size-7);
1114
1115 /* Add on the checksum size and the offset from the
1116 broadcast. */
1117 smi_msg->data_size += 1;
1118
1119 smi_msg->msgid = msgid;
1120}
1121
1122/* Separate from ipmi_request so that the user does not have to be
1123 supplied in certain circumstances (mainly at panic time). If
1124 messages are supplied, they will be freed, even if an error
1125 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001126static int i_ipmi_request(ipmi_user_t user,
1127 ipmi_smi_t intf,
1128 struct ipmi_addr *addr,
1129 long msgid,
1130 struct kernel_ipmi_msg *msg,
1131 void *user_msg_data,
1132 void *supplied_smi,
1133 struct ipmi_recv_msg *supplied_recv,
1134 int priority,
1135 unsigned char source_address,
1136 unsigned char source_lun,
1137 int retries,
1138 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139{
1140 int rv = 0;
1141 struct ipmi_smi_msg *smi_msg;
1142 struct ipmi_recv_msg *recv_msg;
1143 unsigned long flags;
1144
1145
1146 if (supplied_recv) {
1147 recv_msg = supplied_recv;
1148 } else {
1149 recv_msg = ipmi_alloc_recv_msg();
1150 if (recv_msg == NULL) {
1151 return -ENOMEM;
1152 }
1153 }
1154 recv_msg->user_msg_data = user_msg_data;
1155
1156 if (supplied_smi) {
1157 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1158 } else {
1159 smi_msg = ipmi_alloc_smi_msg();
1160 if (smi_msg == NULL) {
1161 ipmi_free_recv_msg(recv_msg);
1162 return -ENOMEM;
1163 }
1164 }
1165
1166 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001167 if (user)
1168 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 recv_msg->msgid = msgid;
1170 /* Store the message to send in the receive message so timeout
1171 responses can get the proper response data. */
1172 recv_msg->msg = *msg;
1173
1174 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1175 struct ipmi_system_interface_addr *smi_addr;
1176
1177 if (msg->netfn & 1) {
1178 /* Responses are not allowed to the SMI. */
1179 rv = -EINVAL;
1180 goto out_err;
1181 }
1182
1183 smi_addr = (struct ipmi_system_interface_addr *) addr;
1184 if (smi_addr->lun > 3) {
1185 spin_lock_irqsave(&intf->counter_lock, flags);
1186 intf->sent_invalid_commands++;
1187 spin_unlock_irqrestore(&intf->counter_lock, flags);
1188 rv = -EINVAL;
1189 goto out_err;
1190 }
1191
1192 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1193
1194 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1195 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1196 || (msg->cmd == IPMI_GET_MSG_CMD)
1197 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1198 {
1199 /* We don't let the user do these, since we manage
1200 the sequence numbers. */
1201 spin_lock_irqsave(&intf->counter_lock, flags);
1202 intf->sent_invalid_commands++;
1203 spin_unlock_irqrestore(&intf->counter_lock, flags);
1204 rv = -EINVAL;
1205 goto out_err;
1206 }
1207
1208 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1209 spin_lock_irqsave(&intf->counter_lock, flags);
1210 intf->sent_invalid_commands++;
1211 spin_unlock_irqrestore(&intf->counter_lock, flags);
1212 rv = -EMSGSIZE;
1213 goto out_err;
1214 }
1215
1216 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1217 smi_msg->data[1] = msg->cmd;
1218 smi_msg->msgid = msgid;
1219 smi_msg->user_data = recv_msg;
1220 if (msg->data_len > 0)
1221 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1222 smi_msg->data_size = msg->data_len + 2;
1223 spin_lock_irqsave(&intf->counter_lock, flags);
1224 intf->sent_local_commands++;
1225 spin_unlock_irqrestore(&intf->counter_lock, flags);
1226 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1227 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1228 {
1229 struct ipmi_ipmb_addr *ipmb_addr;
1230 unsigned char ipmb_seq;
1231 long seqid;
1232 int broadcast = 0;
1233
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001234 if (addr->channel >= IPMI_MAX_CHANNELS) {
1235 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 intf->sent_invalid_commands++;
1237 spin_unlock_irqrestore(&intf->counter_lock, flags);
1238 rv = -EINVAL;
1239 goto out_err;
1240 }
1241
1242 if (intf->channels[addr->channel].medium
1243 != IPMI_CHANNEL_MEDIUM_IPMB)
1244 {
1245 spin_lock_irqsave(&intf->counter_lock, flags);
1246 intf->sent_invalid_commands++;
1247 spin_unlock_irqrestore(&intf->counter_lock, flags);
1248 rv = -EINVAL;
1249 goto out_err;
1250 }
1251
1252 if (retries < 0) {
1253 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1254 retries = 0; /* Don't retry broadcasts. */
1255 else
1256 retries = 4;
1257 }
1258 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1259 /* Broadcasts add a zero at the beginning of the
1260 message, but otherwise is the same as an IPMB
1261 address. */
1262 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1263 broadcast = 1;
1264 }
1265
1266
1267 /* Default to 1 second retries. */
1268 if (retry_time_ms == 0)
1269 retry_time_ms = 1000;
1270
1271 /* 9 for the header and 1 for the checksum, plus
1272 possibly one for the broadcast. */
1273 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1274 spin_lock_irqsave(&intf->counter_lock, flags);
1275 intf->sent_invalid_commands++;
1276 spin_unlock_irqrestore(&intf->counter_lock, flags);
1277 rv = -EMSGSIZE;
1278 goto out_err;
1279 }
1280
1281 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1282 if (ipmb_addr->lun > 3) {
1283 spin_lock_irqsave(&intf->counter_lock, flags);
1284 intf->sent_invalid_commands++;
1285 spin_unlock_irqrestore(&intf->counter_lock, flags);
1286 rv = -EINVAL;
1287 goto out_err;
1288 }
1289
1290 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1291
1292 if (recv_msg->msg.netfn & 0x1) {
1293 /* It's a response, so use the user's sequence
1294 from msgid. */
1295 spin_lock_irqsave(&intf->counter_lock, flags);
1296 intf->sent_ipmb_responses++;
1297 spin_unlock_irqrestore(&intf->counter_lock, flags);
1298 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1299 msgid, broadcast,
1300 source_address, source_lun);
1301
1302 /* Save the receive message so we can use it
1303 to deliver the response. */
1304 smi_msg->user_data = recv_msg;
1305 } else {
1306 /* It's a command, so get a sequence for it. */
1307
1308 spin_lock_irqsave(&(intf->seq_lock), flags);
1309
1310 spin_lock(&intf->counter_lock);
1311 intf->sent_ipmb_commands++;
1312 spin_unlock(&intf->counter_lock);
1313
1314 /* Create a sequence number with a 1 second
1315 timeout and 4 retries. */
1316 rv = intf_next_seq(intf,
1317 recv_msg,
1318 retry_time_ms,
1319 retries,
1320 broadcast,
1321 &ipmb_seq,
1322 &seqid);
1323 if (rv) {
1324 /* We have used up all the sequence numbers,
1325 probably, so abort. */
1326 spin_unlock_irqrestore(&(intf->seq_lock),
1327 flags);
1328 goto out_err;
1329 }
1330
1331 /* Store the sequence number in the message,
1332 so that when the send message response
1333 comes back we can start the timer. */
1334 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1335 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1336 ipmb_seq, broadcast,
1337 source_address, source_lun);
1338
1339 /* Copy the message into the recv message data, so we
1340 can retransmit it later if necessary. */
1341 memcpy(recv_msg->msg_data, smi_msg->data,
1342 smi_msg->data_size);
1343 recv_msg->msg.data = recv_msg->msg_data;
1344 recv_msg->msg.data_len = smi_msg->data_size;
1345
1346 /* We don't unlock until here, because we need
1347 to copy the completed message into the
1348 recv_msg before we release the lock.
1349 Otherwise, race conditions may bite us. I
1350 know that's pretty paranoid, but I prefer
1351 to be correct. */
1352 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1353 }
1354 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1355 struct ipmi_lan_addr *lan_addr;
1356 unsigned char ipmb_seq;
1357 long seqid;
1358
Jayachandran C12fc1d72006-02-03 03:04:51 -08001359 if (addr->channel >= IPMI_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 spin_lock_irqsave(&intf->counter_lock, flags);
1361 intf->sent_invalid_commands++;
1362 spin_unlock_irqrestore(&intf->counter_lock, flags);
1363 rv = -EINVAL;
1364 goto out_err;
1365 }
1366
1367 if ((intf->channels[addr->channel].medium
1368 != IPMI_CHANNEL_MEDIUM_8023LAN)
1369 && (intf->channels[addr->channel].medium
1370 != IPMI_CHANNEL_MEDIUM_ASYNC))
1371 {
1372 spin_lock_irqsave(&intf->counter_lock, flags);
1373 intf->sent_invalid_commands++;
1374 spin_unlock_irqrestore(&intf->counter_lock, flags);
1375 rv = -EINVAL;
1376 goto out_err;
1377 }
1378
1379 retries = 4;
1380
1381 /* Default to 1 second retries. */
1382 if (retry_time_ms == 0)
1383 retry_time_ms = 1000;
1384
1385 /* 11 for the header and 1 for the checksum. */
1386 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1387 spin_lock_irqsave(&intf->counter_lock, flags);
1388 intf->sent_invalid_commands++;
1389 spin_unlock_irqrestore(&intf->counter_lock, flags);
1390 rv = -EMSGSIZE;
1391 goto out_err;
1392 }
1393
1394 lan_addr = (struct ipmi_lan_addr *) addr;
1395 if (lan_addr->lun > 3) {
1396 spin_lock_irqsave(&intf->counter_lock, flags);
1397 intf->sent_invalid_commands++;
1398 spin_unlock_irqrestore(&intf->counter_lock, flags);
1399 rv = -EINVAL;
1400 goto out_err;
1401 }
1402
1403 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1404
1405 if (recv_msg->msg.netfn & 0x1) {
1406 /* It's a response, so use the user's sequence
1407 from msgid. */
1408 spin_lock_irqsave(&intf->counter_lock, flags);
1409 intf->sent_lan_responses++;
1410 spin_unlock_irqrestore(&intf->counter_lock, flags);
1411 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1412 msgid, source_lun);
1413
1414 /* Save the receive message so we can use it
1415 to deliver the response. */
1416 smi_msg->user_data = recv_msg;
1417 } else {
1418 /* It's a command, so get a sequence for it. */
1419
1420 spin_lock_irqsave(&(intf->seq_lock), flags);
1421
1422 spin_lock(&intf->counter_lock);
1423 intf->sent_lan_commands++;
1424 spin_unlock(&intf->counter_lock);
1425
1426 /* Create a sequence number with a 1 second
1427 timeout and 4 retries. */
1428 rv = intf_next_seq(intf,
1429 recv_msg,
1430 retry_time_ms,
1431 retries,
1432 0,
1433 &ipmb_seq,
1434 &seqid);
1435 if (rv) {
1436 /* We have used up all the sequence numbers,
1437 probably, so abort. */
1438 spin_unlock_irqrestore(&(intf->seq_lock),
1439 flags);
1440 goto out_err;
1441 }
1442
1443 /* Store the sequence number in the message,
1444 so that when the send message response
1445 comes back we can start the timer. */
1446 format_lan_msg(smi_msg, msg, lan_addr,
1447 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1448 ipmb_seq, source_lun);
1449
1450 /* Copy the message into the recv message data, so we
1451 can retransmit it later if necessary. */
1452 memcpy(recv_msg->msg_data, smi_msg->data,
1453 smi_msg->data_size);
1454 recv_msg->msg.data = recv_msg->msg_data;
1455 recv_msg->msg.data_len = smi_msg->data_size;
1456
1457 /* We don't unlock until here, because we need
1458 to copy the completed message into the
1459 recv_msg before we release the lock.
1460 Otherwise, race conditions may bite us. I
1461 know that's pretty paranoid, but I prefer
1462 to be correct. */
1463 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1464 }
1465 } else {
1466 /* Unknown address type. */
1467 spin_lock_irqsave(&intf->counter_lock, flags);
1468 intf->sent_invalid_commands++;
1469 spin_unlock_irqrestore(&intf->counter_lock, flags);
1470 rv = -EINVAL;
1471 goto out_err;
1472 }
1473
1474#ifdef DEBUG_MSGING
1475 {
1476 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001477 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 printk(" %2.2x", smi_msg->data[m]);
1479 printk("\n");
1480 }
1481#endif
1482 intf->handlers->sender(intf->send_info, smi_msg, priority);
1483
1484 return 0;
1485
1486 out_err:
1487 ipmi_free_smi_msg(smi_msg);
1488 ipmi_free_recv_msg(recv_msg);
1489 return rv;
1490}
1491
Corey Minyardc14979b2005-09-06 15:18:38 -07001492static int check_addr(ipmi_smi_t intf,
1493 struct ipmi_addr *addr,
1494 unsigned char *saddr,
1495 unsigned char *lun)
1496{
1497 if (addr->channel >= IPMI_MAX_CHANNELS)
1498 return -EINVAL;
1499 *lun = intf->channels[addr->channel].lun;
1500 *saddr = intf->channels[addr->channel].address;
1501 return 0;
1502}
1503
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504int ipmi_request_settime(ipmi_user_t user,
1505 struct ipmi_addr *addr,
1506 long msgid,
1507 struct kernel_ipmi_msg *msg,
1508 void *user_msg_data,
1509 int priority,
1510 int retries,
1511 unsigned int retry_time_ms)
1512{
Corey Minyardc14979b2005-09-06 15:18:38 -07001513 unsigned char saddr, lun;
1514 int rv;
1515
Corey Minyard8a3628d2006-03-31 02:30:40 -08001516 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001517 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001518 rv = check_addr(user->intf, addr, &saddr, &lun);
1519 if (rv)
1520 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 return i_ipmi_request(user,
1522 user->intf,
1523 addr,
1524 msgid,
1525 msg,
1526 user_msg_data,
1527 NULL, NULL,
1528 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001529 saddr,
1530 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 retries,
1532 retry_time_ms);
1533}
1534
1535int ipmi_request_supply_msgs(ipmi_user_t user,
1536 struct ipmi_addr *addr,
1537 long msgid,
1538 struct kernel_ipmi_msg *msg,
1539 void *user_msg_data,
1540 void *supplied_smi,
1541 struct ipmi_recv_msg *supplied_recv,
1542 int priority)
1543{
Corey Minyardc14979b2005-09-06 15:18:38 -07001544 unsigned char saddr, lun;
1545 int rv;
1546
Corey Minyard8a3628d2006-03-31 02:30:40 -08001547 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001548 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001549 rv = check_addr(user->intf, addr, &saddr, &lun);
1550 if (rv)
1551 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 return i_ipmi_request(user,
1553 user->intf,
1554 addr,
1555 msgid,
1556 msg,
1557 user_msg_data,
1558 supplied_smi,
1559 supplied_recv,
1560 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001561 saddr,
1562 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 -1, 0);
1564}
1565
1566static int ipmb_file_read_proc(char *page, char **start, off_t off,
1567 int count, int *eof, void *data)
1568{
1569 char *out = (char *) page;
1570 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001571 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001572 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573
Corey Minyarde8b33612005-09-06 15:18:45 -07001574 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001575 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1576 out[rv-1] = '\n'; /* Replace the final space with a newline */
1577 out[rv] = '\0';
1578 rv++;
1579 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580}
1581
1582static int version_file_read_proc(char *page, char **start, off_t off,
1583 int count, int *eof, void *data)
1584{
1585 char *out = (char *) page;
1586 ipmi_smi_t intf = data;
1587
1588 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001589 ipmi_version_major(&intf->bmc->id),
1590 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591}
1592
1593static int stat_file_read_proc(char *page, char **start, off_t off,
1594 int count, int *eof, void *data)
1595{
1596 char *out = (char *) page;
1597 ipmi_smi_t intf = data;
1598
1599 out += sprintf(out, "sent_invalid_commands: %d\n",
1600 intf->sent_invalid_commands);
1601 out += sprintf(out, "sent_local_commands: %d\n",
1602 intf->sent_local_commands);
1603 out += sprintf(out, "handled_local_responses: %d\n",
1604 intf->handled_local_responses);
1605 out += sprintf(out, "unhandled_local_responses: %d\n",
1606 intf->unhandled_local_responses);
1607 out += sprintf(out, "sent_ipmb_commands: %d\n",
1608 intf->sent_ipmb_commands);
1609 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1610 intf->sent_ipmb_command_errs);
1611 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1612 intf->retransmitted_ipmb_commands);
1613 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1614 intf->timed_out_ipmb_commands);
1615 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1616 intf->timed_out_ipmb_broadcasts);
1617 out += sprintf(out, "sent_ipmb_responses: %d\n",
1618 intf->sent_ipmb_responses);
1619 out += sprintf(out, "handled_ipmb_responses: %d\n",
1620 intf->handled_ipmb_responses);
1621 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1622 intf->invalid_ipmb_responses);
1623 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1624 intf->unhandled_ipmb_responses);
1625 out += sprintf(out, "sent_lan_commands: %d\n",
1626 intf->sent_lan_commands);
1627 out += sprintf(out, "sent_lan_command_errs: %d\n",
1628 intf->sent_lan_command_errs);
1629 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1630 intf->retransmitted_lan_commands);
1631 out += sprintf(out, "timed_out_lan_commands: %d\n",
1632 intf->timed_out_lan_commands);
1633 out += sprintf(out, "sent_lan_responses: %d\n",
1634 intf->sent_lan_responses);
1635 out += sprintf(out, "handled_lan_responses: %d\n",
1636 intf->handled_lan_responses);
1637 out += sprintf(out, "invalid_lan_responses: %d\n",
1638 intf->invalid_lan_responses);
1639 out += sprintf(out, "unhandled_lan_responses: %d\n",
1640 intf->unhandled_lan_responses);
1641 out += sprintf(out, "handled_commands: %d\n",
1642 intf->handled_commands);
1643 out += sprintf(out, "invalid_commands: %d\n",
1644 intf->invalid_commands);
1645 out += sprintf(out, "unhandled_commands: %d\n",
1646 intf->unhandled_commands);
1647 out += sprintf(out, "invalid_events: %d\n",
1648 intf->invalid_events);
1649 out += sprintf(out, "events: %d\n",
1650 intf->events);
1651
1652 return (out - ((char *) page));
1653}
1654
1655int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1656 read_proc_t *read_proc, write_proc_t *write_proc,
1657 void *data, struct module *owner)
1658{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001660#ifdef CONFIG_PROC_FS
1661 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 struct ipmi_proc_entry *entry;
1663
1664 /* Create a list element. */
1665 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1666 if (!entry)
1667 return -ENOMEM;
1668 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1669 if (!entry->name) {
1670 kfree(entry);
1671 return -ENOMEM;
1672 }
1673 strcpy(entry->name, name);
1674
1675 file = create_proc_entry(name, 0, smi->proc_dir);
1676 if (!file) {
1677 kfree(entry->name);
1678 kfree(entry);
1679 rv = -ENOMEM;
1680 } else {
1681 file->nlink = 1;
1682 file->data = data;
1683 file->read_proc = read_proc;
1684 file->write_proc = write_proc;
1685 file->owner = owner;
1686
Corey Minyard3b625942005-06-23 22:01:42 -07001687 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 /* Stick it on the list. */
1689 entry->next = smi->proc_entries;
1690 smi->proc_entries = entry;
Corey Minyard3b625942005-06-23 22:01:42 -07001691 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 }
Corey Minyard3b625942005-06-23 22:01:42 -07001693#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
1695 return rv;
1696}
1697
1698static int add_proc_entries(ipmi_smi_t smi, int num)
1699{
1700 int rv = 0;
1701
Corey Minyard3b625942005-06-23 22:01:42 -07001702#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 sprintf(smi->proc_dir_name, "%d", num);
1704 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1705 if (!smi->proc_dir)
1706 rv = -ENOMEM;
1707 else {
1708 smi->proc_dir->owner = THIS_MODULE;
1709 }
1710
1711 if (rv == 0)
1712 rv = ipmi_smi_add_proc_entry(smi, "stats",
1713 stat_file_read_proc, NULL,
1714 smi, THIS_MODULE);
1715
1716 if (rv == 0)
1717 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1718 ipmb_file_read_proc, NULL,
1719 smi, THIS_MODULE);
1720
1721 if (rv == 0)
1722 rv = ipmi_smi_add_proc_entry(smi, "version",
1723 version_file_read_proc, NULL,
1724 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001725#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
1727 return rv;
1728}
1729
1730static void remove_proc_entries(ipmi_smi_t smi)
1731{
Corey Minyard3b625942005-06-23 22:01:42 -07001732#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 struct ipmi_proc_entry *entry;
1734
Corey Minyard3b625942005-06-23 22:01:42 -07001735 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 while (smi->proc_entries) {
1737 entry = smi->proc_entries;
1738 smi->proc_entries = entry->next;
1739
1740 remove_proc_entry(entry->name, smi->proc_dir);
1741 kfree(entry->name);
1742 kfree(entry);
1743 }
Corey Minyard3b625942005-06-23 22:01:42 -07001744 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001746#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747}
1748
Corey Minyard50c812b2006-03-26 01:37:21 -08001749static int __find_bmc_guid(struct device *dev, void *data)
1750{
1751 unsigned char *id = data;
1752 struct bmc_device *bmc = dev_get_drvdata(dev);
1753 return memcmp(bmc->guid, id, 16) == 0;
1754}
1755
1756static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1757 unsigned char *guid)
1758{
1759 struct device *dev;
1760
1761 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1762 if (dev)
1763 return dev_get_drvdata(dev);
1764 else
1765 return NULL;
1766}
1767
1768struct prod_dev_id {
1769 unsigned int product_id;
1770 unsigned char device_id;
1771};
1772
1773static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1774{
1775 struct prod_dev_id *id = data;
1776 struct bmc_device *bmc = dev_get_drvdata(dev);
1777
1778 return (bmc->id.product_id == id->product_id
1779 && bmc->id.product_id == id->product_id
1780 && bmc->id.device_id == id->device_id);
1781}
1782
1783static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1784 struct device_driver *drv,
1785 unsigned char product_id, unsigned char device_id)
1786{
1787 struct prod_dev_id id = {
1788 .product_id = product_id,
1789 .device_id = device_id,
1790 };
1791 struct device *dev;
1792
1793 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
1794 if (dev)
1795 return dev_get_drvdata(dev);
1796 else
1797 return NULL;
1798}
1799
1800static ssize_t device_id_show(struct device *dev,
1801 struct device_attribute *attr,
1802 char *buf)
1803{
1804 struct bmc_device *bmc = dev_get_drvdata(dev);
1805
1806 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
1807}
1808
1809static ssize_t provides_dev_sdrs_show(struct device *dev,
1810 struct device_attribute *attr,
1811 char *buf)
1812{
1813 struct bmc_device *bmc = dev_get_drvdata(dev);
1814
1815 return snprintf(buf, 10, "%u\n",
1816 bmc->id.device_revision && 0x80 >> 7);
1817}
1818
1819static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
1820 char *buf)
1821{
1822 struct bmc_device *bmc = dev_get_drvdata(dev);
1823
1824 return snprintf(buf, 20, "%u\n",
1825 bmc->id.device_revision && 0x0F);
1826}
1827
1828static ssize_t firmware_rev_show(struct device *dev,
1829 struct device_attribute *attr,
1830 char *buf)
1831{
1832 struct bmc_device *bmc = dev_get_drvdata(dev);
1833
1834 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
1835 bmc->id.firmware_revision_2);
1836}
1837
1838static ssize_t ipmi_version_show(struct device *dev,
1839 struct device_attribute *attr,
1840 char *buf)
1841{
1842 struct bmc_device *bmc = dev_get_drvdata(dev);
1843
1844 return snprintf(buf, 20, "%u.%u\n",
1845 ipmi_version_major(&bmc->id),
1846 ipmi_version_minor(&bmc->id));
1847}
1848
1849static ssize_t add_dev_support_show(struct device *dev,
1850 struct device_attribute *attr,
1851 char *buf)
1852{
1853 struct bmc_device *bmc = dev_get_drvdata(dev);
1854
1855 return snprintf(buf, 10, "0x%02x\n",
1856 bmc->id.additional_device_support);
1857}
1858
1859static ssize_t manufacturer_id_show(struct device *dev,
1860 struct device_attribute *attr,
1861 char *buf)
1862{
1863 struct bmc_device *bmc = dev_get_drvdata(dev);
1864
1865 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
1866}
1867
1868static ssize_t product_id_show(struct device *dev,
1869 struct device_attribute *attr,
1870 char *buf)
1871{
1872 struct bmc_device *bmc = dev_get_drvdata(dev);
1873
1874 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
1875}
1876
1877static ssize_t aux_firmware_rev_show(struct device *dev,
1878 struct device_attribute *attr,
1879 char *buf)
1880{
1881 struct bmc_device *bmc = dev_get_drvdata(dev);
1882
1883 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
1884 bmc->id.aux_firmware_revision[3],
1885 bmc->id.aux_firmware_revision[2],
1886 bmc->id.aux_firmware_revision[1],
1887 bmc->id.aux_firmware_revision[0]);
1888}
1889
1890static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
1891 char *buf)
1892{
1893 struct bmc_device *bmc = dev_get_drvdata(dev);
1894
1895 return snprintf(buf, 100, "%Lx%Lx\n",
1896 (long long) bmc->guid[0],
1897 (long long) bmc->guid[8]);
1898}
1899
1900static void
1901cleanup_bmc_device(struct kref *ref)
1902{
1903 struct bmc_device *bmc;
1904
1905 bmc = container_of(ref, struct bmc_device, refcount);
1906
1907 device_remove_file(&bmc->dev->dev,
1908 &bmc->device_id_attr);
1909 device_remove_file(&bmc->dev->dev,
1910 &bmc->provides_dev_sdrs_attr);
1911 device_remove_file(&bmc->dev->dev,
1912 &bmc->revision_attr);
1913 device_remove_file(&bmc->dev->dev,
1914 &bmc->firmware_rev_attr);
1915 device_remove_file(&bmc->dev->dev,
1916 &bmc->version_attr);
1917 device_remove_file(&bmc->dev->dev,
1918 &bmc->add_dev_support_attr);
1919 device_remove_file(&bmc->dev->dev,
1920 &bmc->manufacturer_id_attr);
1921 device_remove_file(&bmc->dev->dev,
1922 &bmc->product_id_attr);
1923 if (bmc->id.aux_firmware_revision_set)
1924 device_remove_file(&bmc->dev->dev,
1925 &bmc->aux_firmware_rev_attr);
1926 if (bmc->guid_set)
1927 device_remove_file(&bmc->dev->dev,
1928 &bmc->guid_attr);
1929 platform_device_unregister(bmc->dev);
1930 kfree(bmc);
1931}
1932
1933static void ipmi_bmc_unregister(ipmi_smi_t intf)
1934{
1935 struct bmc_device *bmc = intf->bmc;
1936
1937 sysfs_remove_link(&intf->si_dev->kobj, "bmc");
1938 if (intf->my_dev_name) {
1939 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
1940 kfree(intf->my_dev_name);
1941 intf->my_dev_name = NULL;
1942 }
1943
1944 mutex_lock(&ipmidriver_mutex);
1945 kref_put(&bmc->refcount, cleanup_bmc_device);
1946 mutex_unlock(&ipmidriver_mutex);
1947}
1948
1949static int ipmi_bmc_register(ipmi_smi_t intf)
1950{
1951 int rv;
1952 struct bmc_device *bmc = intf->bmc;
1953 struct bmc_device *old_bmc;
1954 int size;
1955 char dummy[1];
1956
1957 mutex_lock(&ipmidriver_mutex);
1958
1959 /*
1960 * Try to find if there is an bmc_device struct
1961 * representing the interfaced BMC already
1962 */
1963 if (bmc->guid_set)
1964 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
1965 else
1966 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
1967 bmc->id.product_id,
1968 bmc->id.device_id);
1969
1970 /*
1971 * If there is already an bmc_device, free the new one,
1972 * otherwise register the new BMC device
1973 */
1974 if (old_bmc) {
1975 kfree(bmc);
1976 intf->bmc = old_bmc;
1977 bmc = old_bmc;
1978
1979 kref_get(&bmc->refcount);
1980 mutex_unlock(&ipmidriver_mutex);
1981
1982 printk(KERN_INFO
1983 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
1984 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
1985 bmc->id.manufacturer_id,
1986 bmc->id.product_id,
1987 bmc->id.device_id);
1988 } else {
1989 bmc->dev = platform_device_alloc("ipmi_bmc",
1990 bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08001991 if (!bmc->dev) {
Corey Minyard50c812b2006-03-26 01:37:21 -08001992 printk(KERN_ERR
1993 "ipmi_msghandler:"
1994 " Unable to allocate platform device\n");
1995 return -ENOMEM;
1996 }
1997 bmc->dev->dev.driver = &ipmidriver;
1998 dev_set_drvdata(&bmc->dev->dev, bmc);
1999 kref_init(&bmc->refcount);
2000
2001 rv = platform_device_register(bmc->dev);
2002 mutex_unlock(&ipmidriver_mutex);
2003 if (rv) {
2004 printk(KERN_ERR
2005 "ipmi_msghandler:"
2006 " Unable to register bmc device: %d\n",
2007 rv);
2008 /* Don't go to out_err, you can only do that if
2009 the device is registered already. */
2010 return rv;
2011 }
2012
2013 bmc->device_id_attr.attr.name = "device_id";
2014 bmc->device_id_attr.attr.owner = THIS_MODULE;
2015 bmc->device_id_attr.attr.mode = S_IRUGO;
2016 bmc->device_id_attr.show = device_id_show;
2017
2018 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
2019 bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
2020 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2021 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2022
2023
2024 bmc->revision_attr.attr.name = "revision";
2025 bmc->revision_attr.attr.owner = THIS_MODULE;
2026 bmc->revision_attr.attr.mode = S_IRUGO;
2027 bmc->revision_attr.show = revision_show;
2028
2029 bmc->firmware_rev_attr.attr.name = "firmware_revision";
2030 bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
2031 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2032 bmc->firmware_rev_attr.show = firmware_rev_show;
2033
2034 bmc->version_attr.attr.name = "ipmi_version";
2035 bmc->version_attr.attr.owner = THIS_MODULE;
2036 bmc->version_attr.attr.mode = S_IRUGO;
2037 bmc->version_attr.show = ipmi_version_show;
2038
2039 bmc->add_dev_support_attr.attr.name
2040 = "additional_device_support";
2041 bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
2042 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2043 bmc->add_dev_support_attr.show = add_dev_support_show;
2044
2045 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
2046 bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
2047 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2048 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2049
2050 bmc->product_id_attr.attr.name = "product_id";
2051 bmc->product_id_attr.attr.owner = THIS_MODULE;
2052 bmc->product_id_attr.attr.mode = S_IRUGO;
2053 bmc->product_id_attr.show = product_id_show;
2054
2055 bmc->guid_attr.attr.name = "guid";
2056 bmc->guid_attr.attr.owner = THIS_MODULE;
2057 bmc->guid_attr.attr.mode = S_IRUGO;
2058 bmc->guid_attr.show = guid_show;
2059
2060 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
2061 bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
2062 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2063 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2064
2065 device_create_file(&bmc->dev->dev,
2066 &bmc->device_id_attr);
2067 device_create_file(&bmc->dev->dev,
2068 &bmc->provides_dev_sdrs_attr);
2069 device_create_file(&bmc->dev->dev,
2070 &bmc->revision_attr);
2071 device_create_file(&bmc->dev->dev,
2072 &bmc->firmware_rev_attr);
2073 device_create_file(&bmc->dev->dev,
2074 &bmc->version_attr);
2075 device_create_file(&bmc->dev->dev,
2076 &bmc->add_dev_support_attr);
2077 device_create_file(&bmc->dev->dev,
2078 &bmc->manufacturer_id_attr);
2079 device_create_file(&bmc->dev->dev,
2080 &bmc->product_id_attr);
2081 if (bmc->id.aux_firmware_revision_set)
2082 device_create_file(&bmc->dev->dev,
2083 &bmc->aux_firmware_rev_attr);
2084 if (bmc->guid_set)
2085 device_create_file(&bmc->dev->dev,
2086 &bmc->guid_attr);
2087
2088 printk(KERN_INFO
2089 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2090 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2091 bmc->id.manufacturer_id,
2092 bmc->id.product_id,
2093 bmc->id.device_id);
2094 }
2095
2096 /*
2097 * create symlink from system interface device to bmc device
2098 * and back.
2099 */
2100 rv = sysfs_create_link(&intf->si_dev->kobj,
2101 &bmc->dev->dev.kobj, "bmc");
2102 if (rv) {
2103 printk(KERN_ERR
2104 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2105 rv);
2106 goto out_err;
2107 }
2108
2109 size = snprintf(dummy, 0, "ipmi%d", intf->intf_num);
2110 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2111 if (!intf->my_dev_name) {
2112 rv = -ENOMEM;
2113 printk(KERN_ERR
2114 "ipmi_msghandler: allocate link from BMC: %d\n",
2115 rv);
2116 goto out_err;
2117 }
2118 snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num);
2119
2120 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2121 intf->my_dev_name);
2122 if (rv) {
2123 kfree(intf->my_dev_name);
2124 intf->my_dev_name = NULL;
2125 printk(KERN_ERR
2126 "ipmi_msghandler:"
2127 " Unable to create symlink to bmc: %d\n",
2128 rv);
2129 goto out_err;
2130 }
2131
2132 return 0;
2133
2134out_err:
2135 ipmi_bmc_unregister(intf);
2136 return rv;
2137}
2138
2139static int
2140send_guid_cmd(ipmi_smi_t intf, int chan)
2141{
2142 struct kernel_ipmi_msg msg;
2143 struct ipmi_system_interface_addr si;
2144
2145 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2146 si.channel = IPMI_BMC_CHANNEL;
2147 si.lun = 0;
2148
2149 msg.netfn = IPMI_NETFN_APP_REQUEST;
2150 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2151 msg.data = NULL;
2152 msg.data_len = 0;
2153 return i_ipmi_request(NULL,
2154 intf,
2155 (struct ipmi_addr *) &si,
2156 0,
2157 &msg,
2158 intf,
2159 NULL,
2160 NULL,
2161 0,
2162 intf->channels[0].address,
2163 intf->channels[0].lun,
2164 -1, 0);
2165}
2166
2167static void
2168guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2169{
2170 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2171 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2172 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2173 /* Not for me */
2174 return;
2175
2176 if (msg->msg.data[0] != 0) {
2177 /* Error from getting the GUID, the BMC doesn't have one. */
2178 intf->bmc->guid_set = 0;
2179 goto out;
2180 }
2181
2182 if (msg->msg.data_len < 17) {
2183 intf->bmc->guid_set = 0;
2184 printk(KERN_WARNING PFX
2185 "guid_handler: The GUID response from the BMC was too"
2186 " short, it was %d but should have been 17. Assuming"
2187 " GUID is not available.\n",
2188 msg->msg.data_len);
2189 goto out;
2190 }
2191
2192 memcpy(intf->bmc->guid, msg->msg.data, 16);
2193 intf->bmc->guid_set = 1;
2194 out:
2195 wake_up(&intf->waitq);
2196}
2197
2198static void
2199get_guid(ipmi_smi_t intf)
2200{
2201 int rv;
2202
2203 intf->bmc->guid_set = 0x2;
2204 intf->null_user_handler = guid_handler;
2205 rv = send_guid_cmd(intf, 0);
2206 if (rv)
2207 /* Send failed, no GUID available. */
2208 intf->bmc->guid_set = 0;
2209 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2210 intf->null_user_handler = NULL;
2211}
2212
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213static int
2214send_channel_info_cmd(ipmi_smi_t intf, int chan)
2215{
2216 struct kernel_ipmi_msg msg;
2217 unsigned char data[1];
2218 struct ipmi_system_interface_addr si;
2219
2220 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2221 si.channel = IPMI_BMC_CHANNEL;
2222 si.lun = 0;
2223
2224 msg.netfn = IPMI_NETFN_APP_REQUEST;
2225 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2226 msg.data = data;
2227 msg.data_len = 1;
2228 data[0] = chan;
2229 return i_ipmi_request(NULL,
2230 intf,
2231 (struct ipmi_addr *) &si,
2232 0,
2233 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002234 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 NULL,
2236 NULL,
2237 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002238 intf->channels[0].address,
2239 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 -1, 0);
2241}
2242
2243static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002244channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245{
2246 int rv = 0;
2247 int chan;
2248
Corey Minyard56a55ec2005-09-06 15:18:42 -07002249 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2250 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2251 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 {
2253 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002254 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 /* Got an error from the channel, just go on. */
2256
Corey Minyard56a55ec2005-09-06 15:18:42 -07002257 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 /* If the MC does not support this
2259 command, that is legal. We just
2260 assume it has one IPMB at channel
2261 zero. */
2262 intf->channels[0].medium
2263 = IPMI_CHANNEL_MEDIUM_IPMB;
2264 intf->channels[0].protocol
2265 = IPMI_CHANNEL_PROTOCOL_IPMB;
2266 rv = -ENOSYS;
2267
2268 intf->curr_channel = IPMI_MAX_CHANNELS;
2269 wake_up(&intf->waitq);
2270 goto out;
2271 }
2272 goto next_channel;
2273 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002274 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 /* Message not big enough, just go on. */
2276 goto next_channel;
2277 }
2278 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002279 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2280 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281
2282 next_channel:
2283 intf->curr_channel++;
2284 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2285 wake_up(&intf->waitq);
2286 else
2287 rv = send_channel_info_cmd(intf, intf->curr_channel);
2288
2289 if (rv) {
2290 /* Got an error somehow, just give up. */
2291 intf->curr_channel = IPMI_MAX_CHANNELS;
2292 wake_up(&intf->waitq);
2293
2294 printk(KERN_WARNING PFX
2295 "Error sending channel information: %d\n",
2296 rv);
2297 }
2298 }
2299 out:
2300 return;
2301}
2302
2303int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2304 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002305 struct ipmi_device_id *device_id,
2306 struct device *si_dev,
Corey Minyard453823b2006-03-31 02:30:39 -08002307 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308{
2309 int i, j;
2310 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002311 ipmi_smi_t intf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 unsigned long flags;
Corey Minyard50c812b2006-03-26 01:37:21 -08002313 int version_major;
2314 int version_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
Corey Minyard50c812b2006-03-26 01:37:21 -08002316 version_major = ipmi_version_major(device_id);
2317 version_minor = ipmi_version_minor(device_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
2319 /* Make sure the driver is actually initialized, this handles
2320 problems with initialization order. */
2321 if (!initialized) {
2322 rv = ipmi_init_msghandler();
2323 if (rv)
2324 return rv;
2325 /* The init code doesn't return an error if it was turned
2326 off, but it won't initialize. Check that. */
2327 if (!initialized)
2328 return -ENODEV;
2329 }
2330
Corey Minyard393d2cc2005-11-07 00:59:54 -08002331 intf = kmalloc(sizeof(*intf), GFP_KERNEL);
2332 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002334 memset(intf, 0, sizeof(*intf));
Corey Minyard50c812b2006-03-26 01:37:21 -08002335 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2336 if (!intf->bmc) {
2337 kfree(intf);
2338 return -ENOMEM;
2339 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002340 intf->intf_num = -1;
2341 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002342 intf->bmc->id = *device_id;
2343 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002344 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2345 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2346 intf->channels[j].lun = 2;
2347 }
2348 if (slave_addr != 0)
2349 intf->channels[0].address = slave_addr;
2350 INIT_LIST_HEAD(&intf->users);
2351 intf->handlers = handlers;
2352 intf->send_info = send_info;
2353 spin_lock_init(&intf->seq_lock);
2354 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2355 intf->seq_table[j].inuse = 0;
2356 intf->seq_table[j].seqid = 0;
2357 }
2358 intf->curr_seq = 0;
2359#ifdef CONFIG_PROC_FS
2360 spin_lock_init(&intf->proc_entry_lock);
2361#endif
2362 spin_lock_init(&intf->waiting_msgs_lock);
2363 INIT_LIST_HEAD(&intf->waiting_msgs);
2364 spin_lock_init(&intf->events_lock);
2365 INIT_LIST_HEAD(&intf->waiting_events);
2366 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002367 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002368 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2369 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
Corey Minyard393d2cc2005-11-07 00:59:54 -08002371 spin_lock_init(&intf->counter_lock);
2372 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
2374 rv = -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002375 spin_lock_irqsave(&interfaces_lock, flags);
Corey Minyarde8b33612005-09-06 15:18:45 -07002376 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 if (ipmi_interfaces[i] == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002378 intf->intf_num = i;
2379 /* Reserve the entry till we are done. */
2380 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 break;
2383 }
2384 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002385 spin_unlock_irqrestore(&interfaces_lock, flags);
2386 if (rv)
2387 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388
Corey Minyard453823b2006-03-31 02:30:39 -08002389 rv = handlers->start_processing(send_info, intf);
2390 if (rv)
2391 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002392
Corey Minyard50c812b2006-03-26 01:37:21 -08002393 get_guid(intf);
2394
Corey Minyard393d2cc2005-11-07 00:59:54 -08002395 if ((version_major > 1)
2396 || ((version_major == 1) && (version_minor >= 5)))
2397 {
2398 /* Start scanning the channels to see what is
2399 available. */
2400 intf->null_user_handler = channel_handler;
2401 intf->curr_channel = 0;
2402 rv = send_channel_info_cmd(intf, 0);
2403 if (rv)
2404 goto out;
2405
2406 /* Wait for the channel info to be read. */
2407 wait_event(intf->waitq,
2408 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002409 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002410 } else {
2411 /* Assume a single IPMB channel at zero. */
2412 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2413 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
2416 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002417 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
Corey Minyard50c812b2006-03-26 01:37:21 -08002419 rv = ipmi_bmc_register(intf);
2420
Corey Minyard393d2cc2005-11-07 00:59:54 -08002421 out:
2422 if (rv) {
2423 if (intf->proc_dir)
2424 remove_proc_entries(intf);
2425 kref_put(&intf->refcount, intf_free);
2426 if (i < MAX_IPMI_INTERFACES) {
2427 spin_lock_irqsave(&interfaces_lock, flags);
2428 ipmi_interfaces[i] = NULL;
2429 spin_unlock_irqrestore(&interfaces_lock, flags);
2430 }
2431 } else {
2432 spin_lock_irqsave(&interfaces_lock, flags);
2433 ipmi_interfaces[i] = intf;
2434 spin_unlock_irqrestore(&interfaces_lock, flags);
Corey Minyard50c812b2006-03-26 01:37:21 -08002435 call_smi_watchers(i, intf->si_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 }
2437
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 return rv;
2439}
2440
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441int ipmi_unregister_smi(ipmi_smi_t intf)
2442{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 int i;
2444 struct ipmi_smi_watcher *w;
2445 unsigned long flags;
2446
Corey Minyard50c812b2006-03-26 01:37:21 -08002447 ipmi_bmc_unregister(intf);
2448
Corey Minyard393d2cc2005-11-07 00:59:54 -08002449 spin_lock_irqsave(&interfaces_lock, flags);
2450 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
2451 if (ipmi_interfaces[i] == intf) {
2452 /* Set the interface number reserved until we
2453 * are done. */
2454 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
2455 intf->intf_num = -1;
2456 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002459 spin_unlock_irqrestore(&interfaces_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
Corey Minyard393d2cc2005-11-07 00:59:54 -08002461 if (i == MAX_IPMI_INTERFACES)
2462 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
Corey Minyard393d2cc2005-11-07 00:59:54 -08002464 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
2466 /* Call all the watcher interfaces to tell them that
2467 an interface is gone. */
2468 down_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002469 list_for_each_entry(w, &smi_watchers, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 w->smi_gone(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 up_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002472
2473 /* Allow the entry to be reused now. */
2474 spin_lock_irqsave(&interfaces_lock, flags);
2475 ipmi_interfaces[i] = NULL;
2476 spin_unlock_irqrestore(&interfaces_lock,flags);
2477
2478 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 return 0;
2480}
2481
2482static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2483 struct ipmi_smi_msg *msg)
2484{
2485 struct ipmi_ipmb_addr ipmb_addr;
2486 struct ipmi_recv_msg *recv_msg;
2487 unsigned long flags;
2488
2489
2490 /* This is 11, not 10, because the response must contain a
2491 * completion code. */
2492 if (msg->rsp_size < 11) {
2493 /* Message not big enough, just ignore it. */
2494 spin_lock_irqsave(&intf->counter_lock, flags);
2495 intf->invalid_ipmb_responses++;
2496 spin_unlock_irqrestore(&intf->counter_lock, flags);
2497 return 0;
2498 }
2499
2500 if (msg->rsp[2] != 0) {
2501 /* An error getting the response, just ignore it. */
2502 return 0;
2503 }
2504
2505 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
2506 ipmb_addr.slave_addr = msg->rsp[6];
2507 ipmb_addr.channel = msg->rsp[3] & 0x0f;
2508 ipmb_addr.lun = msg->rsp[7] & 3;
2509
2510 /* It's a response from a remote entity. Look up the sequence
2511 number and handle the response. */
2512 if (intf_find_seq(intf,
2513 msg->rsp[7] >> 2,
2514 msg->rsp[3] & 0x0f,
2515 msg->rsp[8],
2516 (msg->rsp[4] >> 2) & (~1),
2517 (struct ipmi_addr *) &(ipmb_addr),
2518 &recv_msg))
2519 {
2520 /* We were unable to find the sequence number,
2521 so just nuke the message. */
2522 spin_lock_irqsave(&intf->counter_lock, flags);
2523 intf->unhandled_ipmb_responses++;
2524 spin_unlock_irqrestore(&intf->counter_lock, flags);
2525 return 0;
2526 }
2527
2528 memcpy(recv_msg->msg_data,
2529 &(msg->rsp[9]),
2530 msg->rsp_size - 9);
2531 /* THe other fields matched, so no need to set them, except
2532 for netfn, which needs to be the response that was
2533 returned, not the request value. */
2534 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2535 recv_msg->msg.data = recv_msg->msg_data;
2536 recv_msg->msg.data_len = msg->rsp_size - 10;
2537 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2538 spin_lock_irqsave(&intf->counter_lock, flags);
2539 intf->handled_ipmb_responses++;
2540 spin_unlock_irqrestore(&intf->counter_lock, flags);
2541 deliver_response(recv_msg);
2542
2543 return 0;
2544}
2545
2546static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2547 struct ipmi_smi_msg *msg)
2548{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002549 struct cmd_rcvr *rcvr;
2550 int rv = 0;
2551 unsigned char netfn;
2552 unsigned char cmd;
2553 ipmi_user_t user = NULL;
2554 struct ipmi_ipmb_addr *ipmb_addr;
2555 struct ipmi_recv_msg *recv_msg;
2556 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557
2558 if (msg->rsp_size < 10) {
2559 /* Message not big enough, just ignore it. */
2560 spin_lock_irqsave(&intf->counter_lock, flags);
2561 intf->invalid_commands++;
2562 spin_unlock_irqrestore(&intf->counter_lock, flags);
2563 return 0;
2564 }
2565
2566 if (msg->rsp[2] != 0) {
2567 /* An error getting the response, just ignore it. */
2568 return 0;
2569 }
2570
2571 netfn = msg->rsp[4] >> 2;
2572 cmd = msg->rsp[8];
2573
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002574 rcu_read_lock();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002575 rcvr = find_cmd_rcvr(intf, netfn, cmd);
2576 if (rcvr) {
2577 user = rcvr->user;
2578 kref_get(&user->refcount);
2579 } else
2580 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002581 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582
2583 if (user == NULL) {
2584 /* We didn't find a user, deliver an error response. */
2585 spin_lock_irqsave(&intf->counter_lock, flags);
2586 intf->unhandled_commands++;
2587 spin_unlock_irqrestore(&intf->counter_lock, flags);
2588
2589 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2590 msg->data[1] = IPMI_SEND_MSG_CMD;
2591 msg->data[2] = msg->rsp[3];
2592 msg->data[3] = msg->rsp[6];
2593 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2594 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002595 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 /* rqseq/lun */
2597 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2598 msg->data[8] = msg->rsp[8]; /* cmd */
2599 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2600 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2601 msg->data_size = 11;
2602
2603#ifdef DEBUG_MSGING
2604 {
2605 int m;
2606 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002607 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 printk(" %2.2x", msg->data[m]);
2609 printk("\n");
2610 }
2611#endif
2612 intf->handlers->sender(intf->send_info, msg, 0);
2613
2614 rv = -1; /* We used the message, so return the value that
2615 causes it to not be freed or queued. */
2616 } else {
2617 /* Deliver the message to the user. */
2618 spin_lock_irqsave(&intf->counter_lock, flags);
2619 intf->handled_commands++;
2620 spin_unlock_irqrestore(&intf->counter_lock, flags);
2621
2622 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002623 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 /* We couldn't allocate memory for the
2625 message, so requeue it for handling
2626 later. */
2627 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002628 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 } else {
2630 /* Extract the source address from the data. */
2631 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2632 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2633 ipmb_addr->slave_addr = msg->rsp[6];
2634 ipmb_addr->lun = msg->rsp[7] & 3;
2635 ipmb_addr->channel = msg->rsp[3] & 0xf;
2636
2637 /* Extract the rest of the message information
2638 from the IPMB header.*/
2639 recv_msg->user = user;
2640 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2641 recv_msg->msgid = msg->rsp[7] >> 2;
2642 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2643 recv_msg->msg.cmd = msg->rsp[8];
2644 recv_msg->msg.data = recv_msg->msg_data;
2645
2646 /* We chop off 10, not 9 bytes because the checksum
2647 at the end also needs to be removed. */
2648 recv_msg->msg.data_len = msg->rsp_size - 10;
2649 memcpy(recv_msg->msg_data,
2650 &(msg->rsp[9]),
2651 msg->rsp_size - 10);
2652 deliver_response(recv_msg);
2653 }
2654 }
2655
2656 return rv;
2657}
2658
2659static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
2660 struct ipmi_smi_msg *msg)
2661{
2662 struct ipmi_lan_addr lan_addr;
2663 struct ipmi_recv_msg *recv_msg;
2664 unsigned long flags;
2665
2666
2667 /* This is 13, not 12, because the response must contain a
2668 * completion code. */
2669 if (msg->rsp_size < 13) {
2670 /* Message not big enough, just ignore it. */
2671 spin_lock_irqsave(&intf->counter_lock, flags);
2672 intf->invalid_lan_responses++;
2673 spin_unlock_irqrestore(&intf->counter_lock, flags);
2674 return 0;
2675 }
2676
2677 if (msg->rsp[2] != 0) {
2678 /* An error getting the response, just ignore it. */
2679 return 0;
2680 }
2681
2682 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
2683 lan_addr.session_handle = msg->rsp[4];
2684 lan_addr.remote_SWID = msg->rsp[8];
2685 lan_addr.local_SWID = msg->rsp[5];
2686 lan_addr.channel = msg->rsp[3] & 0x0f;
2687 lan_addr.privilege = msg->rsp[3] >> 4;
2688 lan_addr.lun = msg->rsp[9] & 3;
2689
2690 /* It's a response from a remote entity. Look up the sequence
2691 number and handle the response. */
2692 if (intf_find_seq(intf,
2693 msg->rsp[9] >> 2,
2694 msg->rsp[3] & 0x0f,
2695 msg->rsp[10],
2696 (msg->rsp[6] >> 2) & (~1),
2697 (struct ipmi_addr *) &(lan_addr),
2698 &recv_msg))
2699 {
2700 /* We were unable to find the sequence number,
2701 so just nuke the message. */
2702 spin_lock_irqsave(&intf->counter_lock, flags);
2703 intf->unhandled_lan_responses++;
2704 spin_unlock_irqrestore(&intf->counter_lock, flags);
2705 return 0;
2706 }
2707
2708 memcpy(recv_msg->msg_data,
2709 &(msg->rsp[11]),
2710 msg->rsp_size - 11);
2711 /* The other fields matched, so no need to set them, except
2712 for netfn, which needs to be the response that was
2713 returned, not the request value. */
2714 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2715 recv_msg->msg.data = recv_msg->msg_data;
2716 recv_msg->msg.data_len = msg->rsp_size - 12;
2717 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2718 spin_lock_irqsave(&intf->counter_lock, flags);
2719 intf->handled_lan_responses++;
2720 spin_unlock_irqrestore(&intf->counter_lock, flags);
2721 deliver_response(recv_msg);
2722
2723 return 0;
2724}
2725
2726static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2727 struct ipmi_smi_msg *msg)
2728{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002729 struct cmd_rcvr *rcvr;
2730 int rv = 0;
2731 unsigned char netfn;
2732 unsigned char cmd;
2733 ipmi_user_t user = NULL;
2734 struct ipmi_lan_addr *lan_addr;
2735 struct ipmi_recv_msg *recv_msg;
2736 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737
2738 if (msg->rsp_size < 12) {
2739 /* Message not big enough, just ignore it. */
2740 spin_lock_irqsave(&intf->counter_lock, flags);
2741 intf->invalid_commands++;
2742 spin_unlock_irqrestore(&intf->counter_lock, flags);
2743 return 0;
2744 }
2745
2746 if (msg->rsp[2] != 0) {
2747 /* An error getting the response, just ignore it. */
2748 return 0;
2749 }
2750
2751 netfn = msg->rsp[6] >> 2;
2752 cmd = msg->rsp[10];
2753
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002754 rcu_read_lock();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002755 rcvr = find_cmd_rcvr(intf, netfn, cmd);
2756 if (rcvr) {
2757 user = rcvr->user;
2758 kref_get(&user->refcount);
2759 } else
2760 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002761 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
2763 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002764 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 spin_lock_irqsave(&intf->counter_lock, flags);
2766 intf->unhandled_commands++;
2767 spin_unlock_irqrestore(&intf->counter_lock, flags);
2768
2769 rv = 0; /* Don't do anything with these messages, just
2770 allow them to be freed. */
2771 } else {
2772 /* Deliver the message to the user. */
2773 spin_lock_irqsave(&intf->counter_lock, flags);
2774 intf->handled_commands++;
2775 spin_unlock_irqrestore(&intf->counter_lock, flags);
2776
2777 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002778 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 /* We couldn't allocate memory for the
2780 message, so requeue it for handling
2781 later. */
2782 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002783 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 } else {
2785 /* Extract the source address from the data. */
2786 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
2787 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
2788 lan_addr->session_handle = msg->rsp[4];
2789 lan_addr->remote_SWID = msg->rsp[8];
2790 lan_addr->local_SWID = msg->rsp[5];
2791 lan_addr->lun = msg->rsp[9] & 3;
2792 lan_addr->channel = msg->rsp[3] & 0xf;
2793 lan_addr->privilege = msg->rsp[3] >> 4;
2794
2795 /* Extract the rest of the message information
2796 from the IPMB header.*/
2797 recv_msg->user = user;
2798 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2799 recv_msg->msgid = msg->rsp[9] >> 2;
2800 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2801 recv_msg->msg.cmd = msg->rsp[10];
2802 recv_msg->msg.data = recv_msg->msg_data;
2803
2804 /* We chop off 12, not 11 bytes because the checksum
2805 at the end also needs to be removed. */
2806 recv_msg->msg.data_len = msg->rsp_size - 12;
2807 memcpy(recv_msg->msg_data,
2808 &(msg->rsp[11]),
2809 msg->rsp_size - 12);
2810 deliver_response(recv_msg);
2811 }
2812 }
2813
2814 return rv;
2815}
2816
2817static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
2818 struct ipmi_smi_msg *msg)
2819{
2820 struct ipmi_system_interface_addr *smi_addr;
2821
2822 recv_msg->msgid = 0;
2823 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
2824 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2825 smi_addr->channel = IPMI_BMC_CHANNEL;
2826 smi_addr->lun = msg->rsp[0] & 3;
2827 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
2828 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2829 recv_msg->msg.cmd = msg->rsp[1];
2830 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
2831 recv_msg->msg.data = recv_msg->msg_data;
2832 recv_msg->msg.data_len = msg->rsp_size - 3;
2833}
2834
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835static int handle_read_event_rsp(ipmi_smi_t intf,
2836 struct ipmi_smi_msg *msg)
2837{
2838 struct ipmi_recv_msg *recv_msg, *recv_msg2;
2839 struct list_head msgs;
2840 ipmi_user_t user;
2841 int rv = 0;
2842 int deliver_count = 0;
2843 unsigned long flags;
2844
2845 if (msg->rsp_size < 19) {
2846 /* Message is too small to be an IPMB event. */
2847 spin_lock_irqsave(&intf->counter_lock, flags);
2848 intf->invalid_events++;
2849 spin_unlock_irqrestore(&intf->counter_lock, flags);
2850 return 0;
2851 }
2852
2853 if (msg->rsp[2] != 0) {
2854 /* An error getting the event, just ignore it. */
2855 return 0;
2856 }
2857
2858 INIT_LIST_HEAD(&msgs);
2859
Corey Minyard393d2cc2005-11-07 00:59:54 -08002860 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861
2862 spin_lock(&intf->counter_lock);
2863 intf->events++;
2864 spin_unlock(&intf->counter_lock);
2865
2866 /* Allocate and fill in one message for every user that is getting
2867 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002868 rcu_read_lock();
2869 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08002870 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 continue;
2872
2873 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002874 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002875 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002876 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
2877 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 list_del(&recv_msg->link);
2879 ipmi_free_recv_msg(recv_msg);
2880 }
2881 /* We couldn't allocate memory for the
2882 message, so requeue it for handling
2883 later. */
2884 rv = 1;
2885 goto out;
2886 }
2887
2888 deliver_count++;
2889
2890 copy_event_into_recv_msg(recv_msg, msg);
2891 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002892 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 list_add_tail(&(recv_msg->link), &msgs);
2894 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002895 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
2897 if (deliver_count) {
2898 /* Now deliver all the messages. */
2899 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
2900 list_del(&recv_msg->link);
2901 deliver_response(recv_msg);
2902 }
2903 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
2904 /* No one to receive the message, put it in queue if there's
2905 not already too many things in the queue. */
2906 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002907 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 /* We couldn't allocate memory for the
2909 message, so requeue it for handling
2910 later. */
2911 rv = 1;
2912 goto out;
2913 }
2914
2915 copy_event_into_recv_msg(recv_msg, msg);
2916 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
Corey Minyard4791c032006-04-10 22:54:31 -07002917 intf->waiting_events_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 } else {
2919 /* There's too many things in the queue, discard this
2920 message. */
2921 printk(KERN_WARNING PFX "Event queue full, discarding an"
2922 " incoming event\n");
2923 }
2924
2925 out:
2926 spin_unlock_irqrestore(&(intf->events_lock), flags);
2927
2928 return rv;
2929}
2930
2931static int handle_bmc_rsp(ipmi_smi_t intf,
2932 struct ipmi_smi_msg *msg)
2933{
2934 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002936 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
2938 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002939 if (recv_msg == NULL)
2940 {
2941 printk(KERN_WARNING"IPMI message received with no owner. This\n"
2942 "could be because of a malformed message, or\n"
2943 "because of a hardware error. Contact your\n"
2944 "hardware vender for assistance\n");
2945 return 0;
2946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947
Corey Minyard393d2cc2005-11-07 00:59:54 -08002948 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002950 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07002951 /* The user for the message went away, so give up. */
2952 spin_lock_irqsave(&intf->counter_lock, flags);
2953 intf->unhandled_local_responses++;
2954 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 ipmi_free_recv_msg(recv_msg);
2956 } else {
2957 struct ipmi_system_interface_addr *smi_addr;
2958
2959 spin_lock_irqsave(&intf->counter_lock, flags);
2960 intf->handled_local_responses++;
2961 spin_unlock_irqrestore(&intf->counter_lock, flags);
2962 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2963 recv_msg->msgid = msg->msgid;
2964 smi_addr = ((struct ipmi_system_interface_addr *)
2965 &(recv_msg->addr));
2966 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2967 smi_addr->channel = IPMI_BMC_CHANNEL;
2968 smi_addr->lun = msg->rsp[0] & 3;
2969 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2970 recv_msg->msg.cmd = msg->rsp[1];
2971 memcpy(recv_msg->msg_data,
2972 &(msg->rsp[2]),
2973 msg->rsp_size - 2);
2974 recv_msg->msg.data = recv_msg->msg_data;
2975 recv_msg->msg.data_len = msg->rsp_size - 2;
2976 deliver_response(recv_msg);
2977 }
2978
2979 return 0;
2980}
2981
2982/* Handle a new message. Return 1 if the message should be requeued,
2983 0 if the message should be freed, or -1 if the message should not
2984 be freed or requeued. */
2985static int handle_new_recv_msg(ipmi_smi_t intf,
2986 struct ipmi_smi_msg *msg)
2987{
2988 int requeue;
2989 int chan;
2990
2991#ifdef DEBUG_MSGING
2992 int m;
2993 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002994 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 printk(" %2.2x", msg->rsp[m]);
2996 printk("\n");
2997#endif
2998 if (msg->rsp_size < 2) {
2999 /* Message is too small to be correct. */
3000 printk(KERN_WARNING PFX "BMC returned to small a message"
3001 " for netfn %x cmd %x, got %d bytes\n",
3002 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3003
3004 /* Generate an error response for the message. */
3005 msg->rsp[0] = msg->data[0] | (1 << 2);
3006 msg->rsp[1] = msg->data[1];
3007 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3008 msg->rsp_size = 3;
3009 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3010 || (msg->rsp[1] != msg->data[1])) /* Command */
3011 {
3012 /* The response is not even marginally correct. */
3013 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3014 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3015 (msg->data[0] >> 2) | 1, msg->data[1],
3016 msg->rsp[0] >> 2, msg->rsp[1]);
3017
3018 /* Generate an error response for the message. */
3019 msg->rsp[0] = msg->data[0] | (1 << 2);
3020 msg->rsp[1] = msg->data[1];
3021 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3022 msg->rsp_size = 3;
3023 }
3024
3025 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3026 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3027 && (msg->user_data != NULL))
3028 {
3029 /* It's a response to a response we sent. For this we
3030 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003031 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032
3033 requeue = 0;
3034 if (msg->rsp_size < 2)
3035 /* Message is too small to be correct. */
3036 goto out;
3037
3038 chan = msg->data[2] & 0x0f;
3039 if (chan >= IPMI_MAX_CHANNELS)
3040 /* Invalid channel number */
3041 goto out;
3042
Corey Minyard393d2cc2005-11-07 00:59:54 -08003043 if (!recv_msg)
3044 goto out;
3045
3046 /* Make sure the user still exists. */
3047 if (!recv_msg->user || !recv_msg->user->valid)
3048 goto out;
3049
3050 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3051 recv_msg->msg.data = recv_msg->msg_data;
3052 recv_msg->msg.data_len = 1;
3053 recv_msg->msg_data[0] = msg->rsp[2];
3054 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3056 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3057 {
3058 /* It's from the receive queue. */
3059 chan = msg->rsp[3] & 0xf;
3060 if (chan >= IPMI_MAX_CHANNELS) {
3061 /* Invalid channel number */
3062 requeue = 0;
3063 goto out;
3064 }
3065
3066 switch (intf->channels[chan].medium) {
3067 case IPMI_CHANNEL_MEDIUM_IPMB:
3068 if (msg->rsp[4] & 0x04) {
3069 /* It's a response, so find the
3070 requesting message and send it up. */
3071 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3072 } else {
3073 /* It's a command to the SMS from some other
3074 entity. Handle that. */
3075 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3076 }
3077 break;
3078
3079 case IPMI_CHANNEL_MEDIUM_8023LAN:
3080 case IPMI_CHANNEL_MEDIUM_ASYNC:
3081 if (msg->rsp[6] & 0x04) {
3082 /* It's a response, so find the
3083 requesting message and send it up. */
3084 requeue = handle_lan_get_msg_rsp(intf, msg);
3085 } else {
3086 /* It's a command to the SMS from some other
3087 entity. Handle that. */
3088 requeue = handle_lan_get_msg_cmd(intf, msg);
3089 }
3090 break;
3091
3092 default:
3093 /* We don't handle the channel type, so just
3094 * free the message. */
3095 requeue = 0;
3096 }
3097
3098 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3099 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3100 {
3101 /* It's an asyncronous event. */
3102 requeue = handle_read_event_rsp(intf, msg);
3103 } else {
3104 /* It's a response from the local BMC. */
3105 requeue = handle_bmc_rsp(intf, msg);
3106 }
3107
3108 out:
3109 return requeue;
3110}
3111
3112/* Handle a new message from the lower layer. */
3113void ipmi_smi_msg_received(ipmi_smi_t intf,
3114 struct ipmi_smi_msg *msg)
3115{
3116 unsigned long flags;
3117 int rv;
3118
3119
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 if ((msg->data_size >= 2)
3121 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3122 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003123 && (msg->user_data == NULL))
3124 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 /* This is the local response to a command send, start
3126 the timer for these. The user_data will not be
3127 NULL if this is a response send, and we will let
3128 response sends just go through. */
3129
3130 /* Check for errors, if we get certain errors (ones
3131 that mean basically we can try again later), we
3132 ignore them and start the timer. Otherwise we
3133 report the error immediately. */
3134 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3135 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
3136 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR))
3137 {
3138 int chan = msg->rsp[3] & 0xf;
3139
3140 /* Got an error sending the message, handle it. */
3141 spin_lock_irqsave(&intf->counter_lock, flags);
3142 if (chan >= IPMI_MAX_CHANNELS)
3143 ; /* This shouldn't happen */
3144 else if ((intf->channels[chan].medium
3145 == IPMI_CHANNEL_MEDIUM_8023LAN)
3146 || (intf->channels[chan].medium
3147 == IPMI_CHANNEL_MEDIUM_ASYNC))
3148 intf->sent_lan_command_errs++;
3149 else
3150 intf->sent_ipmb_command_errs++;
3151 spin_unlock_irqrestore(&intf->counter_lock, flags);
3152 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3153 } else {
3154 /* The message was sent, start the timer. */
3155 intf_start_seq_timer(intf, msg->msgid);
3156 }
3157
3158 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003159 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 }
3161
3162 /* To preserve message order, if the list is not empty, we
3163 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003164 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
3165 if (!list_empty(&intf->waiting_msgs)) {
3166 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003167 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003168 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003170 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
3172 rv = handle_new_recv_msg(intf, msg);
3173 if (rv > 0) {
3174 /* Could not handle the message now, just add it to a
3175 list to handle later. */
Hironobu Ishii177294d2005-11-11 08:12:21 -06003176 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003177 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003178 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 } else if (rv == 0) {
3180 ipmi_free_smi_msg(msg);
3181 }
3182
Corey Minyard393d2cc2005-11-07 00:59:54 -08003183 out:
3184 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185}
3186
3187void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3188{
3189 ipmi_user_t user;
3190
Corey Minyard393d2cc2005-11-07 00:59:54 -08003191 rcu_read_lock();
3192 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003193 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 continue;
3195
3196 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3197 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003198 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199}
3200
3201static void
3202handle_msg_timeout(struct ipmi_recv_msg *msg)
3203{
3204 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3205 msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;
3206 msg->msg.netfn |= 1; /* Convert to a response. */
3207 msg->msg.data_len = 1;
3208 msg->msg.data = msg->msg_data;
3209 deliver_response(msg);
3210}
3211
Corey Minyard882fe012005-05-01 08:59:12 -07003212static struct ipmi_smi_msg *
3213smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3214 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215{
Corey Minyard882fe012005-05-01 08:59:12 -07003216 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 if (!smi_msg)
3218 /* If we can't allocate the message, then just return, we
3219 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003220 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221
3222 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3223 smi_msg->data_size = recv_msg->msg.data_len;
3224 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3225
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226#ifdef DEBUG_MSGING
3227 {
3228 int m;
3229 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003230 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 printk(" %2.2x", smi_msg->data[m]);
3232 printk("\n");
3233 }
3234#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003235 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236}
3237
Corey Minyard393d2cc2005-11-07 00:59:54 -08003238static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3239 struct list_head *timeouts, long timeout_period,
3240 int slot, unsigned long *flags)
3241{
3242 struct ipmi_recv_msg *msg;
3243
3244 if (!ent->inuse)
3245 return;
3246
3247 ent->timeout -= timeout_period;
3248 if (ent->timeout > 0)
3249 return;
3250
3251 if (ent->retries_left == 0) {
3252 /* The message has used all its retries. */
3253 ent->inuse = 0;
3254 msg = ent->recv_msg;
3255 list_add_tail(&msg->link, timeouts);
3256 spin_lock(&intf->counter_lock);
3257 if (ent->broadcast)
3258 intf->timed_out_ipmb_broadcasts++;
3259 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3260 intf->timed_out_lan_commands++;
3261 else
3262 intf->timed_out_ipmb_commands++;
3263 spin_unlock(&intf->counter_lock);
3264 } else {
3265 struct ipmi_smi_msg *smi_msg;
3266 /* More retries, send again. */
3267
3268 /* Start with the max timer, set to normal
3269 timer after the message is sent. */
3270 ent->timeout = MAX_MSG_TIMEOUT;
3271 ent->retries_left--;
3272 spin_lock(&intf->counter_lock);
3273 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3274 intf->retransmitted_lan_commands++;
3275 else
3276 intf->retransmitted_ipmb_commands++;
3277 spin_unlock(&intf->counter_lock);
3278
3279 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3280 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003281 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003282 return;
3283
3284 spin_unlock_irqrestore(&intf->seq_lock, *flags);
3285 /* Send the new message. We send with a zero
3286 * priority. It timed out, I doubt time is
3287 * that critical now, and high priority
3288 * messages are really only for messages to the
3289 * local MC, which don't get resent. */
3290 intf->handlers->sender(intf->send_info,
3291 smi_msg, 0);
3292 spin_lock_irqsave(&intf->seq_lock, *flags);
3293 }
3294}
3295
3296static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297{
3298 ipmi_smi_t intf;
3299 struct list_head timeouts;
3300 struct ipmi_recv_msg *msg, *msg2;
3301 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3302 unsigned long flags;
3303 int i, j;
3304
3305 INIT_LIST_HEAD(&timeouts);
3306
3307 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07003308 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003310 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 continue;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003312 kref_get(&intf->refcount);
3313 spin_unlock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314
3315 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003316 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003317 list_for_each_entry_safe(smi_msg, smi_msg2,
3318 &intf->waiting_msgs, link) {
3319 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 list_del(&smi_msg->link);
3321 ipmi_free_smi_msg(smi_msg);
3322 } else {
3323 /* To preserve message order, quit if we
3324 can't handle a message. */
3325 break;
3326 }
3327 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003328 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
3330 /* Go through the seq table and find any messages that
3331 have timed out, putting them in the timeouts
3332 list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003333 spin_lock_irqsave(&intf->seq_lock, flags);
3334 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++)
3335 check_msg_timeout(intf, &(intf->seq_table[j]),
3336 &timeouts, timeout_period, j,
3337 &flags);
3338 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
Corey Minyard393d2cc2005-11-07 00:59:54 -08003340 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 handle_msg_timeout(msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342
Corey Minyard393d2cc2005-11-07 00:59:54 -08003343 kref_put(&intf->refcount, intf_free);
3344 spin_lock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 }
3346 spin_unlock(&interfaces_lock);
3347}
3348
3349static void ipmi_request_event(void)
3350{
3351 ipmi_smi_t intf;
3352 int i;
3353
3354 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07003355 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003357 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 continue;
3359
3360 intf->handlers->request_events(intf->send_info);
3361 }
3362 spin_unlock(&interfaces_lock);
3363}
3364
3365static struct timer_list ipmi_timer;
3366
3367/* Call every ~100 ms. */
3368#define IPMI_TIMEOUT_TIME 100
3369
3370/* How many jiffies does it take to get to the timeout time. */
3371#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3372
3373/* Request events from the queue every second (this is the number of
3374 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3375 future, IPMI will add a way to know immediately if an event is in
3376 the queue and this silliness can go away. */
3377#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3378
Corey Minyard8f43f842005-06-23 22:01:40 -07003379static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3381
3382static void ipmi_timeout(unsigned long data)
3383{
Corey Minyard8f43f842005-06-23 22:01:40 -07003384 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386
3387 ticks_to_req_ev--;
3388 if (ticks_to_req_ev == 0) {
3389 ipmi_request_event();
3390 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3391 }
3392
3393 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3394
Corey Minyard8f43f842005-06-23 22:01:40 -07003395 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396}
3397
3398
3399static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3400static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3401
3402/* FIXME - convert these to slabs. */
3403static void free_smi_msg(struct ipmi_smi_msg *msg)
3404{
3405 atomic_dec(&smi_msg_inuse_count);
3406 kfree(msg);
3407}
3408
3409struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3410{
3411 struct ipmi_smi_msg *rv;
3412 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3413 if (rv) {
3414 rv->done = free_smi_msg;
3415 rv->user_data = NULL;
3416 atomic_inc(&smi_msg_inuse_count);
3417 }
3418 return rv;
3419}
3420
3421static void free_recv_msg(struct ipmi_recv_msg *msg)
3422{
3423 atomic_dec(&recv_msg_inuse_count);
3424 kfree(msg);
3425}
3426
3427struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3428{
3429 struct ipmi_recv_msg *rv;
3430
3431 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3432 if (rv) {
3433 rv->done = free_recv_msg;
3434 atomic_inc(&recv_msg_inuse_count);
3435 }
3436 return rv;
3437}
3438
Corey Minyard393d2cc2005-11-07 00:59:54 -08003439void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3440{
3441 if (msg->user)
3442 kref_put(&msg->user->refcount, free_user);
3443 msg->done(msg);
3444}
3445
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446#ifdef CONFIG_IPMI_PANIC_EVENT
3447
3448static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3449{
3450}
3451
3452static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3453{
3454}
3455
3456#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003457static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003459 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3460 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3461 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3462 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 {
3464 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003465 intf->event_receiver = msg->msg.data[1];
3466 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 }
3468}
3469
Corey Minyard56a55ec2005-09-06 15:18:42 -07003470static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003472 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3473 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3474 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3475 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 {
3477 /* A get device id command, save if we are an event
3478 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003479 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3480 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 }
3482}
3483#endif
3484
3485static void send_panic_events(char *str)
3486{
3487 struct kernel_ipmi_msg msg;
3488 ipmi_smi_t intf;
3489 unsigned char data[16];
3490 int i;
3491 struct ipmi_system_interface_addr *si;
3492 struct ipmi_addr addr;
3493 struct ipmi_smi_msg smi_msg;
3494 struct ipmi_recv_msg recv_msg;
3495
3496 si = (struct ipmi_system_interface_addr *) &addr;
3497 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3498 si->channel = IPMI_BMC_CHANNEL;
3499 si->lun = 0;
3500
3501 /* Fill in an event telling that we have failed. */
3502 msg.netfn = 0x04; /* Sensor or Event. */
3503 msg.cmd = 2; /* Platform event command. */
3504 msg.data = data;
3505 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003506 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 data[1] = 0x03; /* This is for IPMI 1.0. */
3508 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3509 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3510 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3511
3512 /* Put a few breadcrumbs in. Hopefully later we can add more things
3513 to make the panic events more useful. */
3514 if (str) {
3515 data[3] = str[0];
3516 data[6] = str[1];
3517 data[7] = str[2];
3518 }
3519
3520 smi_msg.done = dummy_smi_done_handler;
3521 recv_msg.done = dummy_recv_done_handler;
3522
3523 /* For every registered interface, send the event. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003524 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003526 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 continue;
3528
3529 /* Send the event announcing the panic. */
3530 intf->handlers->set_run_to_completion(intf->send_info, 1);
3531 i_ipmi_request(NULL,
3532 intf,
3533 &addr,
3534 0,
3535 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003536 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 &smi_msg,
3538 &recv_msg,
3539 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003540 intf->channels[0].address,
3541 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 0, 1); /* Don't retry, and don't wait. */
3543 }
3544
3545#ifdef CONFIG_IPMI_PANIC_STRING
3546 /* On every interface, dump a bunch of OEM event holding the
3547 string. */
3548 if (!str)
3549 return;
3550
Corey Minyarde8b33612005-09-06 15:18:45 -07003551 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 char *p = str;
3553 struct ipmi_ipmb_addr *ipmb;
3554 int j;
3555
3556 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003557 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 continue;
3559
3560 /* First job here is to figure out where to send the
3561 OEM events. There's no way in IPMI to send OEM
3562 events using an event send command, so we have to
3563 find the SEL to put them in and stick them in
3564 there. */
3565
3566 /* Get capabilities from the get device id. */
3567 intf->local_sel_device = 0;
3568 intf->local_event_generator = 0;
3569 intf->event_receiver = 0;
3570
3571 /* Request the device info from the local MC. */
3572 msg.netfn = IPMI_NETFN_APP_REQUEST;
3573 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3574 msg.data = NULL;
3575 msg.data_len = 0;
3576 intf->null_user_handler = device_id_fetcher;
3577 i_ipmi_request(NULL,
3578 intf,
3579 &addr,
3580 0,
3581 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003582 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 &smi_msg,
3584 &recv_msg,
3585 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003586 intf->channels[0].address,
3587 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 0, 1); /* Don't retry, and don't wait. */
3589
3590 if (intf->local_event_generator) {
3591 /* Request the event receiver from the local MC. */
3592 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3593 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3594 msg.data = NULL;
3595 msg.data_len = 0;
3596 intf->null_user_handler = event_receiver_fetcher;
3597 i_ipmi_request(NULL,
3598 intf,
3599 &addr,
3600 0,
3601 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003602 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 &smi_msg,
3604 &recv_msg,
3605 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003606 intf->channels[0].address,
3607 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 0, 1); /* no retry, and no wait. */
3609 }
3610 intf->null_user_handler = NULL;
3611
3612 /* Validate the event receiver. The low bit must not
3613 be 1 (it must be a valid IPMB address), it cannot
3614 be zero, and it must not be my address. */
3615 if (((intf->event_receiver & 1) == 0)
3616 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003617 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 {
3619 /* The event receiver is valid, send an IPMB
3620 message. */
3621 ipmb = (struct ipmi_ipmb_addr *) &addr;
3622 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3623 ipmb->channel = 0; /* FIXME - is this right? */
3624 ipmb->lun = intf->event_receiver_lun;
3625 ipmb->slave_addr = intf->event_receiver;
3626 } else if (intf->local_sel_device) {
3627 /* The event receiver was not valid (or was
3628 me), but I am an SEL device, just dump it
3629 in my SEL. */
3630 si = (struct ipmi_system_interface_addr *) &addr;
3631 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3632 si->channel = IPMI_BMC_CHANNEL;
3633 si->lun = 0;
3634 } else
3635 continue; /* No where to send the event. */
3636
3637
3638 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
3639 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
3640 msg.data = data;
3641 msg.data_len = 16;
3642
3643 j = 0;
3644 while (*p) {
3645 int size = strlen(p);
3646
3647 if (size > 11)
3648 size = 11;
3649 data[0] = 0;
3650 data[1] = 0;
3651 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07003652 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 data[4] = j++; /* sequence # */
3654 /* Always give 11 bytes, so strncpy will fill
3655 it with zeroes for me. */
3656 strncpy(data+5, p, 11);
3657 p += size;
3658
3659 i_ipmi_request(NULL,
3660 intf,
3661 &addr,
3662 0,
3663 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003664 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 &smi_msg,
3666 &recv_msg,
3667 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003668 intf->channels[0].address,
3669 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 0, 1); /* no retry, and no wait. */
3671 }
3672 }
3673#endif /* CONFIG_IPMI_PANIC_STRING */
3674}
3675#endif /* CONFIG_IPMI_PANIC_EVENT */
3676
3677static int has_paniced = 0;
3678
3679static int panic_event(struct notifier_block *this,
3680 unsigned long event,
3681 void *ptr)
3682{
3683 int i;
3684 ipmi_smi_t intf;
3685
3686 if (has_paniced)
3687 return NOTIFY_DONE;
3688 has_paniced = 1;
3689
3690 /* For every registered interface, set it to run to completion. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003691 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003693 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 continue;
3695
3696 intf->handlers->set_run_to_completion(intf->send_info, 1);
3697 }
3698
3699#ifdef CONFIG_IPMI_PANIC_EVENT
3700 send_panic_events(ptr);
3701#endif
3702
3703 return NOTIFY_DONE;
3704}
3705
3706static struct notifier_block panic_block = {
3707 .notifier_call = panic_event,
3708 .next = NULL,
3709 .priority = 200 /* priority: INT_MAX >= x >= 0 */
3710};
3711
3712static int ipmi_init_msghandler(void)
3713{
3714 int i;
Corey Minyard50c812b2006-03-26 01:37:21 -08003715 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716
3717 if (initialized)
3718 return 0;
3719
Corey Minyard50c812b2006-03-26 01:37:21 -08003720 rv = driver_register(&ipmidriver);
3721 if (rv) {
3722 printk(KERN_ERR PFX "Could not register IPMI driver\n");
3723 return rv;
3724 }
3725
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003727 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728
Corey Minyard393d2cc2005-11-07 00:59:54 -08003729 for (i = 0; i < MAX_IPMI_INTERFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 ipmi_interfaces[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731
Corey Minyard3b625942005-06-23 22:01:42 -07003732#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 proc_ipmi_root = proc_mkdir("ipmi", NULL);
3734 if (!proc_ipmi_root) {
3735 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
3736 return -ENOMEM;
3737 }
3738
3739 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07003740#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741
3742 init_timer(&ipmi_timer);
3743 ipmi_timer.data = 0;
3744 ipmi_timer.function = ipmi_timeout;
3745 ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
3746 add_timer(&ipmi_timer);
3747
Alan Sterne041c682006-03-27 01:16:30 -08003748 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749
3750 initialized = 1;
3751
3752 return 0;
3753}
3754
3755static __init int ipmi_init_msghandler_mod(void)
3756{
3757 ipmi_init_msghandler();
3758 return 0;
3759}
3760
3761static __exit void cleanup_ipmi(void)
3762{
3763 int count;
3764
3765 if (!initialized)
3766 return;
3767
Alan Sterne041c682006-03-27 01:16:30 -08003768 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769
3770 /* This can't be called if any interfaces exist, so no worry about
3771 shutting down the interfaces. */
3772
3773 /* Tell the timer to stop, then wait for it to stop. This avoids
3774 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07003775 atomic_inc(&stop_operation);
3776 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777
Corey Minyard3b625942005-06-23 22:01:42 -07003778#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 remove_proc_entry(proc_ipmi_root->name, &proc_root);
Corey Minyard3b625942005-06-23 22:01:42 -07003780#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781
Corey Minyard50c812b2006-03-26 01:37:21 -08003782 driver_unregister(&ipmidriver);
3783
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 initialized = 0;
3785
3786 /* Check for buffer leaks. */
3787 count = atomic_read(&smi_msg_inuse_count);
3788 if (count != 0)
3789 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
3790 count);
3791 count = atomic_read(&recv_msg_inuse_count);
3792 if (count != 0)
3793 printk(KERN_WARNING PFX "recv message count %d at exit\n",
3794 count);
3795}
3796module_exit(cleanup_ipmi);
3797
3798module_init(ipmi_init_msghandler_mod);
3799MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003800MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
3801MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
3802MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803
3804EXPORT_SYMBOL(ipmi_create_user);
3805EXPORT_SYMBOL(ipmi_destroy_user);
3806EXPORT_SYMBOL(ipmi_get_version);
3807EXPORT_SYMBOL(ipmi_request_settime);
3808EXPORT_SYMBOL(ipmi_request_supply_msgs);
3809EXPORT_SYMBOL(ipmi_register_smi);
3810EXPORT_SYMBOL(ipmi_unregister_smi);
3811EXPORT_SYMBOL(ipmi_register_for_cmd);
3812EXPORT_SYMBOL(ipmi_unregister_for_cmd);
3813EXPORT_SYMBOL(ipmi_smi_msg_received);
3814EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
3815EXPORT_SYMBOL(ipmi_alloc_smi_msg);
3816EXPORT_SYMBOL(ipmi_addr_length);
3817EXPORT_SYMBOL(ipmi_validate_addr);
3818EXPORT_SYMBOL(ipmi_set_gets_events);
3819EXPORT_SYMBOL(ipmi_smi_watcher_register);
3820EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
3821EXPORT_SYMBOL(ipmi_set_my_address);
3822EXPORT_SYMBOL(ipmi_get_my_address);
3823EXPORT_SYMBOL(ipmi_set_my_LUN);
3824EXPORT_SYMBOL(ipmi_get_my_LUN);
3825EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003827EXPORT_SYMBOL(ipmi_free_recv_msg);