blob: 761ed2699204c676ae6c9e5bb10f8bf6cf2ef803 [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
Corey Minyardbca03242006-12-06 20:40:57 -0800196 /* Used for a list of interfaces. */
197 struct list_head link;
198
Corey Minyard393d2cc2005-11-07 00:59:54 -0800199 /* The list of upper layers that are using me. seq_lock
200 * protects this. */
201 struct list_head users;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 /* Used for wake ups at startup. */
204 wait_queue_head_t waitq;
205
Corey Minyard50c812b2006-03-26 01:37:21 -0800206 struct bmc_device *bmc;
207 char *my_dev_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 /* This is the lower-layer's sender routine. */
210 struct ipmi_smi_handlers *handlers;
211 void *send_info;
212
Corey Minyard3b625942005-06-23 22:01:42 -0700213#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 /* A list of proc entries for this interface. This does not
215 need a lock, only one thread creates it and only one thread
216 destroys it. */
Corey Minyard3b625942005-06-23 22:01:42 -0700217 spinlock_t proc_entry_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 struct ipmi_proc_entry *proc_entries;
Corey Minyard3b625942005-06-23 22:01:42 -0700219#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Corey Minyard50c812b2006-03-26 01:37:21 -0800221 /* Driver-model device for the system interface. */
222 struct device *si_dev;
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 /* A table of sequence numbers for this interface. We use the
225 sequence numbers for IPMB messages that go out of the
226 interface to match them up with their responses. A routine
227 is called periodically to time the items in this list. */
228 spinlock_t seq_lock;
229 struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
230 int curr_seq;
231
232 /* Messages that were delayed for some reason (out of memory,
233 for instance), will go in here to be processed later in a
234 periodic timer interrupt. */
235 spinlock_t waiting_msgs_lock;
236 struct list_head waiting_msgs;
237
238 /* The list of command receivers that are registered for commands
239 on this interface. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800240 struct mutex cmd_rcvrs_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 struct list_head cmd_rcvrs;
242
243 /* Events that were queues because no one was there to receive
244 them. */
245 spinlock_t events_lock; /* For dealing with event stuff. */
246 struct list_head waiting_events;
247 unsigned int waiting_events_count; /* How many events in queue? */
248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 /* The event receiver for my BMC, only really used at panic
250 shutdown as a place to store this. */
251 unsigned char event_receiver;
252 unsigned char event_receiver_lun;
253 unsigned char local_sel_device;
254 unsigned char local_event_generator;
255
256 /* A cheap hack, if this is non-null and a message to an
257 interface comes in with a NULL user, call this routine with
258 it. Note that the message will still be freed by the
259 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700260 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262 /* When we are scanning the channels for an SMI, this will
263 tell which channel we are scanning. */
264 int curr_channel;
265
266 /* Channel information */
267 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
268
269 /* Proc FS stuff. */
270 struct proc_dir_entry *proc_dir;
271 char proc_dir_name[10];
272
273 spinlock_t counter_lock; /* For making counters atomic. */
274
275 /* Commands we got that were invalid. */
276 unsigned int sent_invalid_commands;
277
278 /* Commands we sent to the MC. */
279 unsigned int sent_local_commands;
280 /* Responses from the MC that were delivered to a user. */
281 unsigned int handled_local_responses;
282 /* Responses from the MC that were not delivered to a user. */
283 unsigned int unhandled_local_responses;
284
285 /* Commands we sent out to the IPMB bus. */
286 unsigned int sent_ipmb_commands;
287 /* Commands sent on the IPMB that had errors on the SEND CMD */
288 unsigned int sent_ipmb_command_errs;
289 /* Each retransmit increments this count. */
290 unsigned int retransmitted_ipmb_commands;
291 /* When a message times out (runs out of retransmits) this is
292 incremented. */
293 unsigned int timed_out_ipmb_commands;
294
295 /* This is like above, but for broadcasts. Broadcasts are
296 *not* included in the above count (they are expected to
297 time out). */
298 unsigned int timed_out_ipmb_broadcasts;
299
300 /* Responses I have sent to the IPMB bus. */
301 unsigned int sent_ipmb_responses;
302
303 /* The response was delivered to the user. */
304 unsigned int handled_ipmb_responses;
305 /* The response had invalid data in it. */
306 unsigned int invalid_ipmb_responses;
307 /* The response didn't have anyone waiting for it. */
308 unsigned int unhandled_ipmb_responses;
309
310 /* Commands we sent out to the IPMB bus. */
311 unsigned int sent_lan_commands;
312 /* Commands sent on the IPMB that had errors on the SEND CMD */
313 unsigned int sent_lan_command_errs;
314 /* Each retransmit increments this count. */
315 unsigned int retransmitted_lan_commands;
316 /* When a message times out (runs out of retransmits) this is
317 incremented. */
318 unsigned int timed_out_lan_commands;
319
320 /* Responses I have sent to the IPMB bus. */
321 unsigned int sent_lan_responses;
322
323 /* The response was delivered to the user. */
324 unsigned int handled_lan_responses;
325 /* The response had invalid data in it. */
326 unsigned int invalid_lan_responses;
327 /* The response didn't have anyone waiting for it. */
328 unsigned int unhandled_lan_responses;
329
330 /* The command was delivered to the user. */
331 unsigned int handled_commands;
332 /* The command had invalid data in it. */
333 unsigned int invalid_commands;
334 /* The command didn't have anyone waiting for it. */
335 unsigned int unhandled_commands;
336
337 /* Invalid data in an event. */
338 unsigned int invalid_events;
339 /* Events that were received with the proper format. */
340 unsigned int events;
341};
Corey Minyard50c812b2006-03-26 01:37:21 -0800342#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Corey Minyard50c812b2006-03-26 01:37:21 -0800344/**
345 * The driver model view of the IPMI messaging driver.
346 */
347static struct device_driver ipmidriver = {
348 .name = "ipmi",
349 .bus = &platform_bus_type
350};
351static DEFINE_MUTEX(ipmidriver_mutex);
352
Corey Minyardbca03242006-12-06 20:40:57 -0800353static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces);
354static DEFINE_MUTEX(ipmi_interfaces_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356/* List of watchers that want to know when smi's are added and
357 deleted. */
358static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
359static DECLARE_RWSEM(smi_watchers_sem);
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Corey Minyard393d2cc2005-11-07 00:59:54 -0800362static void free_recv_msg_list(struct list_head *q)
363{
364 struct ipmi_recv_msg *msg, *msg2;
365
366 list_for_each_entry_safe(msg, msg2, q, link) {
367 list_del(&msg->link);
368 ipmi_free_recv_msg(msg);
369 }
370}
371
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800372static void free_smi_msg_list(struct list_head *q)
373{
374 struct ipmi_smi_msg *msg, *msg2;
375
376 list_for_each_entry_safe(msg, msg2, q, link) {
377 list_del(&msg->link);
378 ipmi_free_smi_msg(msg);
379 }
380}
381
Corey Minyard393d2cc2005-11-07 00:59:54 -0800382static void clean_up_interface_data(ipmi_smi_t intf)
383{
384 int i;
385 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800386 struct list_head list;
387
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800388 free_smi_msg_list(&intf->waiting_msgs);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800389 free_recv_msg_list(&intf->waiting_events);
390
391 /* Wholesale remove all the entries from the list in the
392 * interface and wait for RCU to know that none are in use. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800393 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800394 list_add_rcu(&list, &intf->cmd_rcvrs);
395 list_del_rcu(&intf->cmd_rcvrs);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800396 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800397 synchronize_rcu();
398
399 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
400 kfree(rcvr);
401
402 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
403 if ((intf->seq_table[i].inuse)
404 && (intf->seq_table[i].recv_msg))
405 {
406 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 }
408 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800409}
410
411static void intf_free(struct kref *ref)
412{
413 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
414
415 clean_up_interface_data(intf);
416 kfree(intf);
417}
418
Corey Minyardbca03242006-12-06 20:40:57 -0800419struct watcher_entry {
420 struct list_head link;
421 int intf_num;
422};
423
Corey Minyard393d2cc2005-11-07 00:59:54 -0800424int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
425{
Corey Minyardbca03242006-12-06 20:40:57 -0800426 ipmi_smi_t intf;
427 struct list_head to_deliver = LIST_HEAD_INIT(to_deliver);
428 struct watcher_entry *e, *e2;
429
430 mutex_lock(&ipmi_interfaces_mutex);
431
432 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
433 if (intf->intf_num == -1)
434 continue;
435 e = kmalloc(sizeof(*e), GFP_KERNEL);
436 if (!e)
437 goto out_err;
438 e->intf_num = intf->intf_num;
439 list_add_tail(&e->link, &to_deliver);
440 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800441
442 down_write(&smi_watchers_sem);
443 list_add(&(watcher->link), &smi_watchers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 up_write(&smi_watchers_sem);
Corey Minyardbca03242006-12-06 20:40:57 -0800445
446 mutex_unlock(&ipmi_interfaces_mutex);
447
448 list_for_each_entry_safe(e, e2, &to_deliver, link) {
449 list_del(&e->link);
450 watcher->new_smi(e->intf_num, intf->si_dev);
451 kfree(e);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800452 }
Corey Minyardbca03242006-12-06 20:40:57 -0800453
454
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 return 0;
Corey Minyardbca03242006-12-06 20:40:57 -0800456
457 out_err:
458 list_for_each_entry_safe(e, e2, &to_deliver, link) {
459 list_del(&e->link);
460 kfree(e);
461 }
462 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463}
464
465int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
466{
467 down_write(&smi_watchers_sem);
468 list_del(&(watcher->link));
469 up_write(&smi_watchers_sem);
470 return 0;
471}
472
473static void
Corey Minyard50c812b2006-03-26 01:37:21 -0800474call_smi_watchers(int i, struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
476 struct ipmi_smi_watcher *w;
477
478 down_read(&smi_watchers_sem);
479 list_for_each_entry(w, &smi_watchers, link) {
480 if (try_module_get(w->owner)) {
Corey Minyard50c812b2006-03-26 01:37:21 -0800481 w->new_smi(i, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 module_put(w->owner);
483 }
484 }
485 up_read(&smi_watchers_sem);
486}
487
488static int
489ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
490{
491 if (addr1->addr_type != addr2->addr_type)
492 return 0;
493
494 if (addr1->channel != addr2->channel)
495 return 0;
496
497 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
498 struct ipmi_system_interface_addr *smi_addr1
499 = (struct ipmi_system_interface_addr *) addr1;
500 struct ipmi_system_interface_addr *smi_addr2
501 = (struct ipmi_system_interface_addr *) addr2;
502 return (smi_addr1->lun == smi_addr2->lun);
503 }
504
505 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
506 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
507 {
508 struct ipmi_ipmb_addr *ipmb_addr1
509 = (struct ipmi_ipmb_addr *) addr1;
510 struct ipmi_ipmb_addr *ipmb_addr2
511 = (struct ipmi_ipmb_addr *) addr2;
512
513 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
514 && (ipmb_addr1->lun == ipmb_addr2->lun));
515 }
516
517 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
518 struct ipmi_lan_addr *lan_addr1
519 = (struct ipmi_lan_addr *) addr1;
520 struct ipmi_lan_addr *lan_addr2
521 = (struct ipmi_lan_addr *) addr2;
522
523 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
524 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
525 && (lan_addr1->session_handle
526 == lan_addr2->session_handle)
527 && (lan_addr1->lun == lan_addr2->lun));
528 }
529
530 return 1;
531}
532
533int ipmi_validate_addr(struct ipmi_addr *addr, int len)
534{
535 if (len < sizeof(struct ipmi_system_interface_addr)) {
536 return -EINVAL;
537 }
538
539 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
540 if (addr->channel != IPMI_BMC_CHANNEL)
541 return -EINVAL;
542 return 0;
543 }
544
545 if ((addr->channel == IPMI_BMC_CHANNEL)
Jayachandran C12fc1d72006-02-03 03:04:51 -0800546 || (addr->channel >= IPMI_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 || (addr->channel < 0))
548 return -EINVAL;
549
550 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
551 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
552 {
553 if (len < sizeof(struct ipmi_ipmb_addr)) {
554 return -EINVAL;
555 }
556 return 0;
557 }
558
559 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
560 if (len < sizeof(struct ipmi_lan_addr)) {
561 return -EINVAL;
562 }
563 return 0;
564 }
565
566 return -EINVAL;
567}
568
569unsigned int ipmi_addr_length(int addr_type)
570{
571 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
572 return sizeof(struct ipmi_system_interface_addr);
573
574 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
575 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
576 {
577 return sizeof(struct ipmi_ipmb_addr);
578 }
579
580 if (addr_type == IPMI_LAN_ADDR_TYPE)
581 return sizeof(struct ipmi_lan_addr);
582
583 return 0;
584}
585
586static void deliver_response(struct ipmi_recv_msg *msg)
587{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800588 if (!msg->user) {
Corey Minyard56a55ec2005-09-06 15:18:42 -0700589 ipmi_smi_t intf = msg->user_msg_data;
590 unsigned long flags;
591
592 /* Special handling for NULL users. */
593 if (intf->null_user_handler) {
594 intf->null_user_handler(intf, msg);
595 spin_lock_irqsave(&intf->counter_lock, flags);
596 intf->handled_local_responses++;
597 spin_unlock_irqrestore(&intf->counter_lock, flags);
598 } else {
599 /* No handler, so give up. */
600 spin_lock_irqsave(&intf->counter_lock, flags);
601 intf->unhandled_local_responses++;
602 spin_unlock_irqrestore(&intf->counter_lock, flags);
603 }
604 ipmi_free_recv_msg(msg);
605 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800606 ipmi_user_t user = msg->user;
607 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609}
610
611/* Find the next sequence number not being used and add the given
612 message with the given timeout to the sequence table. This must be
613 called with the interface's seq_lock held. */
614static int intf_next_seq(ipmi_smi_t intf,
615 struct ipmi_recv_msg *recv_msg,
616 unsigned long timeout,
617 int retries,
618 int broadcast,
619 unsigned char *seq,
620 long *seqid)
621{
622 int rv = 0;
623 unsigned int i;
624
Corey Minyarde8b33612005-09-06 15:18:45 -0700625 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700627 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800629 if (!intf->seq_table[i].inuse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 break;
631 }
632
Corey Minyard8a3628d2006-03-31 02:30:40 -0800633 if (!intf->seq_table[i].inuse) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 intf->seq_table[i].recv_msg = recv_msg;
635
636 /* Start with the maximum timeout, when the send response
637 comes in we will start the real timer. */
638 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
639 intf->seq_table[i].orig_timeout = timeout;
640 intf->seq_table[i].retries_left = retries;
641 intf->seq_table[i].broadcast = broadcast;
642 intf->seq_table[i].inuse = 1;
643 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
644 *seq = i;
645 *seqid = intf->seq_table[i].seqid;
646 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
647 } else {
648 rv = -EAGAIN;
649 }
650
651 return rv;
652}
653
654/* Return the receive message for the given sequence number and
655 release the sequence number so it can be reused. Some other data
656 is passed in to be sure the message matches up correctly (to help
657 guard against message coming in after their timeout and the
658 sequence number being reused). */
659static int intf_find_seq(ipmi_smi_t intf,
660 unsigned char seq,
661 short channel,
662 unsigned char cmd,
663 unsigned char netfn,
664 struct ipmi_addr *addr,
665 struct ipmi_recv_msg **recv_msg)
666{
667 int rv = -ENODEV;
668 unsigned long flags;
669
670 if (seq >= IPMI_IPMB_NUM_SEQ)
671 return -EINVAL;
672
673 spin_lock_irqsave(&(intf->seq_lock), flags);
674 if (intf->seq_table[seq].inuse) {
675 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
676
677 if ((msg->addr.channel == channel)
678 && (msg->msg.cmd == cmd)
679 && (msg->msg.netfn == netfn)
680 && (ipmi_addr_equal(addr, &(msg->addr))))
681 {
682 *recv_msg = msg;
683 intf->seq_table[seq].inuse = 0;
684 rv = 0;
685 }
686 }
687 spin_unlock_irqrestore(&(intf->seq_lock), flags);
688
689 return rv;
690}
691
692
693/* Start the timer for a specific sequence table entry. */
694static int intf_start_seq_timer(ipmi_smi_t intf,
695 long msgid)
696{
697 int rv = -ENODEV;
698 unsigned long flags;
699 unsigned char seq;
700 unsigned long seqid;
701
702
703 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
704
705 spin_lock_irqsave(&(intf->seq_lock), flags);
706 /* We do this verification because the user can be deleted
707 while a message is outstanding. */
708 if ((intf->seq_table[seq].inuse)
709 && (intf->seq_table[seq].seqid == seqid))
710 {
711 struct seq_table *ent = &(intf->seq_table[seq]);
712 ent->timeout = ent->orig_timeout;
713 rv = 0;
714 }
715 spin_unlock_irqrestore(&(intf->seq_lock), flags);
716
717 return rv;
718}
719
720/* Got an error for the send message for a specific sequence number. */
721static int intf_err_seq(ipmi_smi_t intf,
722 long msgid,
723 unsigned int err)
724{
725 int rv = -ENODEV;
726 unsigned long flags;
727 unsigned char seq;
728 unsigned long seqid;
729 struct ipmi_recv_msg *msg = NULL;
730
731
732 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
733
734 spin_lock_irqsave(&(intf->seq_lock), flags);
735 /* We do this verification because the user can be deleted
736 while a message is outstanding. */
737 if ((intf->seq_table[seq].inuse)
738 && (intf->seq_table[seq].seqid == seqid))
739 {
740 struct seq_table *ent = &(intf->seq_table[seq]);
741
742 ent->inuse = 0;
743 msg = ent->recv_msg;
744 rv = 0;
745 }
746 spin_unlock_irqrestore(&(intf->seq_lock), flags);
747
748 if (msg) {
749 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
750 msg->msg_data[0] = err;
751 msg->msg.netfn |= 1; /* Convert to a response. */
752 msg->msg.data_len = 1;
753 msg->msg.data = msg->msg_data;
754 deliver_response(msg);
755 }
756
757 return rv;
758}
759
760
761int ipmi_create_user(unsigned int if_num,
762 struct ipmi_user_hndl *handler,
763 void *handler_data,
764 ipmi_user_t *user)
765{
766 unsigned long flags;
767 ipmi_user_t new_user;
768 int rv = 0;
769 ipmi_smi_t intf;
770
771 /* There is no module usecount here, because it's not
772 required. Since this can only be used by and called from
773 other modules, they will implicitly use this module, and
774 thus this can't be removed unless the other modules are
775 removed. */
776
777 if (handler == NULL)
778 return -EINVAL;
779
780 /* Make sure the driver is actually initialized, this handles
781 problems with initialization order. */
782 if (!initialized) {
783 rv = ipmi_init_msghandler();
784 if (rv)
785 return rv;
786
787 /* The init code doesn't return an error if it was turned
788 off, but it won't initialize. Check that. */
789 if (!initialized)
790 return -ENODEV;
791 }
792
793 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800794 if (!new_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 return -ENOMEM;
796
Corey Minyardbca03242006-12-06 20:40:57 -0800797 rcu_read_lock();
798 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
799 if (intf->intf_num == if_num)
800 goto found;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 }
Corey Minyardbca03242006-12-06 20:40:57 -0800802 rcu_read_unlock();
803 rv = -EINVAL;
804 goto out_kfree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Corey Minyardbca03242006-12-06 20:40:57 -0800806 found:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800807 /* Note that each existing user holds a refcount to the interface. */
808 kref_get(&intf->refcount);
Corey Minyardbca03242006-12-06 20:40:57 -0800809 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
Corey Minyard393d2cc2005-11-07 00:59:54 -0800811 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 new_user->handler = handler;
813 new_user->handler_data = handler_data;
814 new_user->intf = intf;
815 new_user->gets_events = 0;
816
817 if (!try_module_get(intf->handlers->owner)) {
818 rv = -ENODEV;
Adrian Bunk5c98d292006-03-25 03:07:52 -0800819 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 }
821
822 if (intf->handlers->inc_usecount) {
823 rv = intf->handlers->inc_usecount(intf->send_info);
824 if (rv) {
825 module_put(intf->handlers->owner);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800826 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 }
828 }
829
Corey Minyard393d2cc2005-11-07 00:59:54 -0800830 new_user->valid = 1;
831 spin_lock_irqsave(&intf->seq_lock, flags);
832 list_add_rcu(&new_user->link, &intf->users);
833 spin_unlock_irqrestore(&intf->seq_lock, flags);
834 *user = new_user;
835 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Adrian Bunk5c98d292006-03-25 03:07:52 -0800837out_kref:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800838 kref_put(&intf->refcount, intf_free);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800839out_kfree:
840 kfree(new_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 return rv;
842}
843
Corey Minyard393d2cc2005-11-07 00:59:54 -0800844static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800846 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848}
849
850int ipmi_destroy_user(ipmi_user_t user)
851{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800852 ipmi_smi_t intf = user->intf;
853 int i;
854 unsigned long flags;
855 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800856 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Corey Minyard8a3628d2006-03-31 02:30:40 -0800858 user->valid = 0;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800859
860 /* Remove the user from the interface's sequence table. */
861 spin_lock_irqsave(&intf->seq_lock, flags);
862 list_del_rcu(&user->link);
863
864 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
865 if (intf->seq_table[i].inuse
866 && (intf->seq_table[i].recv_msg->user == user))
867 {
868 intf->seq_table[i].inuse = 0;
869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800871 spin_unlock_irqrestore(&intf->seq_lock, flags);
872
873 /*
874 * Remove the user from the command receiver's table. First
875 * we build a list of everything (not using the standard link,
876 * since other things may be using it till we do
877 * synchronize_rcu()) then free everything in that list.
878 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800879 mutex_lock(&intf->cmd_rcvrs_mutex);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800880 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800881 if (rcvr->user == user) {
882 list_del_rcu(&rcvr->link);
883 rcvr->next = rcvrs;
884 rcvrs = rcvr;
885 }
886 }
Corey Minyardd6dfd132006-03-31 02:30:41 -0800887 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800888 synchronize_rcu();
889 while (rcvrs) {
890 rcvr = rcvrs;
891 rcvrs = rcvr->next;
892 kfree(rcvr);
893 }
894
895 module_put(intf->handlers->owner);
896 if (intf->handlers->dec_usecount)
897 intf->handlers->dec_usecount(intf->send_info);
898
899 kref_put(&intf->refcount, intf_free);
900
901 kref_put(&user->refcount, free_user);
902
Corey Minyard8a3628d2006-03-31 02:30:40 -0800903 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904}
905
906void ipmi_get_version(ipmi_user_t user,
907 unsigned char *major,
908 unsigned char *minor)
909{
Corey Minyard50c812b2006-03-26 01:37:21 -0800910 *major = ipmi_version_major(&user->intf->bmc->id);
911 *minor = ipmi_version_minor(&user->intf->bmc->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912}
913
Corey Minyardc14979b2005-09-06 15:18:38 -0700914int ipmi_set_my_address(ipmi_user_t user,
915 unsigned int channel,
916 unsigned char address)
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].address = address;
921 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922}
923
Corey Minyardc14979b2005-09-06 15:18:38 -0700924int ipmi_get_my_address(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].address;
931 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932}
933
Corey Minyardc14979b2005-09-06 15:18:38 -0700934int ipmi_set_my_LUN(ipmi_user_t user,
935 unsigned int channel,
936 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
Corey Minyardc14979b2005-09-06 15:18:38 -0700938 if (channel >= IPMI_MAX_CHANNELS)
939 return -EINVAL;
940 user->intf->channels[channel].lun = LUN & 0x3;
941 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942}
943
Corey Minyardc14979b2005-09-06 15:18:38 -0700944int ipmi_get_my_LUN(ipmi_user_t user,
945 unsigned int channel,
946 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947{
Corey Minyardc14979b2005-09-06 15:18:38 -0700948 if (channel >= IPMI_MAX_CHANNELS)
949 return -EINVAL;
950 *address = user->intf->channels[channel].lun;
951 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952}
953
954int ipmi_set_gets_events(ipmi_user_t user, int val)
955{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800956 unsigned long flags;
957 ipmi_smi_t intf = user->intf;
958 struct ipmi_recv_msg *msg, *msg2;
959 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Corey Minyard393d2cc2005-11-07 00:59:54 -0800961 INIT_LIST_HEAD(&msgs);
962
963 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 user->gets_events = val;
965
966 if (val) {
967 /* Deliver any queued events. */
Akinobu Mita179e0912006-06-26 00:24:41 -0700968 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
969 list_move_tail(&msg->link, &msgs);
Corey Minyard4791c032006-04-10 22:54:31 -0700970 intf->waiting_events_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800972
973 /* Hold the events lock while doing this to preserve order. */
974 list_for_each_entry_safe(msg, msg2, &msgs, link) {
975 msg->user = user;
976 kref_get(&user->refcount);
977 deliver_response(msg);
978 }
979
980 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982 return 0;
983}
984
Corey Minyard393d2cc2005-11-07 00:59:54 -0800985static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
986 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -0700987 unsigned char cmd,
988 unsigned char chan)
Corey Minyard393d2cc2005-11-07 00:59:54 -0800989{
990 struct cmd_rcvr *rcvr;
991
992 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyardc69c3122006-09-30 23:27:56 -0700993 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
994 && (rcvr->chans & (1 << chan)))
Corey Minyard393d2cc2005-11-07 00:59:54 -0800995 return rcvr;
996 }
997 return NULL;
998}
999
Corey Minyardc69c3122006-09-30 23:27:56 -07001000static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
1001 unsigned char netfn,
1002 unsigned char cmd,
1003 unsigned int chans)
1004{
1005 struct cmd_rcvr *rcvr;
1006
1007 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
1008 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1009 && (rcvr->chans & chans))
1010 return 0;
1011 }
1012 return 1;
1013}
1014
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015int ipmi_register_for_cmd(ipmi_user_t user,
1016 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001017 unsigned char cmd,
1018 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001020 ipmi_smi_t intf = user->intf;
1021 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001022 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024
1025 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -08001026 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001028 rcvr->cmd = cmd;
1029 rcvr->netfn = netfn;
Corey Minyardc69c3122006-09-30 23:27:56 -07001030 rcvr->chans = chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001031 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Corey Minyardd6dfd132006-03-31 02:30:41 -08001033 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 /* Make sure the command/netfn is not already registered. */
Corey Minyardc69c3122006-09-30 23:27:56 -07001035 if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08001036 rv = -EBUSY;
1037 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 }
1039
Corey Minyard393d2cc2005-11-07 00:59:54 -08001040 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -07001041
Corey Minyard393d2cc2005-11-07 00:59:54 -08001042 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -08001043 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 if (rv)
1045 kfree(rcvr);
1046
1047 return rv;
1048}
1049
1050int ipmi_unregister_for_cmd(ipmi_user_t user,
1051 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001052 unsigned char cmd,
1053 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001055 ipmi_smi_t intf = user->intf;
1056 struct cmd_rcvr *rcvr;
Corey Minyardc69c3122006-09-30 23:27:56 -07001057 struct cmd_rcvr *rcvrs = NULL;
1058 int i, rv = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
Corey Minyardd6dfd132006-03-31 02:30:41 -08001060 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyardc69c3122006-09-30 23:27:56 -07001061 for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
1062 if (((1 << i) & chans) == 0)
1063 continue;
1064 rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
1065 if (rcvr == NULL)
1066 continue;
1067 if (rcvr->user == user) {
1068 rv = 0;
1069 rcvr->chans &= ~chans;
1070 if (rcvr->chans == 0) {
1071 list_del_rcu(&rcvr->link);
1072 rcvr->next = rcvrs;
1073 rcvrs = rcvr;
1074 }
1075 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 }
Corey Minyardc69c3122006-09-30 23:27:56 -07001077 mutex_unlock(&intf->cmd_rcvrs_mutex);
1078 synchronize_rcu();
1079 while (rcvrs) {
1080 rcvr = rcvrs;
1081 rcvrs = rcvr->next;
1082 kfree(rcvr);
1083 }
1084 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085}
1086
1087void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
1088{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001089 ipmi_smi_t intf = user->intf;
1090 intf->handlers->set_run_to_completion(intf->send_info, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091}
1092
1093static unsigned char
1094ipmb_checksum(unsigned char *data, int size)
1095{
1096 unsigned char csum = 0;
1097
1098 for (; size > 0; size--, data++)
1099 csum += *data;
1100
1101 return -csum;
1102}
1103
1104static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1105 struct kernel_ipmi_msg *msg,
1106 struct ipmi_ipmb_addr *ipmb_addr,
1107 long msgid,
1108 unsigned char ipmb_seq,
1109 int broadcast,
1110 unsigned char source_address,
1111 unsigned char source_lun)
1112{
1113 int i = broadcast;
1114
1115 /* Format the IPMB header data. */
1116 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1117 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1118 smi_msg->data[2] = ipmb_addr->channel;
1119 if (broadcast)
1120 smi_msg->data[3] = 0;
1121 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1122 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1123 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1124 smi_msg->data[i+6] = source_address;
1125 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1126 smi_msg->data[i+8] = msg->cmd;
1127
1128 /* Now tack on the data to the message. */
1129 if (msg->data_len > 0)
1130 memcpy(&(smi_msg->data[i+9]), msg->data,
1131 msg->data_len);
1132 smi_msg->data_size = msg->data_len + 9;
1133
1134 /* Now calculate the checksum and tack it on. */
1135 smi_msg->data[i+smi_msg->data_size]
1136 = ipmb_checksum(&(smi_msg->data[i+6]),
1137 smi_msg->data_size-6);
1138
1139 /* Add on the checksum size and the offset from the
1140 broadcast. */
1141 smi_msg->data_size += 1 + i;
1142
1143 smi_msg->msgid = msgid;
1144}
1145
1146static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1147 struct kernel_ipmi_msg *msg,
1148 struct ipmi_lan_addr *lan_addr,
1149 long msgid,
1150 unsigned char ipmb_seq,
1151 unsigned char source_lun)
1152{
1153 /* Format the IPMB header data. */
1154 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1155 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1156 smi_msg->data[2] = lan_addr->channel;
1157 smi_msg->data[3] = lan_addr->session_handle;
1158 smi_msg->data[4] = lan_addr->remote_SWID;
1159 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1160 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1161 smi_msg->data[7] = lan_addr->local_SWID;
1162 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1163 smi_msg->data[9] = msg->cmd;
1164
1165 /* Now tack on the data to the message. */
1166 if (msg->data_len > 0)
1167 memcpy(&(smi_msg->data[10]), msg->data,
1168 msg->data_len);
1169 smi_msg->data_size = msg->data_len + 10;
1170
1171 /* Now calculate the checksum and tack it on. */
1172 smi_msg->data[smi_msg->data_size]
1173 = ipmb_checksum(&(smi_msg->data[7]),
1174 smi_msg->data_size-7);
1175
1176 /* Add on the checksum size and the offset from the
1177 broadcast. */
1178 smi_msg->data_size += 1;
1179
1180 smi_msg->msgid = msgid;
1181}
1182
1183/* Separate from ipmi_request so that the user does not have to be
1184 supplied in certain circumstances (mainly at panic time). If
1185 messages are supplied, they will be freed, even if an error
1186 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001187static int i_ipmi_request(ipmi_user_t user,
1188 ipmi_smi_t intf,
1189 struct ipmi_addr *addr,
1190 long msgid,
1191 struct kernel_ipmi_msg *msg,
1192 void *user_msg_data,
1193 void *supplied_smi,
1194 struct ipmi_recv_msg *supplied_recv,
1195 int priority,
1196 unsigned char source_address,
1197 unsigned char source_lun,
1198 int retries,
1199 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200{
1201 int rv = 0;
1202 struct ipmi_smi_msg *smi_msg;
1203 struct ipmi_recv_msg *recv_msg;
1204 unsigned long flags;
1205
1206
1207 if (supplied_recv) {
1208 recv_msg = supplied_recv;
1209 } else {
1210 recv_msg = ipmi_alloc_recv_msg();
1211 if (recv_msg == NULL) {
1212 return -ENOMEM;
1213 }
1214 }
1215 recv_msg->user_msg_data = user_msg_data;
1216
1217 if (supplied_smi) {
1218 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1219 } else {
1220 smi_msg = ipmi_alloc_smi_msg();
1221 if (smi_msg == NULL) {
1222 ipmi_free_recv_msg(recv_msg);
1223 return -ENOMEM;
1224 }
1225 }
1226
1227 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001228 if (user)
1229 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 recv_msg->msgid = msgid;
1231 /* Store the message to send in the receive message so timeout
1232 responses can get the proper response data. */
1233 recv_msg->msg = *msg;
1234
1235 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1236 struct ipmi_system_interface_addr *smi_addr;
1237
1238 if (msg->netfn & 1) {
1239 /* Responses are not allowed to the SMI. */
1240 rv = -EINVAL;
1241 goto out_err;
1242 }
1243
1244 smi_addr = (struct ipmi_system_interface_addr *) addr;
1245 if (smi_addr->lun > 3) {
1246 spin_lock_irqsave(&intf->counter_lock, flags);
1247 intf->sent_invalid_commands++;
1248 spin_unlock_irqrestore(&intf->counter_lock, flags);
1249 rv = -EINVAL;
1250 goto out_err;
1251 }
1252
1253 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1254
1255 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1256 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1257 || (msg->cmd == IPMI_GET_MSG_CMD)
1258 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1259 {
1260 /* We don't let the user do these, since we manage
1261 the sequence numbers. */
1262 spin_lock_irqsave(&intf->counter_lock, flags);
1263 intf->sent_invalid_commands++;
1264 spin_unlock_irqrestore(&intf->counter_lock, flags);
1265 rv = -EINVAL;
1266 goto out_err;
1267 }
1268
1269 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1270 spin_lock_irqsave(&intf->counter_lock, flags);
1271 intf->sent_invalid_commands++;
1272 spin_unlock_irqrestore(&intf->counter_lock, flags);
1273 rv = -EMSGSIZE;
1274 goto out_err;
1275 }
1276
1277 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1278 smi_msg->data[1] = msg->cmd;
1279 smi_msg->msgid = msgid;
1280 smi_msg->user_data = recv_msg;
1281 if (msg->data_len > 0)
1282 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1283 smi_msg->data_size = msg->data_len + 2;
1284 spin_lock_irqsave(&intf->counter_lock, flags);
1285 intf->sent_local_commands++;
1286 spin_unlock_irqrestore(&intf->counter_lock, flags);
1287 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1288 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1289 {
1290 struct ipmi_ipmb_addr *ipmb_addr;
1291 unsigned char ipmb_seq;
1292 long seqid;
1293 int broadcast = 0;
1294
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001295 if (addr->channel >= IPMI_MAX_CHANNELS) {
1296 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 intf->sent_invalid_commands++;
1298 spin_unlock_irqrestore(&intf->counter_lock, flags);
1299 rv = -EINVAL;
1300 goto out_err;
1301 }
1302
1303 if (intf->channels[addr->channel].medium
1304 != IPMI_CHANNEL_MEDIUM_IPMB)
1305 {
1306 spin_lock_irqsave(&intf->counter_lock, flags);
1307 intf->sent_invalid_commands++;
1308 spin_unlock_irqrestore(&intf->counter_lock, flags);
1309 rv = -EINVAL;
1310 goto out_err;
1311 }
1312
1313 if (retries < 0) {
1314 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1315 retries = 0; /* Don't retry broadcasts. */
1316 else
1317 retries = 4;
1318 }
1319 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1320 /* Broadcasts add a zero at the beginning of the
1321 message, but otherwise is the same as an IPMB
1322 address. */
1323 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1324 broadcast = 1;
1325 }
1326
1327
1328 /* Default to 1 second retries. */
1329 if (retry_time_ms == 0)
1330 retry_time_ms = 1000;
1331
1332 /* 9 for the header and 1 for the checksum, plus
1333 possibly one for the broadcast. */
1334 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1335 spin_lock_irqsave(&intf->counter_lock, flags);
1336 intf->sent_invalid_commands++;
1337 spin_unlock_irqrestore(&intf->counter_lock, flags);
1338 rv = -EMSGSIZE;
1339 goto out_err;
1340 }
1341
1342 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1343 if (ipmb_addr->lun > 3) {
1344 spin_lock_irqsave(&intf->counter_lock, flags);
1345 intf->sent_invalid_commands++;
1346 spin_unlock_irqrestore(&intf->counter_lock, flags);
1347 rv = -EINVAL;
1348 goto out_err;
1349 }
1350
1351 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1352
1353 if (recv_msg->msg.netfn & 0x1) {
1354 /* It's a response, so use the user's sequence
1355 from msgid. */
1356 spin_lock_irqsave(&intf->counter_lock, flags);
1357 intf->sent_ipmb_responses++;
1358 spin_unlock_irqrestore(&intf->counter_lock, flags);
1359 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1360 msgid, broadcast,
1361 source_address, source_lun);
1362
1363 /* Save the receive message so we can use it
1364 to deliver the response. */
1365 smi_msg->user_data = recv_msg;
1366 } else {
1367 /* It's a command, so get a sequence for it. */
1368
1369 spin_lock_irqsave(&(intf->seq_lock), flags);
1370
1371 spin_lock(&intf->counter_lock);
1372 intf->sent_ipmb_commands++;
1373 spin_unlock(&intf->counter_lock);
1374
1375 /* Create a sequence number with a 1 second
1376 timeout and 4 retries. */
1377 rv = intf_next_seq(intf,
1378 recv_msg,
1379 retry_time_ms,
1380 retries,
1381 broadcast,
1382 &ipmb_seq,
1383 &seqid);
1384 if (rv) {
1385 /* We have used up all the sequence numbers,
1386 probably, so abort. */
1387 spin_unlock_irqrestore(&(intf->seq_lock),
1388 flags);
1389 goto out_err;
1390 }
1391
1392 /* Store the sequence number in the message,
1393 so that when the send message response
1394 comes back we can start the timer. */
1395 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1396 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1397 ipmb_seq, broadcast,
1398 source_address, source_lun);
1399
1400 /* Copy the message into the recv message data, so we
1401 can retransmit it later if necessary. */
1402 memcpy(recv_msg->msg_data, smi_msg->data,
1403 smi_msg->data_size);
1404 recv_msg->msg.data = recv_msg->msg_data;
1405 recv_msg->msg.data_len = smi_msg->data_size;
1406
1407 /* We don't unlock until here, because we need
1408 to copy the completed message into the
1409 recv_msg before we release the lock.
1410 Otherwise, race conditions may bite us. I
1411 know that's pretty paranoid, but I prefer
1412 to be correct. */
1413 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1414 }
1415 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1416 struct ipmi_lan_addr *lan_addr;
1417 unsigned char ipmb_seq;
1418 long seqid;
1419
Jayachandran C12fc1d72006-02-03 03:04:51 -08001420 if (addr->channel >= IPMI_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 spin_lock_irqsave(&intf->counter_lock, flags);
1422 intf->sent_invalid_commands++;
1423 spin_unlock_irqrestore(&intf->counter_lock, flags);
1424 rv = -EINVAL;
1425 goto out_err;
1426 }
1427
1428 if ((intf->channels[addr->channel].medium
1429 != IPMI_CHANNEL_MEDIUM_8023LAN)
1430 && (intf->channels[addr->channel].medium
1431 != IPMI_CHANNEL_MEDIUM_ASYNC))
1432 {
1433 spin_lock_irqsave(&intf->counter_lock, flags);
1434 intf->sent_invalid_commands++;
1435 spin_unlock_irqrestore(&intf->counter_lock, flags);
1436 rv = -EINVAL;
1437 goto out_err;
1438 }
1439
1440 retries = 4;
1441
1442 /* Default to 1 second retries. */
1443 if (retry_time_ms == 0)
1444 retry_time_ms = 1000;
1445
1446 /* 11 for the header and 1 for the checksum. */
1447 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1448 spin_lock_irqsave(&intf->counter_lock, flags);
1449 intf->sent_invalid_commands++;
1450 spin_unlock_irqrestore(&intf->counter_lock, flags);
1451 rv = -EMSGSIZE;
1452 goto out_err;
1453 }
1454
1455 lan_addr = (struct ipmi_lan_addr *) addr;
1456 if (lan_addr->lun > 3) {
1457 spin_lock_irqsave(&intf->counter_lock, flags);
1458 intf->sent_invalid_commands++;
1459 spin_unlock_irqrestore(&intf->counter_lock, flags);
1460 rv = -EINVAL;
1461 goto out_err;
1462 }
1463
1464 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1465
1466 if (recv_msg->msg.netfn & 0x1) {
1467 /* It's a response, so use the user's sequence
1468 from msgid. */
1469 spin_lock_irqsave(&intf->counter_lock, flags);
1470 intf->sent_lan_responses++;
1471 spin_unlock_irqrestore(&intf->counter_lock, flags);
1472 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1473 msgid, source_lun);
1474
1475 /* Save the receive message so we can use it
1476 to deliver the response. */
1477 smi_msg->user_data = recv_msg;
1478 } else {
1479 /* It's a command, so get a sequence for it. */
1480
1481 spin_lock_irqsave(&(intf->seq_lock), flags);
1482
1483 spin_lock(&intf->counter_lock);
1484 intf->sent_lan_commands++;
1485 spin_unlock(&intf->counter_lock);
1486
1487 /* Create a sequence number with a 1 second
1488 timeout and 4 retries. */
1489 rv = intf_next_seq(intf,
1490 recv_msg,
1491 retry_time_ms,
1492 retries,
1493 0,
1494 &ipmb_seq,
1495 &seqid);
1496 if (rv) {
1497 /* We have used up all the sequence numbers,
1498 probably, so abort. */
1499 spin_unlock_irqrestore(&(intf->seq_lock),
1500 flags);
1501 goto out_err;
1502 }
1503
1504 /* Store the sequence number in the message,
1505 so that when the send message response
1506 comes back we can start the timer. */
1507 format_lan_msg(smi_msg, msg, lan_addr,
1508 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1509 ipmb_seq, source_lun);
1510
1511 /* Copy the message into the recv message data, so we
1512 can retransmit it later if necessary. */
1513 memcpy(recv_msg->msg_data, smi_msg->data,
1514 smi_msg->data_size);
1515 recv_msg->msg.data = recv_msg->msg_data;
1516 recv_msg->msg.data_len = smi_msg->data_size;
1517
1518 /* We don't unlock until here, because we need
1519 to copy the completed message into the
1520 recv_msg before we release the lock.
1521 Otherwise, race conditions may bite us. I
1522 know that's pretty paranoid, but I prefer
1523 to be correct. */
1524 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1525 }
1526 } else {
1527 /* Unknown address type. */
1528 spin_lock_irqsave(&intf->counter_lock, flags);
1529 intf->sent_invalid_commands++;
1530 spin_unlock_irqrestore(&intf->counter_lock, flags);
1531 rv = -EINVAL;
1532 goto out_err;
1533 }
1534
1535#ifdef DEBUG_MSGING
1536 {
1537 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001538 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 printk(" %2.2x", smi_msg->data[m]);
1540 printk("\n");
1541 }
1542#endif
1543 intf->handlers->sender(intf->send_info, smi_msg, priority);
1544
1545 return 0;
1546
1547 out_err:
1548 ipmi_free_smi_msg(smi_msg);
1549 ipmi_free_recv_msg(recv_msg);
1550 return rv;
1551}
1552
Corey Minyardc14979b2005-09-06 15:18:38 -07001553static int check_addr(ipmi_smi_t intf,
1554 struct ipmi_addr *addr,
1555 unsigned char *saddr,
1556 unsigned char *lun)
1557{
1558 if (addr->channel >= IPMI_MAX_CHANNELS)
1559 return -EINVAL;
1560 *lun = intf->channels[addr->channel].lun;
1561 *saddr = intf->channels[addr->channel].address;
1562 return 0;
1563}
1564
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565int ipmi_request_settime(ipmi_user_t user,
1566 struct ipmi_addr *addr,
1567 long msgid,
1568 struct kernel_ipmi_msg *msg,
1569 void *user_msg_data,
1570 int priority,
1571 int retries,
1572 unsigned int retry_time_ms)
1573{
Corey Minyardc14979b2005-09-06 15:18:38 -07001574 unsigned char saddr, lun;
1575 int rv;
1576
Corey Minyard8a3628d2006-03-31 02:30:40 -08001577 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001578 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001579 rv = check_addr(user->intf, addr, &saddr, &lun);
1580 if (rv)
1581 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 return i_ipmi_request(user,
1583 user->intf,
1584 addr,
1585 msgid,
1586 msg,
1587 user_msg_data,
1588 NULL, NULL,
1589 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001590 saddr,
1591 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 retries,
1593 retry_time_ms);
1594}
1595
1596int ipmi_request_supply_msgs(ipmi_user_t user,
1597 struct ipmi_addr *addr,
1598 long msgid,
1599 struct kernel_ipmi_msg *msg,
1600 void *user_msg_data,
1601 void *supplied_smi,
1602 struct ipmi_recv_msg *supplied_recv,
1603 int priority)
1604{
Corey Minyardc14979b2005-09-06 15:18:38 -07001605 unsigned char saddr, lun;
1606 int rv;
1607
Corey Minyard8a3628d2006-03-31 02:30:40 -08001608 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001609 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001610 rv = check_addr(user->intf, addr, &saddr, &lun);
1611 if (rv)
1612 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 return i_ipmi_request(user,
1614 user->intf,
1615 addr,
1616 msgid,
1617 msg,
1618 user_msg_data,
1619 supplied_smi,
1620 supplied_recv,
1621 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001622 saddr,
1623 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 -1, 0);
1625}
1626
1627static int ipmb_file_read_proc(char *page, char **start, off_t off,
1628 int count, int *eof, void *data)
1629{
1630 char *out = (char *) page;
1631 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001632 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001633 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
Corey Minyarde8b33612005-09-06 15:18:45 -07001635 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001636 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1637 out[rv-1] = '\n'; /* Replace the final space with a newline */
1638 out[rv] = '\0';
1639 rv++;
1640 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641}
1642
1643static int version_file_read_proc(char *page, char **start, off_t off,
1644 int count, int *eof, void *data)
1645{
1646 char *out = (char *) page;
1647 ipmi_smi_t intf = data;
1648
1649 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001650 ipmi_version_major(&intf->bmc->id),
1651 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652}
1653
1654static int stat_file_read_proc(char *page, char **start, off_t off,
1655 int count, int *eof, void *data)
1656{
1657 char *out = (char *) page;
1658 ipmi_smi_t intf = data;
1659
1660 out += sprintf(out, "sent_invalid_commands: %d\n",
1661 intf->sent_invalid_commands);
1662 out += sprintf(out, "sent_local_commands: %d\n",
1663 intf->sent_local_commands);
1664 out += sprintf(out, "handled_local_responses: %d\n",
1665 intf->handled_local_responses);
1666 out += sprintf(out, "unhandled_local_responses: %d\n",
1667 intf->unhandled_local_responses);
1668 out += sprintf(out, "sent_ipmb_commands: %d\n",
1669 intf->sent_ipmb_commands);
1670 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1671 intf->sent_ipmb_command_errs);
1672 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1673 intf->retransmitted_ipmb_commands);
1674 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1675 intf->timed_out_ipmb_commands);
1676 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1677 intf->timed_out_ipmb_broadcasts);
1678 out += sprintf(out, "sent_ipmb_responses: %d\n",
1679 intf->sent_ipmb_responses);
1680 out += sprintf(out, "handled_ipmb_responses: %d\n",
1681 intf->handled_ipmb_responses);
1682 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1683 intf->invalid_ipmb_responses);
1684 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1685 intf->unhandled_ipmb_responses);
1686 out += sprintf(out, "sent_lan_commands: %d\n",
1687 intf->sent_lan_commands);
1688 out += sprintf(out, "sent_lan_command_errs: %d\n",
1689 intf->sent_lan_command_errs);
1690 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1691 intf->retransmitted_lan_commands);
1692 out += sprintf(out, "timed_out_lan_commands: %d\n",
1693 intf->timed_out_lan_commands);
1694 out += sprintf(out, "sent_lan_responses: %d\n",
1695 intf->sent_lan_responses);
1696 out += sprintf(out, "handled_lan_responses: %d\n",
1697 intf->handled_lan_responses);
1698 out += sprintf(out, "invalid_lan_responses: %d\n",
1699 intf->invalid_lan_responses);
1700 out += sprintf(out, "unhandled_lan_responses: %d\n",
1701 intf->unhandled_lan_responses);
1702 out += sprintf(out, "handled_commands: %d\n",
1703 intf->handled_commands);
1704 out += sprintf(out, "invalid_commands: %d\n",
1705 intf->invalid_commands);
1706 out += sprintf(out, "unhandled_commands: %d\n",
1707 intf->unhandled_commands);
1708 out += sprintf(out, "invalid_events: %d\n",
1709 intf->invalid_events);
1710 out += sprintf(out, "events: %d\n",
1711 intf->events);
1712
1713 return (out - ((char *) page));
1714}
1715
1716int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1717 read_proc_t *read_proc, write_proc_t *write_proc,
1718 void *data, struct module *owner)
1719{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001721#ifdef CONFIG_PROC_FS
1722 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 struct ipmi_proc_entry *entry;
1724
1725 /* Create a list element. */
1726 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1727 if (!entry)
1728 return -ENOMEM;
1729 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1730 if (!entry->name) {
1731 kfree(entry);
1732 return -ENOMEM;
1733 }
1734 strcpy(entry->name, name);
1735
1736 file = create_proc_entry(name, 0, smi->proc_dir);
1737 if (!file) {
1738 kfree(entry->name);
1739 kfree(entry);
1740 rv = -ENOMEM;
1741 } else {
1742 file->nlink = 1;
1743 file->data = data;
1744 file->read_proc = read_proc;
1745 file->write_proc = write_proc;
1746 file->owner = owner;
1747
Corey Minyard3b625942005-06-23 22:01:42 -07001748 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 /* Stick it on the list. */
1750 entry->next = smi->proc_entries;
1751 smi->proc_entries = entry;
Corey Minyard3b625942005-06-23 22:01:42 -07001752 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 }
Corey Minyard3b625942005-06-23 22:01:42 -07001754#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 return rv;
1757}
1758
1759static int add_proc_entries(ipmi_smi_t smi, int num)
1760{
1761 int rv = 0;
1762
Corey Minyard3b625942005-06-23 22:01:42 -07001763#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 sprintf(smi->proc_dir_name, "%d", num);
1765 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1766 if (!smi->proc_dir)
1767 rv = -ENOMEM;
1768 else {
1769 smi->proc_dir->owner = THIS_MODULE;
1770 }
1771
1772 if (rv == 0)
1773 rv = ipmi_smi_add_proc_entry(smi, "stats",
1774 stat_file_read_proc, NULL,
1775 smi, THIS_MODULE);
1776
1777 if (rv == 0)
1778 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1779 ipmb_file_read_proc, NULL,
1780 smi, THIS_MODULE);
1781
1782 if (rv == 0)
1783 rv = ipmi_smi_add_proc_entry(smi, "version",
1784 version_file_read_proc, NULL,
1785 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001786#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
1788 return rv;
1789}
1790
1791static void remove_proc_entries(ipmi_smi_t smi)
1792{
Corey Minyard3b625942005-06-23 22:01:42 -07001793#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 struct ipmi_proc_entry *entry;
1795
Corey Minyard3b625942005-06-23 22:01:42 -07001796 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 while (smi->proc_entries) {
1798 entry = smi->proc_entries;
1799 smi->proc_entries = entry->next;
1800
1801 remove_proc_entry(entry->name, smi->proc_dir);
1802 kfree(entry->name);
1803 kfree(entry);
1804 }
Corey Minyard3b625942005-06-23 22:01:42 -07001805 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001807#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808}
1809
Corey Minyard50c812b2006-03-26 01:37:21 -08001810static int __find_bmc_guid(struct device *dev, void *data)
1811{
1812 unsigned char *id = data;
1813 struct bmc_device *bmc = dev_get_drvdata(dev);
1814 return memcmp(bmc->guid, id, 16) == 0;
1815}
1816
1817static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1818 unsigned char *guid)
1819{
1820 struct device *dev;
1821
1822 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1823 if (dev)
1824 return dev_get_drvdata(dev);
1825 else
1826 return NULL;
1827}
1828
1829struct prod_dev_id {
1830 unsigned int product_id;
1831 unsigned char device_id;
1832};
1833
1834static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1835{
1836 struct prod_dev_id *id = data;
1837 struct bmc_device *bmc = dev_get_drvdata(dev);
1838
1839 return (bmc->id.product_id == id->product_id
Corey Minyard50c812b2006-03-26 01:37:21 -08001840 && bmc->id.device_id == id->device_id);
1841}
1842
1843static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1844 struct device_driver *drv,
Corey Minyardf0b55da2006-12-06 20:40:54 -08001845 unsigned int product_id, unsigned char device_id)
Corey Minyard50c812b2006-03-26 01:37:21 -08001846{
1847 struct prod_dev_id id = {
1848 .product_id = product_id,
1849 .device_id = device_id,
1850 };
1851 struct device *dev;
1852
1853 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
1854 if (dev)
1855 return dev_get_drvdata(dev);
1856 else
1857 return NULL;
1858}
1859
1860static ssize_t device_id_show(struct device *dev,
1861 struct device_attribute *attr,
1862 char *buf)
1863{
1864 struct bmc_device *bmc = dev_get_drvdata(dev);
1865
1866 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
1867}
1868
1869static ssize_t provides_dev_sdrs_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, 10, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08001876 (bmc->id.device_revision & 0x80) >> 7);
Corey Minyard50c812b2006-03-26 01:37:21 -08001877}
1878
1879static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
1880 char *buf)
1881{
1882 struct bmc_device *bmc = dev_get_drvdata(dev);
1883
1884 return snprintf(buf, 20, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08001885 bmc->id.device_revision & 0x0F);
Corey Minyard50c812b2006-03-26 01:37:21 -08001886}
1887
1888static ssize_t firmware_rev_show(struct device *dev,
1889 struct device_attribute *attr,
1890 char *buf)
1891{
1892 struct bmc_device *bmc = dev_get_drvdata(dev);
1893
1894 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
1895 bmc->id.firmware_revision_2);
1896}
1897
1898static ssize_t ipmi_version_show(struct device *dev,
1899 struct device_attribute *attr,
1900 char *buf)
1901{
1902 struct bmc_device *bmc = dev_get_drvdata(dev);
1903
1904 return snprintf(buf, 20, "%u.%u\n",
1905 ipmi_version_major(&bmc->id),
1906 ipmi_version_minor(&bmc->id));
1907}
1908
1909static ssize_t add_dev_support_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%02x\n",
1916 bmc->id.additional_device_support);
1917}
1918
1919static ssize_t manufacturer_id_show(struct device *dev,
1920 struct device_attribute *attr,
1921 char *buf)
1922{
1923 struct bmc_device *bmc = dev_get_drvdata(dev);
1924
1925 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
1926}
1927
1928static ssize_t product_id_show(struct device *dev,
1929 struct device_attribute *attr,
1930 char *buf)
1931{
1932 struct bmc_device *bmc = dev_get_drvdata(dev);
1933
1934 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
1935}
1936
1937static ssize_t aux_firmware_rev_show(struct device *dev,
1938 struct device_attribute *attr,
1939 char *buf)
1940{
1941 struct bmc_device *bmc = dev_get_drvdata(dev);
1942
1943 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
1944 bmc->id.aux_firmware_revision[3],
1945 bmc->id.aux_firmware_revision[2],
1946 bmc->id.aux_firmware_revision[1],
1947 bmc->id.aux_firmware_revision[0]);
1948}
1949
1950static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
1951 char *buf)
1952{
1953 struct bmc_device *bmc = dev_get_drvdata(dev);
1954
1955 return snprintf(buf, 100, "%Lx%Lx\n",
1956 (long long) bmc->guid[0],
1957 (long long) bmc->guid[8]);
1958}
1959
Jeff Garzik5e593932006-10-11 01:22:21 -07001960static void remove_files(struct bmc_device *bmc)
Corey Minyard50c812b2006-03-26 01:37:21 -08001961{
Corey Minyardf0b55da2006-12-06 20:40:54 -08001962 if (!bmc->dev)
1963 return;
1964
Corey Minyard50c812b2006-03-26 01:37:21 -08001965 device_remove_file(&bmc->dev->dev,
1966 &bmc->device_id_attr);
1967 device_remove_file(&bmc->dev->dev,
1968 &bmc->provides_dev_sdrs_attr);
1969 device_remove_file(&bmc->dev->dev,
1970 &bmc->revision_attr);
1971 device_remove_file(&bmc->dev->dev,
1972 &bmc->firmware_rev_attr);
1973 device_remove_file(&bmc->dev->dev,
1974 &bmc->version_attr);
1975 device_remove_file(&bmc->dev->dev,
1976 &bmc->add_dev_support_attr);
1977 device_remove_file(&bmc->dev->dev,
1978 &bmc->manufacturer_id_attr);
1979 device_remove_file(&bmc->dev->dev,
1980 &bmc->product_id_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07001981
Corey Minyard50c812b2006-03-26 01:37:21 -08001982 if (bmc->id.aux_firmware_revision_set)
1983 device_remove_file(&bmc->dev->dev,
1984 &bmc->aux_firmware_rev_attr);
1985 if (bmc->guid_set)
1986 device_remove_file(&bmc->dev->dev,
1987 &bmc->guid_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07001988}
1989
1990static void
1991cleanup_bmc_device(struct kref *ref)
1992{
1993 struct bmc_device *bmc;
1994
1995 bmc = container_of(ref, struct bmc_device, refcount);
1996
1997 remove_files(bmc);
Corey Minyardf0b55da2006-12-06 20:40:54 -08001998 if (bmc->dev)
1999 platform_device_unregister(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002000 kfree(bmc);
2001}
2002
2003static void ipmi_bmc_unregister(ipmi_smi_t intf)
2004{
2005 struct bmc_device *bmc = intf->bmc;
2006
2007 sysfs_remove_link(&intf->si_dev->kobj, "bmc");
2008 if (intf->my_dev_name) {
2009 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
2010 kfree(intf->my_dev_name);
2011 intf->my_dev_name = NULL;
2012 }
2013
2014 mutex_lock(&ipmidriver_mutex);
2015 kref_put(&bmc->refcount, cleanup_bmc_device);
Corey Minyardf0b55da2006-12-06 20:40:54 -08002016 intf->bmc = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002017 mutex_unlock(&ipmidriver_mutex);
2018}
2019
Jeff Garzik5e593932006-10-11 01:22:21 -07002020static int create_files(struct bmc_device *bmc)
2021{
2022 int err;
2023
Corey Minyardf0b55da2006-12-06 20:40:54 -08002024 bmc->device_id_attr.attr.name = "device_id";
2025 bmc->device_id_attr.attr.owner = THIS_MODULE;
2026 bmc->device_id_attr.attr.mode = S_IRUGO;
2027 bmc->device_id_attr.show = device_id_show;
2028
2029 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
2030 bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
2031 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2032 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2033
2034 bmc->revision_attr.attr.name = "revision";
2035 bmc->revision_attr.attr.owner = THIS_MODULE;
2036 bmc->revision_attr.attr.mode = S_IRUGO;
2037 bmc->revision_attr.show = revision_show;
2038
2039 bmc->firmware_rev_attr.attr.name = "firmware_revision";
2040 bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
2041 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2042 bmc->firmware_rev_attr.show = firmware_rev_show;
2043
2044 bmc->version_attr.attr.name = "ipmi_version";
2045 bmc->version_attr.attr.owner = THIS_MODULE;
2046 bmc->version_attr.attr.mode = S_IRUGO;
2047 bmc->version_attr.show = ipmi_version_show;
2048
2049 bmc->add_dev_support_attr.attr.name = "additional_device_support";
2050 bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
2051 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2052 bmc->add_dev_support_attr.show = add_dev_support_show;
2053
2054 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
2055 bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
2056 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2057 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2058
2059 bmc->product_id_attr.attr.name = "product_id";
2060 bmc->product_id_attr.attr.owner = THIS_MODULE;
2061 bmc->product_id_attr.attr.mode = S_IRUGO;
2062 bmc->product_id_attr.show = product_id_show;
2063
2064 bmc->guid_attr.attr.name = "guid";
2065 bmc->guid_attr.attr.owner = THIS_MODULE;
2066 bmc->guid_attr.attr.mode = S_IRUGO;
2067 bmc->guid_attr.show = guid_show;
2068
2069 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
2070 bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
2071 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2072 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2073
Jeff Garzik5e593932006-10-11 01:22:21 -07002074 err = device_create_file(&bmc->dev->dev,
2075 &bmc->device_id_attr);
2076 if (err) goto out;
2077 err = device_create_file(&bmc->dev->dev,
2078 &bmc->provides_dev_sdrs_attr);
2079 if (err) goto out_devid;
2080 err = device_create_file(&bmc->dev->dev,
2081 &bmc->revision_attr);
2082 if (err) goto out_sdrs;
2083 err = device_create_file(&bmc->dev->dev,
2084 &bmc->firmware_rev_attr);
2085 if (err) goto out_rev;
2086 err = device_create_file(&bmc->dev->dev,
2087 &bmc->version_attr);
2088 if (err) goto out_firm;
2089 err = device_create_file(&bmc->dev->dev,
2090 &bmc->add_dev_support_attr);
2091 if (err) goto out_version;
2092 err = device_create_file(&bmc->dev->dev,
2093 &bmc->manufacturer_id_attr);
2094 if (err) goto out_add_dev;
2095 err = device_create_file(&bmc->dev->dev,
2096 &bmc->product_id_attr);
2097 if (err) goto out_manu;
2098 if (bmc->id.aux_firmware_revision_set) {
2099 err = device_create_file(&bmc->dev->dev,
2100 &bmc->aux_firmware_rev_attr);
2101 if (err) goto out_prod_id;
2102 }
2103 if (bmc->guid_set) {
2104 err = device_create_file(&bmc->dev->dev,
2105 &bmc->guid_attr);
2106 if (err) goto out_aux_firm;
2107 }
2108
2109 return 0;
2110
2111out_aux_firm:
2112 if (bmc->id.aux_firmware_revision_set)
2113 device_remove_file(&bmc->dev->dev,
2114 &bmc->aux_firmware_rev_attr);
2115out_prod_id:
2116 device_remove_file(&bmc->dev->dev,
2117 &bmc->product_id_attr);
2118out_manu:
2119 device_remove_file(&bmc->dev->dev,
2120 &bmc->manufacturer_id_attr);
2121out_add_dev:
2122 device_remove_file(&bmc->dev->dev,
2123 &bmc->add_dev_support_attr);
2124out_version:
2125 device_remove_file(&bmc->dev->dev,
2126 &bmc->version_attr);
2127out_firm:
2128 device_remove_file(&bmc->dev->dev,
2129 &bmc->firmware_rev_attr);
2130out_rev:
2131 device_remove_file(&bmc->dev->dev,
2132 &bmc->revision_attr);
2133out_sdrs:
2134 device_remove_file(&bmc->dev->dev,
2135 &bmc->provides_dev_sdrs_attr);
2136out_devid:
2137 device_remove_file(&bmc->dev->dev,
2138 &bmc->device_id_attr);
2139out:
2140 return err;
2141}
2142
Corey Minyard50c812b2006-03-26 01:37:21 -08002143static int ipmi_bmc_register(ipmi_smi_t intf)
2144{
2145 int rv;
2146 struct bmc_device *bmc = intf->bmc;
2147 struct bmc_device *old_bmc;
2148 int size;
2149 char dummy[1];
2150
2151 mutex_lock(&ipmidriver_mutex);
2152
2153 /*
2154 * Try to find if there is an bmc_device struct
2155 * representing the interfaced BMC already
2156 */
2157 if (bmc->guid_set)
2158 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
2159 else
2160 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
2161 bmc->id.product_id,
2162 bmc->id.device_id);
2163
2164 /*
2165 * If there is already an bmc_device, free the new one,
2166 * otherwise register the new BMC device
2167 */
2168 if (old_bmc) {
2169 kfree(bmc);
2170 intf->bmc = old_bmc;
2171 bmc = old_bmc;
2172
2173 kref_get(&bmc->refcount);
2174 mutex_unlock(&ipmidriver_mutex);
2175
2176 printk(KERN_INFO
2177 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
2178 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2179 bmc->id.manufacturer_id,
2180 bmc->id.product_id,
2181 bmc->id.device_id);
2182 } else {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002183 char name[14];
2184 unsigned char orig_dev_id = bmc->id.device_id;
2185 int warn_printed = 0;
2186
2187 snprintf(name, sizeof(name),
2188 "ipmi_bmc.%4.4x", bmc->id.product_id);
2189
2190 while (ipmi_find_bmc_prod_dev_id(&ipmidriver,
2191 bmc->id.product_id,
2192 bmc->id.device_id))
2193 {
2194 if (!warn_printed) {
2195 printk(KERN_WARNING PFX
2196 "This machine has two different BMCs"
2197 " with the same product id and device"
2198 " id. This is an error in the"
2199 " firmware, but incrementing the"
2200 " device id to work around the problem."
2201 " Prod ID = 0x%x, Dev ID = 0x%x\n",
2202 bmc->id.product_id, bmc->id.device_id);
2203 warn_printed = 1;
2204 }
2205 bmc->id.device_id++; /* Wraps at 255 */
2206 if (bmc->id.device_id == orig_dev_id) {
2207 printk(KERN_ERR PFX
2208 "Out of device ids!\n");
2209 break;
2210 }
2211 }
2212
2213 bmc->dev = platform_device_alloc(name, bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08002214 if (!bmc->dev) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002215 mutex_unlock(&ipmidriver_mutex);
Corey Minyard50c812b2006-03-26 01:37:21 -08002216 printk(KERN_ERR
2217 "ipmi_msghandler:"
2218 " Unable to allocate platform device\n");
2219 return -ENOMEM;
2220 }
2221 bmc->dev->dev.driver = &ipmidriver;
2222 dev_set_drvdata(&bmc->dev->dev, bmc);
2223 kref_init(&bmc->refcount);
2224
Zhang, Yanminb48f5452006-11-16 01:19:08 -08002225 rv = platform_device_add(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002226 mutex_unlock(&ipmidriver_mutex);
2227 if (rv) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002228 platform_device_put(bmc->dev);
2229 bmc->dev = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002230 printk(KERN_ERR
2231 "ipmi_msghandler:"
2232 " Unable to register bmc device: %d\n",
2233 rv);
2234 /* Don't go to out_err, you can only do that if
2235 the device is registered already. */
2236 return rv;
2237 }
2238
Jeff Garzik5e593932006-10-11 01:22:21 -07002239 rv = create_files(bmc);
2240 if (rv) {
2241 mutex_lock(&ipmidriver_mutex);
2242 platform_device_unregister(bmc->dev);
2243 mutex_unlock(&ipmidriver_mutex);
2244
2245 return rv;
2246 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002247
2248 printk(KERN_INFO
2249 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2250 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2251 bmc->id.manufacturer_id,
2252 bmc->id.product_id,
2253 bmc->id.device_id);
2254 }
2255
2256 /*
2257 * create symlink from system interface device to bmc device
2258 * and back.
2259 */
2260 rv = sysfs_create_link(&intf->si_dev->kobj,
2261 &bmc->dev->dev.kobj, "bmc");
2262 if (rv) {
2263 printk(KERN_ERR
2264 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2265 rv);
2266 goto out_err;
2267 }
2268
2269 size = snprintf(dummy, 0, "ipmi%d", intf->intf_num);
2270 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2271 if (!intf->my_dev_name) {
2272 rv = -ENOMEM;
2273 printk(KERN_ERR
2274 "ipmi_msghandler: allocate link from BMC: %d\n",
2275 rv);
2276 goto out_err;
2277 }
2278 snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num);
2279
2280 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2281 intf->my_dev_name);
2282 if (rv) {
2283 kfree(intf->my_dev_name);
2284 intf->my_dev_name = NULL;
2285 printk(KERN_ERR
2286 "ipmi_msghandler:"
2287 " Unable to create symlink to bmc: %d\n",
2288 rv);
2289 goto out_err;
2290 }
2291
2292 return 0;
2293
2294out_err:
2295 ipmi_bmc_unregister(intf);
2296 return rv;
2297}
2298
2299static int
2300send_guid_cmd(ipmi_smi_t intf, int chan)
2301{
2302 struct kernel_ipmi_msg msg;
2303 struct ipmi_system_interface_addr si;
2304
2305 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2306 si.channel = IPMI_BMC_CHANNEL;
2307 si.lun = 0;
2308
2309 msg.netfn = IPMI_NETFN_APP_REQUEST;
2310 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2311 msg.data = NULL;
2312 msg.data_len = 0;
2313 return i_ipmi_request(NULL,
2314 intf,
2315 (struct ipmi_addr *) &si,
2316 0,
2317 &msg,
2318 intf,
2319 NULL,
2320 NULL,
2321 0,
2322 intf->channels[0].address,
2323 intf->channels[0].lun,
2324 -1, 0);
2325}
2326
2327static void
2328guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2329{
2330 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2331 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2332 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2333 /* Not for me */
2334 return;
2335
2336 if (msg->msg.data[0] != 0) {
2337 /* Error from getting the GUID, the BMC doesn't have one. */
2338 intf->bmc->guid_set = 0;
2339 goto out;
2340 }
2341
2342 if (msg->msg.data_len < 17) {
2343 intf->bmc->guid_set = 0;
2344 printk(KERN_WARNING PFX
2345 "guid_handler: The GUID response from the BMC was too"
2346 " short, it was %d but should have been 17. Assuming"
2347 " GUID is not available.\n",
2348 msg->msg.data_len);
2349 goto out;
2350 }
2351
2352 memcpy(intf->bmc->guid, msg->msg.data, 16);
2353 intf->bmc->guid_set = 1;
2354 out:
2355 wake_up(&intf->waitq);
2356}
2357
2358static void
2359get_guid(ipmi_smi_t intf)
2360{
2361 int rv;
2362
2363 intf->bmc->guid_set = 0x2;
2364 intf->null_user_handler = guid_handler;
2365 rv = send_guid_cmd(intf, 0);
2366 if (rv)
2367 /* Send failed, no GUID available. */
2368 intf->bmc->guid_set = 0;
2369 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2370 intf->null_user_handler = NULL;
2371}
2372
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373static int
2374send_channel_info_cmd(ipmi_smi_t intf, int chan)
2375{
2376 struct kernel_ipmi_msg msg;
2377 unsigned char data[1];
2378 struct ipmi_system_interface_addr si;
2379
2380 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2381 si.channel = IPMI_BMC_CHANNEL;
2382 si.lun = 0;
2383
2384 msg.netfn = IPMI_NETFN_APP_REQUEST;
2385 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2386 msg.data = data;
2387 msg.data_len = 1;
2388 data[0] = chan;
2389 return i_ipmi_request(NULL,
2390 intf,
2391 (struct ipmi_addr *) &si,
2392 0,
2393 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002394 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 NULL,
2396 NULL,
2397 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002398 intf->channels[0].address,
2399 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 -1, 0);
2401}
2402
2403static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002404channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405{
2406 int rv = 0;
2407 int chan;
2408
Corey Minyard56a55ec2005-09-06 15:18:42 -07002409 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2410 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2411 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 {
2413 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002414 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 /* Got an error from the channel, just go on. */
2416
Corey Minyard56a55ec2005-09-06 15:18:42 -07002417 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 /* If the MC does not support this
2419 command, that is legal. We just
2420 assume it has one IPMB at channel
2421 zero. */
2422 intf->channels[0].medium
2423 = IPMI_CHANNEL_MEDIUM_IPMB;
2424 intf->channels[0].protocol
2425 = IPMI_CHANNEL_PROTOCOL_IPMB;
2426 rv = -ENOSYS;
2427
2428 intf->curr_channel = IPMI_MAX_CHANNELS;
2429 wake_up(&intf->waitq);
2430 goto out;
2431 }
2432 goto next_channel;
2433 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002434 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 /* Message not big enough, just go on. */
2436 goto next_channel;
2437 }
2438 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002439 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2440 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
2442 next_channel:
2443 intf->curr_channel++;
2444 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2445 wake_up(&intf->waitq);
2446 else
2447 rv = send_channel_info_cmd(intf, intf->curr_channel);
2448
2449 if (rv) {
2450 /* Got an error somehow, just give up. */
2451 intf->curr_channel = IPMI_MAX_CHANNELS;
2452 wake_up(&intf->waitq);
2453
2454 printk(KERN_WARNING PFX
2455 "Error sending channel information: %d\n",
2456 rv);
2457 }
2458 }
2459 out:
2460 return;
2461}
2462
2463int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2464 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002465 struct ipmi_device_id *device_id,
2466 struct device *si_dev,
Corey Minyard453823b2006-03-31 02:30:39 -08002467 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468{
2469 int i, j;
2470 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002471 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -08002472 ipmi_smi_t tintf;
Corey Minyard50c812b2006-03-26 01:37:21 -08002473 int version_major;
2474 int version_minor;
Corey Minyardbca03242006-12-06 20:40:57 -08002475 struct list_head *link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476
Corey Minyard50c812b2006-03-26 01:37:21 -08002477 version_major = ipmi_version_major(device_id);
2478 version_minor = ipmi_version_minor(device_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
2480 /* Make sure the driver is actually initialized, this handles
2481 problems with initialization order. */
2482 if (!initialized) {
2483 rv = ipmi_init_msghandler();
2484 if (rv)
2485 return rv;
2486 /* The init code doesn't return an error if it was turned
2487 off, but it won't initialize. Check that. */
2488 if (!initialized)
2489 return -ENODEV;
2490 }
2491
Corey Minyard393d2cc2005-11-07 00:59:54 -08002492 intf = kmalloc(sizeof(*intf), GFP_KERNEL);
2493 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002495 memset(intf, 0, sizeof(*intf));
Corey Minyard50c812b2006-03-26 01:37:21 -08002496 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2497 if (!intf->bmc) {
2498 kfree(intf);
2499 return -ENOMEM;
2500 }
Corey Minyardbca03242006-12-06 20:40:57 -08002501 intf->intf_num = -1; /* Mark it invalid for now. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002502 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002503 intf->bmc->id = *device_id;
2504 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002505 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2506 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2507 intf->channels[j].lun = 2;
2508 }
2509 if (slave_addr != 0)
2510 intf->channels[0].address = slave_addr;
2511 INIT_LIST_HEAD(&intf->users);
2512 intf->handlers = handlers;
2513 intf->send_info = send_info;
2514 spin_lock_init(&intf->seq_lock);
2515 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2516 intf->seq_table[j].inuse = 0;
2517 intf->seq_table[j].seqid = 0;
2518 }
2519 intf->curr_seq = 0;
2520#ifdef CONFIG_PROC_FS
2521 spin_lock_init(&intf->proc_entry_lock);
2522#endif
2523 spin_lock_init(&intf->waiting_msgs_lock);
2524 INIT_LIST_HEAD(&intf->waiting_msgs);
2525 spin_lock_init(&intf->events_lock);
2526 INIT_LIST_HEAD(&intf->waiting_events);
2527 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002528 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002529 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2530 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
Corey Minyard393d2cc2005-11-07 00:59:54 -08002532 spin_lock_init(&intf->counter_lock);
2533 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
Corey Minyardbca03242006-12-06 20:40:57 -08002535 mutex_lock(&ipmi_interfaces_mutex);
2536 /* Look for a hole in the numbers. */
2537 i = 0;
2538 link = &ipmi_interfaces;
2539 list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) {
2540 if (tintf->intf_num != i) {
2541 link = &tintf->link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 break;
2543 }
Corey Minyardbca03242006-12-06 20:40:57 -08002544 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 }
Corey Minyardbca03242006-12-06 20:40:57 -08002546 /* Add the new interface in numeric order. */
2547 if (i == 0)
2548 list_add_rcu(&intf->link, &ipmi_interfaces);
2549 else
2550 list_add_tail_rcu(&intf->link, link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551
Corey Minyard453823b2006-03-31 02:30:39 -08002552 rv = handlers->start_processing(send_info, intf);
2553 if (rv)
2554 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002555
Corey Minyard50c812b2006-03-26 01:37:21 -08002556 get_guid(intf);
2557
Corey Minyard393d2cc2005-11-07 00:59:54 -08002558 if ((version_major > 1)
2559 || ((version_major == 1) && (version_minor >= 5)))
2560 {
2561 /* Start scanning the channels to see what is
2562 available. */
2563 intf->null_user_handler = channel_handler;
2564 intf->curr_channel = 0;
2565 rv = send_channel_info_cmd(intf, 0);
2566 if (rv)
2567 goto out;
2568
2569 /* Wait for the channel info to be read. */
2570 wait_event(intf->waitq,
2571 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002572 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002573 } else {
2574 /* Assume a single IPMB channel at zero. */
2575 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2576 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578
2579 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002580 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
Corey Minyard50c812b2006-03-26 01:37:21 -08002582 rv = ipmi_bmc_register(intf);
2583
Corey Minyard393d2cc2005-11-07 00:59:54 -08002584 out:
2585 if (rv) {
2586 if (intf->proc_dir)
2587 remove_proc_entries(intf);
Corey Minyardbca03242006-12-06 20:40:57 -08002588 list_del_rcu(&intf->link);
2589 mutex_unlock(&ipmi_interfaces_mutex);
2590 synchronize_rcu();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002591 kref_put(&intf->refcount, intf_free);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002592 } else {
Corey Minyardbca03242006-12-06 20:40:57 -08002593 /* After this point the interface is legal to use. */
2594 intf->intf_num = i;
2595 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard50c812b2006-03-26 01:37:21 -08002596 call_smi_watchers(i, intf->si_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 }
2598
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 return rv;
2600}
2601
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602int ipmi_unregister_smi(ipmi_smi_t intf)
2603{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 struct ipmi_smi_watcher *w;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
Corey Minyard50c812b2006-03-26 01:37:21 -08002606 ipmi_bmc_unregister(intf);
2607
Corey Minyardbca03242006-12-06 20:40:57 -08002608 mutex_lock(&ipmi_interfaces_mutex);
2609 list_del_rcu(&intf->link);
2610 mutex_unlock(&ipmi_interfaces_mutex);
2611 synchronize_rcu();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612
Corey Minyard393d2cc2005-11-07 00:59:54 -08002613 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
2615 /* Call all the watcher interfaces to tell them that
2616 an interface is gone. */
2617 down_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002618 list_for_each_entry(w, &smi_watchers, link)
Corey Minyardbca03242006-12-06 20:40:57 -08002619 w->smi_gone(intf->intf_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 up_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002621
Corey Minyard393d2cc2005-11-07 00:59:54 -08002622 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 return 0;
2624}
2625
2626static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2627 struct ipmi_smi_msg *msg)
2628{
2629 struct ipmi_ipmb_addr ipmb_addr;
2630 struct ipmi_recv_msg *recv_msg;
2631 unsigned long flags;
2632
2633
2634 /* This is 11, not 10, because the response must contain a
2635 * completion code. */
2636 if (msg->rsp_size < 11) {
2637 /* Message not big enough, just ignore it. */
2638 spin_lock_irqsave(&intf->counter_lock, flags);
2639 intf->invalid_ipmb_responses++;
2640 spin_unlock_irqrestore(&intf->counter_lock, flags);
2641 return 0;
2642 }
2643
2644 if (msg->rsp[2] != 0) {
2645 /* An error getting the response, just ignore it. */
2646 return 0;
2647 }
2648
2649 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
2650 ipmb_addr.slave_addr = msg->rsp[6];
2651 ipmb_addr.channel = msg->rsp[3] & 0x0f;
2652 ipmb_addr.lun = msg->rsp[7] & 3;
2653
2654 /* It's a response from a remote entity. Look up the sequence
2655 number and handle the response. */
2656 if (intf_find_seq(intf,
2657 msg->rsp[7] >> 2,
2658 msg->rsp[3] & 0x0f,
2659 msg->rsp[8],
2660 (msg->rsp[4] >> 2) & (~1),
2661 (struct ipmi_addr *) &(ipmb_addr),
2662 &recv_msg))
2663 {
2664 /* We were unable to find the sequence number,
2665 so just nuke the message. */
2666 spin_lock_irqsave(&intf->counter_lock, flags);
2667 intf->unhandled_ipmb_responses++;
2668 spin_unlock_irqrestore(&intf->counter_lock, flags);
2669 return 0;
2670 }
2671
2672 memcpy(recv_msg->msg_data,
2673 &(msg->rsp[9]),
2674 msg->rsp_size - 9);
2675 /* THe other fields matched, so no need to set them, except
2676 for netfn, which needs to be the response that was
2677 returned, not the request value. */
2678 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2679 recv_msg->msg.data = recv_msg->msg_data;
2680 recv_msg->msg.data_len = msg->rsp_size - 10;
2681 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2682 spin_lock_irqsave(&intf->counter_lock, flags);
2683 intf->handled_ipmb_responses++;
2684 spin_unlock_irqrestore(&intf->counter_lock, flags);
2685 deliver_response(recv_msg);
2686
2687 return 0;
2688}
2689
2690static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2691 struct ipmi_smi_msg *msg)
2692{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002693 struct cmd_rcvr *rcvr;
2694 int rv = 0;
2695 unsigned char netfn;
2696 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002697 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002698 ipmi_user_t user = NULL;
2699 struct ipmi_ipmb_addr *ipmb_addr;
2700 struct ipmi_recv_msg *recv_msg;
2701 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
2703 if (msg->rsp_size < 10) {
2704 /* Message not big enough, just ignore it. */
2705 spin_lock_irqsave(&intf->counter_lock, flags);
2706 intf->invalid_commands++;
2707 spin_unlock_irqrestore(&intf->counter_lock, flags);
2708 return 0;
2709 }
2710
2711 if (msg->rsp[2] != 0) {
2712 /* An error getting the response, just ignore it. */
2713 return 0;
2714 }
2715
2716 netfn = msg->rsp[4] >> 2;
2717 cmd = msg->rsp[8];
Corey Minyardc69c3122006-09-30 23:27:56 -07002718 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002720 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002721 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002722 if (rcvr) {
2723 user = rcvr->user;
2724 kref_get(&user->refcount);
2725 } else
2726 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002727 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
2729 if (user == NULL) {
2730 /* We didn't find a user, deliver an error response. */
2731 spin_lock_irqsave(&intf->counter_lock, flags);
2732 intf->unhandled_commands++;
2733 spin_unlock_irqrestore(&intf->counter_lock, flags);
2734
2735 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2736 msg->data[1] = IPMI_SEND_MSG_CMD;
2737 msg->data[2] = msg->rsp[3];
2738 msg->data[3] = msg->rsp[6];
2739 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2740 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002741 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 /* rqseq/lun */
2743 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2744 msg->data[8] = msg->rsp[8]; /* cmd */
2745 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2746 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2747 msg->data_size = 11;
2748
2749#ifdef DEBUG_MSGING
2750 {
2751 int m;
2752 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002753 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 printk(" %2.2x", msg->data[m]);
2755 printk("\n");
2756 }
2757#endif
2758 intf->handlers->sender(intf->send_info, msg, 0);
2759
2760 rv = -1; /* We used the message, so return the value that
2761 causes it to not be freed or queued. */
2762 } else {
2763 /* Deliver the message to the user. */
2764 spin_lock_irqsave(&intf->counter_lock, flags);
2765 intf->handled_commands++;
2766 spin_unlock_irqrestore(&intf->counter_lock, flags);
2767
2768 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002769 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 /* We couldn't allocate memory for the
2771 message, so requeue it for handling
2772 later. */
2773 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002774 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 } else {
2776 /* Extract the source address from the data. */
2777 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2778 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2779 ipmb_addr->slave_addr = msg->rsp[6];
2780 ipmb_addr->lun = msg->rsp[7] & 3;
2781 ipmb_addr->channel = msg->rsp[3] & 0xf;
2782
2783 /* Extract the rest of the message information
2784 from the IPMB header.*/
2785 recv_msg->user = user;
2786 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2787 recv_msg->msgid = msg->rsp[7] >> 2;
2788 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2789 recv_msg->msg.cmd = msg->rsp[8];
2790 recv_msg->msg.data = recv_msg->msg_data;
2791
2792 /* We chop off 10, not 9 bytes because the checksum
2793 at the end also needs to be removed. */
2794 recv_msg->msg.data_len = msg->rsp_size - 10;
2795 memcpy(recv_msg->msg_data,
2796 &(msg->rsp[9]),
2797 msg->rsp_size - 10);
2798 deliver_response(recv_msg);
2799 }
2800 }
2801
2802 return rv;
2803}
2804
2805static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
2806 struct ipmi_smi_msg *msg)
2807{
2808 struct ipmi_lan_addr lan_addr;
2809 struct ipmi_recv_msg *recv_msg;
2810 unsigned long flags;
2811
2812
2813 /* This is 13, not 12, because the response must contain a
2814 * completion code. */
2815 if (msg->rsp_size < 13) {
2816 /* Message not big enough, just ignore it. */
2817 spin_lock_irqsave(&intf->counter_lock, flags);
2818 intf->invalid_lan_responses++;
2819 spin_unlock_irqrestore(&intf->counter_lock, flags);
2820 return 0;
2821 }
2822
2823 if (msg->rsp[2] != 0) {
2824 /* An error getting the response, just ignore it. */
2825 return 0;
2826 }
2827
2828 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
2829 lan_addr.session_handle = msg->rsp[4];
2830 lan_addr.remote_SWID = msg->rsp[8];
2831 lan_addr.local_SWID = msg->rsp[5];
2832 lan_addr.channel = msg->rsp[3] & 0x0f;
2833 lan_addr.privilege = msg->rsp[3] >> 4;
2834 lan_addr.lun = msg->rsp[9] & 3;
2835
2836 /* It's a response from a remote entity. Look up the sequence
2837 number and handle the response. */
2838 if (intf_find_seq(intf,
2839 msg->rsp[9] >> 2,
2840 msg->rsp[3] & 0x0f,
2841 msg->rsp[10],
2842 (msg->rsp[6] >> 2) & (~1),
2843 (struct ipmi_addr *) &(lan_addr),
2844 &recv_msg))
2845 {
2846 /* We were unable to find the sequence number,
2847 so just nuke the message. */
2848 spin_lock_irqsave(&intf->counter_lock, flags);
2849 intf->unhandled_lan_responses++;
2850 spin_unlock_irqrestore(&intf->counter_lock, flags);
2851 return 0;
2852 }
2853
2854 memcpy(recv_msg->msg_data,
2855 &(msg->rsp[11]),
2856 msg->rsp_size - 11);
2857 /* The other fields matched, so no need to set them, except
2858 for netfn, which needs to be the response that was
2859 returned, not the request value. */
2860 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2861 recv_msg->msg.data = recv_msg->msg_data;
2862 recv_msg->msg.data_len = msg->rsp_size - 12;
2863 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2864 spin_lock_irqsave(&intf->counter_lock, flags);
2865 intf->handled_lan_responses++;
2866 spin_unlock_irqrestore(&intf->counter_lock, flags);
2867 deliver_response(recv_msg);
2868
2869 return 0;
2870}
2871
2872static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2873 struct ipmi_smi_msg *msg)
2874{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002875 struct cmd_rcvr *rcvr;
2876 int rv = 0;
2877 unsigned char netfn;
2878 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002879 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002880 ipmi_user_t user = NULL;
2881 struct ipmi_lan_addr *lan_addr;
2882 struct ipmi_recv_msg *recv_msg;
2883 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884
2885 if (msg->rsp_size < 12) {
2886 /* Message not big enough, just ignore it. */
2887 spin_lock_irqsave(&intf->counter_lock, flags);
2888 intf->invalid_commands++;
2889 spin_unlock_irqrestore(&intf->counter_lock, flags);
2890 return 0;
2891 }
2892
2893 if (msg->rsp[2] != 0) {
2894 /* An error getting the response, just ignore it. */
2895 return 0;
2896 }
2897
2898 netfn = msg->rsp[6] >> 2;
2899 cmd = msg->rsp[10];
Corey Minyardc69c3122006-09-30 23:27:56 -07002900 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002902 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002903 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002904 if (rcvr) {
2905 user = rcvr->user;
2906 kref_get(&user->refcount);
2907 } else
2908 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002909 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910
2911 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002912 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 spin_lock_irqsave(&intf->counter_lock, flags);
2914 intf->unhandled_commands++;
2915 spin_unlock_irqrestore(&intf->counter_lock, flags);
2916
2917 rv = 0; /* Don't do anything with these messages, just
2918 allow them to be freed. */
2919 } else {
2920 /* Deliver the message to the user. */
2921 spin_lock_irqsave(&intf->counter_lock, flags);
2922 intf->handled_commands++;
2923 spin_unlock_irqrestore(&intf->counter_lock, flags);
2924
2925 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002926 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 /* We couldn't allocate memory for the
2928 message, so requeue it for handling
2929 later. */
2930 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002931 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 } else {
2933 /* Extract the source address from the data. */
2934 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
2935 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
2936 lan_addr->session_handle = msg->rsp[4];
2937 lan_addr->remote_SWID = msg->rsp[8];
2938 lan_addr->local_SWID = msg->rsp[5];
2939 lan_addr->lun = msg->rsp[9] & 3;
2940 lan_addr->channel = msg->rsp[3] & 0xf;
2941 lan_addr->privilege = msg->rsp[3] >> 4;
2942
2943 /* Extract the rest of the message information
2944 from the IPMB header.*/
2945 recv_msg->user = user;
2946 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2947 recv_msg->msgid = msg->rsp[9] >> 2;
2948 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2949 recv_msg->msg.cmd = msg->rsp[10];
2950 recv_msg->msg.data = recv_msg->msg_data;
2951
2952 /* We chop off 12, not 11 bytes because the checksum
2953 at the end also needs to be removed. */
2954 recv_msg->msg.data_len = msg->rsp_size - 12;
2955 memcpy(recv_msg->msg_data,
2956 &(msg->rsp[11]),
2957 msg->rsp_size - 12);
2958 deliver_response(recv_msg);
2959 }
2960 }
2961
2962 return rv;
2963}
2964
2965static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
2966 struct ipmi_smi_msg *msg)
2967{
2968 struct ipmi_system_interface_addr *smi_addr;
2969
2970 recv_msg->msgid = 0;
2971 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
2972 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2973 smi_addr->channel = IPMI_BMC_CHANNEL;
2974 smi_addr->lun = msg->rsp[0] & 3;
2975 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
2976 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2977 recv_msg->msg.cmd = msg->rsp[1];
2978 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
2979 recv_msg->msg.data = recv_msg->msg_data;
2980 recv_msg->msg.data_len = msg->rsp_size - 3;
2981}
2982
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983static int handle_read_event_rsp(ipmi_smi_t intf,
2984 struct ipmi_smi_msg *msg)
2985{
2986 struct ipmi_recv_msg *recv_msg, *recv_msg2;
2987 struct list_head msgs;
2988 ipmi_user_t user;
2989 int rv = 0;
2990 int deliver_count = 0;
2991 unsigned long flags;
2992
2993 if (msg->rsp_size < 19) {
2994 /* Message is too small to be an IPMB event. */
2995 spin_lock_irqsave(&intf->counter_lock, flags);
2996 intf->invalid_events++;
2997 spin_unlock_irqrestore(&intf->counter_lock, flags);
2998 return 0;
2999 }
3000
3001 if (msg->rsp[2] != 0) {
3002 /* An error getting the event, just ignore it. */
3003 return 0;
3004 }
3005
3006 INIT_LIST_HEAD(&msgs);
3007
Corey Minyard393d2cc2005-11-07 00:59:54 -08003008 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009
3010 spin_lock(&intf->counter_lock);
3011 intf->events++;
3012 spin_unlock(&intf->counter_lock);
3013
3014 /* Allocate and fill in one message for every user that is getting
3015 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003016 rcu_read_lock();
3017 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003018 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 continue;
3020
3021 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003022 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003023 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003024 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
3025 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 list_del(&recv_msg->link);
3027 ipmi_free_recv_msg(recv_msg);
3028 }
3029 /* We couldn't allocate memory for the
3030 message, so requeue it for handling
3031 later. */
3032 rv = 1;
3033 goto out;
3034 }
3035
3036 deliver_count++;
3037
3038 copy_event_into_recv_msg(recv_msg, msg);
3039 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003040 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 list_add_tail(&(recv_msg->link), &msgs);
3042 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003043 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
3045 if (deliver_count) {
3046 /* Now deliver all the messages. */
3047 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
3048 list_del(&recv_msg->link);
3049 deliver_response(recv_msg);
3050 }
3051 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
3052 /* No one to receive the message, put it in queue if there's
3053 not already too many things in the queue. */
3054 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003055 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 /* We couldn't allocate memory for the
3057 message, so requeue it for handling
3058 later. */
3059 rv = 1;
3060 goto out;
3061 }
3062
3063 copy_event_into_recv_msg(recv_msg, msg);
3064 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
Corey Minyard4791c032006-04-10 22:54:31 -07003065 intf->waiting_events_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 } else {
3067 /* There's too many things in the queue, discard this
3068 message. */
3069 printk(KERN_WARNING PFX "Event queue full, discarding an"
3070 " incoming event\n");
3071 }
3072
3073 out:
3074 spin_unlock_irqrestore(&(intf->events_lock), flags);
3075
3076 return rv;
3077}
3078
3079static int handle_bmc_rsp(ipmi_smi_t intf,
3080 struct ipmi_smi_msg *msg)
3081{
3082 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003084 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085
3086 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07003087 if (recv_msg == NULL)
3088 {
3089 printk(KERN_WARNING"IPMI message received with no owner. This\n"
3090 "could be because of a malformed message, or\n"
3091 "because of a hardware error. Contact your\n"
3092 "hardware vender for assistance\n");
3093 return 0;
3094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095
Corey Minyard393d2cc2005-11-07 00:59:54 -08003096 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003098 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07003099 /* The user for the message went away, so give up. */
3100 spin_lock_irqsave(&intf->counter_lock, flags);
3101 intf->unhandled_local_responses++;
3102 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 ipmi_free_recv_msg(recv_msg);
3104 } else {
3105 struct ipmi_system_interface_addr *smi_addr;
3106
3107 spin_lock_irqsave(&intf->counter_lock, flags);
3108 intf->handled_local_responses++;
3109 spin_unlock_irqrestore(&intf->counter_lock, flags);
3110 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3111 recv_msg->msgid = msg->msgid;
3112 smi_addr = ((struct ipmi_system_interface_addr *)
3113 &(recv_msg->addr));
3114 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3115 smi_addr->channel = IPMI_BMC_CHANNEL;
3116 smi_addr->lun = msg->rsp[0] & 3;
3117 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3118 recv_msg->msg.cmd = msg->rsp[1];
3119 memcpy(recv_msg->msg_data,
3120 &(msg->rsp[2]),
3121 msg->rsp_size - 2);
3122 recv_msg->msg.data = recv_msg->msg_data;
3123 recv_msg->msg.data_len = msg->rsp_size - 2;
3124 deliver_response(recv_msg);
3125 }
3126
3127 return 0;
3128}
3129
3130/* Handle a new message. Return 1 if the message should be requeued,
3131 0 if the message should be freed, or -1 if the message should not
3132 be freed or requeued. */
3133static int handle_new_recv_msg(ipmi_smi_t intf,
3134 struct ipmi_smi_msg *msg)
3135{
3136 int requeue;
3137 int chan;
3138
3139#ifdef DEBUG_MSGING
3140 int m;
3141 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07003142 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 printk(" %2.2x", msg->rsp[m]);
3144 printk("\n");
3145#endif
3146 if (msg->rsp_size < 2) {
3147 /* Message is too small to be correct. */
3148 printk(KERN_WARNING PFX "BMC returned to small a message"
3149 " for netfn %x cmd %x, got %d bytes\n",
3150 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3151
3152 /* Generate an error response for the message. */
3153 msg->rsp[0] = msg->data[0] | (1 << 2);
3154 msg->rsp[1] = msg->data[1];
3155 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3156 msg->rsp_size = 3;
3157 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3158 || (msg->rsp[1] != msg->data[1])) /* Command */
3159 {
3160 /* The response is not even marginally correct. */
3161 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3162 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3163 (msg->data[0] >> 2) | 1, msg->data[1],
3164 msg->rsp[0] >> 2, msg->rsp[1]);
3165
3166 /* Generate an error response for the message. */
3167 msg->rsp[0] = msg->data[0] | (1 << 2);
3168 msg->rsp[1] = msg->data[1];
3169 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3170 msg->rsp_size = 3;
3171 }
3172
3173 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3174 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3175 && (msg->user_data != NULL))
3176 {
3177 /* It's a response to a response we sent. For this we
3178 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003179 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180
3181 requeue = 0;
3182 if (msg->rsp_size < 2)
3183 /* Message is too small to be correct. */
3184 goto out;
3185
3186 chan = msg->data[2] & 0x0f;
3187 if (chan >= IPMI_MAX_CHANNELS)
3188 /* Invalid channel number */
3189 goto out;
3190
Corey Minyard393d2cc2005-11-07 00:59:54 -08003191 if (!recv_msg)
3192 goto out;
3193
3194 /* Make sure the user still exists. */
3195 if (!recv_msg->user || !recv_msg->user->valid)
3196 goto out;
3197
3198 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3199 recv_msg->msg.data = recv_msg->msg_data;
3200 recv_msg->msg.data_len = 1;
3201 recv_msg->msg_data[0] = msg->rsp[2];
3202 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3204 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3205 {
3206 /* It's from the receive queue. */
3207 chan = msg->rsp[3] & 0xf;
3208 if (chan >= IPMI_MAX_CHANNELS) {
3209 /* Invalid channel number */
3210 requeue = 0;
3211 goto out;
3212 }
3213
3214 switch (intf->channels[chan].medium) {
3215 case IPMI_CHANNEL_MEDIUM_IPMB:
3216 if (msg->rsp[4] & 0x04) {
3217 /* It's a response, so find the
3218 requesting message and send it up. */
3219 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3220 } else {
3221 /* It's a command to the SMS from some other
3222 entity. Handle that. */
3223 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3224 }
3225 break;
3226
3227 case IPMI_CHANNEL_MEDIUM_8023LAN:
3228 case IPMI_CHANNEL_MEDIUM_ASYNC:
3229 if (msg->rsp[6] & 0x04) {
3230 /* It's a response, so find the
3231 requesting message and send it up. */
3232 requeue = handle_lan_get_msg_rsp(intf, msg);
3233 } else {
3234 /* It's a command to the SMS from some other
3235 entity. Handle that. */
3236 requeue = handle_lan_get_msg_cmd(intf, msg);
3237 }
3238 break;
3239
3240 default:
3241 /* We don't handle the channel type, so just
3242 * free the message. */
3243 requeue = 0;
3244 }
3245
3246 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3247 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3248 {
3249 /* It's an asyncronous event. */
3250 requeue = handle_read_event_rsp(intf, msg);
3251 } else {
3252 /* It's a response from the local BMC. */
3253 requeue = handle_bmc_rsp(intf, msg);
3254 }
3255
3256 out:
3257 return requeue;
3258}
3259
3260/* Handle a new message from the lower layer. */
3261void ipmi_smi_msg_received(ipmi_smi_t intf,
3262 struct ipmi_smi_msg *msg)
3263{
3264 unsigned long flags;
3265 int rv;
3266
3267
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 if ((msg->data_size >= 2)
3269 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3270 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003271 && (msg->user_data == NULL))
3272 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 /* This is the local response to a command send, start
3274 the timer for these. The user_data will not be
3275 NULL if this is a response send, and we will let
3276 response sends just go through. */
3277
3278 /* Check for errors, if we get certain errors (ones
3279 that mean basically we can try again later), we
3280 ignore them and start the timer. Otherwise we
3281 report the error immediately. */
3282 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3283 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
Corey Minyard46d52b02006-11-08 17:44:55 -08003284 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
3285 && (msg->rsp[2] != IPMI_BUS_ERR)
3286 && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 {
3288 int chan = msg->rsp[3] & 0xf;
3289
3290 /* Got an error sending the message, handle it. */
3291 spin_lock_irqsave(&intf->counter_lock, flags);
3292 if (chan >= IPMI_MAX_CHANNELS)
3293 ; /* This shouldn't happen */
3294 else if ((intf->channels[chan].medium
3295 == IPMI_CHANNEL_MEDIUM_8023LAN)
3296 || (intf->channels[chan].medium
3297 == IPMI_CHANNEL_MEDIUM_ASYNC))
3298 intf->sent_lan_command_errs++;
3299 else
3300 intf->sent_ipmb_command_errs++;
3301 spin_unlock_irqrestore(&intf->counter_lock, flags);
3302 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3303 } else {
3304 /* The message was sent, start the timer. */
3305 intf_start_seq_timer(intf, msg->msgid);
3306 }
3307
3308 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003309 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 }
3311
3312 /* To preserve message order, if the list is not empty, we
3313 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003314 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
3315 if (!list_empty(&intf->waiting_msgs)) {
3316 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003317 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003318 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003320 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321
3322 rv = handle_new_recv_msg(intf, msg);
3323 if (rv > 0) {
3324 /* Could not handle the message now, just add it to a
3325 list to handle later. */
Hironobu Ishii177294d2005-11-11 08:12:21 -06003326 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003327 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003328 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 } else if (rv == 0) {
3330 ipmi_free_smi_msg(msg);
3331 }
3332
Corey Minyard393d2cc2005-11-07 00:59:54 -08003333 out:
3334 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335}
3336
3337void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3338{
3339 ipmi_user_t user;
3340
Corey Minyard393d2cc2005-11-07 00:59:54 -08003341 rcu_read_lock();
3342 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003343 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 continue;
3345
3346 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3347 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003348 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349}
3350
3351static void
3352handle_msg_timeout(struct ipmi_recv_msg *msg)
3353{
3354 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3355 msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;
3356 msg->msg.netfn |= 1; /* Convert to a response. */
3357 msg->msg.data_len = 1;
3358 msg->msg.data = msg->msg_data;
3359 deliver_response(msg);
3360}
3361
Corey Minyard882fe012005-05-01 08:59:12 -07003362static struct ipmi_smi_msg *
3363smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3364 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365{
Corey Minyard882fe012005-05-01 08:59:12 -07003366 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 if (!smi_msg)
3368 /* If we can't allocate the message, then just return, we
3369 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003370 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371
3372 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3373 smi_msg->data_size = recv_msg->msg.data_len;
3374 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3375
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376#ifdef DEBUG_MSGING
3377 {
3378 int m;
3379 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003380 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 printk(" %2.2x", smi_msg->data[m]);
3382 printk("\n");
3383 }
3384#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003385 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386}
3387
Corey Minyard393d2cc2005-11-07 00:59:54 -08003388static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3389 struct list_head *timeouts, long timeout_period,
3390 int slot, unsigned long *flags)
3391{
3392 struct ipmi_recv_msg *msg;
3393
3394 if (!ent->inuse)
3395 return;
3396
3397 ent->timeout -= timeout_period;
3398 if (ent->timeout > 0)
3399 return;
3400
3401 if (ent->retries_left == 0) {
3402 /* The message has used all its retries. */
3403 ent->inuse = 0;
3404 msg = ent->recv_msg;
3405 list_add_tail(&msg->link, timeouts);
3406 spin_lock(&intf->counter_lock);
3407 if (ent->broadcast)
3408 intf->timed_out_ipmb_broadcasts++;
3409 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3410 intf->timed_out_lan_commands++;
3411 else
3412 intf->timed_out_ipmb_commands++;
3413 spin_unlock(&intf->counter_lock);
3414 } else {
3415 struct ipmi_smi_msg *smi_msg;
3416 /* More retries, send again. */
3417
3418 /* Start with the max timer, set to normal
3419 timer after the message is sent. */
3420 ent->timeout = MAX_MSG_TIMEOUT;
3421 ent->retries_left--;
3422 spin_lock(&intf->counter_lock);
3423 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3424 intf->retransmitted_lan_commands++;
3425 else
3426 intf->retransmitted_ipmb_commands++;
3427 spin_unlock(&intf->counter_lock);
3428
3429 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3430 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003431 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003432 return;
3433
3434 spin_unlock_irqrestore(&intf->seq_lock, *flags);
3435 /* Send the new message. We send with a zero
3436 * priority. It timed out, I doubt time is
3437 * that critical now, and high priority
3438 * messages are really only for messages to the
3439 * local MC, which don't get resent. */
3440 intf->handlers->sender(intf->send_info,
3441 smi_msg, 0);
3442 spin_lock_irqsave(&intf->seq_lock, *flags);
3443 }
3444}
3445
3446static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447{
3448 ipmi_smi_t intf;
3449 struct list_head timeouts;
3450 struct ipmi_recv_msg *msg, *msg2;
3451 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3452 unsigned long flags;
Corey Minyardbca03242006-12-06 20:40:57 -08003453 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454
3455 INIT_LIST_HEAD(&timeouts);
3456
Corey Minyardbca03242006-12-06 20:40:57 -08003457 rcu_read_lock();
3458 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003460 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003461 list_for_each_entry_safe(smi_msg, smi_msg2,
3462 &intf->waiting_msgs, link) {
3463 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 list_del(&smi_msg->link);
3465 ipmi_free_smi_msg(smi_msg);
3466 } else {
3467 /* To preserve message order, quit if we
3468 can't handle a message. */
3469 break;
3470 }
3471 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003472 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473
3474 /* Go through the seq table and find any messages that
3475 have timed out, putting them in the timeouts
3476 list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003477 spin_lock_irqsave(&intf->seq_lock, flags);
Corey Minyardbca03242006-12-06 20:40:57 -08003478 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
3479 check_msg_timeout(intf, &(intf->seq_table[i]),
3480 &timeouts, timeout_period, i,
Corey Minyard393d2cc2005-11-07 00:59:54 -08003481 &flags);
3482 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483
Corey Minyard393d2cc2005-11-07 00:59:54 -08003484 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 handle_msg_timeout(msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 }
Corey Minyardbca03242006-12-06 20:40:57 -08003487 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488}
3489
3490static void ipmi_request_event(void)
3491{
3492 ipmi_smi_t intf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493
Corey Minyardbca03242006-12-06 20:40:57 -08003494 rcu_read_lock();
3495 list_for_each_entry_rcu(intf, &ipmi_interfaces, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 intf->handlers->request_events(intf->send_info);
Corey Minyardbca03242006-12-06 20:40:57 -08003497 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498}
3499
3500static struct timer_list ipmi_timer;
3501
3502/* Call every ~100 ms. */
3503#define IPMI_TIMEOUT_TIME 100
3504
3505/* How many jiffies does it take to get to the timeout time. */
3506#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3507
3508/* Request events from the queue every second (this is the number of
3509 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3510 future, IPMI will add a way to know immediately if an event is in
3511 the queue and this silliness can go away. */
3512#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3513
Corey Minyard8f43f842005-06-23 22:01:40 -07003514static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3516
3517static void ipmi_timeout(unsigned long data)
3518{
Corey Minyard8f43f842005-06-23 22:01:40 -07003519 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521
3522 ticks_to_req_ev--;
3523 if (ticks_to_req_ev == 0) {
3524 ipmi_request_event();
3525 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3526 }
3527
3528 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3529
Corey Minyard8f43f842005-06-23 22:01:40 -07003530 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531}
3532
3533
3534static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3535static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3536
3537/* FIXME - convert these to slabs. */
3538static void free_smi_msg(struct ipmi_smi_msg *msg)
3539{
3540 atomic_dec(&smi_msg_inuse_count);
3541 kfree(msg);
3542}
3543
3544struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3545{
3546 struct ipmi_smi_msg *rv;
3547 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3548 if (rv) {
3549 rv->done = free_smi_msg;
3550 rv->user_data = NULL;
3551 atomic_inc(&smi_msg_inuse_count);
3552 }
3553 return rv;
3554}
3555
3556static void free_recv_msg(struct ipmi_recv_msg *msg)
3557{
3558 atomic_dec(&recv_msg_inuse_count);
3559 kfree(msg);
3560}
3561
3562struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3563{
3564 struct ipmi_recv_msg *rv;
3565
3566 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3567 if (rv) {
Corey Minyarda9eec552006-08-31 21:27:45 -07003568 rv->user = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 rv->done = free_recv_msg;
3570 atomic_inc(&recv_msg_inuse_count);
3571 }
3572 return rv;
3573}
3574
Corey Minyard393d2cc2005-11-07 00:59:54 -08003575void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3576{
3577 if (msg->user)
3578 kref_put(&msg->user->refcount, free_user);
3579 msg->done(msg);
3580}
3581
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582#ifdef CONFIG_IPMI_PANIC_EVENT
3583
3584static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3585{
3586}
3587
3588static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3589{
3590}
3591
3592#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003593static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003595 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3596 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3597 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3598 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 {
3600 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003601 intf->event_receiver = msg->msg.data[1];
3602 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 }
3604}
3605
Corey Minyard56a55ec2005-09-06 15:18:42 -07003606static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003608 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3609 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3610 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3611 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 {
3613 /* A get device id command, save if we are an event
3614 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003615 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3616 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 }
3618}
3619#endif
3620
3621static void send_panic_events(char *str)
3622{
3623 struct kernel_ipmi_msg msg;
3624 ipmi_smi_t intf;
3625 unsigned char data[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 struct ipmi_system_interface_addr *si;
3627 struct ipmi_addr addr;
3628 struct ipmi_smi_msg smi_msg;
3629 struct ipmi_recv_msg recv_msg;
3630
3631 si = (struct ipmi_system_interface_addr *) &addr;
3632 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3633 si->channel = IPMI_BMC_CHANNEL;
3634 si->lun = 0;
3635
3636 /* Fill in an event telling that we have failed. */
3637 msg.netfn = 0x04; /* Sensor or Event. */
3638 msg.cmd = 2; /* Platform event command. */
3639 msg.data = data;
3640 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003641 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 data[1] = 0x03; /* This is for IPMI 1.0. */
3643 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3644 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3645 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3646
3647 /* Put a few breadcrumbs in. Hopefully later we can add more things
3648 to make the panic events more useful. */
3649 if (str) {
3650 data[3] = str[0];
3651 data[6] = str[1];
3652 data[7] = str[2];
3653 }
3654
3655 smi_msg.done = dummy_smi_done_handler;
3656 recv_msg.done = dummy_recv_done_handler;
3657
3658 /* For every registered interface, send the event. */
Corey Minyardbca03242006-12-06 20:40:57 -08003659 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
3660 if (intf->intf_num == -1)
3661 /* Interface was not ready yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 continue;
3663
3664 /* Send the event announcing the panic. */
3665 intf->handlers->set_run_to_completion(intf->send_info, 1);
3666 i_ipmi_request(NULL,
3667 intf,
3668 &addr,
3669 0,
3670 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003671 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 &smi_msg,
3673 &recv_msg,
3674 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003675 intf->channels[0].address,
3676 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 0, 1); /* Don't retry, and don't wait. */
3678 }
3679
3680#ifdef CONFIG_IPMI_PANIC_STRING
3681 /* On every interface, dump a bunch of OEM event holding the
3682 string. */
3683 if (!str)
3684 return;
3685
Corey Minyardbca03242006-12-06 20:40:57 -08003686 /* For every registered interface, send the event. */
3687 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 char *p = str;
3689 struct ipmi_ipmb_addr *ipmb;
3690 int j;
3691
Corey Minyardbca03242006-12-06 20:40:57 -08003692 if (intf->intf_num == -1)
3693 /* Interface was not ready yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 continue;
3695
3696 /* First job here is to figure out where to send the
3697 OEM events. There's no way in IPMI to send OEM
3698 events using an event send command, so we have to
3699 find the SEL to put them in and stick them in
3700 there. */
3701
3702 /* Get capabilities from the get device id. */
3703 intf->local_sel_device = 0;
3704 intf->local_event_generator = 0;
3705 intf->event_receiver = 0;
3706
3707 /* Request the device info from the local MC. */
3708 msg.netfn = IPMI_NETFN_APP_REQUEST;
3709 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3710 msg.data = NULL;
3711 msg.data_len = 0;
3712 intf->null_user_handler = device_id_fetcher;
3713 i_ipmi_request(NULL,
3714 intf,
3715 &addr,
3716 0,
3717 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003718 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 &smi_msg,
3720 &recv_msg,
3721 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003722 intf->channels[0].address,
3723 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 0, 1); /* Don't retry, and don't wait. */
3725
3726 if (intf->local_event_generator) {
3727 /* Request the event receiver from the local MC. */
3728 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3729 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3730 msg.data = NULL;
3731 msg.data_len = 0;
3732 intf->null_user_handler = event_receiver_fetcher;
3733 i_ipmi_request(NULL,
3734 intf,
3735 &addr,
3736 0,
3737 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003738 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 &smi_msg,
3740 &recv_msg,
3741 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003742 intf->channels[0].address,
3743 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 0, 1); /* no retry, and no wait. */
3745 }
3746 intf->null_user_handler = NULL;
3747
3748 /* Validate the event receiver. The low bit must not
3749 be 1 (it must be a valid IPMB address), it cannot
3750 be zero, and it must not be my address. */
3751 if (((intf->event_receiver & 1) == 0)
3752 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003753 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 {
3755 /* The event receiver is valid, send an IPMB
3756 message. */
3757 ipmb = (struct ipmi_ipmb_addr *) &addr;
3758 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3759 ipmb->channel = 0; /* FIXME - is this right? */
3760 ipmb->lun = intf->event_receiver_lun;
3761 ipmb->slave_addr = intf->event_receiver;
3762 } else if (intf->local_sel_device) {
3763 /* The event receiver was not valid (or was
3764 me), but I am an SEL device, just dump it
3765 in my SEL. */
3766 si = (struct ipmi_system_interface_addr *) &addr;
3767 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3768 si->channel = IPMI_BMC_CHANNEL;
3769 si->lun = 0;
3770 } else
3771 continue; /* No where to send the event. */
3772
3773
3774 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
3775 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
3776 msg.data = data;
3777 msg.data_len = 16;
3778
3779 j = 0;
3780 while (*p) {
3781 int size = strlen(p);
3782
3783 if (size > 11)
3784 size = 11;
3785 data[0] = 0;
3786 data[1] = 0;
3787 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07003788 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 data[4] = j++; /* sequence # */
3790 /* Always give 11 bytes, so strncpy will fill
3791 it with zeroes for me. */
3792 strncpy(data+5, p, 11);
3793 p += size;
3794
3795 i_ipmi_request(NULL,
3796 intf,
3797 &addr,
3798 0,
3799 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003800 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 &smi_msg,
3802 &recv_msg,
3803 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003804 intf->channels[0].address,
3805 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 0, 1); /* no retry, and no wait. */
3807 }
3808 }
3809#endif /* CONFIG_IPMI_PANIC_STRING */
3810}
3811#endif /* CONFIG_IPMI_PANIC_EVENT */
3812
Lee Revellf18190b2006-06-26 18:30:00 +02003813static int has_panicked = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814
3815static int panic_event(struct notifier_block *this,
3816 unsigned long event,
3817 void *ptr)
3818{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 ipmi_smi_t intf;
3820
Lee Revellf18190b2006-06-26 18:30:00 +02003821 if (has_panicked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 return NOTIFY_DONE;
Lee Revellf18190b2006-06-26 18:30:00 +02003823 has_panicked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824
3825 /* For every registered interface, set it to run to completion. */
Corey Minyardbca03242006-12-06 20:40:57 -08003826 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
3827 if (intf->intf_num == -1)
3828 /* Interface was not ready yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 continue;
3830
3831 intf->handlers->set_run_to_completion(intf->send_info, 1);
3832 }
3833
3834#ifdef CONFIG_IPMI_PANIC_EVENT
3835 send_panic_events(ptr);
3836#endif
3837
3838 return NOTIFY_DONE;
3839}
3840
3841static struct notifier_block panic_block = {
3842 .notifier_call = panic_event,
3843 .next = NULL,
3844 .priority = 200 /* priority: INT_MAX >= x >= 0 */
3845};
3846
3847static int ipmi_init_msghandler(void)
3848{
Corey Minyard50c812b2006-03-26 01:37:21 -08003849 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850
3851 if (initialized)
3852 return 0;
3853
Corey Minyard50c812b2006-03-26 01:37:21 -08003854 rv = driver_register(&ipmidriver);
3855 if (rv) {
3856 printk(KERN_ERR PFX "Could not register IPMI driver\n");
3857 return rv;
3858 }
3859
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003861 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862
Corey Minyard3b625942005-06-23 22:01:42 -07003863#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 proc_ipmi_root = proc_mkdir("ipmi", NULL);
3865 if (!proc_ipmi_root) {
3866 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
3867 return -ENOMEM;
3868 }
3869
3870 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07003871#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872
Corey Minyard409035e2006-06-28 04:26:53 -07003873 setup_timer(&ipmi_timer, ipmi_timeout, 0);
3874 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875
Alan Sterne041c682006-03-27 01:16:30 -08003876 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877
3878 initialized = 1;
3879
3880 return 0;
3881}
3882
3883static __init int ipmi_init_msghandler_mod(void)
3884{
3885 ipmi_init_msghandler();
3886 return 0;
3887}
3888
3889static __exit void cleanup_ipmi(void)
3890{
3891 int count;
3892
3893 if (!initialized)
3894 return;
3895
Alan Sterne041c682006-03-27 01:16:30 -08003896 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897
3898 /* This can't be called if any interfaces exist, so no worry about
3899 shutting down the interfaces. */
3900
3901 /* Tell the timer to stop, then wait for it to stop. This avoids
3902 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07003903 atomic_inc(&stop_operation);
3904 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905
Corey Minyard3b625942005-06-23 22:01:42 -07003906#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 remove_proc_entry(proc_ipmi_root->name, &proc_root);
Corey Minyard3b625942005-06-23 22:01:42 -07003908#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909
Corey Minyard50c812b2006-03-26 01:37:21 -08003910 driver_unregister(&ipmidriver);
3911
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 initialized = 0;
3913
3914 /* Check for buffer leaks. */
3915 count = atomic_read(&smi_msg_inuse_count);
3916 if (count != 0)
3917 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
3918 count);
3919 count = atomic_read(&recv_msg_inuse_count);
3920 if (count != 0)
3921 printk(KERN_WARNING PFX "recv message count %d at exit\n",
3922 count);
3923}
3924module_exit(cleanup_ipmi);
3925
3926module_init(ipmi_init_msghandler_mod);
3927MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003928MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
3929MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
3930MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931
3932EXPORT_SYMBOL(ipmi_create_user);
3933EXPORT_SYMBOL(ipmi_destroy_user);
3934EXPORT_SYMBOL(ipmi_get_version);
3935EXPORT_SYMBOL(ipmi_request_settime);
3936EXPORT_SYMBOL(ipmi_request_supply_msgs);
3937EXPORT_SYMBOL(ipmi_register_smi);
3938EXPORT_SYMBOL(ipmi_unregister_smi);
3939EXPORT_SYMBOL(ipmi_register_for_cmd);
3940EXPORT_SYMBOL(ipmi_unregister_for_cmd);
3941EXPORT_SYMBOL(ipmi_smi_msg_received);
3942EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
3943EXPORT_SYMBOL(ipmi_alloc_smi_msg);
3944EXPORT_SYMBOL(ipmi_addr_length);
3945EXPORT_SYMBOL(ipmi_validate_addr);
3946EXPORT_SYMBOL(ipmi_set_gets_events);
3947EXPORT_SYMBOL(ipmi_smi_watcher_register);
3948EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
3949EXPORT_SYMBOL(ipmi_set_my_address);
3950EXPORT_SYMBOL(ipmi_get_my_address);
3951EXPORT_SYMBOL(ipmi_set_my_LUN);
3952EXPORT_SYMBOL(ipmi_get_my_LUN);
3953EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003955EXPORT_SYMBOL(ipmi_free_recv_msg);