blob: 843d34c8627c38d3a72889557f216513bc9fe638 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ipmi_msghandler.c
3 *
4 * Incoming and outgoing message routing for an IPMI interface.
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2002 MontaVista Software Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/module.h>
35#include <linux/errno.h>
36#include <asm/system.h>
37#include <linux/sched.h>
38#include <linux/poll.h>
39#include <linux/spinlock.h>
Corey Minyardd6dfd132006-03-31 02:30:41 -080040#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/slab.h>
42#include <linux/ipmi.h>
43#include <linux/ipmi_smi.h>
44#include <linux/notifier.h>
45#include <linux/init.h>
46#include <linux/proc_fs.h>
Corey Minyard393d2cc2005-11-07 00:59:54 -080047#include <linux/rcupdate.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#define PFX "IPMI message handler: "
Corey Minyard1fdd75b2005-09-06 15:18:42 -070050
Corey Minyarda23f9a32006-03-26 01:37:22 -080051#define IPMI_DRIVER_VERSION "39.0"
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
54static int ipmi_init_msghandler(void);
55
56static int initialized = 0;
57
Corey Minyard3b625942005-06-23 22:01:42 -070058#ifdef CONFIG_PROC_FS
Adrian Bunk456229a2006-06-27 02:55:07 -070059static struct proc_dir_entry *proc_ipmi_root = NULL;
Corey Minyard3b625942005-06-23 22:01:42 -070060#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62#define MAX_EVENTS_IN_QUEUE 25
63
64/* Don't let a message sit in a queue forever, always time it with at lest
65 the max message timer. This is in milliseconds. */
66#define MAX_MSG_TIMEOUT 60000
67
Corey Minyard393d2cc2005-11-07 00:59:54 -080068
69/*
70 * The main "user" data structure.
71 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070072struct ipmi_user
73{
74 struct list_head link;
75
Corey Minyard393d2cc2005-11-07 00:59:54 -080076 /* Set to "0" when the user is destroyed. */
77 int valid;
78
79 struct kref refcount;
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 /* The upper layer that handles receive messages. */
82 struct ipmi_user_hndl *handler;
83 void *handler_data;
84
85 /* The interface this user is bound to. */
86 ipmi_smi_t intf;
87
88 /* Does this interface receive IPMI events? */
89 int gets_events;
90};
91
92struct cmd_rcvr
93{
94 struct list_head link;
95
96 ipmi_user_t user;
97 unsigned char netfn;
98 unsigned char cmd;
Corey Minyard393d2cc2005-11-07 00:59:54 -080099
100 /*
101 * This is used to form a linked lised during mass deletion.
102 * Since this is in an RCU list, we cannot use the link above
103 * or change any data until the RCU period completes. So we
104 * use this next variable during mass deletion so we can have
105 * a list and don't have to wait and restart the search on
106 * every individual deletion of a command. */
107 struct cmd_rcvr *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
110struct seq_table
111{
112 unsigned int inuse : 1;
113 unsigned int broadcast : 1;
114
115 unsigned long timeout;
116 unsigned long orig_timeout;
117 unsigned int retries_left;
118
119 /* To verify on an incoming send message response that this is
120 the message that the response is for, we keep a sequence id
121 and increment it every time we send a message. */
122 long seqid;
123
124 /* This is held so we can properly respond to the message on a
125 timeout, and it is used to hold the temporary data for
126 retransmission, too. */
127 struct ipmi_recv_msg *recv_msg;
128};
129
130/* Store the information in a msgid (long) to allow us to find a
131 sequence table entry from the msgid. */
132#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
133
134#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
135 do { \
136 seq = ((msgid >> 26) & 0x3f); \
137 seqid = (msgid & 0x3fffff); \
Corey Minyarde8b33612005-09-06 15:18:45 -0700138 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
141
142struct ipmi_channel
143{
144 unsigned char medium;
145 unsigned char protocol;
Corey Minyardc14979b2005-09-06 15:18:38 -0700146
147 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
148 but may be changed by the user. */
149 unsigned char address;
150
151 /* My LUN. This should generally stay the SMS LUN, but just in
152 case... */
153 unsigned char lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154};
155
Corey Minyard3b625942005-06-23 22:01:42 -0700156#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157struct ipmi_proc_entry
158{
159 char *name;
160 struct ipmi_proc_entry *next;
161};
Corey Minyard3b625942005-06-23 22:01:42 -0700162#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
Corey Minyard50c812b2006-03-26 01:37:21 -0800164struct bmc_device
165{
166 struct platform_device *dev;
167 struct ipmi_device_id id;
168 unsigned char guid[16];
169 int guid_set;
170
171 struct kref refcount;
172
173 /* bmc device attributes */
174 struct device_attribute device_id_attr;
175 struct device_attribute provides_dev_sdrs_attr;
176 struct device_attribute revision_attr;
177 struct device_attribute firmware_rev_attr;
178 struct device_attribute version_attr;
179 struct device_attribute add_dev_support_attr;
180 struct device_attribute manufacturer_id_attr;
181 struct device_attribute product_id_attr;
182 struct device_attribute guid_attr;
183 struct device_attribute aux_firmware_rev_attr;
184};
185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186#define IPMI_IPMB_NUM_SEQ 64
Corey Minyardc14979b2005-09-06 15:18:38 -0700187#define IPMI_MAX_CHANNELS 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188struct ipmi_smi
189{
190 /* What interface number are we? */
191 int intf_num;
192
Corey Minyard393d2cc2005-11-07 00:59:54 -0800193 struct kref refcount;
194
195 /* The list of upper layers that are using me. seq_lock
196 * protects this. */
197 struct list_head users;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199 /* Used for wake ups at startup. */
200 wait_queue_head_t waitq;
201
Corey Minyard50c812b2006-03-26 01:37:21 -0800202 struct bmc_device *bmc;
203 char *my_dev_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205 /* This is the lower-layer's sender routine. */
206 struct ipmi_smi_handlers *handlers;
207 void *send_info;
208
Corey Minyard3b625942005-06-23 22:01:42 -0700209#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 /* A list of proc entries for this interface. This does not
211 need a lock, only one thread creates it and only one thread
212 destroys it. */
Corey Minyard3b625942005-06-23 22:01:42 -0700213 spinlock_t proc_entry_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 struct ipmi_proc_entry *proc_entries;
Corey Minyard3b625942005-06-23 22:01:42 -0700215#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Corey Minyard50c812b2006-03-26 01:37:21 -0800217 /* Driver-model device for the system interface. */
218 struct device *si_dev;
219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 /* A table of sequence numbers for this interface. We use the
221 sequence numbers for IPMB messages that go out of the
222 interface to match them up with their responses. A routine
223 is called periodically to time the items in this list. */
224 spinlock_t seq_lock;
225 struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
226 int curr_seq;
227
228 /* Messages that were delayed for some reason (out of memory,
229 for instance), will go in here to be processed later in a
230 periodic timer interrupt. */
231 spinlock_t waiting_msgs_lock;
232 struct list_head waiting_msgs;
233
234 /* The list of command receivers that are registered for commands
235 on this interface. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800236 struct mutex cmd_rcvrs_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 struct list_head cmd_rcvrs;
238
239 /* Events that were queues because no one was there to receive
240 them. */
241 spinlock_t events_lock; /* For dealing with event stuff. */
242 struct list_head waiting_events;
243 unsigned int waiting_events_count; /* How many events in queue? */
244
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 /* The event receiver for my BMC, only really used at panic
246 shutdown as a place to store this. */
247 unsigned char event_receiver;
248 unsigned char event_receiver_lun;
249 unsigned char local_sel_device;
250 unsigned char local_event_generator;
251
252 /* A cheap hack, if this is non-null and a message to an
253 interface comes in with a NULL user, call this routine with
254 it. Note that the message will still be freed by the
255 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700256 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258 /* When we are scanning the channels for an SMI, this will
259 tell which channel we are scanning. */
260 int curr_channel;
261
262 /* Channel information */
263 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
264
265 /* Proc FS stuff. */
266 struct proc_dir_entry *proc_dir;
267 char proc_dir_name[10];
268
269 spinlock_t counter_lock; /* For making counters atomic. */
270
271 /* Commands we got that were invalid. */
272 unsigned int sent_invalid_commands;
273
274 /* Commands we sent to the MC. */
275 unsigned int sent_local_commands;
276 /* Responses from the MC that were delivered to a user. */
277 unsigned int handled_local_responses;
278 /* Responses from the MC that were not delivered to a user. */
279 unsigned int unhandled_local_responses;
280
281 /* Commands we sent out to the IPMB bus. */
282 unsigned int sent_ipmb_commands;
283 /* Commands sent on the IPMB that had errors on the SEND CMD */
284 unsigned int sent_ipmb_command_errs;
285 /* Each retransmit increments this count. */
286 unsigned int retransmitted_ipmb_commands;
287 /* When a message times out (runs out of retransmits) this is
288 incremented. */
289 unsigned int timed_out_ipmb_commands;
290
291 /* This is like above, but for broadcasts. Broadcasts are
292 *not* included in the above count (they are expected to
293 time out). */
294 unsigned int timed_out_ipmb_broadcasts;
295
296 /* Responses I have sent to the IPMB bus. */
297 unsigned int sent_ipmb_responses;
298
299 /* The response was delivered to the user. */
300 unsigned int handled_ipmb_responses;
301 /* The response had invalid data in it. */
302 unsigned int invalid_ipmb_responses;
303 /* The response didn't have anyone waiting for it. */
304 unsigned int unhandled_ipmb_responses;
305
306 /* Commands we sent out to the IPMB bus. */
307 unsigned int sent_lan_commands;
308 /* Commands sent on the IPMB that had errors on the SEND CMD */
309 unsigned int sent_lan_command_errs;
310 /* Each retransmit increments this count. */
311 unsigned int retransmitted_lan_commands;
312 /* When a message times out (runs out of retransmits) this is
313 incremented. */
314 unsigned int timed_out_lan_commands;
315
316 /* Responses I have sent to the IPMB bus. */
317 unsigned int sent_lan_responses;
318
319 /* The response was delivered to the user. */
320 unsigned int handled_lan_responses;
321 /* The response had invalid data in it. */
322 unsigned int invalid_lan_responses;
323 /* The response didn't have anyone waiting for it. */
324 unsigned int unhandled_lan_responses;
325
326 /* The command was delivered to the user. */
327 unsigned int handled_commands;
328 /* The command had invalid data in it. */
329 unsigned int invalid_commands;
330 /* The command didn't have anyone waiting for it. */
331 unsigned int unhandled_commands;
332
333 /* Invalid data in an event. */
334 unsigned int invalid_events;
335 /* Events that were received with the proper format. */
336 unsigned int events;
337};
Corey Minyard50c812b2006-03-26 01:37:21 -0800338#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Corey Minyard393d2cc2005-11-07 00:59:54 -0800340/* Used to mark an interface entry that cannot be used but is not a
341 * free entry, either, primarily used at creation and deletion time so
342 * a slot doesn't get reused too quickly. */
343#define IPMI_INVALID_INTERFACE_ENTRY ((ipmi_smi_t) ((long) 1))
344#define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \
345 || (i == IPMI_INVALID_INTERFACE_ENTRY))
346
Corey Minyard50c812b2006-03-26 01:37:21 -0800347/**
348 * The driver model view of the IPMI messaging driver.
349 */
350static struct device_driver ipmidriver = {
351 .name = "ipmi",
352 .bus = &platform_bus_type
353};
354static DEFINE_MUTEX(ipmidriver_mutex);
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356#define MAX_IPMI_INTERFACES 4
357static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
358
Corey Minyard393d2cc2005-11-07 00:59:54 -0800359/* Directly protects the ipmi_interfaces data structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360static DEFINE_SPINLOCK(interfaces_lock);
361
362/* List of watchers that want to know when smi's are added and
363 deleted. */
364static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
365static DECLARE_RWSEM(smi_watchers_sem);
366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Corey Minyard393d2cc2005-11-07 00:59:54 -0800368static void free_recv_msg_list(struct list_head *q)
369{
370 struct ipmi_recv_msg *msg, *msg2;
371
372 list_for_each_entry_safe(msg, msg2, q, link) {
373 list_del(&msg->link);
374 ipmi_free_recv_msg(msg);
375 }
376}
377
378static void clean_up_interface_data(ipmi_smi_t intf)
379{
380 int i;
381 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800382 struct list_head list;
383
384 free_recv_msg_list(&intf->waiting_msgs);
385 free_recv_msg_list(&intf->waiting_events);
386
387 /* Wholesale remove all the entries from the list in the
388 * interface and wait for RCU to know that none are in use. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800389 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800390 list_add_rcu(&list, &intf->cmd_rcvrs);
391 list_del_rcu(&intf->cmd_rcvrs);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800392 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800393 synchronize_rcu();
394
395 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
396 kfree(rcvr);
397
398 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
399 if ((intf->seq_table[i].inuse)
400 && (intf->seq_table[i].recv_msg))
401 {
402 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 }
404 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800405}
406
407static void intf_free(struct kref *ref)
408{
409 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
410
411 clean_up_interface_data(intf);
412 kfree(intf);
413}
414
415int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
416{
417 int i;
418 unsigned long flags;
419
420 down_write(&smi_watchers_sem);
421 list_add(&(watcher->link), &smi_watchers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 up_write(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800423 spin_lock_irqsave(&interfaces_lock, flags);
424 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
425 ipmi_smi_t intf = ipmi_interfaces[i];
426 if (IPMI_INVALID_INTERFACE(intf))
427 continue;
428 spin_unlock_irqrestore(&interfaces_lock, flags);
Corey Minyard50c812b2006-03-26 01:37:21 -0800429 watcher->new_smi(i, intf->si_dev);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800430 spin_lock_irqsave(&interfaces_lock, flags);
431 }
432 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 return 0;
434}
435
436int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
437{
438 down_write(&smi_watchers_sem);
439 list_del(&(watcher->link));
440 up_write(&smi_watchers_sem);
441 return 0;
442}
443
444static void
Corey Minyard50c812b2006-03-26 01:37:21 -0800445call_smi_watchers(int i, struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
447 struct ipmi_smi_watcher *w;
448
449 down_read(&smi_watchers_sem);
450 list_for_each_entry(w, &smi_watchers, link) {
451 if (try_module_get(w->owner)) {
Corey Minyard50c812b2006-03-26 01:37:21 -0800452 w->new_smi(i, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 module_put(w->owner);
454 }
455 }
456 up_read(&smi_watchers_sem);
457}
458
459static int
460ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
461{
462 if (addr1->addr_type != addr2->addr_type)
463 return 0;
464
465 if (addr1->channel != addr2->channel)
466 return 0;
467
468 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
469 struct ipmi_system_interface_addr *smi_addr1
470 = (struct ipmi_system_interface_addr *) addr1;
471 struct ipmi_system_interface_addr *smi_addr2
472 = (struct ipmi_system_interface_addr *) addr2;
473 return (smi_addr1->lun == smi_addr2->lun);
474 }
475
476 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
477 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
478 {
479 struct ipmi_ipmb_addr *ipmb_addr1
480 = (struct ipmi_ipmb_addr *) addr1;
481 struct ipmi_ipmb_addr *ipmb_addr2
482 = (struct ipmi_ipmb_addr *) addr2;
483
484 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
485 && (ipmb_addr1->lun == ipmb_addr2->lun));
486 }
487
488 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
489 struct ipmi_lan_addr *lan_addr1
490 = (struct ipmi_lan_addr *) addr1;
491 struct ipmi_lan_addr *lan_addr2
492 = (struct ipmi_lan_addr *) addr2;
493
494 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
495 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
496 && (lan_addr1->session_handle
497 == lan_addr2->session_handle)
498 && (lan_addr1->lun == lan_addr2->lun));
499 }
500
501 return 1;
502}
503
504int ipmi_validate_addr(struct ipmi_addr *addr, int len)
505{
506 if (len < sizeof(struct ipmi_system_interface_addr)) {
507 return -EINVAL;
508 }
509
510 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
511 if (addr->channel != IPMI_BMC_CHANNEL)
512 return -EINVAL;
513 return 0;
514 }
515
516 if ((addr->channel == IPMI_BMC_CHANNEL)
Jayachandran C12fc1d72006-02-03 03:04:51 -0800517 || (addr->channel >= IPMI_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 || (addr->channel < 0))
519 return -EINVAL;
520
521 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
522 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
523 {
524 if (len < sizeof(struct ipmi_ipmb_addr)) {
525 return -EINVAL;
526 }
527 return 0;
528 }
529
530 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
531 if (len < sizeof(struct ipmi_lan_addr)) {
532 return -EINVAL;
533 }
534 return 0;
535 }
536
537 return -EINVAL;
538}
539
540unsigned int ipmi_addr_length(int addr_type)
541{
542 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
543 return sizeof(struct ipmi_system_interface_addr);
544
545 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
546 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
547 {
548 return sizeof(struct ipmi_ipmb_addr);
549 }
550
551 if (addr_type == IPMI_LAN_ADDR_TYPE)
552 return sizeof(struct ipmi_lan_addr);
553
554 return 0;
555}
556
557static void deliver_response(struct ipmi_recv_msg *msg)
558{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800559 if (!msg->user) {
Corey Minyard56a55ec2005-09-06 15:18:42 -0700560 ipmi_smi_t intf = msg->user_msg_data;
561 unsigned long flags;
562
563 /* Special handling for NULL users. */
564 if (intf->null_user_handler) {
565 intf->null_user_handler(intf, msg);
566 spin_lock_irqsave(&intf->counter_lock, flags);
567 intf->handled_local_responses++;
568 spin_unlock_irqrestore(&intf->counter_lock, flags);
569 } else {
570 /* No handler, so give up. */
571 spin_lock_irqsave(&intf->counter_lock, flags);
572 intf->unhandled_local_responses++;
573 spin_unlock_irqrestore(&intf->counter_lock, flags);
574 }
575 ipmi_free_recv_msg(msg);
576 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800577 ipmi_user_t user = msg->user;
578 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
582/* Find the next sequence number not being used and add the given
583 message with the given timeout to the sequence table. This must be
584 called with the interface's seq_lock held. */
585static int intf_next_seq(ipmi_smi_t intf,
586 struct ipmi_recv_msg *recv_msg,
587 unsigned long timeout,
588 int retries,
589 int broadcast,
590 unsigned char *seq,
591 long *seqid)
592{
593 int rv = 0;
594 unsigned int i;
595
Corey Minyarde8b33612005-09-06 15:18:45 -0700596 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700598 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800600 if (!intf->seq_table[i].inuse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 break;
602 }
603
Corey Minyard8a3628d2006-03-31 02:30:40 -0800604 if (!intf->seq_table[i].inuse) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 intf->seq_table[i].recv_msg = recv_msg;
606
607 /* Start with the maximum timeout, when the send response
608 comes in we will start the real timer. */
609 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
610 intf->seq_table[i].orig_timeout = timeout;
611 intf->seq_table[i].retries_left = retries;
612 intf->seq_table[i].broadcast = broadcast;
613 intf->seq_table[i].inuse = 1;
614 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
615 *seq = i;
616 *seqid = intf->seq_table[i].seqid;
617 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
618 } else {
619 rv = -EAGAIN;
620 }
621
622 return rv;
623}
624
625/* Return the receive message for the given sequence number and
626 release the sequence number so it can be reused. Some other data
627 is passed in to be sure the message matches up correctly (to help
628 guard against message coming in after their timeout and the
629 sequence number being reused). */
630static int intf_find_seq(ipmi_smi_t intf,
631 unsigned char seq,
632 short channel,
633 unsigned char cmd,
634 unsigned char netfn,
635 struct ipmi_addr *addr,
636 struct ipmi_recv_msg **recv_msg)
637{
638 int rv = -ENODEV;
639 unsigned long flags;
640
641 if (seq >= IPMI_IPMB_NUM_SEQ)
642 return -EINVAL;
643
644 spin_lock_irqsave(&(intf->seq_lock), flags);
645 if (intf->seq_table[seq].inuse) {
646 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
647
648 if ((msg->addr.channel == channel)
649 && (msg->msg.cmd == cmd)
650 && (msg->msg.netfn == netfn)
651 && (ipmi_addr_equal(addr, &(msg->addr))))
652 {
653 *recv_msg = msg;
654 intf->seq_table[seq].inuse = 0;
655 rv = 0;
656 }
657 }
658 spin_unlock_irqrestore(&(intf->seq_lock), flags);
659
660 return rv;
661}
662
663
664/* Start the timer for a specific sequence table entry. */
665static int intf_start_seq_timer(ipmi_smi_t intf,
666 long msgid)
667{
668 int rv = -ENODEV;
669 unsigned long flags;
670 unsigned char seq;
671 unsigned long seqid;
672
673
674 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
675
676 spin_lock_irqsave(&(intf->seq_lock), flags);
677 /* We do this verification because the user can be deleted
678 while a message is outstanding. */
679 if ((intf->seq_table[seq].inuse)
680 && (intf->seq_table[seq].seqid == seqid))
681 {
682 struct seq_table *ent = &(intf->seq_table[seq]);
683 ent->timeout = ent->orig_timeout;
684 rv = 0;
685 }
686 spin_unlock_irqrestore(&(intf->seq_lock), flags);
687
688 return rv;
689}
690
691/* Got an error for the send message for a specific sequence number. */
692static int intf_err_seq(ipmi_smi_t intf,
693 long msgid,
694 unsigned int err)
695{
696 int rv = -ENODEV;
697 unsigned long flags;
698 unsigned char seq;
699 unsigned long seqid;
700 struct ipmi_recv_msg *msg = NULL;
701
702
703 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
704
705 spin_lock_irqsave(&(intf->seq_lock), flags);
706 /* We do this verification because the user can be deleted
707 while a message is outstanding. */
708 if ((intf->seq_table[seq].inuse)
709 && (intf->seq_table[seq].seqid == seqid))
710 {
711 struct seq_table *ent = &(intf->seq_table[seq]);
712
713 ent->inuse = 0;
714 msg = ent->recv_msg;
715 rv = 0;
716 }
717 spin_unlock_irqrestore(&(intf->seq_lock), flags);
718
719 if (msg) {
720 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
721 msg->msg_data[0] = err;
722 msg->msg.netfn |= 1; /* Convert to a response. */
723 msg->msg.data_len = 1;
724 msg->msg.data = msg->msg_data;
725 deliver_response(msg);
726 }
727
728 return rv;
729}
730
731
732int ipmi_create_user(unsigned int if_num,
733 struct ipmi_user_hndl *handler,
734 void *handler_data,
735 ipmi_user_t *user)
736{
737 unsigned long flags;
738 ipmi_user_t new_user;
739 int rv = 0;
740 ipmi_smi_t intf;
741
742 /* There is no module usecount here, because it's not
743 required. Since this can only be used by and called from
744 other modules, they will implicitly use this module, and
745 thus this can't be removed unless the other modules are
746 removed. */
747
748 if (handler == NULL)
749 return -EINVAL;
750
751 /* Make sure the driver is actually initialized, this handles
752 problems with initialization order. */
753 if (!initialized) {
754 rv = ipmi_init_msghandler();
755 if (rv)
756 return rv;
757
758 /* The init code doesn't return an error if it was turned
759 off, but it won't initialize. Check that. */
760 if (!initialized)
761 return -ENODEV;
762 }
763
764 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800765 if (!new_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return -ENOMEM;
767
Corey Minyard393d2cc2005-11-07 00:59:54 -0800768 spin_lock_irqsave(&interfaces_lock, flags);
769 intf = ipmi_interfaces[if_num];
770 if ((if_num >= MAX_IPMI_INTERFACES) || IPMI_INVALID_INTERFACE(intf)) {
771 spin_unlock_irqrestore(&interfaces_lock, flags);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800772 rv = -EINVAL;
773 goto out_kfree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
775
Corey Minyard393d2cc2005-11-07 00:59:54 -0800776 /* Note that each existing user holds a refcount to the interface. */
777 kref_get(&intf->refcount);
778 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Corey Minyard393d2cc2005-11-07 00:59:54 -0800780 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 new_user->handler = handler;
782 new_user->handler_data = handler_data;
783 new_user->intf = intf;
784 new_user->gets_events = 0;
785
786 if (!try_module_get(intf->handlers->owner)) {
787 rv = -ENODEV;
Adrian Bunk5c98d292006-03-25 03:07:52 -0800788 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
790
791 if (intf->handlers->inc_usecount) {
792 rv = intf->handlers->inc_usecount(intf->send_info);
793 if (rv) {
794 module_put(intf->handlers->owner);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800795 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 }
797 }
798
Corey Minyard393d2cc2005-11-07 00:59:54 -0800799 new_user->valid = 1;
800 spin_lock_irqsave(&intf->seq_lock, flags);
801 list_add_rcu(&new_user->link, &intf->users);
802 spin_unlock_irqrestore(&intf->seq_lock, flags);
803 *user = new_user;
804 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Adrian Bunk5c98d292006-03-25 03:07:52 -0800806out_kref:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800807 kref_put(&intf->refcount, intf_free);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800808out_kfree:
809 kfree(new_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return rv;
811}
812
Corey Minyard393d2cc2005-11-07 00:59:54 -0800813static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800815 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817}
818
819int ipmi_destroy_user(ipmi_user_t user)
820{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800821 ipmi_smi_t intf = user->intf;
822 int i;
823 unsigned long flags;
824 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800825 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
Corey Minyard8a3628d2006-03-31 02:30:40 -0800827 user->valid = 0;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800828
829 /* Remove the user from the interface's sequence table. */
830 spin_lock_irqsave(&intf->seq_lock, flags);
831 list_del_rcu(&user->link);
832
833 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
834 if (intf->seq_table[i].inuse
835 && (intf->seq_table[i].recv_msg->user == user))
836 {
837 intf->seq_table[i].inuse = 0;
838 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800840 spin_unlock_irqrestore(&intf->seq_lock, flags);
841
842 /*
843 * Remove the user from the command receiver's table. First
844 * we build a list of everything (not using the standard link,
845 * since other things may be using it till we do
846 * synchronize_rcu()) then free everything in that list.
847 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800848 mutex_lock(&intf->cmd_rcvrs_mutex);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800849 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800850 if (rcvr->user == user) {
851 list_del_rcu(&rcvr->link);
852 rcvr->next = rcvrs;
853 rcvrs = rcvr;
854 }
855 }
Corey Minyardd6dfd132006-03-31 02:30:41 -0800856 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800857 synchronize_rcu();
858 while (rcvrs) {
859 rcvr = rcvrs;
860 rcvrs = rcvr->next;
861 kfree(rcvr);
862 }
863
864 module_put(intf->handlers->owner);
865 if (intf->handlers->dec_usecount)
866 intf->handlers->dec_usecount(intf->send_info);
867
868 kref_put(&intf->refcount, intf_free);
869
870 kref_put(&user->refcount, free_user);
871
Corey Minyard8a3628d2006-03-31 02:30:40 -0800872 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873}
874
875void ipmi_get_version(ipmi_user_t user,
876 unsigned char *major,
877 unsigned char *minor)
878{
Corey Minyard50c812b2006-03-26 01:37:21 -0800879 *major = ipmi_version_major(&user->intf->bmc->id);
880 *minor = ipmi_version_minor(&user->intf->bmc->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881}
882
Corey Minyardc14979b2005-09-06 15:18:38 -0700883int ipmi_set_my_address(ipmi_user_t user,
884 unsigned int channel,
885 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
Corey Minyardc14979b2005-09-06 15:18:38 -0700887 if (channel >= IPMI_MAX_CHANNELS)
888 return -EINVAL;
889 user->intf->channels[channel].address = address;
890 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891}
892
Corey Minyardc14979b2005-09-06 15:18:38 -0700893int ipmi_get_my_address(ipmi_user_t user,
894 unsigned int channel,
895 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
Corey Minyardc14979b2005-09-06 15:18:38 -0700897 if (channel >= IPMI_MAX_CHANNELS)
898 return -EINVAL;
899 *address = user->intf->channels[channel].address;
900 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901}
902
Corey Minyardc14979b2005-09-06 15:18:38 -0700903int ipmi_set_my_LUN(ipmi_user_t user,
904 unsigned int channel,
905 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
Corey Minyardc14979b2005-09-06 15:18:38 -0700907 if (channel >= IPMI_MAX_CHANNELS)
908 return -EINVAL;
909 user->intf->channels[channel].lun = LUN & 0x3;
910 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911}
912
Corey Minyardc14979b2005-09-06 15:18:38 -0700913int ipmi_get_my_LUN(ipmi_user_t user,
914 unsigned int channel,
915 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916{
Corey Minyardc14979b2005-09-06 15:18:38 -0700917 if (channel >= IPMI_MAX_CHANNELS)
918 return -EINVAL;
919 *address = user->intf->channels[channel].lun;
920 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921}
922
923int ipmi_set_gets_events(ipmi_user_t user, int val)
924{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800925 unsigned long flags;
926 ipmi_smi_t intf = user->intf;
927 struct ipmi_recv_msg *msg, *msg2;
928 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
Corey Minyard393d2cc2005-11-07 00:59:54 -0800930 INIT_LIST_HEAD(&msgs);
931
932 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 user->gets_events = val;
934
935 if (val) {
936 /* Deliver any queued events. */
Akinobu Mita179e0912006-06-26 00:24:41 -0700937 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
938 list_move_tail(&msg->link, &msgs);
Corey Minyard4791c032006-04-10 22:54:31 -0700939 intf->waiting_events_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800941
942 /* Hold the events lock while doing this to preserve order. */
943 list_for_each_entry_safe(msg, msg2, &msgs, link) {
944 msg->user = user;
945 kref_get(&user->refcount);
946 deliver_response(msg);
947 }
948
949 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
951 return 0;
952}
953
Corey Minyard393d2cc2005-11-07 00:59:54 -0800954static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
955 unsigned char netfn,
956 unsigned char cmd)
957{
958 struct cmd_rcvr *rcvr;
959
960 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
961 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd))
962 return rcvr;
963 }
964 return NULL;
965}
966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967int ipmi_register_for_cmd(ipmi_user_t user,
968 unsigned char netfn,
969 unsigned char cmd)
970{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800971 ipmi_smi_t intf = user->intf;
972 struct cmd_rcvr *rcvr;
973 struct cmd_rcvr *entry;
974 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976
977 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800978 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800980 rcvr->cmd = cmd;
981 rcvr->netfn = netfn;
982 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Corey Minyardd6dfd132006-03-31 02:30:41 -0800984 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 /* Make sure the command/netfn is not already registered. */
Corey Minyard393d2cc2005-11-07 00:59:54 -0800986 entry = find_cmd_rcvr(intf, netfn, cmd);
987 if (entry) {
988 rv = -EBUSY;
989 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 }
991
Corey Minyard393d2cc2005-11-07 00:59:54 -0800992 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -0700993
Corey Minyard393d2cc2005-11-07 00:59:54 -0800994 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -0800995 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 if (rv)
997 kfree(rcvr);
998
999 return rv;
1000}
1001
1002int ipmi_unregister_for_cmd(ipmi_user_t user,
1003 unsigned char netfn,
1004 unsigned char cmd)
1005{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001006 ipmi_smi_t intf = user->intf;
1007 struct cmd_rcvr *rcvr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
Corey Minyardd6dfd132006-03-31 02:30:41 -08001009 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 /* Make sure the command/netfn is not already registered. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001011 rcvr = find_cmd_rcvr(intf, netfn, cmd);
1012 if ((rcvr) && (rcvr->user == user)) {
1013 list_del_rcu(&rcvr->link);
Corey Minyardd6dfd132006-03-31 02:30:41 -08001014 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001015 synchronize_rcu();
1016 kfree(rcvr);
1017 return 0;
1018 } else {
Corey Minyardd6dfd132006-03-31 02:30:41 -08001019 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08001020 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022}
1023
1024void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
1025{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001026 ipmi_smi_t intf = user->intf;
1027 intf->handlers->set_run_to_completion(intf->send_info, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028}
1029
1030static unsigned char
1031ipmb_checksum(unsigned char *data, int size)
1032{
1033 unsigned char csum = 0;
1034
1035 for (; size > 0; size--, data++)
1036 csum += *data;
1037
1038 return -csum;
1039}
1040
1041static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1042 struct kernel_ipmi_msg *msg,
1043 struct ipmi_ipmb_addr *ipmb_addr,
1044 long msgid,
1045 unsigned char ipmb_seq,
1046 int broadcast,
1047 unsigned char source_address,
1048 unsigned char source_lun)
1049{
1050 int i = broadcast;
1051
1052 /* Format the IPMB header data. */
1053 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1054 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1055 smi_msg->data[2] = ipmb_addr->channel;
1056 if (broadcast)
1057 smi_msg->data[3] = 0;
1058 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1059 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1060 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1061 smi_msg->data[i+6] = source_address;
1062 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1063 smi_msg->data[i+8] = msg->cmd;
1064
1065 /* Now tack on the data to the message. */
1066 if (msg->data_len > 0)
1067 memcpy(&(smi_msg->data[i+9]), msg->data,
1068 msg->data_len);
1069 smi_msg->data_size = msg->data_len + 9;
1070
1071 /* Now calculate the checksum and tack it on. */
1072 smi_msg->data[i+smi_msg->data_size]
1073 = ipmb_checksum(&(smi_msg->data[i+6]),
1074 smi_msg->data_size-6);
1075
1076 /* Add on the checksum size and the offset from the
1077 broadcast. */
1078 smi_msg->data_size += 1 + i;
1079
1080 smi_msg->msgid = msgid;
1081}
1082
1083static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1084 struct kernel_ipmi_msg *msg,
1085 struct ipmi_lan_addr *lan_addr,
1086 long msgid,
1087 unsigned char ipmb_seq,
1088 unsigned char source_lun)
1089{
1090 /* Format the IPMB header data. */
1091 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1092 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1093 smi_msg->data[2] = lan_addr->channel;
1094 smi_msg->data[3] = lan_addr->session_handle;
1095 smi_msg->data[4] = lan_addr->remote_SWID;
1096 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1097 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1098 smi_msg->data[7] = lan_addr->local_SWID;
1099 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1100 smi_msg->data[9] = msg->cmd;
1101
1102 /* Now tack on the data to the message. */
1103 if (msg->data_len > 0)
1104 memcpy(&(smi_msg->data[10]), msg->data,
1105 msg->data_len);
1106 smi_msg->data_size = msg->data_len + 10;
1107
1108 /* Now calculate the checksum and tack it on. */
1109 smi_msg->data[smi_msg->data_size]
1110 = ipmb_checksum(&(smi_msg->data[7]),
1111 smi_msg->data_size-7);
1112
1113 /* Add on the checksum size and the offset from the
1114 broadcast. */
1115 smi_msg->data_size += 1;
1116
1117 smi_msg->msgid = msgid;
1118}
1119
1120/* Separate from ipmi_request so that the user does not have to be
1121 supplied in certain circumstances (mainly at panic time). If
1122 messages are supplied, they will be freed, even if an error
1123 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001124static int i_ipmi_request(ipmi_user_t user,
1125 ipmi_smi_t intf,
1126 struct ipmi_addr *addr,
1127 long msgid,
1128 struct kernel_ipmi_msg *msg,
1129 void *user_msg_data,
1130 void *supplied_smi,
1131 struct ipmi_recv_msg *supplied_recv,
1132 int priority,
1133 unsigned char source_address,
1134 unsigned char source_lun,
1135 int retries,
1136 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137{
1138 int rv = 0;
1139 struct ipmi_smi_msg *smi_msg;
1140 struct ipmi_recv_msg *recv_msg;
1141 unsigned long flags;
1142
1143
1144 if (supplied_recv) {
1145 recv_msg = supplied_recv;
1146 } else {
1147 recv_msg = ipmi_alloc_recv_msg();
1148 if (recv_msg == NULL) {
1149 return -ENOMEM;
1150 }
1151 }
1152 recv_msg->user_msg_data = user_msg_data;
1153
1154 if (supplied_smi) {
1155 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1156 } else {
1157 smi_msg = ipmi_alloc_smi_msg();
1158 if (smi_msg == NULL) {
1159 ipmi_free_recv_msg(recv_msg);
1160 return -ENOMEM;
1161 }
1162 }
1163
1164 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001165 if (user)
1166 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 recv_msg->msgid = msgid;
1168 /* Store the message to send in the receive message so timeout
1169 responses can get the proper response data. */
1170 recv_msg->msg = *msg;
1171
1172 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1173 struct ipmi_system_interface_addr *smi_addr;
1174
1175 if (msg->netfn & 1) {
1176 /* Responses are not allowed to the SMI. */
1177 rv = -EINVAL;
1178 goto out_err;
1179 }
1180
1181 smi_addr = (struct ipmi_system_interface_addr *) addr;
1182 if (smi_addr->lun > 3) {
1183 spin_lock_irqsave(&intf->counter_lock, flags);
1184 intf->sent_invalid_commands++;
1185 spin_unlock_irqrestore(&intf->counter_lock, flags);
1186 rv = -EINVAL;
1187 goto out_err;
1188 }
1189
1190 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1191
1192 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1193 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1194 || (msg->cmd == IPMI_GET_MSG_CMD)
1195 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1196 {
1197 /* We don't let the user do these, since we manage
1198 the sequence numbers. */
1199 spin_lock_irqsave(&intf->counter_lock, flags);
1200 intf->sent_invalid_commands++;
1201 spin_unlock_irqrestore(&intf->counter_lock, flags);
1202 rv = -EINVAL;
1203 goto out_err;
1204 }
1205
1206 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1207 spin_lock_irqsave(&intf->counter_lock, flags);
1208 intf->sent_invalid_commands++;
1209 spin_unlock_irqrestore(&intf->counter_lock, flags);
1210 rv = -EMSGSIZE;
1211 goto out_err;
1212 }
1213
1214 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1215 smi_msg->data[1] = msg->cmd;
1216 smi_msg->msgid = msgid;
1217 smi_msg->user_data = recv_msg;
1218 if (msg->data_len > 0)
1219 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1220 smi_msg->data_size = msg->data_len + 2;
1221 spin_lock_irqsave(&intf->counter_lock, flags);
1222 intf->sent_local_commands++;
1223 spin_unlock_irqrestore(&intf->counter_lock, flags);
1224 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1225 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1226 {
1227 struct ipmi_ipmb_addr *ipmb_addr;
1228 unsigned char ipmb_seq;
1229 long seqid;
1230 int broadcast = 0;
1231
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001232 if (addr->channel >= IPMI_MAX_CHANNELS) {
1233 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 intf->sent_invalid_commands++;
1235 spin_unlock_irqrestore(&intf->counter_lock, flags);
1236 rv = -EINVAL;
1237 goto out_err;
1238 }
1239
1240 if (intf->channels[addr->channel].medium
1241 != IPMI_CHANNEL_MEDIUM_IPMB)
1242 {
1243 spin_lock_irqsave(&intf->counter_lock, flags);
1244 intf->sent_invalid_commands++;
1245 spin_unlock_irqrestore(&intf->counter_lock, flags);
1246 rv = -EINVAL;
1247 goto out_err;
1248 }
1249
1250 if (retries < 0) {
1251 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1252 retries = 0; /* Don't retry broadcasts. */
1253 else
1254 retries = 4;
1255 }
1256 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1257 /* Broadcasts add a zero at the beginning of the
1258 message, but otherwise is the same as an IPMB
1259 address. */
1260 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1261 broadcast = 1;
1262 }
1263
1264
1265 /* Default to 1 second retries. */
1266 if (retry_time_ms == 0)
1267 retry_time_ms = 1000;
1268
1269 /* 9 for the header and 1 for the checksum, plus
1270 possibly one for the broadcast. */
1271 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1272 spin_lock_irqsave(&intf->counter_lock, flags);
1273 intf->sent_invalid_commands++;
1274 spin_unlock_irqrestore(&intf->counter_lock, flags);
1275 rv = -EMSGSIZE;
1276 goto out_err;
1277 }
1278
1279 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1280 if (ipmb_addr->lun > 3) {
1281 spin_lock_irqsave(&intf->counter_lock, flags);
1282 intf->sent_invalid_commands++;
1283 spin_unlock_irqrestore(&intf->counter_lock, flags);
1284 rv = -EINVAL;
1285 goto out_err;
1286 }
1287
1288 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1289
1290 if (recv_msg->msg.netfn & 0x1) {
1291 /* It's a response, so use the user's sequence
1292 from msgid. */
1293 spin_lock_irqsave(&intf->counter_lock, flags);
1294 intf->sent_ipmb_responses++;
1295 spin_unlock_irqrestore(&intf->counter_lock, flags);
1296 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1297 msgid, broadcast,
1298 source_address, source_lun);
1299
1300 /* Save the receive message so we can use it
1301 to deliver the response. */
1302 smi_msg->user_data = recv_msg;
1303 } else {
1304 /* It's a command, so get a sequence for it. */
1305
1306 spin_lock_irqsave(&(intf->seq_lock), flags);
1307
1308 spin_lock(&intf->counter_lock);
1309 intf->sent_ipmb_commands++;
1310 spin_unlock(&intf->counter_lock);
1311
1312 /* Create a sequence number with a 1 second
1313 timeout and 4 retries. */
1314 rv = intf_next_seq(intf,
1315 recv_msg,
1316 retry_time_ms,
1317 retries,
1318 broadcast,
1319 &ipmb_seq,
1320 &seqid);
1321 if (rv) {
1322 /* We have used up all the sequence numbers,
1323 probably, so abort. */
1324 spin_unlock_irqrestore(&(intf->seq_lock),
1325 flags);
1326 goto out_err;
1327 }
1328
1329 /* Store the sequence number in the message,
1330 so that when the send message response
1331 comes back we can start the timer. */
1332 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1333 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1334 ipmb_seq, broadcast,
1335 source_address, source_lun);
1336
1337 /* Copy the message into the recv message data, so we
1338 can retransmit it later if necessary. */
1339 memcpy(recv_msg->msg_data, smi_msg->data,
1340 smi_msg->data_size);
1341 recv_msg->msg.data = recv_msg->msg_data;
1342 recv_msg->msg.data_len = smi_msg->data_size;
1343
1344 /* We don't unlock until here, because we need
1345 to copy the completed message into the
1346 recv_msg before we release the lock.
1347 Otherwise, race conditions may bite us. I
1348 know that's pretty paranoid, but I prefer
1349 to be correct. */
1350 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1351 }
1352 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1353 struct ipmi_lan_addr *lan_addr;
1354 unsigned char ipmb_seq;
1355 long seqid;
1356
Jayachandran C12fc1d72006-02-03 03:04:51 -08001357 if (addr->channel >= IPMI_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 spin_lock_irqsave(&intf->counter_lock, flags);
1359 intf->sent_invalid_commands++;
1360 spin_unlock_irqrestore(&intf->counter_lock, flags);
1361 rv = -EINVAL;
1362 goto out_err;
1363 }
1364
1365 if ((intf->channels[addr->channel].medium
1366 != IPMI_CHANNEL_MEDIUM_8023LAN)
1367 && (intf->channels[addr->channel].medium
1368 != IPMI_CHANNEL_MEDIUM_ASYNC))
1369 {
1370 spin_lock_irqsave(&intf->counter_lock, flags);
1371 intf->sent_invalid_commands++;
1372 spin_unlock_irqrestore(&intf->counter_lock, flags);
1373 rv = -EINVAL;
1374 goto out_err;
1375 }
1376
1377 retries = 4;
1378
1379 /* Default to 1 second retries. */
1380 if (retry_time_ms == 0)
1381 retry_time_ms = 1000;
1382
1383 /* 11 for the header and 1 for the checksum. */
1384 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1385 spin_lock_irqsave(&intf->counter_lock, flags);
1386 intf->sent_invalid_commands++;
1387 spin_unlock_irqrestore(&intf->counter_lock, flags);
1388 rv = -EMSGSIZE;
1389 goto out_err;
1390 }
1391
1392 lan_addr = (struct ipmi_lan_addr *) addr;
1393 if (lan_addr->lun > 3) {
1394 spin_lock_irqsave(&intf->counter_lock, flags);
1395 intf->sent_invalid_commands++;
1396 spin_unlock_irqrestore(&intf->counter_lock, flags);
1397 rv = -EINVAL;
1398 goto out_err;
1399 }
1400
1401 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1402
1403 if (recv_msg->msg.netfn & 0x1) {
1404 /* It's a response, so use the user's sequence
1405 from msgid. */
1406 spin_lock_irqsave(&intf->counter_lock, flags);
1407 intf->sent_lan_responses++;
1408 spin_unlock_irqrestore(&intf->counter_lock, flags);
1409 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1410 msgid, source_lun);
1411
1412 /* Save the receive message so we can use it
1413 to deliver the response. */
1414 smi_msg->user_data = recv_msg;
1415 } else {
1416 /* It's a command, so get a sequence for it. */
1417
1418 spin_lock_irqsave(&(intf->seq_lock), flags);
1419
1420 spin_lock(&intf->counter_lock);
1421 intf->sent_lan_commands++;
1422 spin_unlock(&intf->counter_lock);
1423
1424 /* Create a sequence number with a 1 second
1425 timeout and 4 retries. */
1426 rv = intf_next_seq(intf,
1427 recv_msg,
1428 retry_time_ms,
1429 retries,
1430 0,
1431 &ipmb_seq,
1432 &seqid);
1433 if (rv) {
1434 /* We have used up all the sequence numbers,
1435 probably, so abort. */
1436 spin_unlock_irqrestore(&(intf->seq_lock),
1437 flags);
1438 goto out_err;
1439 }
1440
1441 /* Store the sequence number in the message,
1442 so that when the send message response
1443 comes back we can start the timer. */
1444 format_lan_msg(smi_msg, msg, lan_addr,
1445 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1446 ipmb_seq, source_lun);
1447
1448 /* Copy the message into the recv message data, so we
1449 can retransmit it later if necessary. */
1450 memcpy(recv_msg->msg_data, smi_msg->data,
1451 smi_msg->data_size);
1452 recv_msg->msg.data = recv_msg->msg_data;
1453 recv_msg->msg.data_len = smi_msg->data_size;
1454
1455 /* We don't unlock until here, because we need
1456 to copy the completed message into the
1457 recv_msg before we release the lock.
1458 Otherwise, race conditions may bite us. I
1459 know that's pretty paranoid, but I prefer
1460 to be correct. */
1461 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1462 }
1463 } else {
1464 /* Unknown address type. */
1465 spin_lock_irqsave(&intf->counter_lock, flags);
1466 intf->sent_invalid_commands++;
1467 spin_unlock_irqrestore(&intf->counter_lock, flags);
1468 rv = -EINVAL;
1469 goto out_err;
1470 }
1471
1472#ifdef DEBUG_MSGING
1473 {
1474 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001475 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 printk(" %2.2x", smi_msg->data[m]);
1477 printk("\n");
1478 }
1479#endif
1480 intf->handlers->sender(intf->send_info, smi_msg, priority);
1481
1482 return 0;
1483
1484 out_err:
1485 ipmi_free_smi_msg(smi_msg);
1486 ipmi_free_recv_msg(recv_msg);
1487 return rv;
1488}
1489
Corey Minyardc14979b2005-09-06 15:18:38 -07001490static int check_addr(ipmi_smi_t intf,
1491 struct ipmi_addr *addr,
1492 unsigned char *saddr,
1493 unsigned char *lun)
1494{
1495 if (addr->channel >= IPMI_MAX_CHANNELS)
1496 return -EINVAL;
1497 *lun = intf->channels[addr->channel].lun;
1498 *saddr = intf->channels[addr->channel].address;
1499 return 0;
1500}
1501
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502int ipmi_request_settime(ipmi_user_t user,
1503 struct ipmi_addr *addr,
1504 long msgid,
1505 struct kernel_ipmi_msg *msg,
1506 void *user_msg_data,
1507 int priority,
1508 int retries,
1509 unsigned int retry_time_ms)
1510{
Corey Minyardc14979b2005-09-06 15:18:38 -07001511 unsigned char saddr, lun;
1512 int rv;
1513
Corey Minyard8a3628d2006-03-31 02:30:40 -08001514 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001515 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001516 rv = check_addr(user->intf, addr, &saddr, &lun);
1517 if (rv)
1518 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 return i_ipmi_request(user,
1520 user->intf,
1521 addr,
1522 msgid,
1523 msg,
1524 user_msg_data,
1525 NULL, NULL,
1526 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001527 saddr,
1528 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 retries,
1530 retry_time_ms);
1531}
1532
1533int ipmi_request_supply_msgs(ipmi_user_t user,
1534 struct ipmi_addr *addr,
1535 long msgid,
1536 struct kernel_ipmi_msg *msg,
1537 void *user_msg_data,
1538 void *supplied_smi,
1539 struct ipmi_recv_msg *supplied_recv,
1540 int priority)
1541{
Corey Minyardc14979b2005-09-06 15:18:38 -07001542 unsigned char saddr, lun;
1543 int rv;
1544
Corey Minyard8a3628d2006-03-31 02:30:40 -08001545 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001546 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001547 rv = check_addr(user->intf, addr, &saddr, &lun);
1548 if (rv)
1549 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 return i_ipmi_request(user,
1551 user->intf,
1552 addr,
1553 msgid,
1554 msg,
1555 user_msg_data,
1556 supplied_smi,
1557 supplied_recv,
1558 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001559 saddr,
1560 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 -1, 0);
1562}
1563
1564static int ipmb_file_read_proc(char *page, char **start, off_t off,
1565 int count, int *eof, void *data)
1566{
1567 char *out = (char *) page;
1568 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001569 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001570 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571
Corey Minyarde8b33612005-09-06 15:18:45 -07001572 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001573 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1574 out[rv-1] = '\n'; /* Replace the final space with a newline */
1575 out[rv] = '\0';
1576 rv++;
1577 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578}
1579
1580static int version_file_read_proc(char *page, char **start, off_t off,
1581 int count, int *eof, void *data)
1582{
1583 char *out = (char *) page;
1584 ipmi_smi_t intf = data;
1585
1586 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001587 ipmi_version_major(&intf->bmc->id),
1588 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589}
1590
1591static int stat_file_read_proc(char *page, char **start, off_t off,
1592 int count, int *eof, void *data)
1593{
1594 char *out = (char *) page;
1595 ipmi_smi_t intf = data;
1596
1597 out += sprintf(out, "sent_invalid_commands: %d\n",
1598 intf->sent_invalid_commands);
1599 out += sprintf(out, "sent_local_commands: %d\n",
1600 intf->sent_local_commands);
1601 out += sprintf(out, "handled_local_responses: %d\n",
1602 intf->handled_local_responses);
1603 out += sprintf(out, "unhandled_local_responses: %d\n",
1604 intf->unhandled_local_responses);
1605 out += sprintf(out, "sent_ipmb_commands: %d\n",
1606 intf->sent_ipmb_commands);
1607 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1608 intf->sent_ipmb_command_errs);
1609 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1610 intf->retransmitted_ipmb_commands);
1611 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1612 intf->timed_out_ipmb_commands);
1613 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1614 intf->timed_out_ipmb_broadcasts);
1615 out += sprintf(out, "sent_ipmb_responses: %d\n",
1616 intf->sent_ipmb_responses);
1617 out += sprintf(out, "handled_ipmb_responses: %d\n",
1618 intf->handled_ipmb_responses);
1619 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1620 intf->invalid_ipmb_responses);
1621 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1622 intf->unhandled_ipmb_responses);
1623 out += sprintf(out, "sent_lan_commands: %d\n",
1624 intf->sent_lan_commands);
1625 out += sprintf(out, "sent_lan_command_errs: %d\n",
1626 intf->sent_lan_command_errs);
1627 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1628 intf->retransmitted_lan_commands);
1629 out += sprintf(out, "timed_out_lan_commands: %d\n",
1630 intf->timed_out_lan_commands);
1631 out += sprintf(out, "sent_lan_responses: %d\n",
1632 intf->sent_lan_responses);
1633 out += sprintf(out, "handled_lan_responses: %d\n",
1634 intf->handled_lan_responses);
1635 out += sprintf(out, "invalid_lan_responses: %d\n",
1636 intf->invalid_lan_responses);
1637 out += sprintf(out, "unhandled_lan_responses: %d\n",
1638 intf->unhandled_lan_responses);
1639 out += sprintf(out, "handled_commands: %d\n",
1640 intf->handled_commands);
1641 out += sprintf(out, "invalid_commands: %d\n",
1642 intf->invalid_commands);
1643 out += sprintf(out, "unhandled_commands: %d\n",
1644 intf->unhandled_commands);
1645 out += sprintf(out, "invalid_events: %d\n",
1646 intf->invalid_events);
1647 out += sprintf(out, "events: %d\n",
1648 intf->events);
1649
1650 return (out - ((char *) page));
1651}
1652
1653int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1654 read_proc_t *read_proc, write_proc_t *write_proc,
1655 void *data, struct module *owner)
1656{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001658#ifdef CONFIG_PROC_FS
1659 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 struct ipmi_proc_entry *entry;
1661
1662 /* Create a list element. */
1663 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1664 if (!entry)
1665 return -ENOMEM;
1666 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1667 if (!entry->name) {
1668 kfree(entry);
1669 return -ENOMEM;
1670 }
1671 strcpy(entry->name, name);
1672
1673 file = create_proc_entry(name, 0, smi->proc_dir);
1674 if (!file) {
1675 kfree(entry->name);
1676 kfree(entry);
1677 rv = -ENOMEM;
1678 } else {
1679 file->nlink = 1;
1680 file->data = data;
1681 file->read_proc = read_proc;
1682 file->write_proc = write_proc;
1683 file->owner = owner;
1684
Corey Minyard3b625942005-06-23 22:01:42 -07001685 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 /* Stick it on the list. */
1687 entry->next = smi->proc_entries;
1688 smi->proc_entries = entry;
Corey Minyard3b625942005-06-23 22:01:42 -07001689 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 }
Corey Minyard3b625942005-06-23 22:01:42 -07001691#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693 return rv;
1694}
1695
1696static int add_proc_entries(ipmi_smi_t smi, int num)
1697{
1698 int rv = 0;
1699
Corey Minyard3b625942005-06-23 22:01:42 -07001700#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 sprintf(smi->proc_dir_name, "%d", num);
1702 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1703 if (!smi->proc_dir)
1704 rv = -ENOMEM;
1705 else {
1706 smi->proc_dir->owner = THIS_MODULE;
1707 }
1708
1709 if (rv == 0)
1710 rv = ipmi_smi_add_proc_entry(smi, "stats",
1711 stat_file_read_proc, NULL,
1712 smi, THIS_MODULE);
1713
1714 if (rv == 0)
1715 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1716 ipmb_file_read_proc, NULL,
1717 smi, THIS_MODULE);
1718
1719 if (rv == 0)
1720 rv = ipmi_smi_add_proc_entry(smi, "version",
1721 version_file_read_proc, NULL,
1722 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001723#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
1725 return rv;
1726}
1727
1728static void remove_proc_entries(ipmi_smi_t smi)
1729{
Corey Minyard3b625942005-06-23 22:01:42 -07001730#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 struct ipmi_proc_entry *entry;
1732
Corey Minyard3b625942005-06-23 22:01:42 -07001733 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 while (smi->proc_entries) {
1735 entry = smi->proc_entries;
1736 smi->proc_entries = entry->next;
1737
1738 remove_proc_entry(entry->name, smi->proc_dir);
1739 kfree(entry->name);
1740 kfree(entry);
1741 }
Corey Minyard3b625942005-06-23 22:01:42 -07001742 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001744#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745}
1746
Corey Minyard50c812b2006-03-26 01:37:21 -08001747static int __find_bmc_guid(struct device *dev, void *data)
1748{
1749 unsigned char *id = data;
1750 struct bmc_device *bmc = dev_get_drvdata(dev);
1751 return memcmp(bmc->guid, id, 16) == 0;
1752}
1753
1754static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1755 unsigned char *guid)
1756{
1757 struct device *dev;
1758
1759 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1760 if (dev)
1761 return dev_get_drvdata(dev);
1762 else
1763 return NULL;
1764}
1765
1766struct prod_dev_id {
1767 unsigned int product_id;
1768 unsigned char device_id;
1769};
1770
1771static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1772{
1773 struct prod_dev_id *id = data;
1774 struct bmc_device *bmc = dev_get_drvdata(dev);
1775
1776 return (bmc->id.product_id == id->product_id
1777 && bmc->id.product_id == id->product_id
1778 && bmc->id.device_id == id->device_id);
1779}
1780
1781static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1782 struct device_driver *drv,
1783 unsigned char product_id, unsigned char device_id)
1784{
1785 struct prod_dev_id id = {
1786 .product_id = product_id,
1787 .device_id = device_id,
1788 };
1789 struct device *dev;
1790
1791 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
1792 if (dev)
1793 return dev_get_drvdata(dev);
1794 else
1795 return NULL;
1796}
1797
1798static ssize_t device_id_show(struct device *dev,
1799 struct device_attribute *attr,
1800 char *buf)
1801{
1802 struct bmc_device *bmc = dev_get_drvdata(dev);
1803
1804 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
1805}
1806
1807static ssize_t provides_dev_sdrs_show(struct device *dev,
1808 struct device_attribute *attr,
1809 char *buf)
1810{
1811 struct bmc_device *bmc = dev_get_drvdata(dev);
1812
1813 return snprintf(buf, 10, "%u\n",
1814 bmc->id.device_revision && 0x80 >> 7);
1815}
1816
1817static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
1818 char *buf)
1819{
1820 struct bmc_device *bmc = dev_get_drvdata(dev);
1821
1822 return snprintf(buf, 20, "%u\n",
1823 bmc->id.device_revision && 0x0F);
1824}
1825
1826static ssize_t firmware_rev_show(struct device *dev,
1827 struct device_attribute *attr,
1828 char *buf)
1829{
1830 struct bmc_device *bmc = dev_get_drvdata(dev);
1831
1832 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
1833 bmc->id.firmware_revision_2);
1834}
1835
1836static ssize_t ipmi_version_show(struct device *dev,
1837 struct device_attribute *attr,
1838 char *buf)
1839{
1840 struct bmc_device *bmc = dev_get_drvdata(dev);
1841
1842 return snprintf(buf, 20, "%u.%u\n",
1843 ipmi_version_major(&bmc->id),
1844 ipmi_version_minor(&bmc->id));
1845}
1846
1847static ssize_t add_dev_support_show(struct device *dev,
1848 struct device_attribute *attr,
1849 char *buf)
1850{
1851 struct bmc_device *bmc = dev_get_drvdata(dev);
1852
1853 return snprintf(buf, 10, "0x%02x\n",
1854 bmc->id.additional_device_support);
1855}
1856
1857static ssize_t manufacturer_id_show(struct device *dev,
1858 struct device_attribute *attr,
1859 char *buf)
1860{
1861 struct bmc_device *bmc = dev_get_drvdata(dev);
1862
1863 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
1864}
1865
1866static ssize_t product_id_show(struct device *dev,
1867 struct device_attribute *attr,
1868 char *buf)
1869{
1870 struct bmc_device *bmc = dev_get_drvdata(dev);
1871
1872 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
1873}
1874
1875static ssize_t aux_firmware_rev_show(struct device *dev,
1876 struct device_attribute *attr,
1877 char *buf)
1878{
1879 struct bmc_device *bmc = dev_get_drvdata(dev);
1880
1881 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
1882 bmc->id.aux_firmware_revision[3],
1883 bmc->id.aux_firmware_revision[2],
1884 bmc->id.aux_firmware_revision[1],
1885 bmc->id.aux_firmware_revision[0]);
1886}
1887
1888static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
1889 char *buf)
1890{
1891 struct bmc_device *bmc = dev_get_drvdata(dev);
1892
1893 return snprintf(buf, 100, "%Lx%Lx\n",
1894 (long long) bmc->guid[0],
1895 (long long) bmc->guid[8]);
1896}
1897
1898static void
1899cleanup_bmc_device(struct kref *ref)
1900{
1901 struct bmc_device *bmc;
1902
1903 bmc = container_of(ref, struct bmc_device, refcount);
1904
1905 device_remove_file(&bmc->dev->dev,
1906 &bmc->device_id_attr);
1907 device_remove_file(&bmc->dev->dev,
1908 &bmc->provides_dev_sdrs_attr);
1909 device_remove_file(&bmc->dev->dev,
1910 &bmc->revision_attr);
1911 device_remove_file(&bmc->dev->dev,
1912 &bmc->firmware_rev_attr);
1913 device_remove_file(&bmc->dev->dev,
1914 &bmc->version_attr);
1915 device_remove_file(&bmc->dev->dev,
1916 &bmc->add_dev_support_attr);
1917 device_remove_file(&bmc->dev->dev,
1918 &bmc->manufacturer_id_attr);
1919 device_remove_file(&bmc->dev->dev,
1920 &bmc->product_id_attr);
1921 if (bmc->id.aux_firmware_revision_set)
1922 device_remove_file(&bmc->dev->dev,
1923 &bmc->aux_firmware_rev_attr);
1924 if (bmc->guid_set)
1925 device_remove_file(&bmc->dev->dev,
1926 &bmc->guid_attr);
1927 platform_device_unregister(bmc->dev);
1928 kfree(bmc);
1929}
1930
1931static void ipmi_bmc_unregister(ipmi_smi_t intf)
1932{
1933 struct bmc_device *bmc = intf->bmc;
1934
1935 sysfs_remove_link(&intf->si_dev->kobj, "bmc");
1936 if (intf->my_dev_name) {
1937 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
1938 kfree(intf->my_dev_name);
1939 intf->my_dev_name = NULL;
1940 }
1941
1942 mutex_lock(&ipmidriver_mutex);
1943 kref_put(&bmc->refcount, cleanup_bmc_device);
1944 mutex_unlock(&ipmidriver_mutex);
1945}
1946
1947static int ipmi_bmc_register(ipmi_smi_t intf)
1948{
1949 int rv;
1950 struct bmc_device *bmc = intf->bmc;
1951 struct bmc_device *old_bmc;
1952 int size;
1953 char dummy[1];
1954
1955 mutex_lock(&ipmidriver_mutex);
1956
1957 /*
1958 * Try to find if there is an bmc_device struct
1959 * representing the interfaced BMC already
1960 */
1961 if (bmc->guid_set)
1962 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
1963 else
1964 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
1965 bmc->id.product_id,
1966 bmc->id.device_id);
1967
1968 /*
1969 * If there is already an bmc_device, free the new one,
1970 * otherwise register the new BMC device
1971 */
1972 if (old_bmc) {
1973 kfree(bmc);
1974 intf->bmc = old_bmc;
1975 bmc = old_bmc;
1976
1977 kref_get(&bmc->refcount);
1978 mutex_unlock(&ipmidriver_mutex);
1979
1980 printk(KERN_INFO
1981 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
1982 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
1983 bmc->id.manufacturer_id,
1984 bmc->id.product_id,
1985 bmc->id.device_id);
1986 } else {
1987 bmc->dev = platform_device_alloc("ipmi_bmc",
1988 bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08001989 if (!bmc->dev) {
Corey Minyard50c812b2006-03-26 01:37:21 -08001990 printk(KERN_ERR
1991 "ipmi_msghandler:"
1992 " Unable to allocate platform device\n");
1993 return -ENOMEM;
1994 }
1995 bmc->dev->dev.driver = &ipmidriver;
1996 dev_set_drvdata(&bmc->dev->dev, bmc);
1997 kref_init(&bmc->refcount);
1998
1999 rv = platform_device_register(bmc->dev);
2000 mutex_unlock(&ipmidriver_mutex);
2001 if (rv) {
2002 printk(KERN_ERR
2003 "ipmi_msghandler:"
2004 " Unable to register bmc device: %d\n",
2005 rv);
2006 /* Don't go to out_err, you can only do that if
2007 the device is registered already. */
2008 return rv;
2009 }
2010
2011 bmc->device_id_attr.attr.name = "device_id";
2012 bmc->device_id_attr.attr.owner = THIS_MODULE;
2013 bmc->device_id_attr.attr.mode = S_IRUGO;
2014 bmc->device_id_attr.show = device_id_show;
2015
2016 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
2017 bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
2018 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2019 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2020
2021
2022 bmc->revision_attr.attr.name = "revision";
2023 bmc->revision_attr.attr.owner = THIS_MODULE;
2024 bmc->revision_attr.attr.mode = S_IRUGO;
2025 bmc->revision_attr.show = revision_show;
2026
2027 bmc->firmware_rev_attr.attr.name = "firmware_revision";
2028 bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
2029 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2030 bmc->firmware_rev_attr.show = firmware_rev_show;
2031
2032 bmc->version_attr.attr.name = "ipmi_version";
2033 bmc->version_attr.attr.owner = THIS_MODULE;
2034 bmc->version_attr.attr.mode = S_IRUGO;
2035 bmc->version_attr.show = ipmi_version_show;
2036
2037 bmc->add_dev_support_attr.attr.name
2038 = "additional_device_support";
2039 bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
2040 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2041 bmc->add_dev_support_attr.show = add_dev_support_show;
2042
2043 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
2044 bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
2045 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2046 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2047
2048 bmc->product_id_attr.attr.name = "product_id";
2049 bmc->product_id_attr.attr.owner = THIS_MODULE;
2050 bmc->product_id_attr.attr.mode = S_IRUGO;
2051 bmc->product_id_attr.show = product_id_show;
2052
2053 bmc->guid_attr.attr.name = "guid";
2054 bmc->guid_attr.attr.owner = THIS_MODULE;
2055 bmc->guid_attr.attr.mode = S_IRUGO;
2056 bmc->guid_attr.show = guid_show;
2057
2058 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
2059 bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
2060 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2061 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2062
2063 device_create_file(&bmc->dev->dev,
2064 &bmc->device_id_attr);
2065 device_create_file(&bmc->dev->dev,
2066 &bmc->provides_dev_sdrs_attr);
2067 device_create_file(&bmc->dev->dev,
2068 &bmc->revision_attr);
2069 device_create_file(&bmc->dev->dev,
2070 &bmc->firmware_rev_attr);
2071 device_create_file(&bmc->dev->dev,
2072 &bmc->version_attr);
2073 device_create_file(&bmc->dev->dev,
2074 &bmc->add_dev_support_attr);
2075 device_create_file(&bmc->dev->dev,
2076 &bmc->manufacturer_id_attr);
2077 device_create_file(&bmc->dev->dev,
2078 &bmc->product_id_attr);
2079 if (bmc->id.aux_firmware_revision_set)
2080 device_create_file(&bmc->dev->dev,
2081 &bmc->aux_firmware_rev_attr);
2082 if (bmc->guid_set)
2083 device_create_file(&bmc->dev->dev,
2084 &bmc->guid_attr);
2085
2086 printk(KERN_INFO
2087 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2088 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2089 bmc->id.manufacturer_id,
2090 bmc->id.product_id,
2091 bmc->id.device_id);
2092 }
2093
2094 /*
2095 * create symlink from system interface device to bmc device
2096 * and back.
2097 */
2098 rv = sysfs_create_link(&intf->si_dev->kobj,
2099 &bmc->dev->dev.kobj, "bmc");
2100 if (rv) {
2101 printk(KERN_ERR
2102 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2103 rv);
2104 goto out_err;
2105 }
2106
2107 size = snprintf(dummy, 0, "ipmi%d", intf->intf_num);
2108 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2109 if (!intf->my_dev_name) {
2110 rv = -ENOMEM;
2111 printk(KERN_ERR
2112 "ipmi_msghandler: allocate link from BMC: %d\n",
2113 rv);
2114 goto out_err;
2115 }
2116 snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num);
2117
2118 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2119 intf->my_dev_name);
2120 if (rv) {
2121 kfree(intf->my_dev_name);
2122 intf->my_dev_name = NULL;
2123 printk(KERN_ERR
2124 "ipmi_msghandler:"
2125 " Unable to create symlink to bmc: %d\n",
2126 rv);
2127 goto out_err;
2128 }
2129
2130 return 0;
2131
2132out_err:
2133 ipmi_bmc_unregister(intf);
2134 return rv;
2135}
2136
2137static int
2138send_guid_cmd(ipmi_smi_t intf, int chan)
2139{
2140 struct kernel_ipmi_msg msg;
2141 struct ipmi_system_interface_addr si;
2142
2143 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2144 si.channel = IPMI_BMC_CHANNEL;
2145 si.lun = 0;
2146
2147 msg.netfn = IPMI_NETFN_APP_REQUEST;
2148 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2149 msg.data = NULL;
2150 msg.data_len = 0;
2151 return i_ipmi_request(NULL,
2152 intf,
2153 (struct ipmi_addr *) &si,
2154 0,
2155 &msg,
2156 intf,
2157 NULL,
2158 NULL,
2159 0,
2160 intf->channels[0].address,
2161 intf->channels[0].lun,
2162 -1, 0);
2163}
2164
2165static void
2166guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2167{
2168 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2169 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2170 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2171 /* Not for me */
2172 return;
2173
2174 if (msg->msg.data[0] != 0) {
2175 /* Error from getting the GUID, the BMC doesn't have one. */
2176 intf->bmc->guid_set = 0;
2177 goto out;
2178 }
2179
2180 if (msg->msg.data_len < 17) {
2181 intf->bmc->guid_set = 0;
2182 printk(KERN_WARNING PFX
2183 "guid_handler: The GUID response from the BMC was too"
2184 " short, it was %d but should have been 17. Assuming"
2185 " GUID is not available.\n",
2186 msg->msg.data_len);
2187 goto out;
2188 }
2189
2190 memcpy(intf->bmc->guid, msg->msg.data, 16);
2191 intf->bmc->guid_set = 1;
2192 out:
2193 wake_up(&intf->waitq);
2194}
2195
2196static void
2197get_guid(ipmi_smi_t intf)
2198{
2199 int rv;
2200
2201 intf->bmc->guid_set = 0x2;
2202 intf->null_user_handler = guid_handler;
2203 rv = send_guid_cmd(intf, 0);
2204 if (rv)
2205 /* Send failed, no GUID available. */
2206 intf->bmc->guid_set = 0;
2207 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2208 intf->null_user_handler = NULL;
2209}
2210
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211static int
2212send_channel_info_cmd(ipmi_smi_t intf, int chan)
2213{
2214 struct kernel_ipmi_msg msg;
2215 unsigned char data[1];
2216 struct ipmi_system_interface_addr si;
2217
2218 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2219 si.channel = IPMI_BMC_CHANNEL;
2220 si.lun = 0;
2221
2222 msg.netfn = IPMI_NETFN_APP_REQUEST;
2223 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2224 msg.data = data;
2225 msg.data_len = 1;
2226 data[0] = chan;
2227 return i_ipmi_request(NULL,
2228 intf,
2229 (struct ipmi_addr *) &si,
2230 0,
2231 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002232 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 NULL,
2234 NULL,
2235 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002236 intf->channels[0].address,
2237 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 -1, 0);
2239}
2240
2241static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002242channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243{
2244 int rv = 0;
2245 int chan;
2246
Corey Minyard56a55ec2005-09-06 15:18:42 -07002247 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2248 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2249 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 {
2251 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002252 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 /* Got an error from the channel, just go on. */
2254
Corey Minyard56a55ec2005-09-06 15:18:42 -07002255 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 /* If the MC does not support this
2257 command, that is legal. We just
2258 assume it has one IPMB at channel
2259 zero. */
2260 intf->channels[0].medium
2261 = IPMI_CHANNEL_MEDIUM_IPMB;
2262 intf->channels[0].protocol
2263 = IPMI_CHANNEL_PROTOCOL_IPMB;
2264 rv = -ENOSYS;
2265
2266 intf->curr_channel = IPMI_MAX_CHANNELS;
2267 wake_up(&intf->waitq);
2268 goto out;
2269 }
2270 goto next_channel;
2271 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002272 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 /* Message not big enough, just go on. */
2274 goto next_channel;
2275 }
2276 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002277 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2278 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279
2280 next_channel:
2281 intf->curr_channel++;
2282 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2283 wake_up(&intf->waitq);
2284 else
2285 rv = send_channel_info_cmd(intf, intf->curr_channel);
2286
2287 if (rv) {
2288 /* Got an error somehow, just give up. */
2289 intf->curr_channel = IPMI_MAX_CHANNELS;
2290 wake_up(&intf->waitq);
2291
2292 printk(KERN_WARNING PFX
2293 "Error sending channel information: %d\n",
2294 rv);
2295 }
2296 }
2297 out:
2298 return;
2299}
2300
2301int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2302 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002303 struct ipmi_device_id *device_id,
2304 struct device *si_dev,
Corey Minyard453823b2006-03-31 02:30:39 -08002305 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306{
2307 int i, j;
2308 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002309 ipmi_smi_t intf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 unsigned long flags;
Corey Minyard50c812b2006-03-26 01:37:21 -08002311 int version_major;
2312 int version_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Corey Minyard50c812b2006-03-26 01:37:21 -08002314 version_major = ipmi_version_major(device_id);
2315 version_minor = ipmi_version_minor(device_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
2317 /* Make sure the driver is actually initialized, this handles
2318 problems with initialization order. */
2319 if (!initialized) {
2320 rv = ipmi_init_msghandler();
2321 if (rv)
2322 return rv;
2323 /* The init code doesn't return an error if it was turned
2324 off, but it won't initialize. Check that. */
2325 if (!initialized)
2326 return -ENODEV;
2327 }
2328
Corey Minyard393d2cc2005-11-07 00:59:54 -08002329 intf = kmalloc(sizeof(*intf), GFP_KERNEL);
2330 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002332 memset(intf, 0, sizeof(*intf));
Corey Minyard50c812b2006-03-26 01:37:21 -08002333 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2334 if (!intf->bmc) {
2335 kfree(intf);
2336 return -ENOMEM;
2337 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002338 intf->intf_num = -1;
2339 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002340 intf->bmc->id = *device_id;
2341 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002342 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2343 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2344 intf->channels[j].lun = 2;
2345 }
2346 if (slave_addr != 0)
2347 intf->channels[0].address = slave_addr;
2348 INIT_LIST_HEAD(&intf->users);
2349 intf->handlers = handlers;
2350 intf->send_info = send_info;
2351 spin_lock_init(&intf->seq_lock);
2352 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2353 intf->seq_table[j].inuse = 0;
2354 intf->seq_table[j].seqid = 0;
2355 }
2356 intf->curr_seq = 0;
2357#ifdef CONFIG_PROC_FS
2358 spin_lock_init(&intf->proc_entry_lock);
2359#endif
2360 spin_lock_init(&intf->waiting_msgs_lock);
2361 INIT_LIST_HEAD(&intf->waiting_msgs);
2362 spin_lock_init(&intf->events_lock);
2363 INIT_LIST_HEAD(&intf->waiting_events);
2364 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002365 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002366 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2367 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
Corey Minyard393d2cc2005-11-07 00:59:54 -08002369 spin_lock_init(&intf->counter_lock);
2370 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
2372 rv = -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002373 spin_lock_irqsave(&interfaces_lock, flags);
Corey Minyarde8b33612005-09-06 15:18:45 -07002374 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 if (ipmi_interfaces[i] == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002376 intf->intf_num = i;
2377 /* Reserve the entry till we are done. */
2378 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 break;
2381 }
2382 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002383 spin_unlock_irqrestore(&interfaces_lock, flags);
2384 if (rv)
2385 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
Corey Minyard453823b2006-03-31 02:30:39 -08002387 rv = handlers->start_processing(send_info, intf);
2388 if (rv)
2389 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002390
Corey Minyard50c812b2006-03-26 01:37:21 -08002391 get_guid(intf);
2392
Corey Minyard393d2cc2005-11-07 00:59:54 -08002393 if ((version_major > 1)
2394 || ((version_major == 1) && (version_minor >= 5)))
2395 {
2396 /* Start scanning the channels to see what is
2397 available. */
2398 intf->null_user_handler = channel_handler;
2399 intf->curr_channel = 0;
2400 rv = send_channel_info_cmd(intf, 0);
2401 if (rv)
2402 goto out;
2403
2404 /* Wait for the channel info to be read. */
2405 wait_event(intf->waitq,
2406 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002407 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002408 } else {
2409 /* Assume a single IPMB channel at zero. */
2410 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2411 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
2414 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002415 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
Corey Minyard50c812b2006-03-26 01:37:21 -08002417 rv = ipmi_bmc_register(intf);
2418
Corey Minyard393d2cc2005-11-07 00:59:54 -08002419 out:
2420 if (rv) {
2421 if (intf->proc_dir)
2422 remove_proc_entries(intf);
2423 kref_put(&intf->refcount, intf_free);
2424 if (i < MAX_IPMI_INTERFACES) {
2425 spin_lock_irqsave(&interfaces_lock, flags);
2426 ipmi_interfaces[i] = NULL;
2427 spin_unlock_irqrestore(&interfaces_lock, flags);
2428 }
2429 } else {
2430 spin_lock_irqsave(&interfaces_lock, flags);
2431 ipmi_interfaces[i] = intf;
2432 spin_unlock_irqrestore(&interfaces_lock, flags);
Corey Minyard50c812b2006-03-26 01:37:21 -08002433 call_smi_watchers(i, intf->si_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 }
2435
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 return rv;
2437}
2438
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439int ipmi_unregister_smi(ipmi_smi_t intf)
2440{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 int i;
2442 struct ipmi_smi_watcher *w;
2443 unsigned long flags;
2444
Corey Minyard50c812b2006-03-26 01:37:21 -08002445 ipmi_bmc_unregister(intf);
2446
Corey Minyard393d2cc2005-11-07 00:59:54 -08002447 spin_lock_irqsave(&interfaces_lock, flags);
2448 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
2449 if (ipmi_interfaces[i] == intf) {
2450 /* Set the interface number reserved until we
2451 * are done. */
2452 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
2453 intf->intf_num = -1;
2454 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002457 spin_unlock_irqrestore(&interfaces_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458
Corey Minyard393d2cc2005-11-07 00:59:54 -08002459 if (i == MAX_IPMI_INTERFACES)
2460 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
Corey Minyard393d2cc2005-11-07 00:59:54 -08002462 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
2464 /* Call all the watcher interfaces to tell them that
2465 an interface is gone. */
2466 down_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002467 list_for_each_entry(w, &smi_watchers, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 w->smi_gone(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 up_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002470
2471 /* Allow the entry to be reused now. */
2472 spin_lock_irqsave(&interfaces_lock, flags);
2473 ipmi_interfaces[i] = NULL;
2474 spin_unlock_irqrestore(&interfaces_lock,flags);
2475
2476 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 return 0;
2478}
2479
2480static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2481 struct ipmi_smi_msg *msg)
2482{
2483 struct ipmi_ipmb_addr ipmb_addr;
2484 struct ipmi_recv_msg *recv_msg;
2485 unsigned long flags;
2486
2487
2488 /* This is 11, not 10, because the response must contain a
2489 * completion code. */
2490 if (msg->rsp_size < 11) {
2491 /* Message not big enough, just ignore it. */
2492 spin_lock_irqsave(&intf->counter_lock, flags);
2493 intf->invalid_ipmb_responses++;
2494 spin_unlock_irqrestore(&intf->counter_lock, flags);
2495 return 0;
2496 }
2497
2498 if (msg->rsp[2] != 0) {
2499 /* An error getting the response, just ignore it. */
2500 return 0;
2501 }
2502
2503 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
2504 ipmb_addr.slave_addr = msg->rsp[6];
2505 ipmb_addr.channel = msg->rsp[3] & 0x0f;
2506 ipmb_addr.lun = msg->rsp[7] & 3;
2507
2508 /* It's a response from a remote entity. Look up the sequence
2509 number and handle the response. */
2510 if (intf_find_seq(intf,
2511 msg->rsp[7] >> 2,
2512 msg->rsp[3] & 0x0f,
2513 msg->rsp[8],
2514 (msg->rsp[4] >> 2) & (~1),
2515 (struct ipmi_addr *) &(ipmb_addr),
2516 &recv_msg))
2517 {
2518 /* We were unable to find the sequence number,
2519 so just nuke the message. */
2520 spin_lock_irqsave(&intf->counter_lock, flags);
2521 intf->unhandled_ipmb_responses++;
2522 spin_unlock_irqrestore(&intf->counter_lock, flags);
2523 return 0;
2524 }
2525
2526 memcpy(recv_msg->msg_data,
2527 &(msg->rsp[9]),
2528 msg->rsp_size - 9);
2529 /* THe other fields matched, so no need to set them, except
2530 for netfn, which needs to be the response that was
2531 returned, not the request value. */
2532 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2533 recv_msg->msg.data = recv_msg->msg_data;
2534 recv_msg->msg.data_len = msg->rsp_size - 10;
2535 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2536 spin_lock_irqsave(&intf->counter_lock, flags);
2537 intf->handled_ipmb_responses++;
2538 spin_unlock_irqrestore(&intf->counter_lock, flags);
2539 deliver_response(recv_msg);
2540
2541 return 0;
2542}
2543
2544static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2545 struct ipmi_smi_msg *msg)
2546{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002547 struct cmd_rcvr *rcvr;
2548 int rv = 0;
2549 unsigned char netfn;
2550 unsigned char cmd;
2551 ipmi_user_t user = NULL;
2552 struct ipmi_ipmb_addr *ipmb_addr;
2553 struct ipmi_recv_msg *recv_msg;
2554 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555
2556 if (msg->rsp_size < 10) {
2557 /* Message not big enough, just ignore it. */
2558 spin_lock_irqsave(&intf->counter_lock, flags);
2559 intf->invalid_commands++;
2560 spin_unlock_irqrestore(&intf->counter_lock, flags);
2561 return 0;
2562 }
2563
2564 if (msg->rsp[2] != 0) {
2565 /* An error getting the response, just ignore it. */
2566 return 0;
2567 }
2568
2569 netfn = msg->rsp[4] >> 2;
2570 cmd = msg->rsp[8];
2571
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002572 rcu_read_lock();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002573 rcvr = find_cmd_rcvr(intf, netfn, cmd);
2574 if (rcvr) {
2575 user = rcvr->user;
2576 kref_get(&user->refcount);
2577 } else
2578 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002579 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
2581 if (user == NULL) {
2582 /* We didn't find a user, deliver an error response. */
2583 spin_lock_irqsave(&intf->counter_lock, flags);
2584 intf->unhandled_commands++;
2585 spin_unlock_irqrestore(&intf->counter_lock, flags);
2586
2587 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2588 msg->data[1] = IPMI_SEND_MSG_CMD;
2589 msg->data[2] = msg->rsp[3];
2590 msg->data[3] = msg->rsp[6];
2591 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2592 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002593 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 /* rqseq/lun */
2595 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2596 msg->data[8] = msg->rsp[8]; /* cmd */
2597 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2598 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2599 msg->data_size = 11;
2600
2601#ifdef DEBUG_MSGING
2602 {
2603 int m;
2604 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002605 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 printk(" %2.2x", msg->data[m]);
2607 printk("\n");
2608 }
2609#endif
2610 intf->handlers->sender(intf->send_info, msg, 0);
2611
2612 rv = -1; /* We used the message, so return the value that
2613 causes it to not be freed or queued. */
2614 } else {
2615 /* Deliver the message to the user. */
2616 spin_lock_irqsave(&intf->counter_lock, flags);
2617 intf->handled_commands++;
2618 spin_unlock_irqrestore(&intf->counter_lock, flags);
2619
2620 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002621 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 /* We couldn't allocate memory for the
2623 message, so requeue it for handling
2624 later. */
2625 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002626 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 } else {
2628 /* Extract the source address from the data. */
2629 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2630 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2631 ipmb_addr->slave_addr = msg->rsp[6];
2632 ipmb_addr->lun = msg->rsp[7] & 3;
2633 ipmb_addr->channel = msg->rsp[3] & 0xf;
2634
2635 /* Extract the rest of the message information
2636 from the IPMB header.*/
2637 recv_msg->user = user;
2638 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2639 recv_msg->msgid = msg->rsp[7] >> 2;
2640 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2641 recv_msg->msg.cmd = msg->rsp[8];
2642 recv_msg->msg.data = recv_msg->msg_data;
2643
2644 /* We chop off 10, not 9 bytes because the checksum
2645 at the end also needs to be removed. */
2646 recv_msg->msg.data_len = msg->rsp_size - 10;
2647 memcpy(recv_msg->msg_data,
2648 &(msg->rsp[9]),
2649 msg->rsp_size - 10);
2650 deliver_response(recv_msg);
2651 }
2652 }
2653
2654 return rv;
2655}
2656
2657static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
2658 struct ipmi_smi_msg *msg)
2659{
2660 struct ipmi_lan_addr lan_addr;
2661 struct ipmi_recv_msg *recv_msg;
2662 unsigned long flags;
2663
2664
2665 /* This is 13, not 12, because the response must contain a
2666 * completion code. */
2667 if (msg->rsp_size < 13) {
2668 /* Message not big enough, just ignore it. */
2669 spin_lock_irqsave(&intf->counter_lock, flags);
2670 intf->invalid_lan_responses++;
2671 spin_unlock_irqrestore(&intf->counter_lock, flags);
2672 return 0;
2673 }
2674
2675 if (msg->rsp[2] != 0) {
2676 /* An error getting the response, just ignore it. */
2677 return 0;
2678 }
2679
2680 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
2681 lan_addr.session_handle = msg->rsp[4];
2682 lan_addr.remote_SWID = msg->rsp[8];
2683 lan_addr.local_SWID = msg->rsp[5];
2684 lan_addr.channel = msg->rsp[3] & 0x0f;
2685 lan_addr.privilege = msg->rsp[3] >> 4;
2686 lan_addr.lun = msg->rsp[9] & 3;
2687
2688 /* It's a response from a remote entity. Look up the sequence
2689 number and handle the response. */
2690 if (intf_find_seq(intf,
2691 msg->rsp[9] >> 2,
2692 msg->rsp[3] & 0x0f,
2693 msg->rsp[10],
2694 (msg->rsp[6] >> 2) & (~1),
2695 (struct ipmi_addr *) &(lan_addr),
2696 &recv_msg))
2697 {
2698 /* We were unable to find the sequence number,
2699 so just nuke the message. */
2700 spin_lock_irqsave(&intf->counter_lock, flags);
2701 intf->unhandled_lan_responses++;
2702 spin_unlock_irqrestore(&intf->counter_lock, flags);
2703 return 0;
2704 }
2705
2706 memcpy(recv_msg->msg_data,
2707 &(msg->rsp[11]),
2708 msg->rsp_size - 11);
2709 /* The other fields matched, so no need to set them, except
2710 for netfn, which needs to be the response that was
2711 returned, not the request value. */
2712 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2713 recv_msg->msg.data = recv_msg->msg_data;
2714 recv_msg->msg.data_len = msg->rsp_size - 12;
2715 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2716 spin_lock_irqsave(&intf->counter_lock, flags);
2717 intf->handled_lan_responses++;
2718 spin_unlock_irqrestore(&intf->counter_lock, flags);
2719 deliver_response(recv_msg);
2720
2721 return 0;
2722}
2723
2724static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2725 struct ipmi_smi_msg *msg)
2726{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002727 struct cmd_rcvr *rcvr;
2728 int rv = 0;
2729 unsigned char netfn;
2730 unsigned char cmd;
2731 ipmi_user_t user = NULL;
2732 struct ipmi_lan_addr *lan_addr;
2733 struct ipmi_recv_msg *recv_msg;
2734 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735
2736 if (msg->rsp_size < 12) {
2737 /* Message not big enough, just ignore it. */
2738 spin_lock_irqsave(&intf->counter_lock, flags);
2739 intf->invalid_commands++;
2740 spin_unlock_irqrestore(&intf->counter_lock, flags);
2741 return 0;
2742 }
2743
2744 if (msg->rsp[2] != 0) {
2745 /* An error getting the response, just ignore it. */
2746 return 0;
2747 }
2748
2749 netfn = msg->rsp[6] >> 2;
2750 cmd = msg->rsp[10];
2751
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002752 rcu_read_lock();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002753 rcvr = find_cmd_rcvr(intf, netfn, cmd);
2754 if (rcvr) {
2755 user = rcvr->user;
2756 kref_get(&user->refcount);
2757 } else
2758 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002759 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760
2761 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002762 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 spin_lock_irqsave(&intf->counter_lock, flags);
2764 intf->unhandled_commands++;
2765 spin_unlock_irqrestore(&intf->counter_lock, flags);
2766
2767 rv = 0; /* Don't do anything with these messages, just
2768 allow them to be freed. */
2769 } else {
2770 /* Deliver the message to the user. */
2771 spin_lock_irqsave(&intf->counter_lock, flags);
2772 intf->handled_commands++;
2773 spin_unlock_irqrestore(&intf->counter_lock, flags);
2774
2775 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002776 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 /* We couldn't allocate memory for the
2778 message, so requeue it for handling
2779 later. */
2780 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002781 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 } else {
2783 /* Extract the source address from the data. */
2784 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
2785 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
2786 lan_addr->session_handle = msg->rsp[4];
2787 lan_addr->remote_SWID = msg->rsp[8];
2788 lan_addr->local_SWID = msg->rsp[5];
2789 lan_addr->lun = msg->rsp[9] & 3;
2790 lan_addr->channel = msg->rsp[3] & 0xf;
2791 lan_addr->privilege = msg->rsp[3] >> 4;
2792
2793 /* Extract the rest of the message information
2794 from the IPMB header.*/
2795 recv_msg->user = user;
2796 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2797 recv_msg->msgid = msg->rsp[9] >> 2;
2798 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2799 recv_msg->msg.cmd = msg->rsp[10];
2800 recv_msg->msg.data = recv_msg->msg_data;
2801
2802 /* We chop off 12, not 11 bytes because the checksum
2803 at the end also needs to be removed. */
2804 recv_msg->msg.data_len = msg->rsp_size - 12;
2805 memcpy(recv_msg->msg_data,
2806 &(msg->rsp[11]),
2807 msg->rsp_size - 12);
2808 deliver_response(recv_msg);
2809 }
2810 }
2811
2812 return rv;
2813}
2814
2815static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
2816 struct ipmi_smi_msg *msg)
2817{
2818 struct ipmi_system_interface_addr *smi_addr;
2819
2820 recv_msg->msgid = 0;
2821 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
2822 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2823 smi_addr->channel = IPMI_BMC_CHANNEL;
2824 smi_addr->lun = msg->rsp[0] & 3;
2825 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
2826 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2827 recv_msg->msg.cmd = msg->rsp[1];
2828 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
2829 recv_msg->msg.data = recv_msg->msg_data;
2830 recv_msg->msg.data_len = msg->rsp_size - 3;
2831}
2832
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833static int handle_read_event_rsp(ipmi_smi_t intf,
2834 struct ipmi_smi_msg *msg)
2835{
2836 struct ipmi_recv_msg *recv_msg, *recv_msg2;
2837 struct list_head msgs;
2838 ipmi_user_t user;
2839 int rv = 0;
2840 int deliver_count = 0;
2841 unsigned long flags;
2842
2843 if (msg->rsp_size < 19) {
2844 /* Message is too small to be an IPMB event. */
2845 spin_lock_irqsave(&intf->counter_lock, flags);
2846 intf->invalid_events++;
2847 spin_unlock_irqrestore(&intf->counter_lock, flags);
2848 return 0;
2849 }
2850
2851 if (msg->rsp[2] != 0) {
2852 /* An error getting the event, just ignore it. */
2853 return 0;
2854 }
2855
2856 INIT_LIST_HEAD(&msgs);
2857
Corey Minyard393d2cc2005-11-07 00:59:54 -08002858 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859
2860 spin_lock(&intf->counter_lock);
2861 intf->events++;
2862 spin_unlock(&intf->counter_lock);
2863
2864 /* Allocate and fill in one message for every user that is getting
2865 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002866 rcu_read_lock();
2867 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08002868 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 continue;
2870
2871 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002872 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002873 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002874 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
2875 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 list_del(&recv_msg->link);
2877 ipmi_free_recv_msg(recv_msg);
2878 }
2879 /* We couldn't allocate memory for the
2880 message, so requeue it for handling
2881 later. */
2882 rv = 1;
2883 goto out;
2884 }
2885
2886 deliver_count++;
2887
2888 copy_event_into_recv_msg(recv_msg, msg);
2889 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002890 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 list_add_tail(&(recv_msg->link), &msgs);
2892 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002893 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
2895 if (deliver_count) {
2896 /* Now deliver all the messages. */
2897 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
2898 list_del(&recv_msg->link);
2899 deliver_response(recv_msg);
2900 }
2901 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
2902 /* No one to receive the message, put it in queue if there's
2903 not already too many things in the queue. */
2904 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002905 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 /* We couldn't allocate memory for the
2907 message, so requeue it for handling
2908 later. */
2909 rv = 1;
2910 goto out;
2911 }
2912
2913 copy_event_into_recv_msg(recv_msg, msg);
2914 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
Corey Minyard4791c032006-04-10 22:54:31 -07002915 intf->waiting_events_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 } else {
2917 /* There's too many things in the queue, discard this
2918 message. */
2919 printk(KERN_WARNING PFX "Event queue full, discarding an"
2920 " incoming event\n");
2921 }
2922
2923 out:
2924 spin_unlock_irqrestore(&(intf->events_lock), flags);
2925
2926 return rv;
2927}
2928
2929static int handle_bmc_rsp(ipmi_smi_t intf,
2930 struct ipmi_smi_msg *msg)
2931{
2932 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002934 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
2936 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002937 if (recv_msg == NULL)
2938 {
2939 printk(KERN_WARNING"IPMI message received with no owner. This\n"
2940 "could be because of a malformed message, or\n"
2941 "because of a hardware error. Contact your\n"
2942 "hardware vender for assistance\n");
2943 return 0;
2944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945
Corey Minyard393d2cc2005-11-07 00:59:54 -08002946 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002948 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07002949 /* The user for the message went away, so give up. */
2950 spin_lock_irqsave(&intf->counter_lock, flags);
2951 intf->unhandled_local_responses++;
2952 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 ipmi_free_recv_msg(recv_msg);
2954 } else {
2955 struct ipmi_system_interface_addr *smi_addr;
2956
2957 spin_lock_irqsave(&intf->counter_lock, flags);
2958 intf->handled_local_responses++;
2959 spin_unlock_irqrestore(&intf->counter_lock, flags);
2960 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2961 recv_msg->msgid = msg->msgid;
2962 smi_addr = ((struct ipmi_system_interface_addr *)
2963 &(recv_msg->addr));
2964 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2965 smi_addr->channel = IPMI_BMC_CHANNEL;
2966 smi_addr->lun = msg->rsp[0] & 3;
2967 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2968 recv_msg->msg.cmd = msg->rsp[1];
2969 memcpy(recv_msg->msg_data,
2970 &(msg->rsp[2]),
2971 msg->rsp_size - 2);
2972 recv_msg->msg.data = recv_msg->msg_data;
2973 recv_msg->msg.data_len = msg->rsp_size - 2;
2974 deliver_response(recv_msg);
2975 }
2976
2977 return 0;
2978}
2979
2980/* Handle a new message. Return 1 if the message should be requeued,
2981 0 if the message should be freed, or -1 if the message should not
2982 be freed or requeued. */
2983static int handle_new_recv_msg(ipmi_smi_t intf,
2984 struct ipmi_smi_msg *msg)
2985{
2986 int requeue;
2987 int chan;
2988
2989#ifdef DEBUG_MSGING
2990 int m;
2991 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002992 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 printk(" %2.2x", msg->rsp[m]);
2994 printk("\n");
2995#endif
2996 if (msg->rsp_size < 2) {
2997 /* Message is too small to be correct. */
2998 printk(KERN_WARNING PFX "BMC returned to small a message"
2999 " for netfn %x cmd %x, got %d bytes\n",
3000 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3001
3002 /* Generate an error response for the message. */
3003 msg->rsp[0] = msg->data[0] | (1 << 2);
3004 msg->rsp[1] = msg->data[1];
3005 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3006 msg->rsp_size = 3;
3007 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3008 || (msg->rsp[1] != msg->data[1])) /* Command */
3009 {
3010 /* The response is not even marginally correct. */
3011 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3012 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3013 (msg->data[0] >> 2) | 1, msg->data[1],
3014 msg->rsp[0] >> 2, msg->rsp[1]);
3015
3016 /* Generate an error response for the message. */
3017 msg->rsp[0] = msg->data[0] | (1 << 2);
3018 msg->rsp[1] = msg->data[1];
3019 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3020 msg->rsp_size = 3;
3021 }
3022
3023 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3024 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3025 && (msg->user_data != NULL))
3026 {
3027 /* It's a response to a response we sent. For this we
3028 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003029 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030
3031 requeue = 0;
3032 if (msg->rsp_size < 2)
3033 /* Message is too small to be correct. */
3034 goto out;
3035
3036 chan = msg->data[2] & 0x0f;
3037 if (chan >= IPMI_MAX_CHANNELS)
3038 /* Invalid channel number */
3039 goto out;
3040
Corey Minyard393d2cc2005-11-07 00:59:54 -08003041 if (!recv_msg)
3042 goto out;
3043
3044 /* Make sure the user still exists. */
3045 if (!recv_msg->user || !recv_msg->user->valid)
3046 goto out;
3047
3048 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3049 recv_msg->msg.data = recv_msg->msg_data;
3050 recv_msg->msg.data_len = 1;
3051 recv_msg->msg_data[0] = msg->rsp[2];
3052 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3054 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3055 {
3056 /* It's from the receive queue. */
3057 chan = msg->rsp[3] & 0xf;
3058 if (chan >= IPMI_MAX_CHANNELS) {
3059 /* Invalid channel number */
3060 requeue = 0;
3061 goto out;
3062 }
3063
3064 switch (intf->channels[chan].medium) {
3065 case IPMI_CHANNEL_MEDIUM_IPMB:
3066 if (msg->rsp[4] & 0x04) {
3067 /* It's a response, so find the
3068 requesting message and send it up. */
3069 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3070 } else {
3071 /* It's a command to the SMS from some other
3072 entity. Handle that. */
3073 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3074 }
3075 break;
3076
3077 case IPMI_CHANNEL_MEDIUM_8023LAN:
3078 case IPMI_CHANNEL_MEDIUM_ASYNC:
3079 if (msg->rsp[6] & 0x04) {
3080 /* It's a response, so find the
3081 requesting message and send it up. */
3082 requeue = handle_lan_get_msg_rsp(intf, msg);
3083 } else {
3084 /* It's a command to the SMS from some other
3085 entity. Handle that. */
3086 requeue = handle_lan_get_msg_cmd(intf, msg);
3087 }
3088 break;
3089
3090 default:
3091 /* We don't handle the channel type, so just
3092 * free the message. */
3093 requeue = 0;
3094 }
3095
3096 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3097 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3098 {
3099 /* It's an asyncronous event. */
3100 requeue = handle_read_event_rsp(intf, msg);
3101 } else {
3102 /* It's a response from the local BMC. */
3103 requeue = handle_bmc_rsp(intf, msg);
3104 }
3105
3106 out:
3107 return requeue;
3108}
3109
3110/* Handle a new message from the lower layer. */
3111void ipmi_smi_msg_received(ipmi_smi_t intf,
3112 struct ipmi_smi_msg *msg)
3113{
3114 unsigned long flags;
3115 int rv;
3116
3117
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 if ((msg->data_size >= 2)
3119 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3120 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003121 && (msg->user_data == NULL))
3122 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 /* This is the local response to a command send, start
3124 the timer for these. The user_data will not be
3125 NULL if this is a response send, and we will let
3126 response sends just go through. */
3127
3128 /* Check for errors, if we get certain errors (ones
3129 that mean basically we can try again later), we
3130 ignore them and start the timer. Otherwise we
3131 report the error immediately. */
3132 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3133 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
3134 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR))
3135 {
3136 int chan = msg->rsp[3] & 0xf;
3137
3138 /* Got an error sending the message, handle it. */
3139 spin_lock_irqsave(&intf->counter_lock, flags);
3140 if (chan >= IPMI_MAX_CHANNELS)
3141 ; /* This shouldn't happen */
3142 else if ((intf->channels[chan].medium
3143 == IPMI_CHANNEL_MEDIUM_8023LAN)
3144 || (intf->channels[chan].medium
3145 == IPMI_CHANNEL_MEDIUM_ASYNC))
3146 intf->sent_lan_command_errs++;
3147 else
3148 intf->sent_ipmb_command_errs++;
3149 spin_unlock_irqrestore(&intf->counter_lock, flags);
3150 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3151 } else {
3152 /* The message was sent, start the timer. */
3153 intf_start_seq_timer(intf, msg->msgid);
3154 }
3155
3156 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003157 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 }
3159
3160 /* To preserve message order, if the list is not empty, we
3161 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003162 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
3163 if (!list_empty(&intf->waiting_msgs)) {
3164 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003165 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003166 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003168 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
3170 rv = handle_new_recv_msg(intf, msg);
3171 if (rv > 0) {
3172 /* Could not handle the message now, just add it to a
3173 list to handle later. */
Hironobu Ishii177294d2005-11-11 08:12:21 -06003174 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003175 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003176 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 } else if (rv == 0) {
3178 ipmi_free_smi_msg(msg);
3179 }
3180
Corey Minyard393d2cc2005-11-07 00:59:54 -08003181 out:
3182 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183}
3184
3185void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3186{
3187 ipmi_user_t user;
3188
Corey Minyard393d2cc2005-11-07 00:59:54 -08003189 rcu_read_lock();
3190 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003191 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 continue;
3193
3194 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3195 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003196 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197}
3198
3199static void
3200handle_msg_timeout(struct ipmi_recv_msg *msg)
3201{
3202 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3203 msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;
3204 msg->msg.netfn |= 1; /* Convert to a response. */
3205 msg->msg.data_len = 1;
3206 msg->msg.data = msg->msg_data;
3207 deliver_response(msg);
3208}
3209
Corey Minyard882fe012005-05-01 08:59:12 -07003210static struct ipmi_smi_msg *
3211smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3212 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213{
Corey Minyard882fe012005-05-01 08:59:12 -07003214 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 if (!smi_msg)
3216 /* If we can't allocate the message, then just return, we
3217 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003218 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219
3220 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3221 smi_msg->data_size = recv_msg->msg.data_len;
3222 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3223
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224#ifdef DEBUG_MSGING
3225 {
3226 int m;
3227 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003228 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 printk(" %2.2x", smi_msg->data[m]);
3230 printk("\n");
3231 }
3232#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003233 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234}
3235
Corey Minyard393d2cc2005-11-07 00:59:54 -08003236static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3237 struct list_head *timeouts, long timeout_period,
3238 int slot, unsigned long *flags)
3239{
3240 struct ipmi_recv_msg *msg;
3241
3242 if (!ent->inuse)
3243 return;
3244
3245 ent->timeout -= timeout_period;
3246 if (ent->timeout > 0)
3247 return;
3248
3249 if (ent->retries_left == 0) {
3250 /* The message has used all its retries. */
3251 ent->inuse = 0;
3252 msg = ent->recv_msg;
3253 list_add_tail(&msg->link, timeouts);
3254 spin_lock(&intf->counter_lock);
3255 if (ent->broadcast)
3256 intf->timed_out_ipmb_broadcasts++;
3257 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3258 intf->timed_out_lan_commands++;
3259 else
3260 intf->timed_out_ipmb_commands++;
3261 spin_unlock(&intf->counter_lock);
3262 } else {
3263 struct ipmi_smi_msg *smi_msg;
3264 /* More retries, send again. */
3265
3266 /* Start with the max timer, set to normal
3267 timer after the message is sent. */
3268 ent->timeout = MAX_MSG_TIMEOUT;
3269 ent->retries_left--;
3270 spin_lock(&intf->counter_lock);
3271 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3272 intf->retransmitted_lan_commands++;
3273 else
3274 intf->retransmitted_ipmb_commands++;
3275 spin_unlock(&intf->counter_lock);
3276
3277 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3278 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003279 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003280 return;
3281
3282 spin_unlock_irqrestore(&intf->seq_lock, *flags);
3283 /* Send the new message. We send with a zero
3284 * priority. It timed out, I doubt time is
3285 * that critical now, and high priority
3286 * messages are really only for messages to the
3287 * local MC, which don't get resent. */
3288 intf->handlers->sender(intf->send_info,
3289 smi_msg, 0);
3290 spin_lock_irqsave(&intf->seq_lock, *flags);
3291 }
3292}
3293
3294static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295{
3296 ipmi_smi_t intf;
3297 struct list_head timeouts;
3298 struct ipmi_recv_msg *msg, *msg2;
3299 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3300 unsigned long flags;
3301 int i, j;
3302
3303 INIT_LIST_HEAD(&timeouts);
3304
3305 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07003306 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003308 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 continue;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003310 kref_get(&intf->refcount);
3311 spin_unlock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
3313 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003314 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003315 list_for_each_entry_safe(smi_msg, smi_msg2,
3316 &intf->waiting_msgs, link) {
3317 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 list_del(&smi_msg->link);
3319 ipmi_free_smi_msg(smi_msg);
3320 } else {
3321 /* To preserve message order, quit if we
3322 can't handle a message. */
3323 break;
3324 }
3325 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003326 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327
3328 /* Go through the seq table and find any messages that
3329 have timed out, putting them in the timeouts
3330 list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003331 spin_lock_irqsave(&intf->seq_lock, flags);
3332 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++)
3333 check_msg_timeout(intf, &(intf->seq_table[j]),
3334 &timeouts, timeout_period, j,
3335 &flags);
3336 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337
Corey Minyard393d2cc2005-11-07 00:59:54 -08003338 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 handle_msg_timeout(msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340
Corey Minyard393d2cc2005-11-07 00:59:54 -08003341 kref_put(&intf->refcount, intf_free);
3342 spin_lock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 }
3344 spin_unlock(&interfaces_lock);
3345}
3346
3347static void ipmi_request_event(void)
3348{
3349 ipmi_smi_t intf;
3350 int i;
3351
3352 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07003353 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003355 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 continue;
3357
3358 intf->handlers->request_events(intf->send_info);
3359 }
3360 spin_unlock(&interfaces_lock);
3361}
3362
3363static struct timer_list ipmi_timer;
3364
3365/* Call every ~100 ms. */
3366#define IPMI_TIMEOUT_TIME 100
3367
3368/* How many jiffies does it take to get to the timeout time. */
3369#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3370
3371/* Request events from the queue every second (this is the number of
3372 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3373 future, IPMI will add a way to know immediately if an event is in
3374 the queue and this silliness can go away. */
3375#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3376
Corey Minyard8f43f842005-06-23 22:01:40 -07003377static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3379
3380static void ipmi_timeout(unsigned long data)
3381{
Corey Minyard8f43f842005-06-23 22:01:40 -07003382 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384
3385 ticks_to_req_ev--;
3386 if (ticks_to_req_ev == 0) {
3387 ipmi_request_event();
3388 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3389 }
3390
3391 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3392
Corey Minyard8f43f842005-06-23 22:01:40 -07003393 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394}
3395
3396
3397static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3398static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3399
3400/* FIXME - convert these to slabs. */
3401static void free_smi_msg(struct ipmi_smi_msg *msg)
3402{
3403 atomic_dec(&smi_msg_inuse_count);
3404 kfree(msg);
3405}
3406
3407struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3408{
3409 struct ipmi_smi_msg *rv;
3410 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3411 if (rv) {
3412 rv->done = free_smi_msg;
3413 rv->user_data = NULL;
3414 atomic_inc(&smi_msg_inuse_count);
3415 }
3416 return rv;
3417}
3418
3419static void free_recv_msg(struct ipmi_recv_msg *msg)
3420{
3421 atomic_dec(&recv_msg_inuse_count);
3422 kfree(msg);
3423}
3424
3425struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3426{
3427 struct ipmi_recv_msg *rv;
3428
3429 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3430 if (rv) {
Corey Minyarda9eec552006-08-31 21:27:45 -07003431 rv->user = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 rv->done = free_recv_msg;
3433 atomic_inc(&recv_msg_inuse_count);
3434 }
3435 return rv;
3436}
3437
Corey Minyard393d2cc2005-11-07 00:59:54 -08003438void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3439{
3440 if (msg->user)
3441 kref_put(&msg->user->refcount, free_user);
3442 msg->done(msg);
3443}
3444
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445#ifdef CONFIG_IPMI_PANIC_EVENT
3446
3447static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3448{
3449}
3450
3451static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3452{
3453}
3454
3455#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003456static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003458 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3459 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3460 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3461 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 {
3463 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003464 intf->event_receiver = msg->msg.data[1];
3465 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 }
3467}
3468
Corey Minyard56a55ec2005-09-06 15:18:42 -07003469static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003471 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3472 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3473 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3474 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 {
3476 /* A get device id command, save if we are an event
3477 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003478 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3479 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 }
3481}
3482#endif
3483
3484static void send_panic_events(char *str)
3485{
3486 struct kernel_ipmi_msg msg;
3487 ipmi_smi_t intf;
3488 unsigned char data[16];
3489 int i;
3490 struct ipmi_system_interface_addr *si;
3491 struct ipmi_addr addr;
3492 struct ipmi_smi_msg smi_msg;
3493 struct ipmi_recv_msg recv_msg;
3494
3495 si = (struct ipmi_system_interface_addr *) &addr;
3496 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3497 si->channel = IPMI_BMC_CHANNEL;
3498 si->lun = 0;
3499
3500 /* Fill in an event telling that we have failed. */
3501 msg.netfn = 0x04; /* Sensor or Event. */
3502 msg.cmd = 2; /* Platform event command. */
3503 msg.data = data;
3504 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003505 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 data[1] = 0x03; /* This is for IPMI 1.0. */
3507 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3508 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3509 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3510
3511 /* Put a few breadcrumbs in. Hopefully later we can add more things
3512 to make the panic events more useful. */
3513 if (str) {
3514 data[3] = str[0];
3515 data[6] = str[1];
3516 data[7] = str[2];
3517 }
3518
3519 smi_msg.done = dummy_smi_done_handler;
3520 recv_msg.done = dummy_recv_done_handler;
3521
3522 /* For every registered interface, send the event. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003523 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003525 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 continue;
3527
3528 /* Send the event announcing the panic. */
3529 intf->handlers->set_run_to_completion(intf->send_info, 1);
3530 i_ipmi_request(NULL,
3531 intf,
3532 &addr,
3533 0,
3534 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003535 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 &smi_msg,
3537 &recv_msg,
3538 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003539 intf->channels[0].address,
3540 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 0, 1); /* Don't retry, and don't wait. */
3542 }
3543
3544#ifdef CONFIG_IPMI_PANIC_STRING
3545 /* On every interface, dump a bunch of OEM event holding the
3546 string. */
3547 if (!str)
3548 return;
3549
Corey Minyarde8b33612005-09-06 15:18:45 -07003550 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 char *p = str;
3552 struct ipmi_ipmb_addr *ipmb;
3553 int j;
3554
3555 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003556 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 continue;
3558
3559 /* First job here is to figure out where to send the
3560 OEM events. There's no way in IPMI to send OEM
3561 events using an event send command, so we have to
3562 find the SEL to put them in and stick them in
3563 there. */
3564
3565 /* Get capabilities from the get device id. */
3566 intf->local_sel_device = 0;
3567 intf->local_event_generator = 0;
3568 intf->event_receiver = 0;
3569
3570 /* Request the device info from the local MC. */
3571 msg.netfn = IPMI_NETFN_APP_REQUEST;
3572 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3573 msg.data = NULL;
3574 msg.data_len = 0;
3575 intf->null_user_handler = device_id_fetcher;
3576 i_ipmi_request(NULL,
3577 intf,
3578 &addr,
3579 0,
3580 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003581 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 &smi_msg,
3583 &recv_msg,
3584 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003585 intf->channels[0].address,
3586 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 0, 1); /* Don't retry, and don't wait. */
3588
3589 if (intf->local_event_generator) {
3590 /* Request the event receiver from the local MC. */
3591 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3592 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3593 msg.data = NULL;
3594 msg.data_len = 0;
3595 intf->null_user_handler = event_receiver_fetcher;
3596 i_ipmi_request(NULL,
3597 intf,
3598 &addr,
3599 0,
3600 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003601 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 &smi_msg,
3603 &recv_msg,
3604 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003605 intf->channels[0].address,
3606 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 0, 1); /* no retry, and no wait. */
3608 }
3609 intf->null_user_handler = NULL;
3610
3611 /* Validate the event receiver. The low bit must not
3612 be 1 (it must be a valid IPMB address), it cannot
3613 be zero, and it must not be my address. */
3614 if (((intf->event_receiver & 1) == 0)
3615 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003616 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 {
3618 /* The event receiver is valid, send an IPMB
3619 message. */
3620 ipmb = (struct ipmi_ipmb_addr *) &addr;
3621 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3622 ipmb->channel = 0; /* FIXME - is this right? */
3623 ipmb->lun = intf->event_receiver_lun;
3624 ipmb->slave_addr = intf->event_receiver;
3625 } else if (intf->local_sel_device) {
3626 /* The event receiver was not valid (or was
3627 me), but I am an SEL device, just dump it
3628 in my SEL. */
3629 si = (struct ipmi_system_interface_addr *) &addr;
3630 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3631 si->channel = IPMI_BMC_CHANNEL;
3632 si->lun = 0;
3633 } else
3634 continue; /* No where to send the event. */
3635
3636
3637 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
3638 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
3639 msg.data = data;
3640 msg.data_len = 16;
3641
3642 j = 0;
3643 while (*p) {
3644 int size = strlen(p);
3645
3646 if (size > 11)
3647 size = 11;
3648 data[0] = 0;
3649 data[1] = 0;
3650 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07003651 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 data[4] = j++; /* sequence # */
3653 /* Always give 11 bytes, so strncpy will fill
3654 it with zeroes for me. */
3655 strncpy(data+5, p, 11);
3656 p += size;
3657
3658 i_ipmi_request(NULL,
3659 intf,
3660 &addr,
3661 0,
3662 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003663 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 &smi_msg,
3665 &recv_msg,
3666 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003667 intf->channels[0].address,
3668 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 0, 1); /* no retry, and no wait. */
3670 }
3671 }
3672#endif /* CONFIG_IPMI_PANIC_STRING */
3673}
3674#endif /* CONFIG_IPMI_PANIC_EVENT */
3675
Lee Revellf18190b2006-06-26 18:30:00 +02003676static int has_panicked = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677
3678static int panic_event(struct notifier_block *this,
3679 unsigned long event,
3680 void *ptr)
3681{
3682 int i;
3683 ipmi_smi_t intf;
3684
Lee Revellf18190b2006-06-26 18:30:00 +02003685 if (has_panicked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 return NOTIFY_DONE;
Lee Revellf18190b2006-06-26 18:30:00 +02003687 has_panicked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688
3689 /* For every registered interface, set it to run to completion. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003690 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003692 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 continue;
3694
3695 intf->handlers->set_run_to_completion(intf->send_info, 1);
3696 }
3697
3698#ifdef CONFIG_IPMI_PANIC_EVENT
3699 send_panic_events(ptr);
3700#endif
3701
3702 return NOTIFY_DONE;
3703}
3704
3705static struct notifier_block panic_block = {
3706 .notifier_call = panic_event,
3707 .next = NULL,
3708 .priority = 200 /* priority: INT_MAX >= x >= 0 */
3709};
3710
3711static int ipmi_init_msghandler(void)
3712{
3713 int i;
Corey Minyard50c812b2006-03-26 01:37:21 -08003714 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715
3716 if (initialized)
3717 return 0;
3718
Corey Minyard50c812b2006-03-26 01:37:21 -08003719 rv = driver_register(&ipmidriver);
3720 if (rv) {
3721 printk(KERN_ERR PFX "Could not register IPMI driver\n");
3722 return rv;
3723 }
3724
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003726 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727
Corey Minyard393d2cc2005-11-07 00:59:54 -08003728 for (i = 0; i < MAX_IPMI_INTERFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 ipmi_interfaces[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730
Corey Minyard3b625942005-06-23 22:01:42 -07003731#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 proc_ipmi_root = proc_mkdir("ipmi", NULL);
3733 if (!proc_ipmi_root) {
3734 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
3735 return -ENOMEM;
3736 }
3737
3738 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07003739#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740
Corey Minyard409035e2006-06-28 04:26:53 -07003741 setup_timer(&ipmi_timer, ipmi_timeout, 0);
3742 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743
Alan Sterne041c682006-03-27 01:16:30 -08003744 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745
3746 initialized = 1;
3747
3748 return 0;
3749}
3750
3751static __init int ipmi_init_msghandler_mod(void)
3752{
3753 ipmi_init_msghandler();
3754 return 0;
3755}
3756
3757static __exit void cleanup_ipmi(void)
3758{
3759 int count;
3760
3761 if (!initialized)
3762 return;
3763
Alan Sterne041c682006-03-27 01:16:30 -08003764 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765
3766 /* This can't be called if any interfaces exist, so no worry about
3767 shutting down the interfaces. */
3768
3769 /* Tell the timer to stop, then wait for it to stop. This avoids
3770 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07003771 atomic_inc(&stop_operation);
3772 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773
Corey Minyard3b625942005-06-23 22:01:42 -07003774#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 remove_proc_entry(proc_ipmi_root->name, &proc_root);
Corey Minyard3b625942005-06-23 22:01:42 -07003776#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777
Corey Minyard50c812b2006-03-26 01:37:21 -08003778 driver_unregister(&ipmidriver);
3779
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 initialized = 0;
3781
3782 /* Check for buffer leaks. */
3783 count = atomic_read(&smi_msg_inuse_count);
3784 if (count != 0)
3785 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
3786 count);
3787 count = atomic_read(&recv_msg_inuse_count);
3788 if (count != 0)
3789 printk(KERN_WARNING PFX "recv message count %d at exit\n",
3790 count);
3791}
3792module_exit(cleanup_ipmi);
3793
3794module_init(ipmi_init_msghandler_mod);
3795MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003796MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
3797MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
3798MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799
3800EXPORT_SYMBOL(ipmi_create_user);
3801EXPORT_SYMBOL(ipmi_destroy_user);
3802EXPORT_SYMBOL(ipmi_get_version);
3803EXPORT_SYMBOL(ipmi_request_settime);
3804EXPORT_SYMBOL(ipmi_request_supply_msgs);
3805EXPORT_SYMBOL(ipmi_register_smi);
3806EXPORT_SYMBOL(ipmi_unregister_smi);
3807EXPORT_SYMBOL(ipmi_register_for_cmd);
3808EXPORT_SYMBOL(ipmi_unregister_for_cmd);
3809EXPORT_SYMBOL(ipmi_smi_msg_received);
3810EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
3811EXPORT_SYMBOL(ipmi_alloc_smi_msg);
3812EXPORT_SYMBOL(ipmi_addr_length);
3813EXPORT_SYMBOL(ipmi_validate_addr);
3814EXPORT_SYMBOL(ipmi_set_gets_events);
3815EXPORT_SYMBOL(ipmi_smi_watcher_register);
3816EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
3817EXPORT_SYMBOL(ipmi_set_my_address);
3818EXPORT_SYMBOL(ipmi_get_my_address);
3819EXPORT_SYMBOL(ipmi_set_my_LUN);
3820EXPORT_SYMBOL(ipmi_get_my_LUN);
3821EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003823EXPORT_SYMBOL(ipmi_free_recv_msg);