blob: c47add8e47df3009aaf25d6dffe4ded0b64f0773 [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 Minyardc69c3122006-09-30 23:27:56 -070099 unsigned int chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800100
101 /*
102 * This is used to form a linked lised during mass deletion.
103 * Since this is in an RCU list, we cannot use the link above
104 * or change any data until the RCU period completes. So we
105 * use this next variable during mass deletion so we can have
106 * a list and don't have to wait and restart the search on
107 * every individual deletion of a command. */
108 struct cmd_rcvr *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109};
110
111struct seq_table
112{
113 unsigned int inuse : 1;
114 unsigned int broadcast : 1;
115
116 unsigned long timeout;
117 unsigned long orig_timeout;
118 unsigned int retries_left;
119
120 /* To verify on an incoming send message response that this is
121 the message that the response is for, we keep a sequence id
122 and increment it every time we send a message. */
123 long seqid;
124
125 /* This is held so we can properly respond to the message on a
126 timeout, and it is used to hold the temporary data for
127 retransmission, too. */
128 struct ipmi_recv_msg *recv_msg;
129};
130
131/* Store the information in a msgid (long) to allow us to find a
132 sequence table entry from the msgid. */
133#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
134
135#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
136 do { \
137 seq = ((msgid >> 26) & 0x3f); \
138 seqid = (msgid & 0x3fffff); \
Corey Minyarde8b33612005-09-06 15:18:45 -0700139 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
142
143struct ipmi_channel
144{
145 unsigned char medium;
146 unsigned char protocol;
Corey Minyardc14979b2005-09-06 15:18:38 -0700147
148 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
149 but may be changed by the user. */
150 unsigned char address;
151
152 /* My LUN. This should generally stay the SMS LUN, but just in
153 case... */
154 unsigned char lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155};
156
Corey Minyard3b625942005-06-23 22:01:42 -0700157#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158struct ipmi_proc_entry
159{
160 char *name;
161 struct ipmi_proc_entry *next;
162};
Corey Minyard3b625942005-06-23 22:01:42 -0700163#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Corey Minyard50c812b2006-03-26 01:37:21 -0800165struct bmc_device
166{
167 struct platform_device *dev;
168 struct ipmi_device_id id;
169 unsigned char guid[16];
170 int guid_set;
171
172 struct kref refcount;
173
174 /* bmc device attributes */
175 struct device_attribute device_id_attr;
176 struct device_attribute provides_dev_sdrs_attr;
177 struct device_attribute revision_attr;
178 struct device_attribute firmware_rev_attr;
179 struct device_attribute version_attr;
180 struct device_attribute add_dev_support_attr;
181 struct device_attribute manufacturer_id_attr;
182 struct device_attribute product_id_attr;
183 struct device_attribute guid_attr;
184 struct device_attribute aux_firmware_rev_attr;
185};
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187#define IPMI_IPMB_NUM_SEQ 64
Corey Minyardc14979b2005-09-06 15:18:38 -0700188#define IPMI_MAX_CHANNELS 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189struct ipmi_smi
190{
191 /* What interface number are we? */
192 int intf_num;
193
Corey Minyard393d2cc2005-11-07 00:59:54 -0800194 struct kref refcount;
195
196 /* The list of upper layers that are using me. seq_lock
197 * protects this. */
198 struct list_head users;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200 /* Used for wake ups at startup. */
201 wait_queue_head_t waitq;
202
Corey Minyard50c812b2006-03-26 01:37:21 -0800203 struct bmc_device *bmc;
204 char *my_dev_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206 /* This is the lower-layer's sender routine. */
207 struct ipmi_smi_handlers *handlers;
208 void *send_info;
209
Corey Minyard3b625942005-06-23 22:01:42 -0700210#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 /* A list of proc entries for this interface. This does not
212 need a lock, only one thread creates it and only one thread
213 destroys it. */
Corey Minyard3b625942005-06-23 22:01:42 -0700214 spinlock_t proc_entry_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 struct ipmi_proc_entry *proc_entries;
Corey Minyard3b625942005-06-23 22:01:42 -0700216#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Corey Minyard50c812b2006-03-26 01:37:21 -0800218 /* Driver-model device for the system interface. */
219 struct device *si_dev;
220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 /* A table of sequence numbers for this interface. We use the
222 sequence numbers for IPMB messages that go out of the
223 interface to match them up with their responses. A routine
224 is called periodically to time the items in this list. */
225 spinlock_t seq_lock;
226 struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
227 int curr_seq;
228
229 /* Messages that were delayed for some reason (out of memory,
230 for instance), will go in here to be processed later in a
231 periodic timer interrupt. */
232 spinlock_t waiting_msgs_lock;
233 struct list_head waiting_msgs;
234
235 /* The list of command receivers that are registered for commands
236 on this interface. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800237 struct mutex cmd_rcvrs_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 struct list_head cmd_rcvrs;
239
240 /* Events that were queues because no one was there to receive
241 them. */
242 spinlock_t events_lock; /* For dealing with event stuff. */
243 struct list_head waiting_events;
244 unsigned int waiting_events_count; /* How many events in queue? */
245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 /* The event receiver for my BMC, only really used at panic
247 shutdown as a place to store this. */
248 unsigned char event_receiver;
249 unsigned char event_receiver_lun;
250 unsigned char local_sel_device;
251 unsigned char local_event_generator;
252
253 /* A cheap hack, if this is non-null and a message to an
254 interface comes in with a NULL user, call this routine with
255 it. Note that the message will still be freed by the
256 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700257 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
259 /* When we are scanning the channels for an SMI, this will
260 tell which channel we are scanning. */
261 int curr_channel;
262
263 /* Channel information */
264 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
265
266 /* Proc FS stuff. */
267 struct proc_dir_entry *proc_dir;
268 char proc_dir_name[10];
269
270 spinlock_t counter_lock; /* For making counters atomic. */
271
272 /* Commands we got that were invalid. */
273 unsigned int sent_invalid_commands;
274
275 /* Commands we sent to the MC. */
276 unsigned int sent_local_commands;
277 /* Responses from the MC that were delivered to a user. */
278 unsigned int handled_local_responses;
279 /* Responses from the MC that were not delivered to a user. */
280 unsigned int unhandled_local_responses;
281
282 /* Commands we sent out to the IPMB bus. */
283 unsigned int sent_ipmb_commands;
284 /* Commands sent on the IPMB that had errors on the SEND CMD */
285 unsigned int sent_ipmb_command_errs;
286 /* Each retransmit increments this count. */
287 unsigned int retransmitted_ipmb_commands;
288 /* When a message times out (runs out of retransmits) this is
289 incremented. */
290 unsigned int timed_out_ipmb_commands;
291
292 /* This is like above, but for broadcasts. Broadcasts are
293 *not* included in the above count (they are expected to
294 time out). */
295 unsigned int timed_out_ipmb_broadcasts;
296
297 /* Responses I have sent to the IPMB bus. */
298 unsigned int sent_ipmb_responses;
299
300 /* The response was delivered to the user. */
301 unsigned int handled_ipmb_responses;
302 /* The response had invalid data in it. */
303 unsigned int invalid_ipmb_responses;
304 /* The response didn't have anyone waiting for it. */
305 unsigned int unhandled_ipmb_responses;
306
307 /* Commands we sent out to the IPMB bus. */
308 unsigned int sent_lan_commands;
309 /* Commands sent on the IPMB that had errors on the SEND CMD */
310 unsigned int sent_lan_command_errs;
311 /* Each retransmit increments this count. */
312 unsigned int retransmitted_lan_commands;
313 /* When a message times out (runs out of retransmits) this is
314 incremented. */
315 unsigned int timed_out_lan_commands;
316
317 /* Responses I have sent to the IPMB bus. */
318 unsigned int sent_lan_responses;
319
320 /* The response was delivered to the user. */
321 unsigned int handled_lan_responses;
322 /* The response had invalid data in it. */
323 unsigned int invalid_lan_responses;
324 /* The response didn't have anyone waiting for it. */
325 unsigned int unhandled_lan_responses;
326
327 /* The command was delivered to the user. */
328 unsigned int handled_commands;
329 /* The command had invalid data in it. */
330 unsigned int invalid_commands;
331 /* The command didn't have anyone waiting for it. */
332 unsigned int unhandled_commands;
333
334 /* Invalid data in an event. */
335 unsigned int invalid_events;
336 /* Events that were received with the proper format. */
337 unsigned int events;
338};
Corey Minyard50c812b2006-03-26 01:37:21 -0800339#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Corey Minyard393d2cc2005-11-07 00:59:54 -0800341/* Used to mark an interface entry that cannot be used but is not a
342 * free entry, either, primarily used at creation and deletion time so
343 * a slot doesn't get reused too quickly. */
344#define IPMI_INVALID_INTERFACE_ENTRY ((ipmi_smi_t) ((long) 1))
345#define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \
346 || (i == IPMI_INVALID_INTERFACE_ENTRY))
347
Corey Minyard50c812b2006-03-26 01:37:21 -0800348/**
349 * The driver model view of the IPMI messaging driver.
350 */
351static struct device_driver ipmidriver = {
352 .name = "ipmi",
353 .bus = &platform_bus_type
354};
355static DEFINE_MUTEX(ipmidriver_mutex);
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357#define MAX_IPMI_INTERFACES 4
358static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
359
Corey Minyard393d2cc2005-11-07 00:59:54 -0800360/* Directly protects the ipmi_interfaces data structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361static DEFINE_SPINLOCK(interfaces_lock);
362
363/* List of watchers that want to know when smi's are added and
364 deleted. */
365static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
366static DECLARE_RWSEM(smi_watchers_sem);
367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Corey Minyard393d2cc2005-11-07 00:59:54 -0800369static void free_recv_msg_list(struct list_head *q)
370{
371 struct ipmi_recv_msg *msg, *msg2;
372
373 list_for_each_entry_safe(msg, msg2, q, link) {
374 list_del(&msg->link);
375 ipmi_free_recv_msg(msg);
376 }
377}
378
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800379static void free_smi_msg_list(struct list_head *q)
380{
381 struct ipmi_smi_msg *msg, *msg2;
382
383 list_for_each_entry_safe(msg, msg2, q, link) {
384 list_del(&msg->link);
385 ipmi_free_smi_msg(msg);
386 }
387}
388
Corey Minyard393d2cc2005-11-07 00:59:54 -0800389static void clean_up_interface_data(ipmi_smi_t intf)
390{
391 int i;
392 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800393 struct list_head list;
394
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800395 free_smi_msg_list(&intf->waiting_msgs);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800396 free_recv_msg_list(&intf->waiting_events);
397
398 /* Wholesale remove all the entries from the list in the
399 * interface and wait for RCU to know that none are in use. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800400 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800401 list_add_rcu(&list, &intf->cmd_rcvrs);
402 list_del_rcu(&intf->cmd_rcvrs);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800403 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800404 synchronize_rcu();
405
406 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
407 kfree(rcvr);
408
409 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
410 if ((intf->seq_table[i].inuse)
411 && (intf->seq_table[i].recv_msg))
412 {
413 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 }
415 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800416}
417
418static void intf_free(struct kref *ref)
419{
420 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
421
422 clean_up_interface_data(intf);
423 kfree(intf);
424}
425
426int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
427{
428 int i;
429 unsigned long flags;
430
431 down_write(&smi_watchers_sem);
432 list_add(&(watcher->link), &smi_watchers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 up_write(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800434 spin_lock_irqsave(&interfaces_lock, flags);
435 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
436 ipmi_smi_t intf = ipmi_interfaces[i];
437 if (IPMI_INVALID_INTERFACE(intf))
438 continue;
439 spin_unlock_irqrestore(&interfaces_lock, flags);
Corey Minyard50c812b2006-03-26 01:37:21 -0800440 watcher->new_smi(i, intf->si_dev);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800441 spin_lock_irqsave(&interfaces_lock, flags);
442 }
443 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 return 0;
445}
446
447int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
448{
449 down_write(&smi_watchers_sem);
450 list_del(&(watcher->link));
451 up_write(&smi_watchers_sem);
452 return 0;
453}
454
455static void
Corey Minyard50c812b2006-03-26 01:37:21 -0800456call_smi_watchers(int i, struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457{
458 struct ipmi_smi_watcher *w;
459
460 down_read(&smi_watchers_sem);
461 list_for_each_entry(w, &smi_watchers, link) {
462 if (try_module_get(w->owner)) {
Corey Minyard50c812b2006-03-26 01:37:21 -0800463 w->new_smi(i, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 module_put(w->owner);
465 }
466 }
467 up_read(&smi_watchers_sem);
468}
469
470static int
471ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
472{
473 if (addr1->addr_type != addr2->addr_type)
474 return 0;
475
476 if (addr1->channel != addr2->channel)
477 return 0;
478
479 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
480 struct ipmi_system_interface_addr *smi_addr1
481 = (struct ipmi_system_interface_addr *) addr1;
482 struct ipmi_system_interface_addr *smi_addr2
483 = (struct ipmi_system_interface_addr *) addr2;
484 return (smi_addr1->lun == smi_addr2->lun);
485 }
486
487 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
488 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
489 {
490 struct ipmi_ipmb_addr *ipmb_addr1
491 = (struct ipmi_ipmb_addr *) addr1;
492 struct ipmi_ipmb_addr *ipmb_addr2
493 = (struct ipmi_ipmb_addr *) addr2;
494
495 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
496 && (ipmb_addr1->lun == ipmb_addr2->lun));
497 }
498
499 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
500 struct ipmi_lan_addr *lan_addr1
501 = (struct ipmi_lan_addr *) addr1;
502 struct ipmi_lan_addr *lan_addr2
503 = (struct ipmi_lan_addr *) addr2;
504
505 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
506 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
507 && (lan_addr1->session_handle
508 == lan_addr2->session_handle)
509 && (lan_addr1->lun == lan_addr2->lun));
510 }
511
512 return 1;
513}
514
515int ipmi_validate_addr(struct ipmi_addr *addr, int len)
516{
517 if (len < sizeof(struct ipmi_system_interface_addr)) {
518 return -EINVAL;
519 }
520
521 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
522 if (addr->channel != IPMI_BMC_CHANNEL)
523 return -EINVAL;
524 return 0;
525 }
526
527 if ((addr->channel == IPMI_BMC_CHANNEL)
Jayachandran C12fc1d72006-02-03 03:04:51 -0800528 || (addr->channel >= IPMI_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 || (addr->channel < 0))
530 return -EINVAL;
531
532 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
533 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
534 {
535 if (len < sizeof(struct ipmi_ipmb_addr)) {
536 return -EINVAL;
537 }
538 return 0;
539 }
540
541 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
542 if (len < sizeof(struct ipmi_lan_addr)) {
543 return -EINVAL;
544 }
545 return 0;
546 }
547
548 return -EINVAL;
549}
550
551unsigned int ipmi_addr_length(int addr_type)
552{
553 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
554 return sizeof(struct ipmi_system_interface_addr);
555
556 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
557 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
558 {
559 return sizeof(struct ipmi_ipmb_addr);
560 }
561
562 if (addr_type == IPMI_LAN_ADDR_TYPE)
563 return sizeof(struct ipmi_lan_addr);
564
565 return 0;
566}
567
568static void deliver_response(struct ipmi_recv_msg *msg)
569{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800570 if (!msg->user) {
Corey Minyard56a55ec2005-09-06 15:18:42 -0700571 ipmi_smi_t intf = msg->user_msg_data;
572 unsigned long flags;
573
574 /* Special handling for NULL users. */
575 if (intf->null_user_handler) {
576 intf->null_user_handler(intf, msg);
577 spin_lock_irqsave(&intf->counter_lock, flags);
578 intf->handled_local_responses++;
579 spin_unlock_irqrestore(&intf->counter_lock, flags);
580 } else {
581 /* No handler, so give up. */
582 spin_lock_irqsave(&intf->counter_lock, flags);
583 intf->unhandled_local_responses++;
584 spin_unlock_irqrestore(&intf->counter_lock, flags);
585 }
586 ipmi_free_recv_msg(msg);
587 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800588 ipmi_user_t user = msg->user;
589 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591}
592
593/* Find the next sequence number not being used and add the given
594 message with the given timeout to the sequence table. This must be
595 called with the interface's seq_lock held. */
596static int intf_next_seq(ipmi_smi_t intf,
597 struct ipmi_recv_msg *recv_msg,
598 unsigned long timeout,
599 int retries,
600 int broadcast,
601 unsigned char *seq,
602 long *seqid)
603{
604 int rv = 0;
605 unsigned int i;
606
Corey Minyarde8b33612005-09-06 15:18:45 -0700607 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700609 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800611 if (!intf->seq_table[i].inuse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 break;
613 }
614
Corey Minyard8a3628d2006-03-31 02:30:40 -0800615 if (!intf->seq_table[i].inuse) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 intf->seq_table[i].recv_msg = recv_msg;
617
618 /* Start with the maximum timeout, when the send response
619 comes in we will start the real timer. */
620 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
621 intf->seq_table[i].orig_timeout = timeout;
622 intf->seq_table[i].retries_left = retries;
623 intf->seq_table[i].broadcast = broadcast;
624 intf->seq_table[i].inuse = 1;
625 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
626 *seq = i;
627 *seqid = intf->seq_table[i].seqid;
628 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
629 } else {
630 rv = -EAGAIN;
631 }
632
633 return rv;
634}
635
636/* Return the receive message for the given sequence number and
637 release the sequence number so it can be reused. Some other data
638 is passed in to be sure the message matches up correctly (to help
639 guard against message coming in after their timeout and the
640 sequence number being reused). */
641static int intf_find_seq(ipmi_smi_t intf,
642 unsigned char seq,
643 short channel,
644 unsigned char cmd,
645 unsigned char netfn,
646 struct ipmi_addr *addr,
647 struct ipmi_recv_msg **recv_msg)
648{
649 int rv = -ENODEV;
650 unsigned long flags;
651
652 if (seq >= IPMI_IPMB_NUM_SEQ)
653 return -EINVAL;
654
655 spin_lock_irqsave(&(intf->seq_lock), flags);
656 if (intf->seq_table[seq].inuse) {
657 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
658
659 if ((msg->addr.channel == channel)
660 && (msg->msg.cmd == cmd)
661 && (msg->msg.netfn == netfn)
662 && (ipmi_addr_equal(addr, &(msg->addr))))
663 {
664 *recv_msg = msg;
665 intf->seq_table[seq].inuse = 0;
666 rv = 0;
667 }
668 }
669 spin_unlock_irqrestore(&(intf->seq_lock), flags);
670
671 return rv;
672}
673
674
675/* Start the timer for a specific sequence table entry. */
676static int intf_start_seq_timer(ipmi_smi_t intf,
677 long msgid)
678{
679 int rv = -ENODEV;
680 unsigned long flags;
681 unsigned char seq;
682 unsigned long seqid;
683
684
685 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
686
687 spin_lock_irqsave(&(intf->seq_lock), flags);
688 /* We do this verification because the user can be deleted
689 while a message is outstanding. */
690 if ((intf->seq_table[seq].inuse)
691 && (intf->seq_table[seq].seqid == seqid))
692 {
693 struct seq_table *ent = &(intf->seq_table[seq]);
694 ent->timeout = ent->orig_timeout;
695 rv = 0;
696 }
697 spin_unlock_irqrestore(&(intf->seq_lock), flags);
698
699 return rv;
700}
701
702/* Got an error for the send message for a specific sequence number. */
703static int intf_err_seq(ipmi_smi_t intf,
704 long msgid,
705 unsigned int err)
706{
707 int rv = -ENODEV;
708 unsigned long flags;
709 unsigned char seq;
710 unsigned long seqid;
711 struct ipmi_recv_msg *msg = NULL;
712
713
714 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
715
716 spin_lock_irqsave(&(intf->seq_lock), flags);
717 /* We do this verification because the user can be deleted
718 while a message is outstanding. */
719 if ((intf->seq_table[seq].inuse)
720 && (intf->seq_table[seq].seqid == seqid))
721 {
722 struct seq_table *ent = &(intf->seq_table[seq]);
723
724 ent->inuse = 0;
725 msg = ent->recv_msg;
726 rv = 0;
727 }
728 spin_unlock_irqrestore(&(intf->seq_lock), flags);
729
730 if (msg) {
731 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
732 msg->msg_data[0] = err;
733 msg->msg.netfn |= 1; /* Convert to a response. */
734 msg->msg.data_len = 1;
735 msg->msg.data = msg->msg_data;
736 deliver_response(msg);
737 }
738
739 return rv;
740}
741
742
743int ipmi_create_user(unsigned int if_num,
744 struct ipmi_user_hndl *handler,
745 void *handler_data,
746 ipmi_user_t *user)
747{
748 unsigned long flags;
749 ipmi_user_t new_user;
750 int rv = 0;
751 ipmi_smi_t intf;
752
753 /* There is no module usecount here, because it's not
754 required. Since this can only be used by and called from
755 other modules, they will implicitly use this module, and
756 thus this can't be removed unless the other modules are
757 removed. */
758
759 if (handler == NULL)
760 return -EINVAL;
761
762 /* Make sure the driver is actually initialized, this handles
763 problems with initialization order. */
764 if (!initialized) {
765 rv = ipmi_init_msghandler();
766 if (rv)
767 return rv;
768
769 /* The init code doesn't return an error if it was turned
770 off, but it won't initialize. Check that. */
771 if (!initialized)
772 return -ENODEV;
773 }
774
775 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800776 if (!new_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 return -ENOMEM;
778
Corey Minyard393d2cc2005-11-07 00:59:54 -0800779 spin_lock_irqsave(&interfaces_lock, flags);
780 intf = ipmi_interfaces[if_num];
781 if ((if_num >= MAX_IPMI_INTERFACES) || IPMI_INVALID_INTERFACE(intf)) {
782 spin_unlock_irqrestore(&interfaces_lock, flags);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800783 rv = -EINVAL;
784 goto out_kfree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 }
786
Corey Minyard393d2cc2005-11-07 00:59:54 -0800787 /* Note that each existing user holds a refcount to the interface. */
788 kref_get(&intf->refcount);
789 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Corey Minyard393d2cc2005-11-07 00:59:54 -0800791 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 new_user->handler = handler;
793 new_user->handler_data = handler_data;
794 new_user->intf = intf;
795 new_user->gets_events = 0;
796
797 if (!try_module_get(intf->handlers->owner)) {
798 rv = -ENODEV;
Adrian Bunk5c98d292006-03-25 03:07:52 -0800799 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 }
801
802 if (intf->handlers->inc_usecount) {
803 rv = intf->handlers->inc_usecount(intf->send_info);
804 if (rv) {
805 module_put(intf->handlers->owner);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800806 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 }
808 }
809
Corey Minyard393d2cc2005-11-07 00:59:54 -0800810 new_user->valid = 1;
811 spin_lock_irqsave(&intf->seq_lock, flags);
812 list_add_rcu(&new_user->link, &intf->users);
813 spin_unlock_irqrestore(&intf->seq_lock, flags);
814 *user = new_user;
815 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
Adrian Bunk5c98d292006-03-25 03:07:52 -0800817out_kref:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800818 kref_put(&intf->refcount, intf_free);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800819out_kfree:
820 kfree(new_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 return rv;
822}
823
Corey Minyard393d2cc2005-11-07 00:59:54 -0800824static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800826 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828}
829
830int ipmi_destroy_user(ipmi_user_t user)
831{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800832 ipmi_smi_t intf = user->intf;
833 int i;
834 unsigned long flags;
835 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800836 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Corey Minyard8a3628d2006-03-31 02:30:40 -0800838 user->valid = 0;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800839
840 /* Remove the user from the interface's sequence table. */
841 spin_lock_irqsave(&intf->seq_lock, flags);
842 list_del_rcu(&user->link);
843
844 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
845 if (intf->seq_table[i].inuse
846 && (intf->seq_table[i].recv_msg->user == user))
847 {
848 intf->seq_table[i].inuse = 0;
849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800851 spin_unlock_irqrestore(&intf->seq_lock, flags);
852
853 /*
854 * Remove the user from the command receiver's table. First
855 * we build a list of everything (not using the standard link,
856 * since other things may be using it till we do
857 * synchronize_rcu()) then free everything in that list.
858 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800859 mutex_lock(&intf->cmd_rcvrs_mutex);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800860 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800861 if (rcvr->user == user) {
862 list_del_rcu(&rcvr->link);
863 rcvr->next = rcvrs;
864 rcvrs = rcvr;
865 }
866 }
Corey Minyardd6dfd132006-03-31 02:30:41 -0800867 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800868 synchronize_rcu();
869 while (rcvrs) {
870 rcvr = rcvrs;
871 rcvrs = rcvr->next;
872 kfree(rcvr);
873 }
874
875 module_put(intf->handlers->owner);
876 if (intf->handlers->dec_usecount)
877 intf->handlers->dec_usecount(intf->send_info);
878
879 kref_put(&intf->refcount, intf_free);
880
881 kref_put(&user->refcount, free_user);
882
Corey Minyard8a3628d2006-03-31 02:30:40 -0800883 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884}
885
886void ipmi_get_version(ipmi_user_t user,
887 unsigned char *major,
888 unsigned char *minor)
889{
Corey Minyard50c812b2006-03-26 01:37:21 -0800890 *major = ipmi_version_major(&user->intf->bmc->id);
891 *minor = ipmi_version_minor(&user->intf->bmc->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892}
893
Corey Minyardc14979b2005-09-06 15:18:38 -0700894int ipmi_set_my_address(ipmi_user_t user,
895 unsigned int channel,
896 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897{
Corey Minyardc14979b2005-09-06 15:18:38 -0700898 if (channel >= IPMI_MAX_CHANNELS)
899 return -EINVAL;
900 user->intf->channels[channel].address = address;
901 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902}
903
Corey Minyardc14979b2005-09-06 15:18:38 -0700904int ipmi_get_my_address(ipmi_user_t user,
905 unsigned int channel,
906 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907{
Corey Minyardc14979b2005-09-06 15:18:38 -0700908 if (channel >= IPMI_MAX_CHANNELS)
909 return -EINVAL;
910 *address = user->intf->channels[channel].address;
911 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912}
913
Corey Minyardc14979b2005-09-06 15:18:38 -0700914int ipmi_set_my_LUN(ipmi_user_t user,
915 unsigned int channel,
916 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917{
Corey Minyardc14979b2005-09-06 15:18:38 -0700918 if (channel >= IPMI_MAX_CHANNELS)
919 return -EINVAL;
920 user->intf->channels[channel].lun = LUN & 0x3;
921 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922}
923
Corey Minyardc14979b2005-09-06 15:18:38 -0700924int ipmi_get_my_LUN(ipmi_user_t user,
925 unsigned int channel,
926 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927{
Corey Minyardc14979b2005-09-06 15:18:38 -0700928 if (channel >= IPMI_MAX_CHANNELS)
929 return -EINVAL;
930 *address = user->intf->channels[channel].lun;
931 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932}
933
934int ipmi_set_gets_events(ipmi_user_t user, int val)
935{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800936 unsigned long flags;
937 ipmi_smi_t intf = user->intf;
938 struct ipmi_recv_msg *msg, *msg2;
939 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Corey Minyard393d2cc2005-11-07 00:59:54 -0800941 INIT_LIST_HEAD(&msgs);
942
943 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 user->gets_events = val;
945
946 if (val) {
947 /* Deliver any queued events. */
Akinobu Mita179e0912006-06-26 00:24:41 -0700948 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
949 list_move_tail(&msg->link, &msgs);
Corey Minyard4791c032006-04-10 22:54:31 -0700950 intf->waiting_events_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800952
953 /* Hold the events lock while doing this to preserve order. */
954 list_for_each_entry_safe(msg, msg2, &msgs, link) {
955 msg->user = user;
956 kref_get(&user->refcount);
957 deliver_response(msg);
958 }
959
960 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
962 return 0;
963}
964
Corey Minyard393d2cc2005-11-07 00:59:54 -0800965static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
966 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -0700967 unsigned char cmd,
968 unsigned char chan)
Corey Minyard393d2cc2005-11-07 00:59:54 -0800969{
970 struct cmd_rcvr *rcvr;
971
972 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyardc69c3122006-09-30 23:27:56 -0700973 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
974 && (rcvr->chans & (1 << chan)))
Corey Minyard393d2cc2005-11-07 00:59:54 -0800975 return rcvr;
976 }
977 return NULL;
978}
979
Corey Minyardc69c3122006-09-30 23:27:56 -0700980static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
981 unsigned char netfn,
982 unsigned char cmd,
983 unsigned int chans)
984{
985 struct cmd_rcvr *rcvr;
986
987 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
988 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
989 && (rcvr->chans & chans))
990 return 0;
991 }
992 return 1;
993}
994
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995int ipmi_register_for_cmd(ipmi_user_t user,
996 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -0700997 unsigned char cmd,
998 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001000 ipmi_smi_t intf = user->intf;
1001 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001002 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004
1005 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -08001006 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001008 rcvr->cmd = cmd;
1009 rcvr->netfn = netfn;
Corey Minyardc69c3122006-09-30 23:27:56 -07001010 rcvr->chans = chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001011 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
Corey Minyardd6dfd132006-03-31 02:30:41 -08001013 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 /* Make sure the command/netfn is not already registered. */
Corey Minyardc69c3122006-09-30 23:27:56 -07001015 if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08001016 rv = -EBUSY;
1017 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 }
1019
Corey Minyard393d2cc2005-11-07 00:59:54 -08001020 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -07001021
Corey Minyard393d2cc2005-11-07 00:59:54 -08001022 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -08001023 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 if (rv)
1025 kfree(rcvr);
1026
1027 return rv;
1028}
1029
1030int ipmi_unregister_for_cmd(ipmi_user_t user,
1031 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001032 unsigned char cmd,
1033 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001035 ipmi_smi_t intf = user->intf;
1036 struct cmd_rcvr *rcvr;
Corey Minyardc69c3122006-09-30 23:27:56 -07001037 struct cmd_rcvr *rcvrs = NULL;
1038 int i, rv = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Corey Minyardd6dfd132006-03-31 02:30:41 -08001040 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyardc69c3122006-09-30 23:27:56 -07001041 for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
1042 if (((1 << i) & chans) == 0)
1043 continue;
1044 rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
1045 if (rcvr == NULL)
1046 continue;
1047 if (rcvr->user == user) {
1048 rv = 0;
1049 rcvr->chans &= ~chans;
1050 if (rcvr->chans == 0) {
1051 list_del_rcu(&rcvr->link);
1052 rcvr->next = rcvrs;
1053 rcvrs = rcvr;
1054 }
1055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
Corey Minyardc69c3122006-09-30 23:27:56 -07001057 mutex_unlock(&intf->cmd_rcvrs_mutex);
1058 synchronize_rcu();
1059 while (rcvrs) {
1060 rcvr = rcvrs;
1061 rcvrs = rcvr->next;
1062 kfree(rcvr);
1063 }
1064 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065}
1066
1067void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
1068{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001069 ipmi_smi_t intf = user->intf;
1070 intf->handlers->set_run_to_completion(intf->send_info, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071}
1072
1073static unsigned char
1074ipmb_checksum(unsigned char *data, int size)
1075{
1076 unsigned char csum = 0;
1077
1078 for (; size > 0; size--, data++)
1079 csum += *data;
1080
1081 return -csum;
1082}
1083
1084static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1085 struct kernel_ipmi_msg *msg,
1086 struct ipmi_ipmb_addr *ipmb_addr,
1087 long msgid,
1088 unsigned char ipmb_seq,
1089 int broadcast,
1090 unsigned char source_address,
1091 unsigned char source_lun)
1092{
1093 int i = broadcast;
1094
1095 /* Format the IPMB header data. */
1096 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1097 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1098 smi_msg->data[2] = ipmb_addr->channel;
1099 if (broadcast)
1100 smi_msg->data[3] = 0;
1101 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1102 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1103 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1104 smi_msg->data[i+6] = source_address;
1105 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1106 smi_msg->data[i+8] = msg->cmd;
1107
1108 /* Now tack on the data to the message. */
1109 if (msg->data_len > 0)
1110 memcpy(&(smi_msg->data[i+9]), msg->data,
1111 msg->data_len);
1112 smi_msg->data_size = msg->data_len + 9;
1113
1114 /* Now calculate the checksum and tack it on. */
1115 smi_msg->data[i+smi_msg->data_size]
1116 = ipmb_checksum(&(smi_msg->data[i+6]),
1117 smi_msg->data_size-6);
1118
1119 /* Add on the checksum size and the offset from the
1120 broadcast. */
1121 smi_msg->data_size += 1 + i;
1122
1123 smi_msg->msgid = msgid;
1124}
1125
1126static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1127 struct kernel_ipmi_msg *msg,
1128 struct ipmi_lan_addr *lan_addr,
1129 long msgid,
1130 unsigned char ipmb_seq,
1131 unsigned char source_lun)
1132{
1133 /* Format the IPMB header data. */
1134 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1135 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1136 smi_msg->data[2] = lan_addr->channel;
1137 smi_msg->data[3] = lan_addr->session_handle;
1138 smi_msg->data[4] = lan_addr->remote_SWID;
1139 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1140 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1141 smi_msg->data[7] = lan_addr->local_SWID;
1142 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1143 smi_msg->data[9] = msg->cmd;
1144
1145 /* Now tack on the data to the message. */
1146 if (msg->data_len > 0)
1147 memcpy(&(smi_msg->data[10]), msg->data,
1148 msg->data_len);
1149 smi_msg->data_size = msg->data_len + 10;
1150
1151 /* Now calculate the checksum and tack it on. */
1152 smi_msg->data[smi_msg->data_size]
1153 = ipmb_checksum(&(smi_msg->data[7]),
1154 smi_msg->data_size-7);
1155
1156 /* Add on the checksum size and the offset from the
1157 broadcast. */
1158 smi_msg->data_size += 1;
1159
1160 smi_msg->msgid = msgid;
1161}
1162
1163/* Separate from ipmi_request so that the user does not have to be
1164 supplied in certain circumstances (mainly at panic time). If
1165 messages are supplied, they will be freed, even if an error
1166 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001167static int i_ipmi_request(ipmi_user_t user,
1168 ipmi_smi_t intf,
1169 struct ipmi_addr *addr,
1170 long msgid,
1171 struct kernel_ipmi_msg *msg,
1172 void *user_msg_data,
1173 void *supplied_smi,
1174 struct ipmi_recv_msg *supplied_recv,
1175 int priority,
1176 unsigned char source_address,
1177 unsigned char source_lun,
1178 int retries,
1179 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180{
1181 int rv = 0;
1182 struct ipmi_smi_msg *smi_msg;
1183 struct ipmi_recv_msg *recv_msg;
1184 unsigned long flags;
1185
1186
1187 if (supplied_recv) {
1188 recv_msg = supplied_recv;
1189 } else {
1190 recv_msg = ipmi_alloc_recv_msg();
1191 if (recv_msg == NULL) {
1192 return -ENOMEM;
1193 }
1194 }
1195 recv_msg->user_msg_data = user_msg_data;
1196
1197 if (supplied_smi) {
1198 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1199 } else {
1200 smi_msg = ipmi_alloc_smi_msg();
1201 if (smi_msg == NULL) {
1202 ipmi_free_recv_msg(recv_msg);
1203 return -ENOMEM;
1204 }
1205 }
1206
1207 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001208 if (user)
1209 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 recv_msg->msgid = msgid;
1211 /* Store the message to send in the receive message so timeout
1212 responses can get the proper response data. */
1213 recv_msg->msg = *msg;
1214
1215 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1216 struct ipmi_system_interface_addr *smi_addr;
1217
1218 if (msg->netfn & 1) {
1219 /* Responses are not allowed to the SMI. */
1220 rv = -EINVAL;
1221 goto out_err;
1222 }
1223
1224 smi_addr = (struct ipmi_system_interface_addr *) addr;
1225 if (smi_addr->lun > 3) {
1226 spin_lock_irqsave(&intf->counter_lock, flags);
1227 intf->sent_invalid_commands++;
1228 spin_unlock_irqrestore(&intf->counter_lock, flags);
1229 rv = -EINVAL;
1230 goto out_err;
1231 }
1232
1233 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1234
1235 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1236 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1237 || (msg->cmd == IPMI_GET_MSG_CMD)
1238 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1239 {
1240 /* We don't let the user do these, since we manage
1241 the sequence numbers. */
1242 spin_lock_irqsave(&intf->counter_lock, flags);
1243 intf->sent_invalid_commands++;
1244 spin_unlock_irqrestore(&intf->counter_lock, flags);
1245 rv = -EINVAL;
1246 goto out_err;
1247 }
1248
1249 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1250 spin_lock_irqsave(&intf->counter_lock, flags);
1251 intf->sent_invalid_commands++;
1252 spin_unlock_irqrestore(&intf->counter_lock, flags);
1253 rv = -EMSGSIZE;
1254 goto out_err;
1255 }
1256
1257 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1258 smi_msg->data[1] = msg->cmd;
1259 smi_msg->msgid = msgid;
1260 smi_msg->user_data = recv_msg;
1261 if (msg->data_len > 0)
1262 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1263 smi_msg->data_size = msg->data_len + 2;
1264 spin_lock_irqsave(&intf->counter_lock, flags);
1265 intf->sent_local_commands++;
1266 spin_unlock_irqrestore(&intf->counter_lock, flags);
1267 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1268 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1269 {
1270 struct ipmi_ipmb_addr *ipmb_addr;
1271 unsigned char ipmb_seq;
1272 long seqid;
1273 int broadcast = 0;
1274
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001275 if (addr->channel >= IPMI_MAX_CHANNELS) {
1276 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 intf->sent_invalid_commands++;
1278 spin_unlock_irqrestore(&intf->counter_lock, flags);
1279 rv = -EINVAL;
1280 goto out_err;
1281 }
1282
1283 if (intf->channels[addr->channel].medium
1284 != IPMI_CHANNEL_MEDIUM_IPMB)
1285 {
1286 spin_lock_irqsave(&intf->counter_lock, flags);
1287 intf->sent_invalid_commands++;
1288 spin_unlock_irqrestore(&intf->counter_lock, flags);
1289 rv = -EINVAL;
1290 goto out_err;
1291 }
1292
1293 if (retries < 0) {
1294 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1295 retries = 0; /* Don't retry broadcasts. */
1296 else
1297 retries = 4;
1298 }
1299 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1300 /* Broadcasts add a zero at the beginning of the
1301 message, but otherwise is the same as an IPMB
1302 address. */
1303 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1304 broadcast = 1;
1305 }
1306
1307
1308 /* Default to 1 second retries. */
1309 if (retry_time_ms == 0)
1310 retry_time_ms = 1000;
1311
1312 /* 9 for the header and 1 for the checksum, plus
1313 possibly one for the broadcast. */
1314 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1315 spin_lock_irqsave(&intf->counter_lock, flags);
1316 intf->sent_invalid_commands++;
1317 spin_unlock_irqrestore(&intf->counter_lock, flags);
1318 rv = -EMSGSIZE;
1319 goto out_err;
1320 }
1321
1322 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1323 if (ipmb_addr->lun > 3) {
1324 spin_lock_irqsave(&intf->counter_lock, flags);
1325 intf->sent_invalid_commands++;
1326 spin_unlock_irqrestore(&intf->counter_lock, flags);
1327 rv = -EINVAL;
1328 goto out_err;
1329 }
1330
1331 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1332
1333 if (recv_msg->msg.netfn & 0x1) {
1334 /* It's a response, so use the user's sequence
1335 from msgid. */
1336 spin_lock_irqsave(&intf->counter_lock, flags);
1337 intf->sent_ipmb_responses++;
1338 spin_unlock_irqrestore(&intf->counter_lock, flags);
1339 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1340 msgid, broadcast,
1341 source_address, source_lun);
1342
1343 /* Save the receive message so we can use it
1344 to deliver the response. */
1345 smi_msg->user_data = recv_msg;
1346 } else {
1347 /* It's a command, so get a sequence for it. */
1348
1349 spin_lock_irqsave(&(intf->seq_lock), flags);
1350
1351 spin_lock(&intf->counter_lock);
1352 intf->sent_ipmb_commands++;
1353 spin_unlock(&intf->counter_lock);
1354
1355 /* Create a sequence number with a 1 second
1356 timeout and 4 retries. */
1357 rv = intf_next_seq(intf,
1358 recv_msg,
1359 retry_time_ms,
1360 retries,
1361 broadcast,
1362 &ipmb_seq,
1363 &seqid);
1364 if (rv) {
1365 /* We have used up all the sequence numbers,
1366 probably, so abort. */
1367 spin_unlock_irqrestore(&(intf->seq_lock),
1368 flags);
1369 goto out_err;
1370 }
1371
1372 /* Store the sequence number in the message,
1373 so that when the send message response
1374 comes back we can start the timer. */
1375 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1376 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1377 ipmb_seq, broadcast,
1378 source_address, source_lun);
1379
1380 /* Copy the message into the recv message data, so we
1381 can retransmit it later if necessary. */
1382 memcpy(recv_msg->msg_data, smi_msg->data,
1383 smi_msg->data_size);
1384 recv_msg->msg.data = recv_msg->msg_data;
1385 recv_msg->msg.data_len = smi_msg->data_size;
1386
1387 /* We don't unlock until here, because we need
1388 to copy the completed message into the
1389 recv_msg before we release the lock.
1390 Otherwise, race conditions may bite us. I
1391 know that's pretty paranoid, but I prefer
1392 to be correct. */
1393 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1394 }
1395 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1396 struct ipmi_lan_addr *lan_addr;
1397 unsigned char ipmb_seq;
1398 long seqid;
1399
Jayachandran C12fc1d72006-02-03 03:04:51 -08001400 if (addr->channel >= IPMI_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 spin_lock_irqsave(&intf->counter_lock, flags);
1402 intf->sent_invalid_commands++;
1403 spin_unlock_irqrestore(&intf->counter_lock, flags);
1404 rv = -EINVAL;
1405 goto out_err;
1406 }
1407
1408 if ((intf->channels[addr->channel].medium
1409 != IPMI_CHANNEL_MEDIUM_8023LAN)
1410 && (intf->channels[addr->channel].medium
1411 != IPMI_CHANNEL_MEDIUM_ASYNC))
1412 {
1413 spin_lock_irqsave(&intf->counter_lock, flags);
1414 intf->sent_invalid_commands++;
1415 spin_unlock_irqrestore(&intf->counter_lock, flags);
1416 rv = -EINVAL;
1417 goto out_err;
1418 }
1419
1420 retries = 4;
1421
1422 /* Default to 1 second retries. */
1423 if (retry_time_ms == 0)
1424 retry_time_ms = 1000;
1425
1426 /* 11 for the header and 1 for the checksum. */
1427 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1428 spin_lock_irqsave(&intf->counter_lock, flags);
1429 intf->sent_invalid_commands++;
1430 spin_unlock_irqrestore(&intf->counter_lock, flags);
1431 rv = -EMSGSIZE;
1432 goto out_err;
1433 }
1434
1435 lan_addr = (struct ipmi_lan_addr *) addr;
1436 if (lan_addr->lun > 3) {
1437 spin_lock_irqsave(&intf->counter_lock, flags);
1438 intf->sent_invalid_commands++;
1439 spin_unlock_irqrestore(&intf->counter_lock, flags);
1440 rv = -EINVAL;
1441 goto out_err;
1442 }
1443
1444 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1445
1446 if (recv_msg->msg.netfn & 0x1) {
1447 /* It's a response, so use the user's sequence
1448 from msgid. */
1449 spin_lock_irqsave(&intf->counter_lock, flags);
1450 intf->sent_lan_responses++;
1451 spin_unlock_irqrestore(&intf->counter_lock, flags);
1452 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1453 msgid, source_lun);
1454
1455 /* Save the receive message so we can use it
1456 to deliver the response. */
1457 smi_msg->user_data = recv_msg;
1458 } else {
1459 /* It's a command, so get a sequence for it. */
1460
1461 spin_lock_irqsave(&(intf->seq_lock), flags);
1462
1463 spin_lock(&intf->counter_lock);
1464 intf->sent_lan_commands++;
1465 spin_unlock(&intf->counter_lock);
1466
1467 /* Create a sequence number with a 1 second
1468 timeout and 4 retries. */
1469 rv = intf_next_seq(intf,
1470 recv_msg,
1471 retry_time_ms,
1472 retries,
1473 0,
1474 &ipmb_seq,
1475 &seqid);
1476 if (rv) {
1477 /* We have used up all the sequence numbers,
1478 probably, so abort. */
1479 spin_unlock_irqrestore(&(intf->seq_lock),
1480 flags);
1481 goto out_err;
1482 }
1483
1484 /* Store the sequence number in the message,
1485 so that when the send message response
1486 comes back we can start the timer. */
1487 format_lan_msg(smi_msg, msg, lan_addr,
1488 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1489 ipmb_seq, source_lun);
1490
1491 /* Copy the message into the recv message data, so we
1492 can retransmit it later if necessary. */
1493 memcpy(recv_msg->msg_data, smi_msg->data,
1494 smi_msg->data_size);
1495 recv_msg->msg.data = recv_msg->msg_data;
1496 recv_msg->msg.data_len = smi_msg->data_size;
1497
1498 /* We don't unlock until here, because we need
1499 to copy the completed message into the
1500 recv_msg before we release the lock.
1501 Otherwise, race conditions may bite us. I
1502 know that's pretty paranoid, but I prefer
1503 to be correct. */
1504 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1505 }
1506 } else {
1507 /* Unknown address type. */
1508 spin_lock_irqsave(&intf->counter_lock, flags);
1509 intf->sent_invalid_commands++;
1510 spin_unlock_irqrestore(&intf->counter_lock, flags);
1511 rv = -EINVAL;
1512 goto out_err;
1513 }
1514
1515#ifdef DEBUG_MSGING
1516 {
1517 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001518 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 printk(" %2.2x", smi_msg->data[m]);
1520 printk("\n");
1521 }
1522#endif
1523 intf->handlers->sender(intf->send_info, smi_msg, priority);
1524
1525 return 0;
1526
1527 out_err:
1528 ipmi_free_smi_msg(smi_msg);
1529 ipmi_free_recv_msg(recv_msg);
1530 return rv;
1531}
1532
Corey Minyardc14979b2005-09-06 15:18:38 -07001533static int check_addr(ipmi_smi_t intf,
1534 struct ipmi_addr *addr,
1535 unsigned char *saddr,
1536 unsigned char *lun)
1537{
1538 if (addr->channel >= IPMI_MAX_CHANNELS)
1539 return -EINVAL;
1540 *lun = intf->channels[addr->channel].lun;
1541 *saddr = intf->channels[addr->channel].address;
1542 return 0;
1543}
1544
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545int ipmi_request_settime(ipmi_user_t user,
1546 struct ipmi_addr *addr,
1547 long msgid,
1548 struct kernel_ipmi_msg *msg,
1549 void *user_msg_data,
1550 int priority,
1551 int retries,
1552 unsigned int retry_time_ms)
1553{
Corey Minyardc14979b2005-09-06 15:18:38 -07001554 unsigned char saddr, lun;
1555 int rv;
1556
Corey Minyard8a3628d2006-03-31 02:30:40 -08001557 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001558 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001559 rv = check_addr(user->intf, addr, &saddr, &lun);
1560 if (rv)
1561 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 return i_ipmi_request(user,
1563 user->intf,
1564 addr,
1565 msgid,
1566 msg,
1567 user_msg_data,
1568 NULL, NULL,
1569 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001570 saddr,
1571 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 retries,
1573 retry_time_ms);
1574}
1575
1576int ipmi_request_supply_msgs(ipmi_user_t user,
1577 struct ipmi_addr *addr,
1578 long msgid,
1579 struct kernel_ipmi_msg *msg,
1580 void *user_msg_data,
1581 void *supplied_smi,
1582 struct ipmi_recv_msg *supplied_recv,
1583 int priority)
1584{
Corey Minyardc14979b2005-09-06 15:18:38 -07001585 unsigned char saddr, lun;
1586 int rv;
1587
Corey Minyard8a3628d2006-03-31 02:30:40 -08001588 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001589 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001590 rv = check_addr(user->intf, addr, &saddr, &lun);
1591 if (rv)
1592 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 return i_ipmi_request(user,
1594 user->intf,
1595 addr,
1596 msgid,
1597 msg,
1598 user_msg_data,
1599 supplied_smi,
1600 supplied_recv,
1601 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001602 saddr,
1603 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 -1, 0);
1605}
1606
1607static int ipmb_file_read_proc(char *page, char **start, off_t off,
1608 int count, int *eof, void *data)
1609{
1610 char *out = (char *) page;
1611 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001612 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001613 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
Corey Minyarde8b33612005-09-06 15:18:45 -07001615 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001616 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1617 out[rv-1] = '\n'; /* Replace the final space with a newline */
1618 out[rv] = '\0';
1619 rv++;
1620 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621}
1622
1623static int version_file_read_proc(char *page, char **start, off_t off,
1624 int count, int *eof, void *data)
1625{
1626 char *out = (char *) page;
1627 ipmi_smi_t intf = data;
1628
1629 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001630 ipmi_version_major(&intf->bmc->id),
1631 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632}
1633
1634static int stat_file_read_proc(char *page, char **start, off_t off,
1635 int count, int *eof, void *data)
1636{
1637 char *out = (char *) page;
1638 ipmi_smi_t intf = data;
1639
1640 out += sprintf(out, "sent_invalid_commands: %d\n",
1641 intf->sent_invalid_commands);
1642 out += sprintf(out, "sent_local_commands: %d\n",
1643 intf->sent_local_commands);
1644 out += sprintf(out, "handled_local_responses: %d\n",
1645 intf->handled_local_responses);
1646 out += sprintf(out, "unhandled_local_responses: %d\n",
1647 intf->unhandled_local_responses);
1648 out += sprintf(out, "sent_ipmb_commands: %d\n",
1649 intf->sent_ipmb_commands);
1650 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1651 intf->sent_ipmb_command_errs);
1652 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1653 intf->retransmitted_ipmb_commands);
1654 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1655 intf->timed_out_ipmb_commands);
1656 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1657 intf->timed_out_ipmb_broadcasts);
1658 out += sprintf(out, "sent_ipmb_responses: %d\n",
1659 intf->sent_ipmb_responses);
1660 out += sprintf(out, "handled_ipmb_responses: %d\n",
1661 intf->handled_ipmb_responses);
1662 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1663 intf->invalid_ipmb_responses);
1664 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1665 intf->unhandled_ipmb_responses);
1666 out += sprintf(out, "sent_lan_commands: %d\n",
1667 intf->sent_lan_commands);
1668 out += sprintf(out, "sent_lan_command_errs: %d\n",
1669 intf->sent_lan_command_errs);
1670 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1671 intf->retransmitted_lan_commands);
1672 out += sprintf(out, "timed_out_lan_commands: %d\n",
1673 intf->timed_out_lan_commands);
1674 out += sprintf(out, "sent_lan_responses: %d\n",
1675 intf->sent_lan_responses);
1676 out += sprintf(out, "handled_lan_responses: %d\n",
1677 intf->handled_lan_responses);
1678 out += sprintf(out, "invalid_lan_responses: %d\n",
1679 intf->invalid_lan_responses);
1680 out += sprintf(out, "unhandled_lan_responses: %d\n",
1681 intf->unhandled_lan_responses);
1682 out += sprintf(out, "handled_commands: %d\n",
1683 intf->handled_commands);
1684 out += sprintf(out, "invalid_commands: %d\n",
1685 intf->invalid_commands);
1686 out += sprintf(out, "unhandled_commands: %d\n",
1687 intf->unhandled_commands);
1688 out += sprintf(out, "invalid_events: %d\n",
1689 intf->invalid_events);
1690 out += sprintf(out, "events: %d\n",
1691 intf->events);
1692
1693 return (out - ((char *) page));
1694}
1695
1696int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1697 read_proc_t *read_proc, write_proc_t *write_proc,
1698 void *data, struct module *owner)
1699{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001701#ifdef CONFIG_PROC_FS
1702 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 struct ipmi_proc_entry *entry;
1704
1705 /* Create a list element. */
1706 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1707 if (!entry)
1708 return -ENOMEM;
1709 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1710 if (!entry->name) {
1711 kfree(entry);
1712 return -ENOMEM;
1713 }
1714 strcpy(entry->name, name);
1715
1716 file = create_proc_entry(name, 0, smi->proc_dir);
1717 if (!file) {
1718 kfree(entry->name);
1719 kfree(entry);
1720 rv = -ENOMEM;
1721 } else {
1722 file->nlink = 1;
1723 file->data = data;
1724 file->read_proc = read_proc;
1725 file->write_proc = write_proc;
1726 file->owner = owner;
1727
Corey Minyard3b625942005-06-23 22:01:42 -07001728 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 /* Stick it on the list. */
1730 entry->next = smi->proc_entries;
1731 smi->proc_entries = entry;
Corey Minyard3b625942005-06-23 22:01:42 -07001732 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 }
Corey Minyard3b625942005-06-23 22:01:42 -07001734#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
1736 return rv;
1737}
1738
1739static int add_proc_entries(ipmi_smi_t smi, int num)
1740{
1741 int rv = 0;
1742
Corey Minyard3b625942005-06-23 22:01:42 -07001743#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 sprintf(smi->proc_dir_name, "%d", num);
1745 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1746 if (!smi->proc_dir)
1747 rv = -ENOMEM;
1748 else {
1749 smi->proc_dir->owner = THIS_MODULE;
1750 }
1751
1752 if (rv == 0)
1753 rv = ipmi_smi_add_proc_entry(smi, "stats",
1754 stat_file_read_proc, NULL,
1755 smi, THIS_MODULE);
1756
1757 if (rv == 0)
1758 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1759 ipmb_file_read_proc, NULL,
1760 smi, THIS_MODULE);
1761
1762 if (rv == 0)
1763 rv = ipmi_smi_add_proc_entry(smi, "version",
1764 version_file_read_proc, NULL,
1765 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001766#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 return rv;
1769}
1770
1771static void remove_proc_entries(ipmi_smi_t smi)
1772{
Corey Minyard3b625942005-06-23 22:01:42 -07001773#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 struct ipmi_proc_entry *entry;
1775
Corey Minyard3b625942005-06-23 22:01:42 -07001776 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 while (smi->proc_entries) {
1778 entry = smi->proc_entries;
1779 smi->proc_entries = entry->next;
1780
1781 remove_proc_entry(entry->name, smi->proc_dir);
1782 kfree(entry->name);
1783 kfree(entry);
1784 }
Corey Minyard3b625942005-06-23 22:01:42 -07001785 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001787#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788}
1789
Corey Minyard50c812b2006-03-26 01:37:21 -08001790static int __find_bmc_guid(struct device *dev, void *data)
1791{
1792 unsigned char *id = data;
1793 struct bmc_device *bmc = dev_get_drvdata(dev);
1794 return memcmp(bmc->guid, id, 16) == 0;
1795}
1796
1797static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1798 unsigned char *guid)
1799{
1800 struct device *dev;
1801
1802 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1803 if (dev)
1804 return dev_get_drvdata(dev);
1805 else
1806 return NULL;
1807}
1808
1809struct prod_dev_id {
1810 unsigned int product_id;
1811 unsigned char device_id;
1812};
1813
1814static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1815{
1816 struct prod_dev_id *id = data;
1817 struct bmc_device *bmc = dev_get_drvdata(dev);
1818
1819 return (bmc->id.product_id == id->product_id
1820 && bmc->id.product_id == id->product_id
1821 && bmc->id.device_id == id->device_id);
1822}
1823
1824static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1825 struct device_driver *drv,
1826 unsigned char product_id, unsigned char device_id)
1827{
1828 struct prod_dev_id id = {
1829 .product_id = product_id,
1830 .device_id = device_id,
1831 };
1832 struct device *dev;
1833
1834 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
1835 if (dev)
1836 return dev_get_drvdata(dev);
1837 else
1838 return NULL;
1839}
1840
1841static ssize_t device_id_show(struct device *dev,
1842 struct device_attribute *attr,
1843 char *buf)
1844{
1845 struct bmc_device *bmc = dev_get_drvdata(dev);
1846
1847 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
1848}
1849
1850static ssize_t provides_dev_sdrs_show(struct device *dev,
1851 struct device_attribute *attr,
1852 char *buf)
1853{
1854 struct bmc_device *bmc = dev_get_drvdata(dev);
1855
1856 return snprintf(buf, 10, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08001857 (bmc->id.device_revision & 0x80) >> 7);
Corey Minyard50c812b2006-03-26 01:37:21 -08001858}
1859
1860static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
1861 char *buf)
1862{
1863 struct bmc_device *bmc = dev_get_drvdata(dev);
1864
1865 return snprintf(buf, 20, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08001866 bmc->id.device_revision & 0x0F);
Corey Minyard50c812b2006-03-26 01:37:21 -08001867}
1868
1869static ssize_t firmware_rev_show(struct device *dev,
1870 struct device_attribute *attr,
1871 char *buf)
1872{
1873 struct bmc_device *bmc = dev_get_drvdata(dev);
1874
1875 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
1876 bmc->id.firmware_revision_2);
1877}
1878
1879static ssize_t ipmi_version_show(struct device *dev,
1880 struct device_attribute *attr,
1881 char *buf)
1882{
1883 struct bmc_device *bmc = dev_get_drvdata(dev);
1884
1885 return snprintf(buf, 20, "%u.%u\n",
1886 ipmi_version_major(&bmc->id),
1887 ipmi_version_minor(&bmc->id));
1888}
1889
1890static ssize_t add_dev_support_show(struct device *dev,
1891 struct device_attribute *attr,
1892 char *buf)
1893{
1894 struct bmc_device *bmc = dev_get_drvdata(dev);
1895
1896 return snprintf(buf, 10, "0x%02x\n",
1897 bmc->id.additional_device_support);
1898}
1899
1900static ssize_t manufacturer_id_show(struct device *dev,
1901 struct device_attribute *attr,
1902 char *buf)
1903{
1904 struct bmc_device *bmc = dev_get_drvdata(dev);
1905
1906 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
1907}
1908
1909static ssize_t product_id_show(struct device *dev,
1910 struct device_attribute *attr,
1911 char *buf)
1912{
1913 struct bmc_device *bmc = dev_get_drvdata(dev);
1914
1915 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
1916}
1917
1918static ssize_t aux_firmware_rev_show(struct device *dev,
1919 struct device_attribute *attr,
1920 char *buf)
1921{
1922 struct bmc_device *bmc = dev_get_drvdata(dev);
1923
1924 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
1925 bmc->id.aux_firmware_revision[3],
1926 bmc->id.aux_firmware_revision[2],
1927 bmc->id.aux_firmware_revision[1],
1928 bmc->id.aux_firmware_revision[0]);
1929}
1930
1931static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
1932 char *buf)
1933{
1934 struct bmc_device *bmc = dev_get_drvdata(dev);
1935
1936 return snprintf(buf, 100, "%Lx%Lx\n",
1937 (long long) bmc->guid[0],
1938 (long long) bmc->guid[8]);
1939}
1940
Jeff Garzik5e593932006-10-11 01:22:21 -07001941static void remove_files(struct bmc_device *bmc)
Corey Minyard50c812b2006-03-26 01:37:21 -08001942{
Corey Minyard50c812b2006-03-26 01:37:21 -08001943 device_remove_file(&bmc->dev->dev,
1944 &bmc->device_id_attr);
1945 device_remove_file(&bmc->dev->dev,
1946 &bmc->provides_dev_sdrs_attr);
1947 device_remove_file(&bmc->dev->dev,
1948 &bmc->revision_attr);
1949 device_remove_file(&bmc->dev->dev,
1950 &bmc->firmware_rev_attr);
1951 device_remove_file(&bmc->dev->dev,
1952 &bmc->version_attr);
1953 device_remove_file(&bmc->dev->dev,
1954 &bmc->add_dev_support_attr);
1955 device_remove_file(&bmc->dev->dev,
1956 &bmc->manufacturer_id_attr);
1957 device_remove_file(&bmc->dev->dev,
1958 &bmc->product_id_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07001959
Corey Minyard50c812b2006-03-26 01:37:21 -08001960 if (bmc->id.aux_firmware_revision_set)
1961 device_remove_file(&bmc->dev->dev,
1962 &bmc->aux_firmware_rev_attr);
1963 if (bmc->guid_set)
1964 device_remove_file(&bmc->dev->dev,
1965 &bmc->guid_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07001966}
1967
1968static void
1969cleanup_bmc_device(struct kref *ref)
1970{
1971 struct bmc_device *bmc;
1972
1973 bmc = container_of(ref, struct bmc_device, refcount);
1974
1975 remove_files(bmc);
Corey Minyard50c812b2006-03-26 01:37:21 -08001976 platform_device_unregister(bmc->dev);
1977 kfree(bmc);
1978}
1979
1980static void ipmi_bmc_unregister(ipmi_smi_t intf)
1981{
1982 struct bmc_device *bmc = intf->bmc;
1983
1984 sysfs_remove_link(&intf->si_dev->kobj, "bmc");
1985 if (intf->my_dev_name) {
1986 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
1987 kfree(intf->my_dev_name);
1988 intf->my_dev_name = NULL;
1989 }
1990
1991 mutex_lock(&ipmidriver_mutex);
1992 kref_put(&bmc->refcount, cleanup_bmc_device);
1993 mutex_unlock(&ipmidriver_mutex);
1994}
1995
Jeff Garzik5e593932006-10-11 01:22:21 -07001996static int create_files(struct bmc_device *bmc)
1997{
1998 int err;
1999
2000 err = device_create_file(&bmc->dev->dev,
2001 &bmc->device_id_attr);
2002 if (err) goto out;
2003 err = device_create_file(&bmc->dev->dev,
2004 &bmc->provides_dev_sdrs_attr);
2005 if (err) goto out_devid;
2006 err = device_create_file(&bmc->dev->dev,
2007 &bmc->revision_attr);
2008 if (err) goto out_sdrs;
2009 err = device_create_file(&bmc->dev->dev,
2010 &bmc->firmware_rev_attr);
2011 if (err) goto out_rev;
2012 err = device_create_file(&bmc->dev->dev,
2013 &bmc->version_attr);
2014 if (err) goto out_firm;
2015 err = device_create_file(&bmc->dev->dev,
2016 &bmc->add_dev_support_attr);
2017 if (err) goto out_version;
2018 err = device_create_file(&bmc->dev->dev,
2019 &bmc->manufacturer_id_attr);
2020 if (err) goto out_add_dev;
2021 err = device_create_file(&bmc->dev->dev,
2022 &bmc->product_id_attr);
2023 if (err) goto out_manu;
2024 if (bmc->id.aux_firmware_revision_set) {
2025 err = device_create_file(&bmc->dev->dev,
2026 &bmc->aux_firmware_rev_attr);
2027 if (err) goto out_prod_id;
2028 }
2029 if (bmc->guid_set) {
2030 err = device_create_file(&bmc->dev->dev,
2031 &bmc->guid_attr);
2032 if (err) goto out_aux_firm;
2033 }
2034
2035 return 0;
2036
2037out_aux_firm:
2038 if (bmc->id.aux_firmware_revision_set)
2039 device_remove_file(&bmc->dev->dev,
2040 &bmc->aux_firmware_rev_attr);
2041out_prod_id:
2042 device_remove_file(&bmc->dev->dev,
2043 &bmc->product_id_attr);
2044out_manu:
2045 device_remove_file(&bmc->dev->dev,
2046 &bmc->manufacturer_id_attr);
2047out_add_dev:
2048 device_remove_file(&bmc->dev->dev,
2049 &bmc->add_dev_support_attr);
2050out_version:
2051 device_remove_file(&bmc->dev->dev,
2052 &bmc->version_attr);
2053out_firm:
2054 device_remove_file(&bmc->dev->dev,
2055 &bmc->firmware_rev_attr);
2056out_rev:
2057 device_remove_file(&bmc->dev->dev,
2058 &bmc->revision_attr);
2059out_sdrs:
2060 device_remove_file(&bmc->dev->dev,
2061 &bmc->provides_dev_sdrs_attr);
2062out_devid:
2063 device_remove_file(&bmc->dev->dev,
2064 &bmc->device_id_attr);
2065out:
2066 return err;
2067}
2068
Corey Minyard50c812b2006-03-26 01:37:21 -08002069static int ipmi_bmc_register(ipmi_smi_t intf)
2070{
2071 int rv;
2072 struct bmc_device *bmc = intf->bmc;
2073 struct bmc_device *old_bmc;
2074 int size;
2075 char dummy[1];
2076
2077 mutex_lock(&ipmidriver_mutex);
2078
2079 /*
2080 * Try to find if there is an bmc_device struct
2081 * representing the interfaced BMC already
2082 */
2083 if (bmc->guid_set)
2084 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
2085 else
2086 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
2087 bmc->id.product_id,
2088 bmc->id.device_id);
2089
2090 /*
2091 * If there is already an bmc_device, free the new one,
2092 * otherwise register the new BMC device
2093 */
2094 if (old_bmc) {
2095 kfree(bmc);
2096 intf->bmc = old_bmc;
2097 bmc = old_bmc;
2098
2099 kref_get(&bmc->refcount);
2100 mutex_unlock(&ipmidriver_mutex);
2101
2102 printk(KERN_INFO
2103 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
2104 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2105 bmc->id.manufacturer_id,
2106 bmc->id.product_id,
2107 bmc->id.device_id);
2108 } else {
2109 bmc->dev = platform_device_alloc("ipmi_bmc",
2110 bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08002111 if (!bmc->dev) {
Corey Minyard50c812b2006-03-26 01:37:21 -08002112 printk(KERN_ERR
2113 "ipmi_msghandler:"
2114 " Unable to allocate platform device\n");
2115 return -ENOMEM;
2116 }
2117 bmc->dev->dev.driver = &ipmidriver;
2118 dev_set_drvdata(&bmc->dev->dev, bmc);
2119 kref_init(&bmc->refcount);
2120
Zhang, Yanminb48f5452006-11-16 01:19:08 -08002121 rv = platform_device_add(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002122 mutex_unlock(&ipmidriver_mutex);
2123 if (rv) {
2124 printk(KERN_ERR
2125 "ipmi_msghandler:"
2126 " Unable to register bmc device: %d\n",
2127 rv);
2128 /* Don't go to out_err, you can only do that if
2129 the device is registered already. */
2130 return rv;
2131 }
2132
2133 bmc->device_id_attr.attr.name = "device_id";
2134 bmc->device_id_attr.attr.owner = THIS_MODULE;
2135 bmc->device_id_attr.attr.mode = S_IRUGO;
2136 bmc->device_id_attr.show = device_id_show;
2137
2138 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
2139 bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
2140 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2141 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2142
Corey Minyard50c812b2006-03-26 01:37:21 -08002143 bmc->revision_attr.attr.name = "revision";
2144 bmc->revision_attr.attr.owner = THIS_MODULE;
2145 bmc->revision_attr.attr.mode = S_IRUGO;
2146 bmc->revision_attr.show = revision_show;
2147
2148 bmc->firmware_rev_attr.attr.name = "firmware_revision";
2149 bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
2150 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2151 bmc->firmware_rev_attr.show = firmware_rev_show;
2152
2153 bmc->version_attr.attr.name = "ipmi_version";
2154 bmc->version_attr.attr.owner = THIS_MODULE;
2155 bmc->version_attr.attr.mode = S_IRUGO;
2156 bmc->version_attr.show = ipmi_version_show;
2157
2158 bmc->add_dev_support_attr.attr.name
2159 = "additional_device_support";
2160 bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
2161 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2162 bmc->add_dev_support_attr.show = add_dev_support_show;
2163
2164 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
2165 bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
2166 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2167 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2168
2169 bmc->product_id_attr.attr.name = "product_id";
2170 bmc->product_id_attr.attr.owner = THIS_MODULE;
2171 bmc->product_id_attr.attr.mode = S_IRUGO;
2172 bmc->product_id_attr.show = product_id_show;
2173
2174 bmc->guid_attr.attr.name = "guid";
2175 bmc->guid_attr.attr.owner = THIS_MODULE;
2176 bmc->guid_attr.attr.mode = S_IRUGO;
2177 bmc->guid_attr.show = guid_show;
2178
2179 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
2180 bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
2181 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2182 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2183
Jeff Garzik5e593932006-10-11 01:22:21 -07002184 rv = create_files(bmc);
2185 if (rv) {
2186 mutex_lock(&ipmidriver_mutex);
2187 platform_device_unregister(bmc->dev);
2188 mutex_unlock(&ipmidriver_mutex);
2189
2190 return rv;
2191 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002192
2193 printk(KERN_INFO
2194 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2195 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2196 bmc->id.manufacturer_id,
2197 bmc->id.product_id,
2198 bmc->id.device_id);
2199 }
2200
2201 /*
2202 * create symlink from system interface device to bmc device
2203 * and back.
2204 */
2205 rv = sysfs_create_link(&intf->si_dev->kobj,
2206 &bmc->dev->dev.kobj, "bmc");
2207 if (rv) {
2208 printk(KERN_ERR
2209 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2210 rv);
2211 goto out_err;
2212 }
2213
2214 size = snprintf(dummy, 0, "ipmi%d", intf->intf_num);
2215 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2216 if (!intf->my_dev_name) {
2217 rv = -ENOMEM;
2218 printk(KERN_ERR
2219 "ipmi_msghandler: allocate link from BMC: %d\n",
2220 rv);
2221 goto out_err;
2222 }
2223 snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num);
2224
2225 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2226 intf->my_dev_name);
2227 if (rv) {
2228 kfree(intf->my_dev_name);
2229 intf->my_dev_name = NULL;
2230 printk(KERN_ERR
2231 "ipmi_msghandler:"
2232 " Unable to create symlink to bmc: %d\n",
2233 rv);
2234 goto out_err;
2235 }
2236
2237 return 0;
2238
2239out_err:
2240 ipmi_bmc_unregister(intf);
2241 return rv;
2242}
2243
2244static int
2245send_guid_cmd(ipmi_smi_t intf, int chan)
2246{
2247 struct kernel_ipmi_msg msg;
2248 struct ipmi_system_interface_addr si;
2249
2250 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2251 si.channel = IPMI_BMC_CHANNEL;
2252 si.lun = 0;
2253
2254 msg.netfn = IPMI_NETFN_APP_REQUEST;
2255 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2256 msg.data = NULL;
2257 msg.data_len = 0;
2258 return i_ipmi_request(NULL,
2259 intf,
2260 (struct ipmi_addr *) &si,
2261 0,
2262 &msg,
2263 intf,
2264 NULL,
2265 NULL,
2266 0,
2267 intf->channels[0].address,
2268 intf->channels[0].lun,
2269 -1, 0);
2270}
2271
2272static void
2273guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2274{
2275 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2276 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2277 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2278 /* Not for me */
2279 return;
2280
2281 if (msg->msg.data[0] != 0) {
2282 /* Error from getting the GUID, the BMC doesn't have one. */
2283 intf->bmc->guid_set = 0;
2284 goto out;
2285 }
2286
2287 if (msg->msg.data_len < 17) {
2288 intf->bmc->guid_set = 0;
2289 printk(KERN_WARNING PFX
2290 "guid_handler: The GUID response from the BMC was too"
2291 " short, it was %d but should have been 17. Assuming"
2292 " GUID is not available.\n",
2293 msg->msg.data_len);
2294 goto out;
2295 }
2296
2297 memcpy(intf->bmc->guid, msg->msg.data, 16);
2298 intf->bmc->guid_set = 1;
2299 out:
2300 wake_up(&intf->waitq);
2301}
2302
2303static void
2304get_guid(ipmi_smi_t intf)
2305{
2306 int rv;
2307
2308 intf->bmc->guid_set = 0x2;
2309 intf->null_user_handler = guid_handler;
2310 rv = send_guid_cmd(intf, 0);
2311 if (rv)
2312 /* Send failed, no GUID available. */
2313 intf->bmc->guid_set = 0;
2314 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2315 intf->null_user_handler = NULL;
2316}
2317
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318static int
2319send_channel_info_cmd(ipmi_smi_t intf, int chan)
2320{
2321 struct kernel_ipmi_msg msg;
2322 unsigned char data[1];
2323 struct ipmi_system_interface_addr si;
2324
2325 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2326 si.channel = IPMI_BMC_CHANNEL;
2327 si.lun = 0;
2328
2329 msg.netfn = IPMI_NETFN_APP_REQUEST;
2330 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2331 msg.data = data;
2332 msg.data_len = 1;
2333 data[0] = chan;
2334 return i_ipmi_request(NULL,
2335 intf,
2336 (struct ipmi_addr *) &si,
2337 0,
2338 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002339 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 NULL,
2341 NULL,
2342 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002343 intf->channels[0].address,
2344 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 -1, 0);
2346}
2347
2348static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002349channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350{
2351 int rv = 0;
2352 int chan;
2353
Corey Minyard56a55ec2005-09-06 15:18:42 -07002354 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2355 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2356 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 {
2358 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002359 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 /* Got an error from the channel, just go on. */
2361
Corey Minyard56a55ec2005-09-06 15:18:42 -07002362 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 /* If the MC does not support this
2364 command, that is legal. We just
2365 assume it has one IPMB at channel
2366 zero. */
2367 intf->channels[0].medium
2368 = IPMI_CHANNEL_MEDIUM_IPMB;
2369 intf->channels[0].protocol
2370 = IPMI_CHANNEL_PROTOCOL_IPMB;
2371 rv = -ENOSYS;
2372
2373 intf->curr_channel = IPMI_MAX_CHANNELS;
2374 wake_up(&intf->waitq);
2375 goto out;
2376 }
2377 goto next_channel;
2378 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002379 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 /* Message not big enough, just go on. */
2381 goto next_channel;
2382 }
2383 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002384 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2385 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
2387 next_channel:
2388 intf->curr_channel++;
2389 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2390 wake_up(&intf->waitq);
2391 else
2392 rv = send_channel_info_cmd(intf, intf->curr_channel);
2393
2394 if (rv) {
2395 /* Got an error somehow, just give up. */
2396 intf->curr_channel = IPMI_MAX_CHANNELS;
2397 wake_up(&intf->waitq);
2398
2399 printk(KERN_WARNING PFX
2400 "Error sending channel information: %d\n",
2401 rv);
2402 }
2403 }
2404 out:
2405 return;
2406}
2407
2408int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2409 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002410 struct ipmi_device_id *device_id,
2411 struct device *si_dev,
Corey Minyard453823b2006-03-31 02:30:39 -08002412 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413{
2414 int i, j;
2415 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002416 ipmi_smi_t intf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 unsigned long flags;
Corey Minyard50c812b2006-03-26 01:37:21 -08002418 int version_major;
2419 int version_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Corey Minyard50c812b2006-03-26 01:37:21 -08002421 version_major = ipmi_version_major(device_id);
2422 version_minor = ipmi_version_minor(device_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
2424 /* Make sure the driver is actually initialized, this handles
2425 problems with initialization order. */
2426 if (!initialized) {
2427 rv = ipmi_init_msghandler();
2428 if (rv)
2429 return rv;
2430 /* The init code doesn't return an error if it was turned
2431 off, but it won't initialize. Check that. */
2432 if (!initialized)
2433 return -ENODEV;
2434 }
2435
Corey Minyard393d2cc2005-11-07 00:59:54 -08002436 intf = kmalloc(sizeof(*intf), GFP_KERNEL);
2437 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002439 memset(intf, 0, sizeof(*intf));
Corey Minyard50c812b2006-03-26 01:37:21 -08002440 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2441 if (!intf->bmc) {
2442 kfree(intf);
2443 return -ENOMEM;
2444 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002445 intf->intf_num = -1;
2446 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002447 intf->bmc->id = *device_id;
2448 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002449 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2450 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2451 intf->channels[j].lun = 2;
2452 }
2453 if (slave_addr != 0)
2454 intf->channels[0].address = slave_addr;
2455 INIT_LIST_HEAD(&intf->users);
2456 intf->handlers = handlers;
2457 intf->send_info = send_info;
2458 spin_lock_init(&intf->seq_lock);
2459 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2460 intf->seq_table[j].inuse = 0;
2461 intf->seq_table[j].seqid = 0;
2462 }
2463 intf->curr_seq = 0;
2464#ifdef CONFIG_PROC_FS
2465 spin_lock_init(&intf->proc_entry_lock);
2466#endif
2467 spin_lock_init(&intf->waiting_msgs_lock);
2468 INIT_LIST_HEAD(&intf->waiting_msgs);
2469 spin_lock_init(&intf->events_lock);
2470 INIT_LIST_HEAD(&intf->waiting_events);
2471 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002472 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002473 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2474 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475
Corey Minyard393d2cc2005-11-07 00:59:54 -08002476 spin_lock_init(&intf->counter_lock);
2477 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
2479 rv = -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002480 spin_lock_irqsave(&interfaces_lock, flags);
Corey Minyarde8b33612005-09-06 15:18:45 -07002481 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 if (ipmi_interfaces[i] == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002483 intf->intf_num = i;
2484 /* Reserve the entry till we are done. */
2485 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 break;
2488 }
2489 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002490 spin_unlock_irqrestore(&interfaces_lock, flags);
2491 if (rv)
2492 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493
Corey Minyard453823b2006-03-31 02:30:39 -08002494 rv = handlers->start_processing(send_info, intf);
2495 if (rv)
2496 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002497
Corey Minyard50c812b2006-03-26 01:37:21 -08002498 get_guid(intf);
2499
Corey Minyard393d2cc2005-11-07 00:59:54 -08002500 if ((version_major > 1)
2501 || ((version_major == 1) && (version_minor >= 5)))
2502 {
2503 /* Start scanning the channels to see what is
2504 available. */
2505 intf->null_user_handler = channel_handler;
2506 intf->curr_channel = 0;
2507 rv = send_channel_info_cmd(intf, 0);
2508 if (rv)
2509 goto out;
2510
2511 /* Wait for the channel info to be read. */
2512 wait_event(intf->waitq,
2513 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002514 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002515 } else {
2516 /* Assume a single IPMB channel at zero. */
2517 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2518 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
2521 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002522 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
Corey Minyard50c812b2006-03-26 01:37:21 -08002524 rv = ipmi_bmc_register(intf);
2525
Corey Minyard393d2cc2005-11-07 00:59:54 -08002526 out:
2527 if (rv) {
2528 if (intf->proc_dir)
2529 remove_proc_entries(intf);
2530 kref_put(&intf->refcount, intf_free);
2531 if (i < MAX_IPMI_INTERFACES) {
2532 spin_lock_irqsave(&interfaces_lock, flags);
2533 ipmi_interfaces[i] = NULL;
2534 spin_unlock_irqrestore(&interfaces_lock, flags);
2535 }
2536 } else {
2537 spin_lock_irqsave(&interfaces_lock, flags);
2538 ipmi_interfaces[i] = intf;
2539 spin_unlock_irqrestore(&interfaces_lock, flags);
Corey Minyard50c812b2006-03-26 01:37:21 -08002540 call_smi_watchers(i, intf->si_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 }
2542
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 return rv;
2544}
2545
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546int ipmi_unregister_smi(ipmi_smi_t intf)
2547{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 int i;
2549 struct ipmi_smi_watcher *w;
2550 unsigned long flags;
2551
Corey Minyard50c812b2006-03-26 01:37:21 -08002552 ipmi_bmc_unregister(intf);
2553
Corey Minyard393d2cc2005-11-07 00:59:54 -08002554 spin_lock_irqsave(&interfaces_lock, flags);
2555 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
2556 if (ipmi_interfaces[i] == intf) {
2557 /* Set the interface number reserved until we
2558 * are done. */
2559 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
2560 intf->intf_num = -1;
2561 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002564 spin_unlock_irqrestore(&interfaces_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565
Corey Minyard393d2cc2005-11-07 00:59:54 -08002566 if (i == MAX_IPMI_INTERFACES)
2567 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568
Corey Minyard393d2cc2005-11-07 00:59:54 -08002569 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570
2571 /* Call all the watcher interfaces to tell them that
2572 an interface is gone. */
2573 down_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002574 list_for_each_entry(w, &smi_watchers, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 w->smi_gone(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 up_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002577
2578 /* Allow the entry to be reused now. */
2579 spin_lock_irqsave(&interfaces_lock, flags);
2580 ipmi_interfaces[i] = NULL;
2581 spin_unlock_irqrestore(&interfaces_lock,flags);
2582
2583 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 return 0;
2585}
2586
2587static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2588 struct ipmi_smi_msg *msg)
2589{
2590 struct ipmi_ipmb_addr ipmb_addr;
2591 struct ipmi_recv_msg *recv_msg;
2592 unsigned long flags;
2593
2594
2595 /* This is 11, not 10, because the response must contain a
2596 * completion code. */
2597 if (msg->rsp_size < 11) {
2598 /* Message not big enough, just ignore it. */
2599 spin_lock_irqsave(&intf->counter_lock, flags);
2600 intf->invalid_ipmb_responses++;
2601 spin_unlock_irqrestore(&intf->counter_lock, flags);
2602 return 0;
2603 }
2604
2605 if (msg->rsp[2] != 0) {
2606 /* An error getting the response, just ignore it. */
2607 return 0;
2608 }
2609
2610 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
2611 ipmb_addr.slave_addr = msg->rsp[6];
2612 ipmb_addr.channel = msg->rsp[3] & 0x0f;
2613 ipmb_addr.lun = msg->rsp[7] & 3;
2614
2615 /* It's a response from a remote entity. Look up the sequence
2616 number and handle the response. */
2617 if (intf_find_seq(intf,
2618 msg->rsp[7] >> 2,
2619 msg->rsp[3] & 0x0f,
2620 msg->rsp[8],
2621 (msg->rsp[4] >> 2) & (~1),
2622 (struct ipmi_addr *) &(ipmb_addr),
2623 &recv_msg))
2624 {
2625 /* We were unable to find the sequence number,
2626 so just nuke the message. */
2627 spin_lock_irqsave(&intf->counter_lock, flags);
2628 intf->unhandled_ipmb_responses++;
2629 spin_unlock_irqrestore(&intf->counter_lock, flags);
2630 return 0;
2631 }
2632
2633 memcpy(recv_msg->msg_data,
2634 &(msg->rsp[9]),
2635 msg->rsp_size - 9);
2636 /* THe other fields matched, so no need to set them, except
2637 for netfn, which needs to be the response that was
2638 returned, not the request value. */
2639 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2640 recv_msg->msg.data = recv_msg->msg_data;
2641 recv_msg->msg.data_len = msg->rsp_size - 10;
2642 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2643 spin_lock_irqsave(&intf->counter_lock, flags);
2644 intf->handled_ipmb_responses++;
2645 spin_unlock_irqrestore(&intf->counter_lock, flags);
2646 deliver_response(recv_msg);
2647
2648 return 0;
2649}
2650
2651static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2652 struct ipmi_smi_msg *msg)
2653{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002654 struct cmd_rcvr *rcvr;
2655 int rv = 0;
2656 unsigned char netfn;
2657 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002658 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002659 ipmi_user_t user = NULL;
2660 struct ipmi_ipmb_addr *ipmb_addr;
2661 struct ipmi_recv_msg *recv_msg;
2662 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
2664 if (msg->rsp_size < 10) {
2665 /* Message not big enough, just ignore it. */
2666 spin_lock_irqsave(&intf->counter_lock, flags);
2667 intf->invalid_commands++;
2668 spin_unlock_irqrestore(&intf->counter_lock, flags);
2669 return 0;
2670 }
2671
2672 if (msg->rsp[2] != 0) {
2673 /* An error getting the response, just ignore it. */
2674 return 0;
2675 }
2676
2677 netfn = msg->rsp[4] >> 2;
2678 cmd = msg->rsp[8];
Corey Minyardc69c3122006-09-30 23:27:56 -07002679 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002681 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002682 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002683 if (rcvr) {
2684 user = rcvr->user;
2685 kref_get(&user->refcount);
2686 } else
2687 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002688 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
2690 if (user == NULL) {
2691 /* We didn't find a user, deliver an error response. */
2692 spin_lock_irqsave(&intf->counter_lock, flags);
2693 intf->unhandled_commands++;
2694 spin_unlock_irqrestore(&intf->counter_lock, flags);
2695
2696 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2697 msg->data[1] = IPMI_SEND_MSG_CMD;
2698 msg->data[2] = msg->rsp[3];
2699 msg->data[3] = msg->rsp[6];
2700 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2701 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002702 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 /* rqseq/lun */
2704 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2705 msg->data[8] = msg->rsp[8]; /* cmd */
2706 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2707 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2708 msg->data_size = 11;
2709
2710#ifdef DEBUG_MSGING
2711 {
2712 int m;
2713 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002714 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 printk(" %2.2x", msg->data[m]);
2716 printk("\n");
2717 }
2718#endif
2719 intf->handlers->sender(intf->send_info, msg, 0);
2720
2721 rv = -1; /* We used the message, so return the value that
2722 causes it to not be freed or queued. */
2723 } else {
2724 /* Deliver the message to the user. */
2725 spin_lock_irqsave(&intf->counter_lock, flags);
2726 intf->handled_commands++;
2727 spin_unlock_irqrestore(&intf->counter_lock, flags);
2728
2729 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002730 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 /* We couldn't allocate memory for the
2732 message, so requeue it for handling
2733 later. */
2734 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002735 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 } else {
2737 /* Extract the source address from the data. */
2738 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2739 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2740 ipmb_addr->slave_addr = msg->rsp[6];
2741 ipmb_addr->lun = msg->rsp[7] & 3;
2742 ipmb_addr->channel = msg->rsp[3] & 0xf;
2743
2744 /* Extract the rest of the message information
2745 from the IPMB header.*/
2746 recv_msg->user = user;
2747 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2748 recv_msg->msgid = msg->rsp[7] >> 2;
2749 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2750 recv_msg->msg.cmd = msg->rsp[8];
2751 recv_msg->msg.data = recv_msg->msg_data;
2752
2753 /* We chop off 10, not 9 bytes because the checksum
2754 at the end also needs to be removed. */
2755 recv_msg->msg.data_len = msg->rsp_size - 10;
2756 memcpy(recv_msg->msg_data,
2757 &(msg->rsp[9]),
2758 msg->rsp_size - 10);
2759 deliver_response(recv_msg);
2760 }
2761 }
2762
2763 return rv;
2764}
2765
2766static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
2767 struct ipmi_smi_msg *msg)
2768{
2769 struct ipmi_lan_addr lan_addr;
2770 struct ipmi_recv_msg *recv_msg;
2771 unsigned long flags;
2772
2773
2774 /* This is 13, not 12, because the response must contain a
2775 * completion code. */
2776 if (msg->rsp_size < 13) {
2777 /* Message not big enough, just ignore it. */
2778 spin_lock_irqsave(&intf->counter_lock, flags);
2779 intf->invalid_lan_responses++;
2780 spin_unlock_irqrestore(&intf->counter_lock, flags);
2781 return 0;
2782 }
2783
2784 if (msg->rsp[2] != 0) {
2785 /* An error getting the response, just ignore it. */
2786 return 0;
2787 }
2788
2789 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
2790 lan_addr.session_handle = msg->rsp[4];
2791 lan_addr.remote_SWID = msg->rsp[8];
2792 lan_addr.local_SWID = msg->rsp[5];
2793 lan_addr.channel = msg->rsp[3] & 0x0f;
2794 lan_addr.privilege = msg->rsp[3] >> 4;
2795 lan_addr.lun = msg->rsp[9] & 3;
2796
2797 /* It's a response from a remote entity. Look up the sequence
2798 number and handle the response. */
2799 if (intf_find_seq(intf,
2800 msg->rsp[9] >> 2,
2801 msg->rsp[3] & 0x0f,
2802 msg->rsp[10],
2803 (msg->rsp[6] >> 2) & (~1),
2804 (struct ipmi_addr *) &(lan_addr),
2805 &recv_msg))
2806 {
2807 /* We were unable to find the sequence number,
2808 so just nuke the message. */
2809 spin_lock_irqsave(&intf->counter_lock, flags);
2810 intf->unhandled_lan_responses++;
2811 spin_unlock_irqrestore(&intf->counter_lock, flags);
2812 return 0;
2813 }
2814
2815 memcpy(recv_msg->msg_data,
2816 &(msg->rsp[11]),
2817 msg->rsp_size - 11);
2818 /* The other fields matched, so no need to set them, except
2819 for netfn, which needs to be the response that was
2820 returned, not the request value. */
2821 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2822 recv_msg->msg.data = recv_msg->msg_data;
2823 recv_msg->msg.data_len = msg->rsp_size - 12;
2824 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2825 spin_lock_irqsave(&intf->counter_lock, flags);
2826 intf->handled_lan_responses++;
2827 spin_unlock_irqrestore(&intf->counter_lock, flags);
2828 deliver_response(recv_msg);
2829
2830 return 0;
2831}
2832
2833static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2834 struct ipmi_smi_msg *msg)
2835{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002836 struct cmd_rcvr *rcvr;
2837 int rv = 0;
2838 unsigned char netfn;
2839 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002840 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002841 ipmi_user_t user = NULL;
2842 struct ipmi_lan_addr *lan_addr;
2843 struct ipmi_recv_msg *recv_msg;
2844 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
2846 if (msg->rsp_size < 12) {
2847 /* Message not big enough, just ignore it. */
2848 spin_lock_irqsave(&intf->counter_lock, flags);
2849 intf->invalid_commands++;
2850 spin_unlock_irqrestore(&intf->counter_lock, flags);
2851 return 0;
2852 }
2853
2854 if (msg->rsp[2] != 0) {
2855 /* An error getting the response, just ignore it. */
2856 return 0;
2857 }
2858
2859 netfn = msg->rsp[6] >> 2;
2860 cmd = msg->rsp[10];
Corey Minyardc69c3122006-09-30 23:27:56 -07002861 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002863 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002864 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002865 if (rcvr) {
2866 user = rcvr->user;
2867 kref_get(&user->refcount);
2868 } else
2869 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002870 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871
2872 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002873 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 spin_lock_irqsave(&intf->counter_lock, flags);
2875 intf->unhandled_commands++;
2876 spin_unlock_irqrestore(&intf->counter_lock, flags);
2877
2878 rv = 0; /* Don't do anything with these messages, just
2879 allow them to be freed. */
2880 } else {
2881 /* Deliver the message to the user. */
2882 spin_lock_irqsave(&intf->counter_lock, flags);
2883 intf->handled_commands++;
2884 spin_unlock_irqrestore(&intf->counter_lock, flags);
2885
2886 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002887 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 /* We couldn't allocate memory for the
2889 message, so requeue it for handling
2890 later. */
2891 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002892 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 } else {
2894 /* Extract the source address from the data. */
2895 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
2896 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
2897 lan_addr->session_handle = msg->rsp[4];
2898 lan_addr->remote_SWID = msg->rsp[8];
2899 lan_addr->local_SWID = msg->rsp[5];
2900 lan_addr->lun = msg->rsp[9] & 3;
2901 lan_addr->channel = msg->rsp[3] & 0xf;
2902 lan_addr->privilege = msg->rsp[3] >> 4;
2903
2904 /* Extract the rest of the message information
2905 from the IPMB header.*/
2906 recv_msg->user = user;
2907 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2908 recv_msg->msgid = msg->rsp[9] >> 2;
2909 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2910 recv_msg->msg.cmd = msg->rsp[10];
2911 recv_msg->msg.data = recv_msg->msg_data;
2912
2913 /* We chop off 12, not 11 bytes because the checksum
2914 at the end also needs to be removed. */
2915 recv_msg->msg.data_len = msg->rsp_size - 12;
2916 memcpy(recv_msg->msg_data,
2917 &(msg->rsp[11]),
2918 msg->rsp_size - 12);
2919 deliver_response(recv_msg);
2920 }
2921 }
2922
2923 return rv;
2924}
2925
2926static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
2927 struct ipmi_smi_msg *msg)
2928{
2929 struct ipmi_system_interface_addr *smi_addr;
2930
2931 recv_msg->msgid = 0;
2932 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
2933 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2934 smi_addr->channel = IPMI_BMC_CHANNEL;
2935 smi_addr->lun = msg->rsp[0] & 3;
2936 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
2937 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2938 recv_msg->msg.cmd = msg->rsp[1];
2939 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
2940 recv_msg->msg.data = recv_msg->msg_data;
2941 recv_msg->msg.data_len = msg->rsp_size - 3;
2942}
2943
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944static int handle_read_event_rsp(ipmi_smi_t intf,
2945 struct ipmi_smi_msg *msg)
2946{
2947 struct ipmi_recv_msg *recv_msg, *recv_msg2;
2948 struct list_head msgs;
2949 ipmi_user_t user;
2950 int rv = 0;
2951 int deliver_count = 0;
2952 unsigned long flags;
2953
2954 if (msg->rsp_size < 19) {
2955 /* Message is too small to be an IPMB event. */
2956 spin_lock_irqsave(&intf->counter_lock, flags);
2957 intf->invalid_events++;
2958 spin_unlock_irqrestore(&intf->counter_lock, flags);
2959 return 0;
2960 }
2961
2962 if (msg->rsp[2] != 0) {
2963 /* An error getting the event, just ignore it. */
2964 return 0;
2965 }
2966
2967 INIT_LIST_HEAD(&msgs);
2968
Corey Minyard393d2cc2005-11-07 00:59:54 -08002969 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
2971 spin_lock(&intf->counter_lock);
2972 intf->events++;
2973 spin_unlock(&intf->counter_lock);
2974
2975 /* Allocate and fill in one message for every user that is getting
2976 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002977 rcu_read_lock();
2978 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08002979 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 continue;
2981
2982 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002983 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002984 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002985 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
2986 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 list_del(&recv_msg->link);
2988 ipmi_free_recv_msg(recv_msg);
2989 }
2990 /* We couldn't allocate memory for the
2991 message, so requeue it for handling
2992 later. */
2993 rv = 1;
2994 goto out;
2995 }
2996
2997 deliver_count++;
2998
2999 copy_event_into_recv_msg(recv_msg, msg);
3000 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003001 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 list_add_tail(&(recv_msg->link), &msgs);
3003 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003004 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005
3006 if (deliver_count) {
3007 /* Now deliver all the messages. */
3008 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
3009 list_del(&recv_msg->link);
3010 deliver_response(recv_msg);
3011 }
3012 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
3013 /* No one to receive the message, put it in queue if there's
3014 not already too many things in the queue. */
3015 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003016 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 /* We couldn't allocate memory for the
3018 message, so requeue it for handling
3019 later. */
3020 rv = 1;
3021 goto out;
3022 }
3023
3024 copy_event_into_recv_msg(recv_msg, msg);
3025 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
Corey Minyard4791c032006-04-10 22:54:31 -07003026 intf->waiting_events_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 } else {
3028 /* There's too many things in the queue, discard this
3029 message. */
3030 printk(KERN_WARNING PFX "Event queue full, discarding an"
3031 " incoming event\n");
3032 }
3033
3034 out:
3035 spin_unlock_irqrestore(&(intf->events_lock), flags);
3036
3037 return rv;
3038}
3039
3040static int handle_bmc_rsp(ipmi_smi_t intf,
3041 struct ipmi_smi_msg *msg)
3042{
3043 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003045 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046
3047 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07003048 if (recv_msg == NULL)
3049 {
3050 printk(KERN_WARNING"IPMI message received with no owner. This\n"
3051 "could be because of a malformed message, or\n"
3052 "because of a hardware error. Contact your\n"
3053 "hardware vender for assistance\n");
3054 return 0;
3055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056
Corey Minyard393d2cc2005-11-07 00:59:54 -08003057 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003059 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07003060 /* The user for the message went away, so give up. */
3061 spin_lock_irqsave(&intf->counter_lock, flags);
3062 intf->unhandled_local_responses++;
3063 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 ipmi_free_recv_msg(recv_msg);
3065 } else {
3066 struct ipmi_system_interface_addr *smi_addr;
3067
3068 spin_lock_irqsave(&intf->counter_lock, flags);
3069 intf->handled_local_responses++;
3070 spin_unlock_irqrestore(&intf->counter_lock, flags);
3071 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3072 recv_msg->msgid = msg->msgid;
3073 smi_addr = ((struct ipmi_system_interface_addr *)
3074 &(recv_msg->addr));
3075 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3076 smi_addr->channel = IPMI_BMC_CHANNEL;
3077 smi_addr->lun = msg->rsp[0] & 3;
3078 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3079 recv_msg->msg.cmd = msg->rsp[1];
3080 memcpy(recv_msg->msg_data,
3081 &(msg->rsp[2]),
3082 msg->rsp_size - 2);
3083 recv_msg->msg.data = recv_msg->msg_data;
3084 recv_msg->msg.data_len = msg->rsp_size - 2;
3085 deliver_response(recv_msg);
3086 }
3087
3088 return 0;
3089}
3090
3091/* Handle a new message. Return 1 if the message should be requeued,
3092 0 if the message should be freed, or -1 if the message should not
3093 be freed or requeued. */
3094static int handle_new_recv_msg(ipmi_smi_t intf,
3095 struct ipmi_smi_msg *msg)
3096{
3097 int requeue;
3098 int chan;
3099
3100#ifdef DEBUG_MSGING
3101 int m;
3102 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07003103 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 printk(" %2.2x", msg->rsp[m]);
3105 printk("\n");
3106#endif
3107 if (msg->rsp_size < 2) {
3108 /* Message is too small to be correct. */
3109 printk(KERN_WARNING PFX "BMC returned to small a message"
3110 " for netfn %x cmd %x, got %d bytes\n",
3111 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3112
3113 /* Generate an error response for the message. */
3114 msg->rsp[0] = msg->data[0] | (1 << 2);
3115 msg->rsp[1] = msg->data[1];
3116 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3117 msg->rsp_size = 3;
3118 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3119 || (msg->rsp[1] != msg->data[1])) /* Command */
3120 {
3121 /* The response is not even marginally correct. */
3122 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3123 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3124 (msg->data[0] >> 2) | 1, msg->data[1],
3125 msg->rsp[0] >> 2, msg->rsp[1]);
3126
3127 /* Generate an error response for the message. */
3128 msg->rsp[0] = msg->data[0] | (1 << 2);
3129 msg->rsp[1] = msg->data[1];
3130 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3131 msg->rsp_size = 3;
3132 }
3133
3134 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3135 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3136 && (msg->user_data != NULL))
3137 {
3138 /* It's a response to a response we sent. For this we
3139 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003140 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141
3142 requeue = 0;
3143 if (msg->rsp_size < 2)
3144 /* Message is too small to be correct. */
3145 goto out;
3146
3147 chan = msg->data[2] & 0x0f;
3148 if (chan >= IPMI_MAX_CHANNELS)
3149 /* Invalid channel number */
3150 goto out;
3151
Corey Minyard393d2cc2005-11-07 00:59:54 -08003152 if (!recv_msg)
3153 goto out;
3154
3155 /* Make sure the user still exists. */
3156 if (!recv_msg->user || !recv_msg->user->valid)
3157 goto out;
3158
3159 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3160 recv_msg->msg.data = recv_msg->msg_data;
3161 recv_msg->msg.data_len = 1;
3162 recv_msg->msg_data[0] = msg->rsp[2];
3163 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3165 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3166 {
3167 /* It's from the receive queue. */
3168 chan = msg->rsp[3] & 0xf;
3169 if (chan >= IPMI_MAX_CHANNELS) {
3170 /* Invalid channel number */
3171 requeue = 0;
3172 goto out;
3173 }
3174
3175 switch (intf->channels[chan].medium) {
3176 case IPMI_CHANNEL_MEDIUM_IPMB:
3177 if (msg->rsp[4] & 0x04) {
3178 /* It's a response, so find the
3179 requesting message and send it up. */
3180 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3181 } else {
3182 /* It's a command to the SMS from some other
3183 entity. Handle that. */
3184 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3185 }
3186 break;
3187
3188 case IPMI_CHANNEL_MEDIUM_8023LAN:
3189 case IPMI_CHANNEL_MEDIUM_ASYNC:
3190 if (msg->rsp[6] & 0x04) {
3191 /* It's a response, so find the
3192 requesting message and send it up. */
3193 requeue = handle_lan_get_msg_rsp(intf, msg);
3194 } else {
3195 /* It's a command to the SMS from some other
3196 entity. Handle that. */
3197 requeue = handle_lan_get_msg_cmd(intf, msg);
3198 }
3199 break;
3200
3201 default:
3202 /* We don't handle the channel type, so just
3203 * free the message. */
3204 requeue = 0;
3205 }
3206
3207 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3208 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3209 {
3210 /* It's an asyncronous event. */
3211 requeue = handle_read_event_rsp(intf, msg);
3212 } else {
3213 /* It's a response from the local BMC. */
3214 requeue = handle_bmc_rsp(intf, msg);
3215 }
3216
3217 out:
3218 return requeue;
3219}
3220
3221/* Handle a new message from the lower layer. */
3222void ipmi_smi_msg_received(ipmi_smi_t intf,
3223 struct ipmi_smi_msg *msg)
3224{
3225 unsigned long flags;
3226 int rv;
3227
3228
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 if ((msg->data_size >= 2)
3230 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3231 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003232 && (msg->user_data == NULL))
3233 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 /* This is the local response to a command send, start
3235 the timer for these. The user_data will not be
3236 NULL if this is a response send, and we will let
3237 response sends just go through. */
3238
3239 /* Check for errors, if we get certain errors (ones
3240 that mean basically we can try again later), we
3241 ignore them and start the timer. Otherwise we
3242 report the error immediately. */
3243 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3244 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
Corey Minyard46d52b02006-11-08 17:44:55 -08003245 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
3246 && (msg->rsp[2] != IPMI_BUS_ERR)
3247 && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 {
3249 int chan = msg->rsp[3] & 0xf;
3250
3251 /* Got an error sending the message, handle it. */
3252 spin_lock_irqsave(&intf->counter_lock, flags);
3253 if (chan >= IPMI_MAX_CHANNELS)
3254 ; /* This shouldn't happen */
3255 else if ((intf->channels[chan].medium
3256 == IPMI_CHANNEL_MEDIUM_8023LAN)
3257 || (intf->channels[chan].medium
3258 == IPMI_CHANNEL_MEDIUM_ASYNC))
3259 intf->sent_lan_command_errs++;
3260 else
3261 intf->sent_ipmb_command_errs++;
3262 spin_unlock_irqrestore(&intf->counter_lock, flags);
3263 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3264 } else {
3265 /* The message was sent, start the timer. */
3266 intf_start_seq_timer(intf, msg->msgid);
3267 }
3268
3269 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003270 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 }
3272
3273 /* To preserve message order, if the list is not empty, we
3274 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003275 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
3276 if (!list_empty(&intf->waiting_msgs)) {
3277 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003278 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003279 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003281 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
3283 rv = handle_new_recv_msg(intf, msg);
3284 if (rv > 0) {
3285 /* Could not handle the message now, just add it to a
3286 list to handle later. */
Hironobu Ishii177294d2005-11-11 08:12:21 -06003287 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003288 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003289 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 } else if (rv == 0) {
3291 ipmi_free_smi_msg(msg);
3292 }
3293
Corey Minyard393d2cc2005-11-07 00:59:54 -08003294 out:
3295 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296}
3297
3298void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3299{
3300 ipmi_user_t user;
3301
Corey Minyard393d2cc2005-11-07 00:59:54 -08003302 rcu_read_lock();
3303 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003304 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 continue;
3306
3307 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3308 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003309 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310}
3311
3312static void
3313handle_msg_timeout(struct ipmi_recv_msg *msg)
3314{
3315 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3316 msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;
3317 msg->msg.netfn |= 1; /* Convert to a response. */
3318 msg->msg.data_len = 1;
3319 msg->msg.data = msg->msg_data;
3320 deliver_response(msg);
3321}
3322
Corey Minyard882fe012005-05-01 08:59:12 -07003323static struct ipmi_smi_msg *
3324smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3325 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326{
Corey Minyard882fe012005-05-01 08:59:12 -07003327 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 if (!smi_msg)
3329 /* If we can't allocate the message, then just return, we
3330 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003331 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332
3333 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3334 smi_msg->data_size = recv_msg->msg.data_len;
3335 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3336
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337#ifdef DEBUG_MSGING
3338 {
3339 int m;
3340 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003341 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 printk(" %2.2x", smi_msg->data[m]);
3343 printk("\n");
3344 }
3345#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003346 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347}
3348
Corey Minyard393d2cc2005-11-07 00:59:54 -08003349static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3350 struct list_head *timeouts, long timeout_period,
3351 int slot, unsigned long *flags)
3352{
3353 struct ipmi_recv_msg *msg;
3354
3355 if (!ent->inuse)
3356 return;
3357
3358 ent->timeout -= timeout_period;
3359 if (ent->timeout > 0)
3360 return;
3361
3362 if (ent->retries_left == 0) {
3363 /* The message has used all its retries. */
3364 ent->inuse = 0;
3365 msg = ent->recv_msg;
3366 list_add_tail(&msg->link, timeouts);
3367 spin_lock(&intf->counter_lock);
3368 if (ent->broadcast)
3369 intf->timed_out_ipmb_broadcasts++;
3370 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3371 intf->timed_out_lan_commands++;
3372 else
3373 intf->timed_out_ipmb_commands++;
3374 spin_unlock(&intf->counter_lock);
3375 } else {
3376 struct ipmi_smi_msg *smi_msg;
3377 /* More retries, send again. */
3378
3379 /* Start with the max timer, set to normal
3380 timer after the message is sent. */
3381 ent->timeout = MAX_MSG_TIMEOUT;
3382 ent->retries_left--;
3383 spin_lock(&intf->counter_lock);
3384 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3385 intf->retransmitted_lan_commands++;
3386 else
3387 intf->retransmitted_ipmb_commands++;
3388 spin_unlock(&intf->counter_lock);
3389
3390 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3391 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003392 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003393 return;
3394
3395 spin_unlock_irqrestore(&intf->seq_lock, *flags);
3396 /* Send the new message. We send with a zero
3397 * priority. It timed out, I doubt time is
3398 * that critical now, and high priority
3399 * messages are really only for messages to the
3400 * local MC, which don't get resent. */
3401 intf->handlers->sender(intf->send_info,
3402 smi_msg, 0);
3403 spin_lock_irqsave(&intf->seq_lock, *flags);
3404 }
3405}
3406
3407static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408{
3409 ipmi_smi_t intf;
3410 struct list_head timeouts;
3411 struct ipmi_recv_msg *msg, *msg2;
3412 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3413 unsigned long flags;
3414 int i, j;
3415
3416 INIT_LIST_HEAD(&timeouts);
3417
3418 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07003419 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003421 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 continue;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003423 kref_get(&intf->refcount);
3424 spin_unlock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425
3426 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003427 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003428 list_for_each_entry_safe(smi_msg, smi_msg2,
3429 &intf->waiting_msgs, link) {
3430 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 list_del(&smi_msg->link);
3432 ipmi_free_smi_msg(smi_msg);
3433 } else {
3434 /* To preserve message order, quit if we
3435 can't handle a message. */
3436 break;
3437 }
3438 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003439 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440
3441 /* Go through the seq table and find any messages that
3442 have timed out, putting them in the timeouts
3443 list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003444 spin_lock_irqsave(&intf->seq_lock, flags);
3445 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++)
3446 check_msg_timeout(intf, &(intf->seq_table[j]),
3447 &timeouts, timeout_period, j,
3448 &flags);
3449 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450
Corey Minyard393d2cc2005-11-07 00:59:54 -08003451 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 handle_msg_timeout(msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453
Corey Minyard393d2cc2005-11-07 00:59:54 -08003454 kref_put(&intf->refcount, intf_free);
3455 spin_lock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 }
3457 spin_unlock(&interfaces_lock);
3458}
3459
3460static void ipmi_request_event(void)
3461{
3462 ipmi_smi_t intf;
3463 int i;
3464
3465 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07003466 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003468 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 continue;
3470
3471 intf->handlers->request_events(intf->send_info);
3472 }
3473 spin_unlock(&interfaces_lock);
3474}
3475
3476static struct timer_list ipmi_timer;
3477
3478/* Call every ~100 ms. */
3479#define IPMI_TIMEOUT_TIME 100
3480
3481/* How many jiffies does it take to get to the timeout time. */
3482#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3483
3484/* Request events from the queue every second (this is the number of
3485 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3486 future, IPMI will add a way to know immediately if an event is in
3487 the queue and this silliness can go away. */
3488#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3489
Corey Minyard8f43f842005-06-23 22:01:40 -07003490static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3492
3493static void ipmi_timeout(unsigned long data)
3494{
Corey Minyard8f43f842005-06-23 22:01:40 -07003495 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497
3498 ticks_to_req_ev--;
3499 if (ticks_to_req_ev == 0) {
3500 ipmi_request_event();
3501 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3502 }
3503
3504 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3505
Corey Minyard8f43f842005-06-23 22:01:40 -07003506 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507}
3508
3509
3510static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3511static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3512
3513/* FIXME - convert these to slabs. */
3514static void free_smi_msg(struct ipmi_smi_msg *msg)
3515{
3516 atomic_dec(&smi_msg_inuse_count);
3517 kfree(msg);
3518}
3519
3520struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3521{
3522 struct ipmi_smi_msg *rv;
3523 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3524 if (rv) {
3525 rv->done = free_smi_msg;
3526 rv->user_data = NULL;
3527 atomic_inc(&smi_msg_inuse_count);
3528 }
3529 return rv;
3530}
3531
3532static void free_recv_msg(struct ipmi_recv_msg *msg)
3533{
3534 atomic_dec(&recv_msg_inuse_count);
3535 kfree(msg);
3536}
3537
3538struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3539{
3540 struct ipmi_recv_msg *rv;
3541
3542 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3543 if (rv) {
Corey Minyarda9eec552006-08-31 21:27:45 -07003544 rv->user = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 rv->done = free_recv_msg;
3546 atomic_inc(&recv_msg_inuse_count);
3547 }
3548 return rv;
3549}
3550
Corey Minyard393d2cc2005-11-07 00:59:54 -08003551void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3552{
3553 if (msg->user)
3554 kref_put(&msg->user->refcount, free_user);
3555 msg->done(msg);
3556}
3557
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558#ifdef CONFIG_IPMI_PANIC_EVENT
3559
3560static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3561{
3562}
3563
3564static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3565{
3566}
3567
3568#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003569static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003571 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3572 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3573 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3574 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 {
3576 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003577 intf->event_receiver = msg->msg.data[1];
3578 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 }
3580}
3581
Corey Minyard56a55ec2005-09-06 15:18:42 -07003582static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003584 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3585 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3586 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3587 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 {
3589 /* A get device id command, save if we are an event
3590 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003591 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3592 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 }
3594}
3595#endif
3596
3597static void send_panic_events(char *str)
3598{
3599 struct kernel_ipmi_msg msg;
3600 ipmi_smi_t intf;
3601 unsigned char data[16];
3602 int i;
3603 struct ipmi_system_interface_addr *si;
3604 struct ipmi_addr addr;
3605 struct ipmi_smi_msg smi_msg;
3606 struct ipmi_recv_msg recv_msg;
3607
3608 si = (struct ipmi_system_interface_addr *) &addr;
3609 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3610 si->channel = IPMI_BMC_CHANNEL;
3611 si->lun = 0;
3612
3613 /* Fill in an event telling that we have failed. */
3614 msg.netfn = 0x04; /* Sensor or Event. */
3615 msg.cmd = 2; /* Platform event command. */
3616 msg.data = data;
3617 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003618 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 data[1] = 0x03; /* This is for IPMI 1.0. */
3620 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3621 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3622 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3623
3624 /* Put a few breadcrumbs in. Hopefully later we can add more things
3625 to make the panic events more useful. */
3626 if (str) {
3627 data[3] = str[0];
3628 data[6] = str[1];
3629 data[7] = str[2];
3630 }
3631
3632 smi_msg.done = dummy_smi_done_handler;
3633 recv_msg.done = dummy_recv_done_handler;
3634
3635 /* For every registered interface, send the event. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003636 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003638 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 continue;
3640
3641 /* Send the event announcing the panic. */
3642 intf->handlers->set_run_to_completion(intf->send_info, 1);
3643 i_ipmi_request(NULL,
3644 intf,
3645 &addr,
3646 0,
3647 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003648 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 &smi_msg,
3650 &recv_msg,
3651 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003652 intf->channels[0].address,
3653 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 0, 1); /* Don't retry, and don't wait. */
3655 }
3656
3657#ifdef CONFIG_IPMI_PANIC_STRING
3658 /* On every interface, dump a bunch of OEM event holding the
3659 string. */
3660 if (!str)
3661 return;
3662
Corey Minyarde8b33612005-09-06 15:18:45 -07003663 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 char *p = str;
3665 struct ipmi_ipmb_addr *ipmb;
3666 int j;
3667
3668 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003669 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 continue;
3671
3672 /* First job here is to figure out where to send the
3673 OEM events. There's no way in IPMI to send OEM
3674 events using an event send command, so we have to
3675 find the SEL to put them in and stick them in
3676 there. */
3677
3678 /* Get capabilities from the get device id. */
3679 intf->local_sel_device = 0;
3680 intf->local_event_generator = 0;
3681 intf->event_receiver = 0;
3682
3683 /* Request the device info from the local MC. */
3684 msg.netfn = IPMI_NETFN_APP_REQUEST;
3685 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3686 msg.data = NULL;
3687 msg.data_len = 0;
3688 intf->null_user_handler = device_id_fetcher;
3689 i_ipmi_request(NULL,
3690 intf,
3691 &addr,
3692 0,
3693 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003694 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 &smi_msg,
3696 &recv_msg,
3697 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003698 intf->channels[0].address,
3699 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 0, 1); /* Don't retry, and don't wait. */
3701
3702 if (intf->local_event_generator) {
3703 /* Request the event receiver from the local MC. */
3704 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3705 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3706 msg.data = NULL;
3707 msg.data_len = 0;
3708 intf->null_user_handler = event_receiver_fetcher;
3709 i_ipmi_request(NULL,
3710 intf,
3711 &addr,
3712 0,
3713 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003714 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 &smi_msg,
3716 &recv_msg,
3717 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003718 intf->channels[0].address,
3719 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 0, 1); /* no retry, and no wait. */
3721 }
3722 intf->null_user_handler = NULL;
3723
3724 /* Validate the event receiver. The low bit must not
3725 be 1 (it must be a valid IPMB address), it cannot
3726 be zero, and it must not be my address. */
3727 if (((intf->event_receiver & 1) == 0)
3728 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003729 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 {
3731 /* The event receiver is valid, send an IPMB
3732 message. */
3733 ipmb = (struct ipmi_ipmb_addr *) &addr;
3734 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3735 ipmb->channel = 0; /* FIXME - is this right? */
3736 ipmb->lun = intf->event_receiver_lun;
3737 ipmb->slave_addr = intf->event_receiver;
3738 } else if (intf->local_sel_device) {
3739 /* The event receiver was not valid (or was
3740 me), but I am an SEL device, just dump it
3741 in my SEL. */
3742 si = (struct ipmi_system_interface_addr *) &addr;
3743 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3744 si->channel = IPMI_BMC_CHANNEL;
3745 si->lun = 0;
3746 } else
3747 continue; /* No where to send the event. */
3748
3749
3750 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
3751 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
3752 msg.data = data;
3753 msg.data_len = 16;
3754
3755 j = 0;
3756 while (*p) {
3757 int size = strlen(p);
3758
3759 if (size > 11)
3760 size = 11;
3761 data[0] = 0;
3762 data[1] = 0;
3763 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07003764 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 data[4] = j++; /* sequence # */
3766 /* Always give 11 bytes, so strncpy will fill
3767 it with zeroes for me. */
3768 strncpy(data+5, p, 11);
3769 p += size;
3770
3771 i_ipmi_request(NULL,
3772 intf,
3773 &addr,
3774 0,
3775 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003776 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 &smi_msg,
3778 &recv_msg,
3779 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003780 intf->channels[0].address,
3781 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 0, 1); /* no retry, and no wait. */
3783 }
3784 }
3785#endif /* CONFIG_IPMI_PANIC_STRING */
3786}
3787#endif /* CONFIG_IPMI_PANIC_EVENT */
3788
Lee Revellf18190b2006-06-26 18:30:00 +02003789static int has_panicked = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790
3791static int panic_event(struct notifier_block *this,
3792 unsigned long event,
3793 void *ptr)
3794{
3795 int i;
3796 ipmi_smi_t intf;
3797
Lee Revellf18190b2006-06-26 18:30:00 +02003798 if (has_panicked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 return NOTIFY_DONE;
Lee Revellf18190b2006-06-26 18:30:00 +02003800 has_panicked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801
3802 /* For every registered interface, set it to run to completion. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003803 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003805 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 continue;
3807
3808 intf->handlers->set_run_to_completion(intf->send_info, 1);
3809 }
3810
3811#ifdef CONFIG_IPMI_PANIC_EVENT
3812 send_panic_events(ptr);
3813#endif
3814
3815 return NOTIFY_DONE;
3816}
3817
3818static struct notifier_block panic_block = {
3819 .notifier_call = panic_event,
3820 .next = NULL,
3821 .priority = 200 /* priority: INT_MAX >= x >= 0 */
3822};
3823
3824static int ipmi_init_msghandler(void)
3825{
3826 int i;
Corey Minyard50c812b2006-03-26 01:37:21 -08003827 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828
3829 if (initialized)
3830 return 0;
3831
Corey Minyard50c812b2006-03-26 01:37:21 -08003832 rv = driver_register(&ipmidriver);
3833 if (rv) {
3834 printk(KERN_ERR PFX "Could not register IPMI driver\n");
3835 return rv;
3836 }
3837
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003839 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840
Corey Minyard393d2cc2005-11-07 00:59:54 -08003841 for (i = 0; i < MAX_IPMI_INTERFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 ipmi_interfaces[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843
Corey Minyard3b625942005-06-23 22:01:42 -07003844#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 proc_ipmi_root = proc_mkdir("ipmi", NULL);
3846 if (!proc_ipmi_root) {
3847 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
3848 return -ENOMEM;
3849 }
3850
3851 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07003852#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853
Corey Minyard409035e2006-06-28 04:26:53 -07003854 setup_timer(&ipmi_timer, ipmi_timeout, 0);
3855 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856
Alan Sterne041c682006-03-27 01:16:30 -08003857 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858
3859 initialized = 1;
3860
3861 return 0;
3862}
3863
3864static __init int ipmi_init_msghandler_mod(void)
3865{
3866 ipmi_init_msghandler();
3867 return 0;
3868}
3869
3870static __exit void cleanup_ipmi(void)
3871{
3872 int count;
3873
3874 if (!initialized)
3875 return;
3876
Alan Sterne041c682006-03-27 01:16:30 -08003877 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878
3879 /* This can't be called if any interfaces exist, so no worry about
3880 shutting down the interfaces. */
3881
3882 /* Tell the timer to stop, then wait for it to stop. This avoids
3883 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07003884 atomic_inc(&stop_operation);
3885 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886
Corey Minyard3b625942005-06-23 22:01:42 -07003887#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 remove_proc_entry(proc_ipmi_root->name, &proc_root);
Corey Minyard3b625942005-06-23 22:01:42 -07003889#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890
Corey Minyard50c812b2006-03-26 01:37:21 -08003891 driver_unregister(&ipmidriver);
3892
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 initialized = 0;
3894
3895 /* Check for buffer leaks. */
3896 count = atomic_read(&smi_msg_inuse_count);
3897 if (count != 0)
3898 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
3899 count);
3900 count = atomic_read(&recv_msg_inuse_count);
3901 if (count != 0)
3902 printk(KERN_WARNING PFX "recv message count %d at exit\n",
3903 count);
3904}
3905module_exit(cleanup_ipmi);
3906
3907module_init(ipmi_init_msghandler_mod);
3908MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003909MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
3910MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
3911MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912
3913EXPORT_SYMBOL(ipmi_create_user);
3914EXPORT_SYMBOL(ipmi_destroy_user);
3915EXPORT_SYMBOL(ipmi_get_version);
3916EXPORT_SYMBOL(ipmi_request_settime);
3917EXPORT_SYMBOL(ipmi_request_supply_msgs);
3918EXPORT_SYMBOL(ipmi_register_smi);
3919EXPORT_SYMBOL(ipmi_unregister_smi);
3920EXPORT_SYMBOL(ipmi_register_for_cmd);
3921EXPORT_SYMBOL(ipmi_unregister_for_cmd);
3922EXPORT_SYMBOL(ipmi_smi_msg_received);
3923EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
3924EXPORT_SYMBOL(ipmi_alloc_smi_msg);
3925EXPORT_SYMBOL(ipmi_addr_length);
3926EXPORT_SYMBOL(ipmi_validate_addr);
3927EXPORT_SYMBOL(ipmi_set_gets_events);
3928EXPORT_SYMBOL(ipmi_smi_watcher_register);
3929EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
3930EXPORT_SYMBOL(ipmi_set_my_address);
3931EXPORT_SYMBOL(ipmi_get_my_address);
3932EXPORT_SYMBOL(ipmi_set_my_LUN);
3933EXPORT_SYMBOL(ipmi_get_my_LUN);
3934EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003936EXPORT_SYMBOL(ipmi_free_recv_msg);