blob: 34a4fd13fa817ec0241a05157593872716b49600 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ipmi_msghandler.c
3 *
4 * Incoming and outgoing message routing for an IPMI interface.
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2002 MontaVista Software Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/module.h>
35#include <linux/errno.h>
36#include <asm/system.h>
37#include <linux/sched.h>
38#include <linux/poll.h>
39#include <linux/spinlock.h>
Corey Minyardd6dfd132006-03-31 02:30:41 -080040#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/slab.h>
42#include <linux/ipmi.h>
43#include <linux/ipmi_smi.h>
44#include <linux/notifier.h>
45#include <linux/init.h>
46#include <linux/proc_fs.h>
Corey Minyard393d2cc2005-11-07 00:59:54 -080047#include <linux/rcupdate.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#define PFX "IPMI message handler: "
Corey Minyard1fdd75b2005-09-06 15:18:42 -070050
Corey Minyarda23f9a32006-03-26 01:37:22 -080051#define IPMI_DRIVER_VERSION "39.0"
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
54static int ipmi_init_msghandler(void);
55
56static int initialized = 0;
57
Corey Minyard3b625942005-06-23 22:01:42 -070058#ifdef CONFIG_PROC_FS
Adrian Bunk456229a2006-06-27 02:55:07 -070059static struct proc_dir_entry *proc_ipmi_root = NULL;
Corey Minyard3b625942005-06-23 22:01:42 -070060#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62#define MAX_EVENTS_IN_QUEUE 25
63
64/* Don't let a message sit in a queue forever, always time it with at lest
65 the max message timer. This is in milliseconds. */
66#define MAX_MSG_TIMEOUT 60000
67
Corey Minyard393d2cc2005-11-07 00:59:54 -080068
69/*
70 * The main "user" data structure.
71 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070072struct ipmi_user
73{
74 struct list_head link;
75
Corey Minyard393d2cc2005-11-07 00:59:54 -080076 /* Set to "0" when the user is destroyed. */
77 int valid;
78
79 struct kref refcount;
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 /* The upper layer that handles receive messages. */
82 struct ipmi_user_hndl *handler;
83 void *handler_data;
84
85 /* The interface this user is bound to. */
86 ipmi_smi_t intf;
87
88 /* Does this interface receive IPMI events? */
89 int gets_events;
90};
91
92struct cmd_rcvr
93{
94 struct list_head link;
95
96 ipmi_user_t user;
97 unsigned char netfn;
98 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -070099 unsigned int chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800100
101 /*
102 * This is used to form a linked lised during mass deletion.
103 * Since this is in an RCU list, we cannot use the link above
104 * or change any data until the RCU period completes. So we
105 * use this next variable during mass deletion so we can have
106 * a list and don't have to wait and restart the search on
107 * every individual deletion of a command. */
108 struct cmd_rcvr *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109};
110
111struct seq_table
112{
113 unsigned int inuse : 1;
114 unsigned int broadcast : 1;
115
116 unsigned long timeout;
117 unsigned long orig_timeout;
118 unsigned int retries_left;
119
120 /* To verify on an incoming send message response that this is
121 the message that the response is for, we keep a sequence id
122 and increment it every time we send a message. */
123 long seqid;
124
125 /* This is held so we can properly respond to the message on a
126 timeout, and it is used to hold the temporary data for
127 retransmission, too. */
128 struct ipmi_recv_msg *recv_msg;
129};
130
131/* Store the information in a msgid (long) to allow us to find a
132 sequence table entry from the msgid. */
133#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
134
135#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
136 do { \
137 seq = ((msgid >> 26) & 0x3f); \
138 seqid = (msgid & 0x3fffff); \
Corey Minyarde8b33612005-09-06 15:18:45 -0700139 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
142
143struct ipmi_channel
144{
145 unsigned char medium;
146 unsigned char protocol;
Corey Minyardc14979b2005-09-06 15:18:38 -0700147
148 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
149 but may be changed by the user. */
150 unsigned char address;
151
152 /* My LUN. This should generally stay the SMS LUN, but just in
153 case... */
154 unsigned char lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155};
156
Corey Minyard3b625942005-06-23 22:01:42 -0700157#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158struct ipmi_proc_entry
159{
160 char *name;
161 struct ipmi_proc_entry *next;
162};
Corey Minyard3b625942005-06-23 22:01:42 -0700163#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Corey Minyard50c812b2006-03-26 01:37:21 -0800165struct bmc_device
166{
167 struct platform_device *dev;
168 struct ipmi_device_id id;
169 unsigned char guid[16];
170 int guid_set;
171
172 struct kref refcount;
173
174 /* bmc device attributes */
175 struct device_attribute device_id_attr;
176 struct device_attribute provides_dev_sdrs_attr;
177 struct device_attribute revision_attr;
178 struct device_attribute firmware_rev_attr;
179 struct device_attribute version_attr;
180 struct device_attribute add_dev_support_attr;
181 struct device_attribute manufacturer_id_attr;
182 struct device_attribute product_id_attr;
183 struct device_attribute guid_attr;
184 struct device_attribute aux_firmware_rev_attr;
185};
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187#define IPMI_IPMB_NUM_SEQ 64
Corey Minyardc14979b2005-09-06 15:18:38 -0700188#define IPMI_MAX_CHANNELS 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189struct ipmi_smi
190{
191 /* What interface number are we? */
192 int intf_num;
193
Corey Minyard393d2cc2005-11-07 00:59:54 -0800194 struct kref refcount;
195
196 /* The list of upper layers that are using me. seq_lock
197 * protects this. */
198 struct list_head users;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200 /* Used for wake ups at startup. */
201 wait_queue_head_t waitq;
202
Corey Minyard50c812b2006-03-26 01:37:21 -0800203 struct bmc_device *bmc;
204 char *my_dev_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206 /* This is the lower-layer's sender routine. */
207 struct ipmi_smi_handlers *handlers;
208 void *send_info;
209
Corey Minyard3b625942005-06-23 22:01:42 -0700210#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 /* A list of proc entries for this interface. This does not
212 need a lock, only one thread creates it and only one thread
213 destroys it. */
Corey Minyard3b625942005-06-23 22:01:42 -0700214 spinlock_t proc_entry_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 struct ipmi_proc_entry *proc_entries;
Corey Minyard3b625942005-06-23 22:01:42 -0700216#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Corey Minyard50c812b2006-03-26 01:37:21 -0800218 /* Driver-model device for the system interface. */
219 struct device *si_dev;
220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 /* A table of sequence numbers for this interface. We use the
222 sequence numbers for IPMB messages that go out of the
223 interface to match them up with their responses. A routine
224 is called periodically to time the items in this list. */
225 spinlock_t seq_lock;
226 struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
227 int curr_seq;
228
229 /* Messages that were delayed for some reason (out of memory,
230 for instance), will go in here to be processed later in a
231 periodic timer interrupt. */
232 spinlock_t waiting_msgs_lock;
233 struct list_head waiting_msgs;
234
235 /* The list of command receivers that are registered for commands
236 on this interface. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800237 struct mutex cmd_rcvrs_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 struct list_head cmd_rcvrs;
239
240 /* Events that were queues because no one was there to receive
241 them. */
242 spinlock_t events_lock; /* For dealing with event stuff. */
243 struct list_head waiting_events;
244 unsigned int waiting_events_count; /* How many events in queue? */
245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 /* The event receiver for my BMC, only really used at panic
247 shutdown as a place to store this. */
248 unsigned char event_receiver;
249 unsigned char event_receiver_lun;
250 unsigned char local_sel_device;
251 unsigned char local_event_generator;
252
253 /* A cheap hack, if this is non-null and a message to an
254 interface comes in with a NULL user, call this routine with
255 it. Note that the message will still be freed by the
256 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700257 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
259 /* When we are scanning the channels for an SMI, this will
260 tell which channel we are scanning. */
261 int curr_channel;
262
263 /* Channel information */
264 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
265
266 /* Proc FS stuff. */
267 struct proc_dir_entry *proc_dir;
268 char proc_dir_name[10];
269
270 spinlock_t counter_lock; /* For making counters atomic. */
271
272 /* Commands we got that were invalid. */
273 unsigned int sent_invalid_commands;
274
275 /* Commands we sent to the MC. */
276 unsigned int sent_local_commands;
277 /* Responses from the MC that were delivered to a user. */
278 unsigned int handled_local_responses;
279 /* Responses from the MC that were not delivered to a user. */
280 unsigned int unhandled_local_responses;
281
282 /* Commands we sent out to the IPMB bus. */
283 unsigned int sent_ipmb_commands;
284 /* Commands sent on the IPMB that had errors on the SEND CMD */
285 unsigned int sent_ipmb_command_errs;
286 /* Each retransmit increments this count. */
287 unsigned int retransmitted_ipmb_commands;
288 /* When a message times out (runs out of retransmits) this is
289 incremented. */
290 unsigned int timed_out_ipmb_commands;
291
292 /* This is like above, but for broadcasts. Broadcasts are
293 *not* included in the above count (they are expected to
294 time out). */
295 unsigned int timed_out_ipmb_broadcasts;
296
297 /* Responses I have sent to the IPMB bus. */
298 unsigned int sent_ipmb_responses;
299
300 /* The response was delivered to the user. */
301 unsigned int handled_ipmb_responses;
302 /* The response had invalid data in it. */
303 unsigned int invalid_ipmb_responses;
304 /* The response didn't have anyone waiting for it. */
305 unsigned int unhandled_ipmb_responses;
306
307 /* Commands we sent out to the IPMB bus. */
308 unsigned int sent_lan_commands;
309 /* Commands sent on the IPMB that had errors on the SEND CMD */
310 unsigned int sent_lan_command_errs;
311 /* Each retransmit increments this count. */
312 unsigned int retransmitted_lan_commands;
313 /* When a message times out (runs out of retransmits) this is
314 incremented. */
315 unsigned int timed_out_lan_commands;
316
317 /* Responses I have sent to the IPMB bus. */
318 unsigned int sent_lan_responses;
319
320 /* The response was delivered to the user. */
321 unsigned int handled_lan_responses;
322 /* The response had invalid data in it. */
323 unsigned int invalid_lan_responses;
324 /* The response didn't have anyone waiting for it. */
325 unsigned int unhandled_lan_responses;
326
327 /* The command was delivered to the user. */
328 unsigned int handled_commands;
329 /* The command had invalid data in it. */
330 unsigned int invalid_commands;
331 /* The command didn't have anyone waiting for it. */
332 unsigned int unhandled_commands;
333
334 /* Invalid data in an event. */
335 unsigned int invalid_events;
336 /* Events that were received with the proper format. */
337 unsigned int events;
338};
Corey Minyard50c812b2006-03-26 01:37:21 -0800339#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Corey Minyard393d2cc2005-11-07 00:59:54 -0800341/* Used to mark an interface entry that cannot be used but is not a
342 * free entry, either, primarily used at creation and deletion time so
343 * a slot doesn't get reused too quickly. */
344#define IPMI_INVALID_INTERFACE_ENTRY ((ipmi_smi_t) ((long) 1))
345#define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \
346 || (i == IPMI_INVALID_INTERFACE_ENTRY))
347
Corey Minyard50c812b2006-03-26 01:37:21 -0800348/**
349 * The driver model view of the IPMI messaging driver.
350 */
351static struct device_driver ipmidriver = {
352 .name = "ipmi",
353 .bus = &platform_bus_type
354};
355static DEFINE_MUTEX(ipmidriver_mutex);
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357#define MAX_IPMI_INTERFACES 4
358static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
359
Corey Minyard393d2cc2005-11-07 00:59:54 -0800360/* Directly protects the ipmi_interfaces data structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361static DEFINE_SPINLOCK(interfaces_lock);
362
363/* List of watchers that want to know when smi's are added and
364 deleted. */
365static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
366static DECLARE_RWSEM(smi_watchers_sem);
367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Corey Minyard393d2cc2005-11-07 00:59:54 -0800369static void free_recv_msg_list(struct list_head *q)
370{
371 struct ipmi_recv_msg *msg, *msg2;
372
373 list_for_each_entry_safe(msg, msg2, q, link) {
374 list_del(&msg->link);
375 ipmi_free_recv_msg(msg);
376 }
377}
378
379static void clean_up_interface_data(ipmi_smi_t intf)
380{
381 int i;
382 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800383 struct list_head list;
384
385 free_recv_msg_list(&intf->waiting_msgs);
386 free_recv_msg_list(&intf->waiting_events);
387
388 /* Wholesale remove all the entries from the list in the
389 * interface and wait for RCU to know that none are in use. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800390 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800391 list_add_rcu(&list, &intf->cmd_rcvrs);
392 list_del_rcu(&intf->cmd_rcvrs);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800393 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800394 synchronize_rcu();
395
396 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
397 kfree(rcvr);
398
399 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
400 if ((intf->seq_table[i].inuse)
401 && (intf->seq_table[i].recv_msg))
402 {
403 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
405 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800406}
407
408static void intf_free(struct kref *ref)
409{
410 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
411
412 clean_up_interface_data(intf);
413 kfree(intf);
414}
415
416int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
417{
418 int i;
419 unsigned long flags;
420
421 down_write(&smi_watchers_sem);
422 list_add(&(watcher->link), &smi_watchers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 up_write(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800424 spin_lock_irqsave(&interfaces_lock, flags);
425 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
426 ipmi_smi_t intf = ipmi_interfaces[i];
427 if (IPMI_INVALID_INTERFACE(intf))
428 continue;
429 spin_unlock_irqrestore(&interfaces_lock, flags);
Corey Minyard50c812b2006-03-26 01:37:21 -0800430 watcher->new_smi(i, intf->si_dev);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800431 spin_lock_irqsave(&interfaces_lock, flags);
432 }
433 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 return 0;
435}
436
437int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
438{
439 down_write(&smi_watchers_sem);
440 list_del(&(watcher->link));
441 up_write(&smi_watchers_sem);
442 return 0;
443}
444
445static void
Corey Minyard50c812b2006-03-26 01:37:21 -0800446call_smi_watchers(int i, struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
448 struct ipmi_smi_watcher *w;
449
450 down_read(&smi_watchers_sem);
451 list_for_each_entry(w, &smi_watchers, link) {
452 if (try_module_get(w->owner)) {
Corey Minyard50c812b2006-03-26 01:37:21 -0800453 w->new_smi(i, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 module_put(w->owner);
455 }
456 }
457 up_read(&smi_watchers_sem);
458}
459
460static int
461ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
462{
463 if (addr1->addr_type != addr2->addr_type)
464 return 0;
465
466 if (addr1->channel != addr2->channel)
467 return 0;
468
469 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
470 struct ipmi_system_interface_addr *smi_addr1
471 = (struct ipmi_system_interface_addr *) addr1;
472 struct ipmi_system_interface_addr *smi_addr2
473 = (struct ipmi_system_interface_addr *) addr2;
474 return (smi_addr1->lun == smi_addr2->lun);
475 }
476
477 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
478 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
479 {
480 struct ipmi_ipmb_addr *ipmb_addr1
481 = (struct ipmi_ipmb_addr *) addr1;
482 struct ipmi_ipmb_addr *ipmb_addr2
483 = (struct ipmi_ipmb_addr *) addr2;
484
485 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
486 && (ipmb_addr1->lun == ipmb_addr2->lun));
487 }
488
489 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
490 struct ipmi_lan_addr *lan_addr1
491 = (struct ipmi_lan_addr *) addr1;
492 struct ipmi_lan_addr *lan_addr2
493 = (struct ipmi_lan_addr *) addr2;
494
495 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
496 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
497 && (lan_addr1->session_handle
498 == lan_addr2->session_handle)
499 && (lan_addr1->lun == lan_addr2->lun));
500 }
501
502 return 1;
503}
504
505int ipmi_validate_addr(struct ipmi_addr *addr, int len)
506{
507 if (len < sizeof(struct ipmi_system_interface_addr)) {
508 return -EINVAL;
509 }
510
511 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
512 if (addr->channel != IPMI_BMC_CHANNEL)
513 return -EINVAL;
514 return 0;
515 }
516
517 if ((addr->channel == IPMI_BMC_CHANNEL)
Jayachandran C12fc1d72006-02-03 03:04:51 -0800518 || (addr->channel >= IPMI_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 || (addr->channel < 0))
520 return -EINVAL;
521
522 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
523 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
524 {
525 if (len < sizeof(struct ipmi_ipmb_addr)) {
526 return -EINVAL;
527 }
528 return 0;
529 }
530
531 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
532 if (len < sizeof(struct ipmi_lan_addr)) {
533 return -EINVAL;
534 }
535 return 0;
536 }
537
538 return -EINVAL;
539}
540
541unsigned int ipmi_addr_length(int addr_type)
542{
543 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
544 return sizeof(struct ipmi_system_interface_addr);
545
546 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
547 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
548 {
549 return sizeof(struct ipmi_ipmb_addr);
550 }
551
552 if (addr_type == IPMI_LAN_ADDR_TYPE)
553 return sizeof(struct ipmi_lan_addr);
554
555 return 0;
556}
557
558static void deliver_response(struct ipmi_recv_msg *msg)
559{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800560 if (!msg->user) {
Corey Minyard56a55ec2005-09-06 15:18:42 -0700561 ipmi_smi_t intf = msg->user_msg_data;
562 unsigned long flags;
563
564 /* Special handling for NULL users. */
565 if (intf->null_user_handler) {
566 intf->null_user_handler(intf, msg);
567 spin_lock_irqsave(&intf->counter_lock, flags);
568 intf->handled_local_responses++;
569 spin_unlock_irqrestore(&intf->counter_lock, flags);
570 } else {
571 /* No handler, so give up. */
572 spin_lock_irqsave(&intf->counter_lock, flags);
573 intf->unhandled_local_responses++;
574 spin_unlock_irqrestore(&intf->counter_lock, flags);
575 }
576 ipmi_free_recv_msg(msg);
577 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800578 ipmi_user_t user = msg->user;
579 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581}
582
583/* Find the next sequence number not being used and add the given
584 message with the given timeout to the sequence table. This must be
585 called with the interface's seq_lock held. */
586static int intf_next_seq(ipmi_smi_t intf,
587 struct ipmi_recv_msg *recv_msg,
588 unsigned long timeout,
589 int retries,
590 int broadcast,
591 unsigned char *seq,
592 long *seqid)
593{
594 int rv = 0;
595 unsigned int i;
596
Corey Minyarde8b33612005-09-06 15:18:45 -0700597 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700599 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800601 if (!intf->seq_table[i].inuse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 break;
603 }
604
Corey Minyard8a3628d2006-03-31 02:30:40 -0800605 if (!intf->seq_table[i].inuse) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 intf->seq_table[i].recv_msg = recv_msg;
607
608 /* Start with the maximum timeout, when the send response
609 comes in we will start the real timer. */
610 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
611 intf->seq_table[i].orig_timeout = timeout;
612 intf->seq_table[i].retries_left = retries;
613 intf->seq_table[i].broadcast = broadcast;
614 intf->seq_table[i].inuse = 1;
615 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
616 *seq = i;
617 *seqid = intf->seq_table[i].seqid;
618 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
619 } else {
620 rv = -EAGAIN;
621 }
622
623 return rv;
624}
625
626/* Return the receive message for the given sequence number and
627 release the sequence number so it can be reused. Some other data
628 is passed in to be sure the message matches up correctly (to help
629 guard against message coming in after their timeout and the
630 sequence number being reused). */
631static int intf_find_seq(ipmi_smi_t intf,
632 unsigned char seq,
633 short channel,
634 unsigned char cmd,
635 unsigned char netfn,
636 struct ipmi_addr *addr,
637 struct ipmi_recv_msg **recv_msg)
638{
639 int rv = -ENODEV;
640 unsigned long flags;
641
642 if (seq >= IPMI_IPMB_NUM_SEQ)
643 return -EINVAL;
644
645 spin_lock_irqsave(&(intf->seq_lock), flags);
646 if (intf->seq_table[seq].inuse) {
647 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
648
649 if ((msg->addr.channel == channel)
650 && (msg->msg.cmd == cmd)
651 && (msg->msg.netfn == netfn)
652 && (ipmi_addr_equal(addr, &(msg->addr))))
653 {
654 *recv_msg = msg;
655 intf->seq_table[seq].inuse = 0;
656 rv = 0;
657 }
658 }
659 spin_unlock_irqrestore(&(intf->seq_lock), flags);
660
661 return rv;
662}
663
664
665/* Start the timer for a specific sequence table entry. */
666static int intf_start_seq_timer(ipmi_smi_t intf,
667 long msgid)
668{
669 int rv = -ENODEV;
670 unsigned long flags;
671 unsigned char seq;
672 unsigned long seqid;
673
674
675 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
676
677 spin_lock_irqsave(&(intf->seq_lock), flags);
678 /* We do this verification because the user can be deleted
679 while a message is outstanding. */
680 if ((intf->seq_table[seq].inuse)
681 && (intf->seq_table[seq].seqid == seqid))
682 {
683 struct seq_table *ent = &(intf->seq_table[seq]);
684 ent->timeout = ent->orig_timeout;
685 rv = 0;
686 }
687 spin_unlock_irqrestore(&(intf->seq_lock), flags);
688
689 return rv;
690}
691
692/* Got an error for the send message for a specific sequence number. */
693static int intf_err_seq(ipmi_smi_t intf,
694 long msgid,
695 unsigned int err)
696{
697 int rv = -ENODEV;
698 unsigned long flags;
699 unsigned char seq;
700 unsigned long seqid;
701 struct ipmi_recv_msg *msg = NULL;
702
703
704 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
705
706 spin_lock_irqsave(&(intf->seq_lock), flags);
707 /* We do this verification because the user can be deleted
708 while a message is outstanding. */
709 if ((intf->seq_table[seq].inuse)
710 && (intf->seq_table[seq].seqid == seqid))
711 {
712 struct seq_table *ent = &(intf->seq_table[seq]);
713
714 ent->inuse = 0;
715 msg = ent->recv_msg;
716 rv = 0;
717 }
718 spin_unlock_irqrestore(&(intf->seq_lock), flags);
719
720 if (msg) {
721 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
722 msg->msg_data[0] = err;
723 msg->msg.netfn |= 1; /* Convert to a response. */
724 msg->msg.data_len = 1;
725 msg->msg.data = msg->msg_data;
726 deliver_response(msg);
727 }
728
729 return rv;
730}
731
732
733int ipmi_create_user(unsigned int if_num,
734 struct ipmi_user_hndl *handler,
735 void *handler_data,
736 ipmi_user_t *user)
737{
738 unsigned long flags;
739 ipmi_user_t new_user;
740 int rv = 0;
741 ipmi_smi_t intf;
742
743 /* There is no module usecount here, because it's not
744 required. Since this can only be used by and called from
745 other modules, they will implicitly use this module, and
746 thus this can't be removed unless the other modules are
747 removed. */
748
749 if (handler == NULL)
750 return -EINVAL;
751
752 /* Make sure the driver is actually initialized, this handles
753 problems with initialization order. */
754 if (!initialized) {
755 rv = ipmi_init_msghandler();
756 if (rv)
757 return rv;
758
759 /* The init code doesn't return an error if it was turned
760 off, but it won't initialize. Check that. */
761 if (!initialized)
762 return -ENODEV;
763 }
764
765 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800766 if (!new_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 return -ENOMEM;
768
Corey Minyard393d2cc2005-11-07 00:59:54 -0800769 spin_lock_irqsave(&interfaces_lock, flags);
770 intf = ipmi_interfaces[if_num];
771 if ((if_num >= MAX_IPMI_INTERFACES) || IPMI_INVALID_INTERFACE(intf)) {
772 spin_unlock_irqrestore(&interfaces_lock, flags);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800773 rv = -EINVAL;
774 goto out_kfree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
776
Corey Minyard393d2cc2005-11-07 00:59:54 -0800777 /* Note that each existing user holds a refcount to the interface. */
778 kref_get(&intf->refcount);
779 spin_unlock_irqrestore(&interfaces_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Corey Minyard393d2cc2005-11-07 00:59:54 -0800781 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 new_user->handler = handler;
783 new_user->handler_data = handler_data;
784 new_user->intf = intf;
785 new_user->gets_events = 0;
786
787 if (!try_module_get(intf->handlers->owner)) {
788 rv = -ENODEV;
Adrian Bunk5c98d292006-03-25 03:07:52 -0800789 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791
792 if (intf->handlers->inc_usecount) {
793 rv = intf->handlers->inc_usecount(intf->send_info);
794 if (rv) {
795 module_put(intf->handlers->owner);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800796 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 }
798 }
799
Corey Minyard393d2cc2005-11-07 00:59:54 -0800800 new_user->valid = 1;
801 spin_lock_irqsave(&intf->seq_lock, flags);
802 list_add_rcu(&new_user->link, &intf->users);
803 spin_unlock_irqrestore(&intf->seq_lock, flags);
804 *user = new_user;
805 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
Adrian Bunk5c98d292006-03-25 03:07:52 -0800807out_kref:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800808 kref_put(&intf->refcount, intf_free);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800809out_kfree:
810 kfree(new_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 return rv;
812}
813
Corey Minyard393d2cc2005-11-07 00:59:54 -0800814static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800816 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818}
819
820int ipmi_destroy_user(ipmi_user_t user)
821{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800822 ipmi_smi_t intf = user->intf;
823 int i;
824 unsigned long flags;
825 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800826 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Corey Minyard8a3628d2006-03-31 02:30:40 -0800828 user->valid = 0;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800829
830 /* Remove the user from the interface's sequence table. */
831 spin_lock_irqsave(&intf->seq_lock, flags);
832 list_del_rcu(&user->link);
833
834 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
835 if (intf->seq_table[i].inuse
836 && (intf->seq_table[i].recv_msg->user == user))
837 {
838 intf->seq_table[i].inuse = 0;
839 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800841 spin_unlock_irqrestore(&intf->seq_lock, flags);
842
843 /*
844 * Remove the user from the command receiver's table. First
845 * we build a list of everything (not using the standard link,
846 * since other things may be using it till we do
847 * synchronize_rcu()) then free everything in that list.
848 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800849 mutex_lock(&intf->cmd_rcvrs_mutex);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800850 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800851 if (rcvr->user == user) {
852 list_del_rcu(&rcvr->link);
853 rcvr->next = rcvrs;
854 rcvrs = rcvr;
855 }
856 }
Corey Minyardd6dfd132006-03-31 02:30:41 -0800857 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800858 synchronize_rcu();
859 while (rcvrs) {
860 rcvr = rcvrs;
861 rcvrs = rcvr->next;
862 kfree(rcvr);
863 }
864
865 module_put(intf->handlers->owner);
866 if (intf->handlers->dec_usecount)
867 intf->handlers->dec_usecount(intf->send_info);
868
869 kref_put(&intf->refcount, intf_free);
870
871 kref_put(&user->refcount, free_user);
872
Corey Minyard8a3628d2006-03-31 02:30:40 -0800873 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874}
875
876void ipmi_get_version(ipmi_user_t user,
877 unsigned char *major,
878 unsigned char *minor)
879{
Corey Minyard50c812b2006-03-26 01:37:21 -0800880 *major = ipmi_version_major(&user->intf->bmc->id);
881 *minor = ipmi_version_minor(&user->intf->bmc->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882}
883
Corey Minyardc14979b2005-09-06 15:18:38 -0700884int ipmi_set_my_address(ipmi_user_t user,
885 unsigned int channel,
886 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887{
Corey Minyardc14979b2005-09-06 15:18:38 -0700888 if (channel >= IPMI_MAX_CHANNELS)
889 return -EINVAL;
890 user->intf->channels[channel].address = address;
891 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892}
893
Corey Minyardc14979b2005-09-06 15:18:38 -0700894int ipmi_get_my_address(ipmi_user_t user,
895 unsigned int channel,
896 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897{
Corey Minyardc14979b2005-09-06 15:18:38 -0700898 if (channel >= IPMI_MAX_CHANNELS)
899 return -EINVAL;
900 *address = user->intf->channels[channel].address;
901 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902}
903
Corey Minyardc14979b2005-09-06 15:18:38 -0700904int ipmi_set_my_LUN(ipmi_user_t user,
905 unsigned int channel,
906 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907{
Corey Minyardc14979b2005-09-06 15:18:38 -0700908 if (channel >= IPMI_MAX_CHANNELS)
909 return -EINVAL;
910 user->intf->channels[channel].lun = LUN & 0x3;
911 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912}
913
Corey Minyardc14979b2005-09-06 15:18:38 -0700914int ipmi_get_my_LUN(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 *address = user->intf->channels[channel].lun;
921 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922}
923
924int ipmi_set_gets_events(ipmi_user_t user, int val)
925{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800926 unsigned long flags;
927 ipmi_smi_t intf = user->intf;
928 struct ipmi_recv_msg *msg, *msg2;
929 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
Corey Minyard393d2cc2005-11-07 00:59:54 -0800931 INIT_LIST_HEAD(&msgs);
932
933 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 user->gets_events = val;
935
936 if (val) {
937 /* Deliver any queued events. */
Akinobu Mita179e0912006-06-26 00:24:41 -0700938 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
939 list_move_tail(&msg->link, &msgs);
Corey Minyard4791c032006-04-10 22:54:31 -0700940 intf->waiting_events_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800942
943 /* Hold the events lock while doing this to preserve order. */
944 list_for_each_entry_safe(msg, msg2, &msgs, link) {
945 msg->user = user;
946 kref_get(&user->refcount);
947 deliver_response(msg);
948 }
949
950 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 return 0;
953}
954
Corey Minyard393d2cc2005-11-07 00:59:54 -0800955static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
956 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -0700957 unsigned char cmd,
958 unsigned char chan)
Corey Minyard393d2cc2005-11-07 00:59:54 -0800959{
960 struct cmd_rcvr *rcvr;
961
962 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyardc69c3122006-09-30 23:27:56 -0700963 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
964 && (rcvr->chans & (1 << chan)))
Corey Minyard393d2cc2005-11-07 00:59:54 -0800965 return rcvr;
966 }
967 return NULL;
968}
969
Corey Minyardc69c3122006-09-30 23:27:56 -0700970static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
971 unsigned char netfn,
972 unsigned char cmd,
973 unsigned int chans)
974{
975 struct cmd_rcvr *rcvr;
976
977 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
978 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
979 && (rcvr->chans & chans))
980 return 0;
981 }
982 return 1;
983}
984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985int ipmi_register_for_cmd(ipmi_user_t user,
986 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -0700987 unsigned char cmd,
988 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800990 ipmi_smi_t intf = user->intf;
991 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800992 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
994
995 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800996 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800998 rcvr->cmd = cmd;
999 rcvr->netfn = netfn;
Corey Minyardc69c3122006-09-30 23:27:56 -07001000 rcvr->chans = chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001001 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
Corey Minyardd6dfd132006-03-31 02:30:41 -08001003 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 /* Make sure the command/netfn is not already registered. */
Corey Minyardc69c3122006-09-30 23:27:56 -07001005 if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08001006 rv = -EBUSY;
1007 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 }
1009
Corey Minyard393d2cc2005-11-07 00:59:54 -08001010 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -07001011
Corey Minyard393d2cc2005-11-07 00:59:54 -08001012 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -08001013 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 if (rv)
1015 kfree(rcvr);
1016
1017 return rv;
1018}
1019
1020int ipmi_unregister_for_cmd(ipmi_user_t user,
1021 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001022 unsigned char cmd,
1023 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001025 ipmi_smi_t intf = user->intf;
1026 struct cmd_rcvr *rcvr;
Corey Minyardc69c3122006-09-30 23:27:56 -07001027 struct cmd_rcvr *rcvrs = NULL;
1028 int i, rv = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
Corey Minyardd6dfd132006-03-31 02:30:41 -08001030 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyardc69c3122006-09-30 23:27:56 -07001031 for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
1032 if (((1 << i) & chans) == 0)
1033 continue;
1034 rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
1035 if (rcvr == NULL)
1036 continue;
1037 if (rcvr->user == user) {
1038 rv = 0;
1039 rcvr->chans &= ~chans;
1040 if (rcvr->chans == 0) {
1041 list_del_rcu(&rcvr->link);
1042 rcvr->next = rcvrs;
1043 rcvrs = rcvr;
1044 }
1045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
Corey Minyardc69c3122006-09-30 23:27:56 -07001047 mutex_unlock(&intf->cmd_rcvrs_mutex);
1048 synchronize_rcu();
1049 while (rcvrs) {
1050 rcvr = rcvrs;
1051 rcvrs = rcvr->next;
1052 kfree(rcvr);
1053 }
1054 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055}
1056
1057void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
1058{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001059 ipmi_smi_t intf = user->intf;
1060 intf->handlers->set_run_to_completion(intf->send_info, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061}
1062
1063static unsigned char
1064ipmb_checksum(unsigned char *data, int size)
1065{
1066 unsigned char csum = 0;
1067
1068 for (; size > 0; size--, data++)
1069 csum += *data;
1070
1071 return -csum;
1072}
1073
1074static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1075 struct kernel_ipmi_msg *msg,
1076 struct ipmi_ipmb_addr *ipmb_addr,
1077 long msgid,
1078 unsigned char ipmb_seq,
1079 int broadcast,
1080 unsigned char source_address,
1081 unsigned char source_lun)
1082{
1083 int i = broadcast;
1084
1085 /* Format the IPMB header data. */
1086 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1087 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1088 smi_msg->data[2] = ipmb_addr->channel;
1089 if (broadcast)
1090 smi_msg->data[3] = 0;
1091 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1092 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1093 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1094 smi_msg->data[i+6] = source_address;
1095 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1096 smi_msg->data[i+8] = msg->cmd;
1097
1098 /* Now tack on the data to the message. */
1099 if (msg->data_len > 0)
1100 memcpy(&(smi_msg->data[i+9]), msg->data,
1101 msg->data_len);
1102 smi_msg->data_size = msg->data_len + 9;
1103
1104 /* Now calculate the checksum and tack it on. */
1105 smi_msg->data[i+smi_msg->data_size]
1106 = ipmb_checksum(&(smi_msg->data[i+6]),
1107 smi_msg->data_size-6);
1108
1109 /* Add on the checksum size and the offset from the
1110 broadcast. */
1111 smi_msg->data_size += 1 + i;
1112
1113 smi_msg->msgid = msgid;
1114}
1115
1116static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1117 struct kernel_ipmi_msg *msg,
1118 struct ipmi_lan_addr *lan_addr,
1119 long msgid,
1120 unsigned char ipmb_seq,
1121 unsigned char source_lun)
1122{
1123 /* Format the IPMB header data. */
1124 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1125 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1126 smi_msg->data[2] = lan_addr->channel;
1127 smi_msg->data[3] = lan_addr->session_handle;
1128 smi_msg->data[4] = lan_addr->remote_SWID;
1129 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1130 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1131 smi_msg->data[7] = lan_addr->local_SWID;
1132 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1133 smi_msg->data[9] = msg->cmd;
1134
1135 /* Now tack on the data to the message. */
1136 if (msg->data_len > 0)
1137 memcpy(&(smi_msg->data[10]), msg->data,
1138 msg->data_len);
1139 smi_msg->data_size = msg->data_len + 10;
1140
1141 /* Now calculate the checksum and tack it on. */
1142 smi_msg->data[smi_msg->data_size]
1143 = ipmb_checksum(&(smi_msg->data[7]),
1144 smi_msg->data_size-7);
1145
1146 /* Add on the checksum size and the offset from the
1147 broadcast. */
1148 smi_msg->data_size += 1;
1149
1150 smi_msg->msgid = msgid;
1151}
1152
1153/* Separate from ipmi_request so that the user does not have to be
1154 supplied in certain circumstances (mainly at panic time). If
1155 messages are supplied, they will be freed, even if an error
1156 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001157static int i_ipmi_request(ipmi_user_t user,
1158 ipmi_smi_t intf,
1159 struct ipmi_addr *addr,
1160 long msgid,
1161 struct kernel_ipmi_msg *msg,
1162 void *user_msg_data,
1163 void *supplied_smi,
1164 struct ipmi_recv_msg *supplied_recv,
1165 int priority,
1166 unsigned char source_address,
1167 unsigned char source_lun,
1168 int retries,
1169 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170{
1171 int rv = 0;
1172 struct ipmi_smi_msg *smi_msg;
1173 struct ipmi_recv_msg *recv_msg;
1174 unsigned long flags;
1175
1176
1177 if (supplied_recv) {
1178 recv_msg = supplied_recv;
1179 } else {
1180 recv_msg = ipmi_alloc_recv_msg();
1181 if (recv_msg == NULL) {
1182 return -ENOMEM;
1183 }
1184 }
1185 recv_msg->user_msg_data = user_msg_data;
1186
1187 if (supplied_smi) {
1188 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1189 } else {
1190 smi_msg = ipmi_alloc_smi_msg();
1191 if (smi_msg == NULL) {
1192 ipmi_free_recv_msg(recv_msg);
1193 return -ENOMEM;
1194 }
1195 }
1196
1197 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001198 if (user)
1199 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 recv_msg->msgid = msgid;
1201 /* Store the message to send in the receive message so timeout
1202 responses can get the proper response data. */
1203 recv_msg->msg = *msg;
1204
1205 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1206 struct ipmi_system_interface_addr *smi_addr;
1207
1208 if (msg->netfn & 1) {
1209 /* Responses are not allowed to the SMI. */
1210 rv = -EINVAL;
1211 goto out_err;
1212 }
1213
1214 smi_addr = (struct ipmi_system_interface_addr *) addr;
1215 if (smi_addr->lun > 3) {
1216 spin_lock_irqsave(&intf->counter_lock, flags);
1217 intf->sent_invalid_commands++;
1218 spin_unlock_irqrestore(&intf->counter_lock, flags);
1219 rv = -EINVAL;
1220 goto out_err;
1221 }
1222
1223 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1224
1225 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1226 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1227 || (msg->cmd == IPMI_GET_MSG_CMD)
1228 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1229 {
1230 /* We don't let the user do these, since we manage
1231 the sequence numbers. */
1232 spin_lock_irqsave(&intf->counter_lock, flags);
1233 intf->sent_invalid_commands++;
1234 spin_unlock_irqrestore(&intf->counter_lock, flags);
1235 rv = -EINVAL;
1236 goto out_err;
1237 }
1238
1239 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1240 spin_lock_irqsave(&intf->counter_lock, flags);
1241 intf->sent_invalid_commands++;
1242 spin_unlock_irqrestore(&intf->counter_lock, flags);
1243 rv = -EMSGSIZE;
1244 goto out_err;
1245 }
1246
1247 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1248 smi_msg->data[1] = msg->cmd;
1249 smi_msg->msgid = msgid;
1250 smi_msg->user_data = recv_msg;
1251 if (msg->data_len > 0)
1252 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1253 smi_msg->data_size = msg->data_len + 2;
1254 spin_lock_irqsave(&intf->counter_lock, flags);
1255 intf->sent_local_commands++;
1256 spin_unlock_irqrestore(&intf->counter_lock, flags);
1257 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1258 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1259 {
1260 struct ipmi_ipmb_addr *ipmb_addr;
1261 unsigned char ipmb_seq;
1262 long seqid;
1263 int broadcast = 0;
1264
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001265 if (addr->channel >= IPMI_MAX_CHANNELS) {
1266 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 intf->sent_invalid_commands++;
1268 spin_unlock_irqrestore(&intf->counter_lock, flags);
1269 rv = -EINVAL;
1270 goto out_err;
1271 }
1272
1273 if (intf->channels[addr->channel].medium
1274 != IPMI_CHANNEL_MEDIUM_IPMB)
1275 {
1276 spin_lock_irqsave(&intf->counter_lock, flags);
1277 intf->sent_invalid_commands++;
1278 spin_unlock_irqrestore(&intf->counter_lock, flags);
1279 rv = -EINVAL;
1280 goto out_err;
1281 }
1282
1283 if (retries < 0) {
1284 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1285 retries = 0; /* Don't retry broadcasts. */
1286 else
1287 retries = 4;
1288 }
1289 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1290 /* Broadcasts add a zero at the beginning of the
1291 message, but otherwise is the same as an IPMB
1292 address. */
1293 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1294 broadcast = 1;
1295 }
1296
1297
1298 /* Default to 1 second retries. */
1299 if (retry_time_ms == 0)
1300 retry_time_ms = 1000;
1301
1302 /* 9 for the header and 1 for the checksum, plus
1303 possibly one for the broadcast. */
1304 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1305 spin_lock_irqsave(&intf->counter_lock, flags);
1306 intf->sent_invalid_commands++;
1307 spin_unlock_irqrestore(&intf->counter_lock, flags);
1308 rv = -EMSGSIZE;
1309 goto out_err;
1310 }
1311
1312 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1313 if (ipmb_addr->lun > 3) {
1314 spin_lock_irqsave(&intf->counter_lock, flags);
1315 intf->sent_invalid_commands++;
1316 spin_unlock_irqrestore(&intf->counter_lock, flags);
1317 rv = -EINVAL;
1318 goto out_err;
1319 }
1320
1321 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1322
1323 if (recv_msg->msg.netfn & 0x1) {
1324 /* It's a response, so use the user's sequence
1325 from msgid. */
1326 spin_lock_irqsave(&intf->counter_lock, flags);
1327 intf->sent_ipmb_responses++;
1328 spin_unlock_irqrestore(&intf->counter_lock, flags);
1329 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1330 msgid, broadcast,
1331 source_address, source_lun);
1332
1333 /* Save the receive message so we can use it
1334 to deliver the response. */
1335 smi_msg->user_data = recv_msg;
1336 } else {
1337 /* It's a command, so get a sequence for it. */
1338
1339 spin_lock_irqsave(&(intf->seq_lock), flags);
1340
1341 spin_lock(&intf->counter_lock);
1342 intf->sent_ipmb_commands++;
1343 spin_unlock(&intf->counter_lock);
1344
1345 /* Create a sequence number with a 1 second
1346 timeout and 4 retries. */
1347 rv = intf_next_seq(intf,
1348 recv_msg,
1349 retry_time_ms,
1350 retries,
1351 broadcast,
1352 &ipmb_seq,
1353 &seqid);
1354 if (rv) {
1355 /* We have used up all the sequence numbers,
1356 probably, so abort. */
1357 spin_unlock_irqrestore(&(intf->seq_lock),
1358 flags);
1359 goto out_err;
1360 }
1361
1362 /* Store the sequence number in the message,
1363 so that when the send message response
1364 comes back we can start the timer. */
1365 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1366 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1367 ipmb_seq, broadcast,
1368 source_address, source_lun);
1369
1370 /* Copy the message into the recv message data, so we
1371 can retransmit it later if necessary. */
1372 memcpy(recv_msg->msg_data, smi_msg->data,
1373 smi_msg->data_size);
1374 recv_msg->msg.data = recv_msg->msg_data;
1375 recv_msg->msg.data_len = smi_msg->data_size;
1376
1377 /* We don't unlock until here, because we need
1378 to copy the completed message into the
1379 recv_msg before we release the lock.
1380 Otherwise, race conditions may bite us. I
1381 know that's pretty paranoid, but I prefer
1382 to be correct. */
1383 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1384 }
1385 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1386 struct ipmi_lan_addr *lan_addr;
1387 unsigned char ipmb_seq;
1388 long seqid;
1389
Jayachandran C12fc1d72006-02-03 03:04:51 -08001390 if (addr->channel >= IPMI_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 spin_lock_irqsave(&intf->counter_lock, flags);
1392 intf->sent_invalid_commands++;
1393 spin_unlock_irqrestore(&intf->counter_lock, flags);
1394 rv = -EINVAL;
1395 goto out_err;
1396 }
1397
1398 if ((intf->channels[addr->channel].medium
1399 != IPMI_CHANNEL_MEDIUM_8023LAN)
1400 && (intf->channels[addr->channel].medium
1401 != IPMI_CHANNEL_MEDIUM_ASYNC))
1402 {
1403 spin_lock_irqsave(&intf->counter_lock, flags);
1404 intf->sent_invalid_commands++;
1405 spin_unlock_irqrestore(&intf->counter_lock, flags);
1406 rv = -EINVAL;
1407 goto out_err;
1408 }
1409
1410 retries = 4;
1411
1412 /* Default to 1 second retries. */
1413 if (retry_time_ms == 0)
1414 retry_time_ms = 1000;
1415
1416 /* 11 for the header and 1 for the checksum. */
1417 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1418 spin_lock_irqsave(&intf->counter_lock, flags);
1419 intf->sent_invalid_commands++;
1420 spin_unlock_irqrestore(&intf->counter_lock, flags);
1421 rv = -EMSGSIZE;
1422 goto out_err;
1423 }
1424
1425 lan_addr = (struct ipmi_lan_addr *) addr;
1426 if (lan_addr->lun > 3) {
1427 spin_lock_irqsave(&intf->counter_lock, flags);
1428 intf->sent_invalid_commands++;
1429 spin_unlock_irqrestore(&intf->counter_lock, flags);
1430 rv = -EINVAL;
1431 goto out_err;
1432 }
1433
1434 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1435
1436 if (recv_msg->msg.netfn & 0x1) {
1437 /* It's a response, so use the user's sequence
1438 from msgid. */
1439 spin_lock_irqsave(&intf->counter_lock, flags);
1440 intf->sent_lan_responses++;
1441 spin_unlock_irqrestore(&intf->counter_lock, flags);
1442 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1443 msgid, source_lun);
1444
1445 /* Save the receive message so we can use it
1446 to deliver the response. */
1447 smi_msg->user_data = recv_msg;
1448 } else {
1449 /* It's a command, so get a sequence for it. */
1450
1451 spin_lock_irqsave(&(intf->seq_lock), flags);
1452
1453 spin_lock(&intf->counter_lock);
1454 intf->sent_lan_commands++;
1455 spin_unlock(&intf->counter_lock);
1456
1457 /* Create a sequence number with a 1 second
1458 timeout and 4 retries. */
1459 rv = intf_next_seq(intf,
1460 recv_msg,
1461 retry_time_ms,
1462 retries,
1463 0,
1464 &ipmb_seq,
1465 &seqid);
1466 if (rv) {
1467 /* We have used up all the sequence numbers,
1468 probably, so abort. */
1469 spin_unlock_irqrestore(&(intf->seq_lock),
1470 flags);
1471 goto out_err;
1472 }
1473
1474 /* Store the sequence number in the message,
1475 so that when the send message response
1476 comes back we can start the timer. */
1477 format_lan_msg(smi_msg, msg, lan_addr,
1478 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1479 ipmb_seq, source_lun);
1480
1481 /* Copy the message into the recv message data, so we
1482 can retransmit it later if necessary. */
1483 memcpy(recv_msg->msg_data, smi_msg->data,
1484 smi_msg->data_size);
1485 recv_msg->msg.data = recv_msg->msg_data;
1486 recv_msg->msg.data_len = smi_msg->data_size;
1487
1488 /* We don't unlock until here, because we need
1489 to copy the completed message into the
1490 recv_msg before we release the lock.
1491 Otherwise, race conditions may bite us. I
1492 know that's pretty paranoid, but I prefer
1493 to be correct. */
1494 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1495 }
1496 } else {
1497 /* Unknown address type. */
1498 spin_lock_irqsave(&intf->counter_lock, flags);
1499 intf->sent_invalid_commands++;
1500 spin_unlock_irqrestore(&intf->counter_lock, flags);
1501 rv = -EINVAL;
1502 goto out_err;
1503 }
1504
1505#ifdef DEBUG_MSGING
1506 {
1507 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001508 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 printk(" %2.2x", smi_msg->data[m]);
1510 printk("\n");
1511 }
1512#endif
1513 intf->handlers->sender(intf->send_info, smi_msg, priority);
1514
1515 return 0;
1516
1517 out_err:
1518 ipmi_free_smi_msg(smi_msg);
1519 ipmi_free_recv_msg(recv_msg);
1520 return rv;
1521}
1522
Corey Minyardc14979b2005-09-06 15:18:38 -07001523static int check_addr(ipmi_smi_t intf,
1524 struct ipmi_addr *addr,
1525 unsigned char *saddr,
1526 unsigned char *lun)
1527{
1528 if (addr->channel >= IPMI_MAX_CHANNELS)
1529 return -EINVAL;
1530 *lun = intf->channels[addr->channel].lun;
1531 *saddr = intf->channels[addr->channel].address;
1532 return 0;
1533}
1534
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535int ipmi_request_settime(ipmi_user_t user,
1536 struct ipmi_addr *addr,
1537 long msgid,
1538 struct kernel_ipmi_msg *msg,
1539 void *user_msg_data,
1540 int priority,
1541 int retries,
1542 unsigned int retry_time_ms)
1543{
Corey Minyardc14979b2005-09-06 15:18:38 -07001544 unsigned char saddr, lun;
1545 int rv;
1546
Corey Minyard8a3628d2006-03-31 02:30:40 -08001547 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001548 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001549 rv = check_addr(user->intf, addr, &saddr, &lun);
1550 if (rv)
1551 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 return i_ipmi_request(user,
1553 user->intf,
1554 addr,
1555 msgid,
1556 msg,
1557 user_msg_data,
1558 NULL, NULL,
1559 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001560 saddr,
1561 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 retries,
1563 retry_time_ms);
1564}
1565
1566int ipmi_request_supply_msgs(ipmi_user_t user,
1567 struct ipmi_addr *addr,
1568 long msgid,
1569 struct kernel_ipmi_msg *msg,
1570 void *user_msg_data,
1571 void *supplied_smi,
1572 struct ipmi_recv_msg *supplied_recv,
1573 int priority)
1574{
Corey Minyardc14979b2005-09-06 15:18:38 -07001575 unsigned char saddr, lun;
1576 int rv;
1577
Corey Minyard8a3628d2006-03-31 02:30:40 -08001578 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001579 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001580 rv = check_addr(user->intf, addr, &saddr, &lun);
1581 if (rv)
1582 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 return i_ipmi_request(user,
1584 user->intf,
1585 addr,
1586 msgid,
1587 msg,
1588 user_msg_data,
1589 supplied_smi,
1590 supplied_recv,
1591 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001592 saddr,
1593 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 -1, 0);
1595}
1596
1597static int ipmb_file_read_proc(char *page, char **start, off_t off,
1598 int count, int *eof, void *data)
1599{
1600 char *out = (char *) page;
1601 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001602 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001603 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
Corey Minyarde8b33612005-09-06 15:18:45 -07001605 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001606 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1607 out[rv-1] = '\n'; /* Replace the final space with a newline */
1608 out[rv] = '\0';
1609 rv++;
1610 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611}
1612
1613static int version_file_read_proc(char *page, char **start, off_t off,
1614 int count, int *eof, void *data)
1615{
1616 char *out = (char *) page;
1617 ipmi_smi_t intf = data;
1618
1619 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001620 ipmi_version_major(&intf->bmc->id),
1621 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622}
1623
1624static int stat_file_read_proc(char *page, char **start, off_t off,
1625 int count, int *eof, void *data)
1626{
1627 char *out = (char *) page;
1628 ipmi_smi_t intf = data;
1629
1630 out += sprintf(out, "sent_invalid_commands: %d\n",
1631 intf->sent_invalid_commands);
1632 out += sprintf(out, "sent_local_commands: %d\n",
1633 intf->sent_local_commands);
1634 out += sprintf(out, "handled_local_responses: %d\n",
1635 intf->handled_local_responses);
1636 out += sprintf(out, "unhandled_local_responses: %d\n",
1637 intf->unhandled_local_responses);
1638 out += sprintf(out, "sent_ipmb_commands: %d\n",
1639 intf->sent_ipmb_commands);
1640 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1641 intf->sent_ipmb_command_errs);
1642 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1643 intf->retransmitted_ipmb_commands);
1644 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1645 intf->timed_out_ipmb_commands);
1646 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1647 intf->timed_out_ipmb_broadcasts);
1648 out += sprintf(out, "sent_ipmb_responses: %d\n",
1649 intf->sent_ipmb_responses);
1650 out += sprintf(out, "handled_ipmb_responses: %d\n",
1651 intf->handled_ipmb_responses);
1652 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1653 intf->invalid_ipmb_responses);
1654 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1655 intf->unhandled_ipmb_responses);
1656 out += sprintf(out, "sent_lan_commands: %d\n",
1657 intf->sent_lan_commands);
1658 out += sprintf(out, "sent_lan_command_errs: %d\n",
1659 intf->sent_lan_command_errs);
1660 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1661 intf->retransmitted_lan_commands);
1662 out += sprintf(out, "timed_out_lan_commands: %d\n",
1663 intf->timed_out_lan_commands);
1664 out += sprintf(out, "sent_lan_responses: %d\n",
1665 intf->sent_lan_responses);
1666 out += sprintf(out, "handled_lan_responses: %d\n",
1667 intf->handled_lan_responses);
1668 out += sprintf(out, "invalid_lan_responses: %d\n",
1669 intf->invalid_lan_responses);
1670 out += sprintf(out, "unhandled_lan_responses: %d\n",
1671 intf->unhandled_lan_responses);
1672 out += sprintf(out, "handled_commands: %d\n",
1673 intf->handled_commands);
1674 out += sprintf(out, "invalid_commands: %d\n",
1675 intf->invalid_commands);
1676 out += sprintf(out, "unhandled_commands: %d\n",
1677 intf->unhandled_commands);
1678 out += sprintf(out, "invalid_events: %d\n",
1679 intf->invalid_events);
1680 out += sprintf(out, "events: %d\n",
1681 intf->events);
1682
1683 return (out - ((char *) page));
1684}
1685
1686int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1687 read_proc_t *read_proc, write_proc_t *write_proc,
1688 void *data, struct module *owner)
1689{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001691#ifdef CONFIG_PROC_FS
1692 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 struct ipmi_proc_entry *entry;
1694
1695 /* Create a list element. */
1696 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1697 if (!entry)
1698 return -ENOMEM;
1699 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1700 if (!entry->name) {
1701 kfree(entry);
1702 return -ENOMEM;
1703 }
1704 strcpy(entry->name, name);
1705
1706 file = create_proc_entry(name, 0, smi->proc_dir);
1707 if (!file) {
1708 kfree(entry->name);
1709 kfree(entry);
1710 rv = -ENOMEM;
1711 } else {
1712 file->nlink = 1;
1713 file->data = data;
1714 file->read_proc = read_proc;
1715 file->write_proc = write_proc;
1716 file->owner = owner;
1717
Corey Minyard3b625942005-06-23 22:01:42 -07001718 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 /* Stick it on the list. */
1720 entry->next = smi->proc_entries;
1721 smi->proc_entries = entry;
Corey Minyard3b625942005-06-23 22:01:42 -07001722 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 }
Corey Minyard3b625942005-06-23 22:01:42 -07001724#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
1726 return rv;
1727}
1728
1729static int add_proc_entries(ipmi_smi_t smi, int num)
1730{
1731 int rv = 0;
1732
Corey Minyard3b625942005-06-23 22:01:42 -07001733#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 sprintf(smi->proc_dir_name, "%d", num);
1735 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1736 if (!smi->proc_dir)
1737 rv = -ENOMEM;
1738 else {
1739 smi->proc_dir->owner = THIS_MODULE;
1740 }
1741
1742 if (rv == 0)
1743 rv = ipmi_smi_add_proc_entry(smi, "stats",
1744 stat_file_read_proc, NULL,
1745 smi, THIS_MODULE);
1746
1747 if (rv == 0)
1748 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1749 ipmb_file_read_proc, NULL,
1750 smi, THIS_MODULE);
1751
1752 if (rv == 0)
1753 rv = ipmi_smi_add_proc_entry(smi, "version",
1754 version_file_read_proc, NULL,
1755 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001756#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
1758 return rv;
1759}
1760
1761static void remove_proc_entries(ipmi_smi_t smi)
1762{
Corey Minyard3b625942005-06-23 22:01:42 -07001763#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 struct ipmi_proc_entry *entry;
1765
Corey Minyard3b625942005-06-23 22:01:42 -07001766 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 while (smi->proc_entries) {
1768 entry = smi->proc_entries;
1769 smi->proc_entries = entry->next;
1770
1771 remove_proc_entry(entry->name, smi->proc_dir);
1772 kfree(entry->name);
1773 kfree(entry);
1774 }
Corey Minyard3b625942005-06-23 22:01:42 -07001775 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001777#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778}
1779
Corey Minyard50c812b2006-03-26 01:37:21 -08001780static int __find_bmc_guid(struct device *dev, void *data)
1781{
1782 unsigned char *id = data;
1783 struct bmc_device *bmc = dev_get_drvdata(dev);
1784 return memcmp(bmc->guid, id, 16) == 0;
1785}
1786
1787static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1788 unsigned char *guid)
1789{
1790 struct device *dev;
1791
1792 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1793 if (dev)
1794 return dev_get_drvdata(dev);
1795 else
1796 return NULL;
1797}
1798
1799struct prod_dev_id {
1800 unsigned int product_id;
1801 unsigned char device_id;
1802};
1803
1804static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1805{
1806 struct prod_dev_id *id = data;
1807 struct bmc_device *bmc = dev_get_drvdata(dev);
1808
1809 return (bmc->id.product_id == id->product_id
1810 && bmc->id.product_id == id->product_id
1811 && bmc->id.device_id == id->device_id);
1812}
1813
1814static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1815 struct device_driver *drv,
1816 unsigned char product_id, unsigned char device_id)
1817{
1818 struct prod_dev_id id = {
1819 .product_id = product_id,
1820 .device_id = device_id,
1821 };
1822 struct device *dev;
1823
1824 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
1825 if (dev)
1826 return dev_get_drvdata(dev);
1827 else
1828 return NULL;
1829}
1830
1831static ssize_t device_id_show(struct device *dev,
1832 struct device_attribute *attr,
1833 char *buf)
1834{
1835 struct bmc_device *bmc = dev_get_drvdata(dev);
1836
1837 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
1838}
1839
1840static ssize_t provides_dev_sdrs_show(struct device *dev,
1841 struct device_attribute *attr,
1842 char *buf)
1843{
1844 struct bmc_device *bmc = dev_get_drvdata(dev);
1845
1846 return snprintf(buf, 10, "%u\n",
1847 bmc->id.device_revision && 0x80 >> 7);
1848}
1849
1850static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
1851 char *buf)
1852{
1853 struct bmc_device *bmc = dev_get_drvdata(dev);
1854
1855 return snprintf(buf, 20, "%u\n",
1856 bmc->id.device_revision && 0x0F);
1857}
1858
1859static ssize_t firmware_rev_show(struct device *dev,
1860 struct device_attribute *attr,
1861 char *buf)
1862{
1863 struct bmc_device *bmc = dev_get_drvdata(dev);
1864
1865 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
1866 bmc->id.firmware_revision_2);
1867}
1868
1869static ssize_t ipmi_version_show(struct device *dev,
1870 struct device_attribute *attr,
1871 char *buf)
1872{
1873 struct bmc_device *bmc = dev_get_drvdata(dev);
1874
1875 return snprintf(buf, 20, "%u.%u\n",
1876 ipmi_version_major(&bmc->id),
1877 ipmi_version_minor(&bmc->id));
1878}
1879
1880static ssize_t add_dev_support_show(struct device *dev,
1881 struct device_attribute *attr,
1882 char *buf)
1883{
1884 struct bmc_device *bmc = dev_get_drvdata(dev);
1885
1886 return snprintf(buf, 10, "0x%02x\n",
1887 bmc->id.additional_device_support);
1888}
1889
1890static ssize_t manufacturer_id_show(struct device *dev,
1891 struct device_attribute *attr,
1892 char *buf)
1893{
1894 struct bmc_device *bmc = dev_get_drvdata(dev);
1895
1896 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
1897}
1898
1899static ssize_t product_id_show(struct device *dev,
1900 struct device_attribute *attr,
1901 char *buf)
1902{
1903 struct bmc_device *bmc = dev_get_drvdata(dev);
1904
1905 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
1906}
1907
1908static ssize_t aux_firmware_rev_show(struct device *dev,
1909 struct device_attribute *attr,
1910 char *buf)
1911{
1912 struct bmc_device *bmc = dev_get_drvdata(dev);
1913
1914 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
1915 bmc->id.aux_firmware_revision[3],
1916 bmc->id.aux_firmware_revision[2],
1917 bmc->id.aux_firmware_revision[1],
1918 bmc->id.aux_firmware_revision[0]);
1919}
1920
1921static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
1922 char *buf)
1923{
1924 struct bmc_device *bmc = dev_get_drvdata(dev);
1925
1926 return snprintf(buf, 100, "%Lx%Lx\n",
1927 (long long) bmc->guid[0],
1928 (long long) bmc->guid[8]);
1929}
1930
Jeff Garzik5e593932006-10-11 01:22:21 -07001931static void remove_files(struct bmc_device *bmc)
Corey Minyard50c812b2006-03-26 01:37:21 -08001932{
Corey Minyard50c812b2006-03-26 01:37:21 -08001933 device_remove_file(&bmc->dev->dev,
1934 &bmc->device_id_attr);
1935 device_remove_file(&bmc->dev->dev,
1936 &bmc->provides_dev_sdrs_attr);
1937 device_remove_file(&bmc->dev->dev,
1938 &bmc->revision_attr);
1939 device_remove_file(&bmc->dev->dev,
1940 &bmc->firmware_rev_attr);
1941 device_remove_file(&bmc->dev->dev,
1942 &bmc->version_attr);
1943 device_remove_file(&bmc->dev->dev,
1944 &bmc->add_dev_support_attr);
1945 device_remove_file(&bmc->dev->dev,
1946 &bmc->manufacturer_id_attr);
1947 device_remove_file(&bmc->dev->dev,
1948 &bmc->product_id_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07001949
Corey Minyard50c812b2006-03-26 01:37:21 -08001950 if (bmc->id.aux_firmware_revision_set)
1951 device_remove_file(&bmc->dev->dev,
1952 &bmc->aux_firmware_rev_attr);
1953 if (bmc->guid_set)
1954 device_remove_file(&bmc->dev->dev,
1955 &bmc->guid_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07001956}
1957
1958static void
1959cleanup_bmc_device(struct kref *ref)
1960{
1961 struct bmc_device *bmc;
1962
1963 bmc = container_of(ref, struct bmc_device, refcount);
1964
1965 remove_files(bmc);
Corey Minyard50c812b2006-03-26 01:37:21 -08001966 platform_device_unregister(bmc->dev);
1967 kfree(bmc);
1968}
1969
1970static void ipmi_bmc_unregister(ipmi_smi_t intf)
1971{
1972 struct bmc_device *bmc = intf->bmc;
1973
1974 sysfs_remove_link(&intf->si_dev->kobj, "bmc");
1975 if (intf->my_dev_name) {
1976 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
1977 kfree(intf->my_dev_name);
1978 intf->my_dev_name = NULL;
1979 }
1980
1981 mutex_lock(&ipmidriver_mutex);
1982 kref_put(&bmc->refcount, cleanup_bmc_device);
1983 mutex_unlock(&ipmidriver_mutex);
1984}
1985
Jeff Garzik5e593932006-10-11 01:22:21 -07001986static int create_files(struct bmc_device *bmc)
1987{
1988 int err;
1989
1990 err = device_create_file(&bmc->dev->dev,
1991 &bmc->device_id_attr);
1992 if (err) goto out;
1993 err = device_create_file(&bmc->dev->dev,
1994 &bmc->provides_dev_sdrs_attr);
1995 if (err) goto out_devid;
1996 err = device_create_file(&bmc->dev->dev,
1997 &bmc->revision_attr);
1998 if (err) goto out_sdrs;
1999 err = device_create_file(&bmc->dev->dev,
2000 &bmc->firmware_rev_attr);
2001 if (err) goto out_rev;
2002 err = device_create_file(&bmc->dev->dev,
2003 &bmc->version_attr);
2004 if (err) goto out_firm;
2005 err = device_create_file(&bmc->dev->dev,
2006 &bmc->add_dev_support_attr);
2007 if (err) goto out_version;
2008 err = device_create_file(&bmc->dev->dev,
2009 &bmc->manufacturer_id_attr);
2010 if (err) goto out_add_dev;
2011 err = device_create_file(&bmc->dev->dev,
2012 &bmc->product_id_attr);
2013 if (err) goto out_manu;
2014 if (bmc->id.aux_firmware_revision_set) {
2015 err = device_create_file(&bmc->dev->dev,
2016 &bmc->aux_firmware_rev_attr);
2017 if (err) goto out_prod_id;
2018 }
2019 if (bmc->guid_set) {
2020 err = device_create_file(&bmc->dev->dev,
2021 &bmc->guid_attr);
2022 if (err) goto out_aux_firm;
2023 }
2024
2025 return 0;
2026
2027out_aux_firm:
2028 if (bmc->id.aux_firmware_revision_set)
2029 device_remove_file(&bmc->dev->dev,
2030 &bmc->aux_firmware_rev_attr);
2031out_prod_id:
2032 device_remove_file(&bmc->dev->dev,
2033 &bmc->product_id_attr);
2034out_manu:
2035 device_remove_file(&bmc->dev->dev,
2036 &bmc->manufacturer_id_attr);
2037out_add_dev:
2038 device_remove_file(&bmc->dev->dev,
2039 &bmc->add_dev_support_attr);
2040out_version:
2041 device_remove_file(&bmc->dev->dev,
2042 &bmc->version_attr);
2043out_firm:
2044 device_remove_file(&bmc->dev->dev,
2045 &bmc->firmware_rev_attr);
2046out_rev:
2047 device_remove_file(&bmc->dev->dev,
2048 &bmc->revision_attr);
2049out_sdrs:
2050 device_remove_file(&bmc->dev->dev,
2051 &bmc->provides_dev_sdrs_attr);
2052out_devid:
2053 device_remove_file(&bmc->dev->dev,
2054 &bmc->device_id_attr);
2055out:
2056 return err;
2057}
2058
Corey Minyard50c812b2006-03-26 01:37:21 -08002059static int ipmi_bmc_register(ipmi_smi_t intf)
2060{
2061 int rv;
2062 struct bmc_device *bmc = intf->bmc;
2063 struct bmc_device *old_bmc;
2064 int size;
2065 char dummy[1];
2066
2067 mutex_lock(&ipmidriver_mutex);
2068
2069 /*
2070 * Try to find if there is an bmc_device struct
2071 * representing the interfaced BMC already
2072 */
2073 if (bmc->guid_set)
2074 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
2075 else
2076 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
2077 bmc->id.product_id,
2078 bmc->id.device_id);
2079
2080 /*
2081 * If there is already an bmc_device, free the new one,
2082 * otherwise register the new BMC device
2083 */
2084 if (old_bmc) {
2085 kfree(bmc);
2086 intf->bmc = old_bmc;
2087 bmc = old_bmc;
2088
2089 kref_get(&bmc->refcount);
2090 mutex_unlock(&ipmidriver_mutex);
2091
2092 printk(KERN_INFO
2093 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
2094 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2095 bmc->id.manufacturer_id,
2096 bmc->id.product_id,
2097 bmc->id.device_id);
2098 } else {
2099 bmc->dev = platform_device_alloc("ipmi_bmc",
2100 bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08002101 if (!bmc->dev) {
Corey Minyard50c812b2006-03-26 01:37:21 -08002102 printk(KERN_ERR
2103 "ipmi_msghandler:"
2104 " Unable to allocate platform device\n");
2105 return -ENOMEM;
2106 }
2107 bmc->dev->dev.driver = &ipmidriver;
2108 dev_set_drvdata(&bmc->dev->dev, bmc);
2109 kref_init(&bmc->refcount);
2110
2111 rv = platform_device_register(bmc->dev);
2112 mutex_unlock(&ipmidriver_mutex);
2113 if (rv) {
2114 printk(KERN_ERR
2115 "ipmi_msghandler:"
2116 " Unable to register bmc device: %d\n",
2117 rv);
2118 /* Don't go to out_err, you can only do that if
2119 the device is registered already. */
2120 return rv;
2121 }
2122
2123 bmc->device_id_attr.attr.name = "device_id";
2124 bmc->device_id_attr.attr.owner = THIS_MODULE;
2125 bmc->device_id_attr.attr.mode = S_IRUGO;
2126 bmc->device_id_attr.show = device_id_show;
2127
2128 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
2129 bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
2130 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2131 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2132
Corey Minyard50c812b2006-03-26 01:37:21 -08002133 bmc->revision_attr.attr.name = "revision";
2134 bmc->revision_attr.attr.owner = THIS_MODULE;
2135 bmc->revision_attr.attr.mode = S_IRUGO;
2136 bmc->revision_attr.show = revision_show;
2137
2138 bmc->firmware_rev_attr.attr.name = "firmware_revision";
2139 bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
2140 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2141 bmc->firmware_rev_attr.show = firmware_rev_show;
2142
2143 bmc->version_attr.attr.name = "ipmi_version";
2144 bmc->version_attr.attr.owner = THIS_MODULE;
2145 bmc->version_attr.attr.mode = S_IRUGO;
2146 bmc->version_attr.show = ipmi_version_show;
2147
2148 bmc->add_dev_support_attr.attr.name
2149 = "additional_device_support";
2150 bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
2151 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2152 bmc->add_dev_support_attr.show = add_dev_support_show;
2153
2154 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
2155 bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
2156 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2157 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2158
2159 bmc->product_id_attr.attr.name = "product_id";
2160 bmc->product_id_attr.attr.owner = THIS_MODULE;
2161 bmc->product_id_attr.attr.mode = S_IRUGO;
2162 bmc->product_id_attr.show = product_id_show;
2163
2164 bmc->guid_attr.attr.name = "guid";
2165 bmc->guid_attr.attr.owner = THIS_MODULE;
2166 bmc->guid_attr.attr.mode = S_IRUGO;
2167 bmc->guid_attr.show = guid_show;
2168
2169 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
2170 bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
2171 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2172 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2173
Jeff Garzik5e593932006-10-11 01:22:21 -07002174 rv = create_files(bmc);
2175 if (rv) {
2176 mutex_lock(&ipmidriver_mutex);
2177 platform_device_unregister(bmc->dev);
2178 mutex_unlock(&ipmidriver_mutex);
2179
2180 return rv;
2181 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002182
2183 printk(KERN_INFO
2184 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2185 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2186 bmc->id.manufacturer_id,
2187 bmc->id.product_id,
2188 bmc->id.device_id);
2189 }
2190
2191 /*
2192 * create symlink from system interface device to bmc device
2193 * and back.
2194 */
2195 rv = sysfs_create_link(&intf->si_dev->kobj,
2196 &bmc->dev->dev.kobj, "bmc");
2197 if (rv) {
2198 printk(KERN_ERR
2199 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2200 rv);
2201 goto out_err;
2202 }
2203
2204 size = snprintf(dummy, 0, "ipmi%d", intf->intf_num);
2205 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2206 if (!intf->my_dev_name) {
2207 rv = -ENOMEM;
2208 printk(KERN_ERR
2209 "ipmi_msghandler: allocate link from BMC: %d\n",
2210 rv);
2211 goto out_err;
2212 }
2213 snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num);
2214
2215 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2216 intf->my_dev_name);
2217 if (rv) {
2218 kfree(intf->my_dev_name);
2219 intf->my_dev_name = NULL;
2220 printk(KERN_ERR
2221 "ipmi_msghandler:"
2222 " Unable to create symlink to bmc: %d\n",
2223 rv);
2224 goto out_err;
2225 }
2226
2227 return 0;
2228
2229out_err:
2230 ipmi_bmc_unregister(intf);
2231 return rv;
2232}
2233
2234static int
2235send_guid_cmd(ipmi_smi_t intf, int chan)
2236{
2237 struct kernel_ipmi_msg msg;
2238 struct ipmi_system_interface_addr si;
2239
2240 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2241 si.channel = IPMI_BMC_CHANNEL;
2242 si.lun = 0;
2243
2244 msg.netfn = IPMI_NETFN_APP_REQUEST;
2245 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2246 msg.data = NULL;
2247 msg.data_len = 0;
2248 return i_ipmi_request(NULL,
2249 intf,
2250 (struct ipmi_addr *) &si,
2251 0,
2252 &msg,
2253 intf,
2254 NULL,
2255 NULL,
2256 0,
2257 intf->channels[0].address,
2258 intf->channels[0].lun,
2259 -1, 0);
2260}
2261
2262static void
2263guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2264{
2265 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2266 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2267 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2268 /* Not for me */
2269 return;
2270
2271 if (msg->msg.data[0] != 0) {
2272 /* Error from getting the GUID, the BMC doesn't have one. */
2273 intf->bmc->guid_set = 0;
2274 goto out;
2275 }
2276
2277 if (msg->msg.data_len < 17) {
2278 intf->bmc->guid_set = 0;
2279 printk(KERN_WARNING PFX
2280 "guid_handler: The GUID response from the BMC was too"
2281 " short, it was %d but should have been 17. Assuming"
2282 " GUID is not available.\n",
2283 msg->msg.data_len);
2284 goto out;
2285 }
2286
2287 memcpy(intf->bmc->guid, msg->msg.data, 16);
2288 intf->bmc->guid_set = 1;
2289 out:
2290 wake_up(&intf->waitq);
2291}
2292
2293static void
2294get_guid(ipmi_smi_t intf)
2295{
2296 int rv;
2297
2298 intf->bmc->guid_set = 0x2;
2299 intf->null_user_handler = guid_handler;
2300 rv = send_guid_cmd(intf, 0);
2301 if (rv)
2302 /* Send failed, no GUID available. */
2303 intf->bmc->guid_set = 0;
2304 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2305 intf->null_user_handler = NULL;
2306}
2307
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308static int
2309send_channel_info_cmd(ipmi_smi_t intf, int chan)
2310{
2311 struct kernel_ipmi_msg msg;
2312 unsigned char data[1];
2313 struct ipmi_system_interface_addr si;
2314
2315 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2316 si.channel = IPMI_BMC_CHANNEL;
2317 si.lun = 0;
2318
2319 msg.netfn = IPMI_NETFN_APP_REQUEST;
2320 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2321 msg.data = data;
2322 msg.data_len = 1;
2323 data[0] = chan;
2324 return i_ipmi_request(NULL,
2325 intf,
2326 (struct ipmi_addr *) &si,
2327 0,
2328 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002329 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 NULL,
2331 NULL,
2332 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002333 intf->channels[0].address,
2334 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 -1, 0);
2336}
2337
2338static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002339channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340{
2341 int rv = 0;
2342 int chan;
2343
Corey Minyard56a55ec2005-09-06 15:18:42 -07002344 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2345 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2346 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 {
2348 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002349 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 /* Got an error from the channel, just go on. */
2351
Corey Minyard56a55ec2005-09-06 15:18:42 -07002352 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 /* If the MC does not support this
2354 command, that is legal. We just
2355 assume it has one IPMB at channel
2356 zero. */
2357 intf->channels[0].medium
2358 = IPMI_CHANNEL_MEDIUM_IPMB;
2359 intf->channels[0].protocol
2360 = IPMI_CHANNEL_PROTOCOL_IPMB;
2361 rv = -ENOSYS;
2362
2363 intf->curr_channel = IPMI_MAX_CHANNELS;
2364 wake_up(&intf->waitq);
2365 goto out;
2366 }
2367 goto next_channel;
2368 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002369 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 /* Message not big enough, just go on. */
2371 goto next_channel;
2372 }
2373 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002374 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2375 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376
2377 next_channel:
2378 intf->curr_channel++;
2379 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2380 wake_up(&intf->waitq);
2381 else
2382 rv = send_channel_info_cmd(intf, intf->curr_channel);
2383
2384 if (rv) {
2385 /* Got an error somehow, just give up. */
2386 intf->curr_channel = IPMI_MAX_CHANNELS;
2387 wake_up(&intf->waitq);
2388
2389 printk(KERN_WARNING PFX
2390 "Error sending channel information: %d\n",
2391 rv);
2392 }
2393 }
2394 out:
2395 return;
2396}
2397
2398int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2399 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002400 struct ipmi_device_id *device_id,
2401 struct device *si_dev,
Corey Minyard453823b2006-03-31 02:30:39 -08002402 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403{
2404 int i, j;
2405 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002406 ipmi_smi_t intf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 unsigned long flags;
Corey Minyard50c812b2006-03-26 01:37:21 -08002408 int version_major;
2409 int version_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
Corey Minyard50c812b2006-03-26 01:37:21 -08002411 version_major = ipmi_version_major(device_id);
2412 version_minor = ipmi_version_minor(device_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
2414 /* Make sure the driver is actually initialized, this handles
2415 problems with initialization order. */
2416 if (!initialized) {
2417 rv = ipmi_init_msghandler();
2418 if (rv)
2419 return rv;
2420 /* The init code doesn't return an error if it was turned
2421 off, but it won't initialize. Check that. */
2422 if (!initialized)
2423 return -ENODEV;
2424 }
2425
Corey Minyard393d2cc2005-11-07 00:59:54 -08002426 intf = kmalloc(sizeof(*intf), GFP_KERNEL);
2427 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002429 memset(intf, 0, sizeof(*intf));
Corey Minyard50c812b2006-03-26 01:37:21 -08002430 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2431 if (!intf->bmc) {
2432 kfree(intf);
2433 return -ENOMEM;
2434 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002435 intf->intf_num = -1;
2436 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002437 intf->bmc->id = *device_id;
2438 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002439 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2440 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2441 intf->channels[j].lun = 2;
2442 }
2443 if (slave_addr != 0)
2444 intf->channels[0].address = slave_addr;
2445 INIT_LIST_HEAD(&intf->users);
2446 intf->handlers = handlers;
2447 intf->send_info = send_info;
2448 spin_lock_init(&intf->seq_lock);
2449 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2450 intf->seq_table[j].inuse = 0;
2451 intf->seq_table[j].seqid = 0;
2452 }
2453 intf->curr_seq = 0;
2454#ifdef CONFIG_PROC_FS
2455 spin_lock_init(&intf->proc_entry_lock);
2456#endif
2457 spin_lock_init(&intf->waiting_msgs_lock);
2458 INIT_LIST_HEAD(&intf->waiting_msgs);
2459 spin_lock_init(&intf->events_lock);
2460 INIT_LIST_HEAD(&intf->waiting_events);
2461 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002462 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002463 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2464 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
Corey Minyard393d2cc2005-11-07 00:59:54 -08002466 spin_lock_init(&intf->counter_lock);
2467 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468
2469 rv = -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002470 spin_lock_irqsave(&interfaces_lock, flags);
Corey Minyarde8b33612005-09-06 15:18:45 -07002471 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 if (ipmi_interfaces[i] == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002473 intf->intf_num = i;
2474 /* Reserve the entry till we are done. */
2475 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 break;
2478 }
2479 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002480 spin_unlock_irqrestore(&interfaces_lock, flags);
2481 if (rv)
2482 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483
Corey Minyard453823b2006-03-31 02:30:39 -08002484 rv = handlers->start_processing(send_info, intf);
2485 if (rv)
2486 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002487
Corey Minyard50c812b2006-03-26 01:37:21 -08002488 get_guid(intf);
2489
Corey Minyard393d2cc2005-11-07 00:59:54 -08002490 if ((version_major > 1)
2491 || ((version_major == 1) && (version_minor >= 5)))
2492 {
2493 /* Start scanning the channels to see what is
2494 available. */
2495 intf->null_user_handler = channel_handler;
2496 intf->curr_channel = 0;
2497 rv = send_channel_info_cmd(intf, 0);
2498 if (rv)
2499 goto out;
2500
2501 /* Wait for the channel info to be read. */
2502 wait_event(intf->waitq,
2503 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002504 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002505 } else {
2506 /* Assume a single IPMB channel at zero. */
2507 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2508 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002512 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513
Corey Minyard50c812b2006-03-26 01:37:21 -08002514 rv = ipmi_bmc_register(intf);
2515
Corey Minyard393d2cc2005-11-07 00:59:54 -08002516 out:
2517 if (rv) {
2518 if (intf->proc_dir)
2519 remove_proc_entries(intf);
2520 kref_put(&intf->refcount, intf_free);
2521 if (i < MAX_IPMI_INTERFACES) {
2522 spin_lock_irqsave(&interfaces_lock, flags);
2523 ipmi_interfaces[i] = NULL;
2524 spin_unlock_irqrestore(&interfaces_lock, flags);
2525 }
2526 } else {
2527 spin_lock_irqsave(&interfaces_lock, flags);
2528 ipmi_interfaces[i] = intf;
2529 spin_unlock_irqrestore(&interfaces_lock, flags);
Corey Minyard50c812b2006-03-26 01:37:21 -08002530 call_smi_watchers(i, intf->si_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 }
2532
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 return rv;
2534}
2535
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536int ipmi_unregister_smi(ipmi_smi_t intf)
2537{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 int i;
2539 struct ipmi_smi_watcher *w;
2540 unsigned long flags;
2541
Corey Minyard50c812b2006-03-26 01:37:21 -08002542 ipmi_bmc_unregister(intf);
2543
Corey Minyard393d2cc2005-11-07 00:59:54 -08002544 spin_lock_irqsave(&interfaces_lock, flags);
2545 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
2546 if (ipmi_interfaces[i] == intf) {
2547 /* Set the interface number reserved until we
2548 * are done. */
2549 ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
2550 intf->intf_num = -1;
2551 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002554 spin_unlock_irqrestore(&interfaces_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555
Corey Minyard393d2cc2005-11-07 00:59:54 -08002556 if (i == MAX_IPMI_INTERFACES)
2557 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558
Corey Minyard393d2cc2005-11-07 00:59:54 -08002559 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560
2561 /* Call all the watcher interfaces to tell them that
2562 an interface is gone. */
2563 down_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002564 list_for_each_entry(w, &smi_watchers, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 w->smi_gone(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 up_read(&smi_watchers_sem);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002567
2568 /* Allow the entry to be reused now. */
2569 spin_lock_irqsave(&interfaces_lock, flags);
2570 ipmi_interfaces[i] = NULL;
2571 spin_unlock_irqrestore(&interfaces_lock,flags);
2572
2573 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 return 0;
2575}
2576
2577static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2578 struct ipmi_smi_msg *msg)
2579{
2580 struct ipmi_ipmb_addr ipmb_addr;
2581 struct ipmi_recv_msg *recv_msg;
2582 unsigned long flags;
2583
2584
2585 /* This is 11, not 10, because the response must contain a
2586 * completion code. */
2587 if (msg->rsp_size < 11) {
2588 /* Message not big enough, just ignore it. */
2589 spin_lock_irqsave(&intf->counter_lock, flags);
2590 intf->invalid_ipmb_responses++;
2591 spin_unlock_irqrestore(&intf->counter_lock, flags);
2592 return 0;
2593 }
2594
2595 if (msg->rsp[2] != 0) {
2596 /* An error getting the response, just ignore it. */
2597 return 0;
2598 }
2599
2600 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
2601 ipmb_addr.slave_addr = msg->rsp[6];
2602 ipmb_addr.channel = msg->rsp[3] & 0x0f;
2603 ipmb_addr.lun = msg->rsp[7] & 3;
2604
2605 /* It's a response from a remote entity. Look up the sequence
2606 number and handle the response. */
2607 if (intf_find_seq(intf,
2608 msg->rsp[7] >> 2,
2609 msg->rsp[3] & 0x0f,
2610 msg->rsp[8],
2611 (msg->rsp[4] >> 2) & (~1),
2612 (struct ipmi_addr *) &(ipmb_addr),
2613 &recv_msg))
2614 {
2615 /* We were unable to find the sequence number,
2616 so just nuke the message. */
2617 spin_lock_irqsave(&intf->counter_lock, flags);
2618 intf->unhandled_ipmb_responses++;
2619 spin_unlock_irqrestore(&intf->counter_lock, flags);
2620 return 0;
2621 }
2622
2623 memcpy(recv_msg->msg_data,
2624 &(msg->rsp[9]),
2625 msg->rsp_size - 9);
2626 /* THe other fields matched, so no need to set them, except
2627 for netfn, which needs to be the response that was
2628 returned, not the request value. */
2629 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2630 recv_msg->msg.data = recv_msg->msg_data;
2631 recv_msg->msg.data_len = msg->rsp_size - 10;
2632 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2633 spin_lock_irqsave(&intf->counter_lock, flags);
2634 intf->handled_ipmb_responses++;
2635 spin_unlock_irqrestore(&intf->counter_lock, flags);
2636 deliver_response(recv_msg);
2637
2638 return 0;
2639}
2640
2641static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2642 struct ipmi_smi_msg *msg)
2643{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002644 struct cmd_rcvr *rcvr;
2645 int rv = 0;
2646 unsigned char netfn;
2647 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002648 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002649 ipmi_user_t user = NULL;
2650 struct ipmi_ipmb_addr *ipmb_addr;
2651 struct ipmi_recv_msg *recv_msg;
2652 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653
2654 if (msg->rsp_size < 10) {
2655 /* Message not big enough, just ignore it. */
2656 spin_lock_irqsave(&intf->counter_lock, flags);
2657 intf->invalid_commands++;
2658 spin_unlock_irqrestore(&intf->counter_lock, flags);
2659 return 0;
2660 }
2661
2662 if (msg->rsp[2] != 0) {
2663 /* An error getting the response, just ignore it. */
2664 return 0;
2665 }
2666
2667 netfn = msg->rsp[4] >> 2;
2668 cmd = msg->rsp[8];
Corey Minyardc69c3122006-09-30 23:27:56 -07002669 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002671 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002672 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002673 if (rcvr) {
2674 user = rcvr->user;
2675 kref_get(&user->refcount);
2676 } else
2677 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002678 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679
2680 if (user == NULL) {
2681 /* We didn't find a user, deliver an error response. */
2682 spin_lock_irqsave(&intf->counter_lock, flags);
2683 intf->unhandled_commands++;
2684 spin_unlock_irqrestore(&intf->counter_lock, flags);
2685
2686 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2687 msg->data[1] = IPMI_SEND_MSG_CMD;
2688 msg->data[2] = msg->rsp[3];
2689 msg->data[3] = msg->rsp[6];
2690 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2691 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002692 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 /* rqseq/lun */
2694 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2695 msg->data[8] = msg->rsp[8]; /* cmd */
2696 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2697 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2698 msg->data_size = 11;
2699
2700#ifdef DEBUG_MSGING
2701 {
2702 int m;
2703 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002704 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 printk(" %2.2x", msg->data[m]);
2706 printk("\n");
2707 }
2708#endif
2709 intf->handlers->sender(intf->send_info, msg, 0);
2710
2711 rv = -1; /* We used the message, so return the value that
2712 causes it to not be freed or queued. */
2713 } else {
2714 /* Deliver the message to the user. */
2715 spin_lock_irqsave(&intf->counter_lock, flags);
2716 intf->handled_commands++;
2717 spin_unlock_irqrestore(&intf->counter_lock, flags);
2718
2719 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002720 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 /* We couldn't allocate memory for the
2722 message, so requeue it for handling
2723 later. */
2724 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002725 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 } else {
2727 /* Extract the source address from the data. */
2728 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2729 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2730 ipmb_addr->slave_addr = msg->rsp[6];
2731 ipmb_addr->lun = msg->rsp[7] & 3;
2732 ipmb_addr->channel = msg->rsp[3] & 0xf;
2733
2734 /* Extract the rest of the message information
2735 from the IPMB header.*/
2736 recv_msg->user = user;
2737 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2738 recv_msg->msgid = msg->rsp[7] >> 2;
2739 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2740 recv_msg->msg.cmd = msg->rsp[8];
2741 recv_msg->msg.data = recv_msg->msg_data;
2742
2743 /* We chop off 10, not 9 bytes because the checksum
2744 at the end also needs to be removed. */
2745 recv_msg->msg.data_len = msg->rsp_size - 10;
2746 memcpy(recv_msg->msg_data,
2747 &(msg->rsp[9]),
2748 msg->rsp_size - 10);
2749 deliver_response(recv_msg);
2750 }
2751 }
2752
2753 return rv;
2754}
2755
2756static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
2757 struct ipmi_smi_msg *msg)
2758{
2759 struct ipmi_lan_addr lan_addr;
2760 struct ipmi_recv_msg *recv_msg;
2761 unsigned long flags;
2762
2763
2764 /* This is 13, not 12, because the response must contain a
2765 * completion code. */
2766 if (msg->rsp_size < 13) {
2767 /* Message not big enough, just ignore it. */
2768 spin_lock_irqsave(&intf->counter_lock, flags);
2769 intf->invalid_lan_responses++;
2770 spin_unlock_irqrestore(&intf->counter_lock, flags);
2771 return 0;
2772 }
2773
2774 if (msg->rsp[2] != 0) {
2775 /* An error getting the response, just ignore it. */
2776 return 0;
2777 }
2778
2779 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
2780 lan_addr.session_handle = msg->rsp[4];
2781 lan_addr.remote_SWID = msg->rsp[8];
2782 lan_addr.local_SWID = msg->rsp[5];
2783 lan_addr.channel = msg->rsp[3] & 0x0f;
2784 lan_addr.privilege = msg->rsp[3] >> 4;
2785 lan_addr.lun = msg->rsp[9] & 3;
2786
2787 /* It's a response from a remote entity. Look up the sequence
2788 number and handle the response. */
2789 if (intf_find_seq(intf,
2790 msg->rsp[9] >> 2,
2791 msg->rsp[3] & 0x0f,
2792 msg->rsp[10],
2793 (msg->rsp[6] >> 2) & (~1),
2794 (struct ipmi_addr *) &(lan_addr),
2795 &recv_msg))
2796 {
2797 /* We were unable to find the sequence number,
2798 so just nuke the message. */
2799 spin_lock_irqsave(&intf->counter_lock, flags);
2800 intf->unhandled_lan_responses++;
2801 spin_unlock_irqrestore(&intf->counter_lock, flags);
2802 return 0;
2803 }
2804
2805 memcpy(recv_msg->msg_data,
2806 &(msg->rsp[11]),
2807 msg->rsp_size - 11);
2808 /* The other fields matched, so no need to set them, except
2809 for netfn, which needs to be the response that was
2810 returned, not the request value. */
2811 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2812 recv_msg->msg.data = recv_msg->msg_data;
2813 recv_msg->msg.data_len = msg->rsp_size - 12;
2814 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2815 spin_lock_irqsave(&intf->counter_lock, flags);
2816 intf->handled_lan_responses++;
2817 spin_unlock_irqrestore(&intf->counter_lock, flags);
2818 deliver_response(recv_msg);
2819
2820 return 0;
2821}
2822
2823static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2824 struct ipmi_smi_msg *msg)
2825{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002826 struct cmd_rcvr *rcvr;
2827 int rv = 0;
2828 unsigned char netfn;
2829 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002830 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002831 ipmi_user_t user = NULL;
2832 struct ipmi_lan_addr *lan_addr;
2833 struct ipmi_recv_msg *recv_msg;
2834 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835
2836 if (msg->rsp_size < 12) {
2837 /* Message not big enough, just ignore it. */
2838 spin_lock_irqsave(&intf->counter_lock, flags);
2839 intf->invalid_commands++;
2840 spin_unlock_irqrestore(&intf->counter_lock, flags);
2841 return 0;
2842 }
2843
2844 if (msg->rsp[2] != 0) {
2845 /* An error getting the response, just ignore it. */
2846 return 0;
2847 }
2848
2849 netfn = msg->rsp[6] >> 2;
2850 cmd = msg->rsp[10];
Corey Minyardc69c3122006-09-30 23:27:56 -07002851 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002853 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002854 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002855 if (rcvr) {
2856 user = rcvr->user;
2857 kref_get(&user->refcount);
2858 } else
2859 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002860 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861
2862 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002863 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 spin_lock_irqsave(&intf->counter_lock, flags);
2865 intf->unhandled_commands++;
2866 spin_unlock_irqrestore(&intf->counter_lock, flags);
2867
2868 rv = 0; /* Don't do anything with these messages, just
2869 allow them to be freed. */
2870 } else {
2871 /* Deliver the message to the user. */
2872 spin_lock_irqsave(&intf->counter_lock, flags);
2873 intf->handled_commands++;
2874 spin_unlock_irqrestore(&intf->counter_lock, flags);
2875
2876 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002877 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 /* We couldn't allocate memory for the
2879 message, so requeue it for handling
2880 later. */
2881 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002882 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 } else {
2884 /* Extract the source address from the data. */
2885 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
2886 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
2887 lan_addr->session_handle = msg->rsp[4];
2888 lan_addr->remote_SWID = msg->rsp[8];
2889 lan_addr->local_SWID = msg->rsp[5];
2890 lan_addr->lun = msg->rsp[9] & 3;
2891 lan_addr->channel = msg->rsp[3] & 0xf;
2892 lan_addr->privilege = msg->rsp[3] >> 4;
2893
2894 /* Extract the rest of the message information
2895 from the IPMB header.*/
2896 recv_msg->user = user;
2897 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2898 recv_msg->msgid = msg->rsp[9] >> 2;
2899 recv_msg->msg.netfn = msg->rsp[6] >> 2;
2900 recv_msg->msg.cmd = msg->rsp[10];
2901 recv_msg->msg.data = recv_msg->msg_data;
2902
2903 /* We chop off 12, not 11 bytes because the checksum
2904 at the end also needs to be removed. */
2905 recv_msg->msg.data_len = msg->rsp_size - 12;
2906 memcpy(recv_msg->msg_data,
2907 &(msg->rsp[11]),
2908 msg->rsp_size - 12);
2909 deliver_response(recv_msg);
2910 }
2911 }
2912
2913 return rv;
2914}
2915
2916static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
2917 struct ipmi_smi_msg *msg)
2918{
2919 struct ipmi_system_interface_addr *smi_addr;
2920
2921 recv_msg->msgid = 0;
2922 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
2923 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2924 smi_addr->channel = IPMI_BMC_CHANNEL;
2925 smi_addr->lun = msg->rsp[0] & 3;
2926 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
2927 recv_msg->msg.netfn = msg->rsp[0] >> 2;
2928 recv_msg->msg.cmd = msg->rsp[1];
2929 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
2930 recv_msg->msg.data = recv_msg->msg_data;
2931 recv_msg->msg.data_len = msg->rsp_size - 3;
2932}
2933
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934static int handle_read_event_rsp(ipmi_smi_t intf,
2935 struct ipmi_smi_msg *msg)
2936{
2937 struct ipmi_recv_msg *recv_msg, *recv_msg2;
2938 struct list_head msgs;
2939 ipmi_user_t user;
2940 int rv = 0;
2941 int deliver_count = 0;
2942 unsigned long flags;
2943
2944 if (msg->rsp_size < 19) {
2945 /* Message is too small to be an IPMB event. */
2946 spin_lock_irqsave(&intf->counter_lock, flags);
2947 intf->invalid_events++;
2948 spin_unlock_irqrestore(&intf->counter_lock, flags);
2949 return 0;
2950 }
2951
2952 if (msg->rsp[2] != 0) {
2953 /* An error getting the event, just ignore it. */
2954 return 0;
2955 }
2956
2957 INIT_LIST_HEAD(&msgs);
2958
Corey Minyard393d2cc2005-11-07 00:59:54 -08002959 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960
2961 spin_lock(&intf->counter_lock);
2962 intf->events++;
2963 spin_unlock(&intf->counter_lock);
2964
2965 /* Allocate and fill in one message for every user that is getting
2966 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002967 rcu_read_lock();
2968 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08002969 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 continue;
2971
2972 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002973 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08002974 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002975 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
2976 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 list_del(&recv_msg->link);
2978 ipmi_free_recv_msg(recv_msg);
2979 }
2980 /* We couldn't allocate memory for the
2981 message, so requeue it for handling
2982 later. */
2983 rv = 1;
2984 goto out;
2985 }
2986
2987 deliver_count++;
2988
2989 copy_event_into_recv_msg(recv_msg, msg);
2990 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002991 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 list_add_tail(&(recv_msg->link), &msgs);
2993 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08002994 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995
2996 if (deliver_count) {
2997 /* Now deliver all the messages. */
2998 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
2999 list_del(&recv_msg->link);
3000 deliver_response(recv_msg);
3001 }
3002 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
3003 /* No one to receive the message, put it in queue if there's
3004 not already too many things in the queue. */
3005 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003006 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 /* We couldn't allocate memory for the
3008 message, so requeue it for handling
3009 later. */
3010 rv = 1;
3011 goto out;
3012 }
3013
3014 copy_event_into_recv_msg(recv_msg, msg);
3015 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
Corey Minyard4791c032006-04-10 22:54:31 -07003016 intf->waiting_events_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 } else {
3018 /* There's too many things in the queue, discard this
3019 message. */
3020 printk(KERN_WARNING PFX "Event queue full, discarding an"
3021 " incoming event\n");
3022 }
3023
3024 out:
3025 spin_unlock_irqrestore(&(intf->events_lock), flags);
3026
3027 return rv;
3028}
3029
3030static int handle_bmc_rsp(ipmi_smi_t intf,
3031 struct ipmi_smi_msg *msg)
3032{
3033 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003035 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036
3037 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07003038 if (recv_msg == NULL)
3039 {
3040 printk(KERN_WARNING"IPMI message received with no owner. This\n"
3041 "could be because of a malformed message, or\n"
3042 "because of a hardware error. Contact your\n"
3043 "hardware vender for assistance\n");
3044 return 0;
3045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046
Corey Minyard393d2cc2005-11-07 00:59:54 -08003047 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003049 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07003050 /* The user for the message went away, so give up. */
3051 spin_lock_irqsave(&intf->counter_lock, flags);
3052 intf->unhandled_local_responses++;
3053 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 ipmi_free_recv_msg(recv_msg);
3055 } else {
3056 struct ipmi_system_interface_addr *smi_addr;
3057
3058 spin_lock_irqsave(&intf->counter_lock, flags);
3059 intf->handled_local_responses++;
3060 spin_unlock_irqrestore(&intf->counter_lock, flags);
3061 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3062 recv_msg->msgid = msg->msgid;
3063 smi_addr = ((struct ipmi_system_interface_addr *)
3064 &(recv_msg->addr));
3065 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3066 smi_addr->channel = IPMI_BMC_CHANNEL;
3067 smi_addr->lun = msg->rsp[0] & 3;
3068 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3069 recv_msg->msg.cmd = msg->rsp[1];
3070 memcpy(recv_msg->msg_data,
3071 &(msg->rsp[2]),
3072 msg->rsp_size - 2);
3073 recv_msg->msg.data = recv_msg->msg_data;
3074 recv_msg->msg.data_len = msg->rsp_size - 2;
3075 deliver_response(recv_msg);
3076 }
3077
3078 return 0;
3079}
3080
3081/* Handle a new message. Return 1 if the message should be requeued,
3082 0 if the message should be freed, or -1 if the message should not
3083 be freed or requeued. */
3084static int handle_new_recv_msg(ipmi_smi_t intf,
3085 struct ipmi_smi_msg *msg)
3086{
3087 int requeue;
3088 int chan;
3089
3090#ifdef DEBUG_MSGING
3091 int m;
3092 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07003093 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 printk(" %2.2x", msg->rsp[m]);
3095 printk("\n");
3096#endif
3097 if (msg->rsp_size < 2) {
3098 /* Message is too small to be correct. */
3099 printk(KERN_WARNING PFX "BMC returned to small a message"
3100 " for netfn %x cmd %x, got %d bytes\n",
3101 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3102
3103 /* Generate an error response for the message. */
3104 msg->rsp[0] = msg->data[0] | (1 << 2);
3105 msg->rsp[1] = msg->data[1];
3106 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3107 msg->rsp_size = 3;
3108 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3109 || (msg->rsp[1] != msg->data[1])) /* Command */
3110 {
3111 /* The response is not even marginally correct. */
3112 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3113 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3114 (msg->data[0] >> 2) | 1, msg->data[1],
3115 msg->rsp[0] >> 2, msg->rsp[1]);
3116
3117 /* Generate an error response for the message. */
3118 msg->rsp[0] = msg->data[0] | (1 << 2);
3119 msg->rsp[1] = msg->data[1];
3120 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3121 msg->rsp_size = 3;
3122 }
3123
3124 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3125 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3126 && (msg->user_data != NULL))
3127 {
3128 /* It's a response to a response we sent. For this we
3129 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003130 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131
3132 requeue = 0;
3133 if (msg->rsp_size < 2)
3134 /* Message is too small to be correct. */
3135 goto out;
3136
3137 chan = msg->data[2] & 0x0f;
3138 if (chan >= IPMI_MAX_CHANNELS)
3139 /* Invalid channel number */
3140 goto out;
3141
Corey Minyard393d2cc2005-11-07 00:59:54 -08003142 if (!recv_msg)
3143 goto out;
3144
3145 /* Make sure the user still exists. */
3146 if (!recv_msg->user || !recv_msg->user->valid)
3147 goto out;
3148
3149 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3150 recv_msg->msg.data = recv_msg->msg_data;
3151 recv_msg->msg.data_len = 1;
3152 recv_msg->msg_data[0] = msg->rsp[2];
3153 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3155 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3156 {
3157 /* It's from the receive queue. */
3158 chan = msg->rsp[3] & 0xf;
3159 if (chan >= IPMI_MAX_CHANNELS) {
3160 /* Invalid channel number */
3161 requeue = 0;
3162 goto out;
3163 }
3164
3165 switch (intf->channels[chan].medium) {
3166 case IPMI_CHANNEL_MEDIUM_IPMB:
3167 if (msg->rsp[4] & 0x04) {
3168 /* It's a response, so find the
3169 requesting message and send it up. */
3170 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3171 } else {
3172 /* It's a command to the SMS from some other
3173 entity. Handle that. */
3174 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3175 }
3176 break;
3177
3178 case IPMI_CHANNEL_MEDIUM_8023LAN:
3179 case IPMI_CHANNEL_MEDIUM_ASYNC:
3180 if (msg->rsp[6] & 0x04) {
3181 /* It's a response, so find the
3182 requesting message and send it up. */
3183 requeue = handle_lan_get_msg_rsp(intf, msg);
3184 } else {
3185 /* It's a command to the SMS from some other
3186 entity. Handle that. */
3187 requeue = handle_lan_get_msg_cmd(intf, msg);
3188 }
3189 break;
3190
3191 default:
3192 /* We don't handle the channel type, so just
3193 * free the message. */
3194 requeue = 0;
3195 }
3196
3197 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3198 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3199 {
3200 /* It's an asyncronous event. */
3201 requeue = handle_read_event_rsp(intf, msg);
3202 } else {
3203 /* It's a response from the local BMC. */
3204 requeue = handle_bmc_rsp(intf, msg);
3205 }
3206
3207 out:
3208 return requeue;
3209}
3210
3211/* Handle a new message from the lower layer. */
3212void ipmi_smi_msg_received(ipmi_smi_t intf,
3213 struct ipmi_smi_msg *msg)
3214{
3215 unsigned long flags;
3216 int rv;
3217
3218
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 if ((msg->data_size >= 2)
3220 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3221 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003222 && (msg->user_data == NULL))
3223 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 /* This is the local response to a command send, start
3225 the timer for these. The user_data will not be
3226 NULL if this is a response send, and we will let
3227 response sends just go through. */
3228
3229 /* Check for errors, if we get certain errors (ones
3230 that mean basically we can try again later), we
3231 ignore them and start the timer. Otherwise we
3232 report the error immediately. */
3233 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3234 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
3235 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR))
3236 {
3237 int chan = msg->rsp[3] & 0xf;
3238
3239 /* Got an error sending the message, handle it. */
3240 spin_lock_irqsave(&intf->counter_lock, flags);
3241 if (chan >= IPMI_MAX_CHANNELS)
3242 ; /* This shouldn't happen */
3243 else if ((intf->channels[chan].medium
3244 == IPMI_CHANNEL_MEDIUM_8023LAN)
3245 || (intf->channels[chan].medium
3246 == IPMI_CHANNEL_MEDIUM_ASYNC))
3247 intf->sent_lan_command_errs++;
3248 else
3249 intf->sent_ipmb_command_errs++;
3250 spin_unlock_irqrestore(&intf->counter_lock, flags);
3251 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3252 } else {
3253 /* The message was sent, start the timer. */
3254 intf_start_seq_timer(intf, msg->msgid);
3255 }
3256
3257 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003258 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 }
3260
3261 /* To preserve message order, if the list is not empty, we
3262 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003263 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
3264 if (!list_empty(&intf->waiting_msgs)) {
3265 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003266 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003267 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003269 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270
3271 rv = handle_new_recv_msg(intf, msg);
3272 if (rv > 0) {
3273 /* Could not handle the message now, just add it to a
3274 list to handle later. */
Hironobu Ishii177294d2005-11-11 08:12:21 -06003275 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003276 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003277 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 } else if (rv == 0) {
3279 ipmi_free_smi_msg(msg);
3280 }
3281
Corey Minyard393d2cc2005-11-07 00:59:54 -08003282 out:
3283 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284}
3285
3286void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3287{
3288 ipmi_user_t user;
3289
Corey Minyard393d2cc2005-11-07 00:59:54 -08003290 rcu_read_lock();
3291 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003292 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 continue;
3294
3295 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3296 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003297 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298}
3299
3300static void
3301handle_msg_timeout(struct ipmi_recv_msg *msg)
3302{
3303 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3304 msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;
3305 msg->msg.netfn |= 1; /* Convert to a response. */
3306 msg->msg.data_len = 1;
3307 msg->msg.data = msg->msg_data;
3308 deliver_response(msg);
3309}
3310
Corey Minyard882fe012005-05-01 08:59:12 -07003311static struct ipmi_smi_msg *
3312smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3313 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314{
Corey Minyard882fe012005-05-01 08:59:12 -07003315 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 if (!smi_msg)
3317 /* If we can't allocate the message, then just return, we
3318 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003319 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320
3321 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3322 smi_msg->data_size = recv_msg->msg.data_len;
3323 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3324
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325#ifdef DEBUG_MSGING
3326 {
3327 int m;
3328 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003329 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 printk(" %2.2x", smi_msg->data[m]);
3331 printk("\n");
3332 }
3333#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003334 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335}
3336
Corey Minyard393d2cc2005-11-07 00:59:54 -08003337static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3338 struct list_head *timeouts, long timeout_period,
3339 int slot, unsigned long *flags)
3340{
3341 struct ipmi_recv_msg *msg;
3342
3343 if (!ent->inuse)
3344 return;
3345
3346 ent->timeout -= timeout_period;
3347 if (ent->timeout > 0)
3348 return;
3349
3350 if (ent->retries_left == 0) {
3351 /* The message has used all its retries. */
3352 ent->inuse = 0;
3353 msg = ent->recv_msg;
3354 list_add_tail(&msg->link, timeouts);
3355 spin_lock(&intf->counter_lock);
3356 if (ent->broadcast)
3357 intf->timed_out_ipmb_broadcasts++;
3358 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3359 intf->timed_out_lan_commands++;
3360 else
3361 intf->timed_out_ipmb_commands++;
3362 spin_unlock(&intf->counter_lock);
3363 } else {
3364 struct ipmi_smi_msg *smi_msg;
3365 /* More retries, send again. */
3366
3367 /* Start with the max timer, set to normal
3368 timer after the message is sent. */
3369 ent->timeout = MAX_MSG_TIMEOUT;
3370 ent->retries_left--;
3371 spin_lock(&intf->counter_lock);
3372 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3373 intf->retransmitted_lan_commands++;
3374 else
3375 intf->retransmitted_ipmb_commands++;
3376 spin_unlock(&intf->counter_lock);
3377
3378 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3379 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003380 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003381 return;
3382
3383 spin_unlock_irqrestore(&intf->seq_lock, *flags);
3384 /* Send the new message. We send with a zero
3385 * priority. It timed out, I doubt time is
3386 * that critical now, and high priority
3387 * messages are really only for messages to the
3388 * local MC, which don't get resent. */
3389 intf->handlers->sender(intf->send_info,
3390 smi_msg, 0);
3391 spin_lock_irqsave(&intf->seq_lock, *flags);
3392 }
3393}
3394
3395static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396{
3397 ipmi_smi_t intf;
3398 struct list_head timeouts;
3399 struct ipmi_recv_msg *msg, *msg2;
3400 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3401 unsigned long flags;
3402 int i, j;
3403
3404 INIT_LIST_HEAD(&timeouts);
3405
3406 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07003407 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003409 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 continue;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003411 kref_get(&intf->refcount);
3412 spin_unlock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413
3414 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003415 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003416 list_for_each_entry_safe(smi_msg, smi_msg2,
3417 &intf->waiting_msgs, link) {
3418 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 list_del(&smi_msg->link);
3420 ipmi_free_smi_msg(smi_msg);
3421 } else {
3422 /* To preserve message order, quit if we
3423 can't handle a message. */
3424 break;
3425 }
3426 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003427 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428
3429 /* Go through the seq table and find any messages that
3430 have timed out, putting them in the timeouts
3431 list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003432 spin_lock_irqsave(&intf->seq_lock, flags);
3433 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++)
3434 check_msg_timeout(intf, &(intf->seq_table[j]),
3435 &timeouts, timeout_period, j,
3436 &flags);
3437 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438
Corey Minyard393d2cc2005-11-07 00:59:54 -08003439 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 handle_msg_timeout(msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441
Corey Minyard393d2cc2005-11-07 00:59:54 -08003442 kref_put(&intf->refcount, intf_free);
3443 spin_lock(&interfaces_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 }
3445 spin_unlock(&interfaces_lock);
3446}
3447
3448static void ipmi_request_event(void)
3449{
3450 ipmi_smi_t intf;
3451 int i;
3452
3453 spin_lock(&interfaces_lock);
Corey Minyarde8b33612005-09-06 15:18:45 -07003454 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003456 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 continue;
3458
3459 intf->handlers->request_events(intf->send_info);
3460 }
3461 spin_unlock(&interfaces_lock);
3462}
3463
3464static struct timer_list ipmi_timer;
3465
3466/* Call every ~100 ms. */
3467#define IPMI_TIMEOUT_TIME 100
3468
3469/* How many jiffies does it take to get to the timeout time. */
3470#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3471
3472/* Request events from the queue every second (this is the number of
3473 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3474 future, IPMI will add a way to know immediately if an event is in
3475 the queue and this silliness can go away. */
3476#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3477
Corey Minyard8f43f842005-06-23 22:01:40 -07003478static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3480
3481static void ipmi_timeout(unsigned long data)
3482{
Corey Minyard8f43f842005-06-23 22:01:40 -07003483 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485
3486 ticks_to_req_ev--;
3487 if (ticks_to_req_ev == 0) {
3488 ipmi_request_event();
3489 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3490 }
3491
3492 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3493
Corey Minyard8f43f842005-06-23 22:01:40 -07003494 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495}
3496
3497
3498static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3499static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3500
3501/* FIXME - convert these to slabs. */
3502static void free_smi_msg(struct ipmi_smi_msg *msg)
3503{
3504 atomic_dec(&smi_msg_inuse_count);
3505 kfree(msg);
3506}
3507
3508struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3509{
3510 struct ipmi_smi_msg *rv;
3511 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3512 if (rv) {
3513 rv->done = free_smi_msg;
3514 rv->user_data = NULL;
3515 atomic_inc(&smi_msg_inuse_count);
3516 }
3517 return rv;
3518}
3519
3520static void free_recv_msg(struct ipmi_recv_msg *msg)
3521{
3522 atomic_dec(&recv_msg_inuse_count);
3523 kfree(msg);
3524}
3525
3526struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3527{
3528 struct ipmi_recv_msg *rv;
3529
3530 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3531 if (rv) {
Corey Minyarda9eec552006-08-31 21:27:45 -07003532 rv->user = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 rv->done = free_recv_msg;
3534 atomic_inc(&recv_msg_inuse_count);
3535 }
3536 return rv;
3537}
3538
Corey Minyard393d2cc2005-11-07 00:59:54 -08003539void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3540{
3541 if (msg->user)
3542 kref_put(&msg->user->refcount, free_user);
3543 msg->done(msg);
3544}
3545
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546#ifdef CONFIG_IPMI_PANIC_EVENT
3547
3548static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3549{
3550}
3551
3552static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3553{
3554}
3555
3556#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003557static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003559 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3560 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3561 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3562 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 {
3564 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003565 intf->event_receiver = msg->msg.data[1];
3566 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 }
3568}
3569
Corey Minyard56a55ec2005-09-06 15:18:42 -07003570static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003572 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3573 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3574 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3575 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 {
3577 /* A get device id command, save if we are an event
3578 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003579 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3580 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 }
3582}
3583#endif
3584
3585static void send_panic_events(char *str)
3586{
3587 struct kernel_ipmi_msg msg;
3588 ipmi_smi_t intf;
3589 unsigned char data[16];
3590 int i;
3591 struct ipmi_system_interface_addr *si;
3592 struct ipmi_addr addr;
3593 struct ipmi_smi_msg smi_msg;
3594 struct ipmi_recv_msg recv_msg;
3595
3596 si = (struct ipmi_system_interface_addr *) &addr;
3597 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3598 si->channel = IPMI_BMC_CHANNEL;
3599 si->lun = 0;
3600
3601 /* Fill in an event telling that we have failed. */
3602 msg.netfn = 0x04; /* Sensor or Event. */
3603 msg.cmd = 2; /* Platform event command. */
3604 msg.data = data;
3605 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003606 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 data[1] = 0x03; /* This is for IPMI 1.0. */
3608 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3609 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3610 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3611
3612 /* Put a few breadcrumbs in. Hopefully later we can add more things
3613 to make the panic events more useful. */
3614 if (str) {
3615 data[3] = str[0];
3616 data[6] = str[1];
3617 data[7] = str[2];
3618 }
3619
3620 smi_msg.done = dummy_smi_done_handler;
3621 recv_msg.done = dummy_recv_done_handler;
3622
3623 /* For every registered interface, send the event. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003624 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003626 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 continue;
3628
3629 /* Send the event announcing the panic. */
3630 intf->handlers->set_run_to_completion(intf->send_info, 1);
3631 i_ipmi_request(NULL,
3632 intf,
3633 &addr,
3634 0,
3635 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003636 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 &smi_msg,
3638 &recv_msg,
3639 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003640 intf->channels[0].address,
3641 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 0, 1); /* Don't retry, and don't wait. */
3643 }
3644
3645#ifdef CONFIG_IPMI_PANIC_STRING
3646 /* On every interface, dump a bunch of OEM event holding the
3647 string. */
3648 if (!str)
3649 return;
3650
Corey Minyarde8b33612005-09-06 15:18:45 -07003651 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 char *p = str;
3653 struct ipmi_ipmb_addr *ipmb;
3654 int j;
3655
3656 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003657 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 continue;
3659
3660 /* First job here is to figure out where to send the
3661 OEM events. There's no way in IPMI to send OEM
3662 events using an event send command, so we have to
3663 find the SEL to put them in and stick them in
3664 there. */
3665
3666 /* Get capabilities from the get device id. */
3667 intf->local_sel_device = 0;
3668 intf->local_event_generator = 0;
3669 intf->event_receiver = 0;
3670
3671 /* Request the device info from the local MC. */
3672 msg.netfn = IPMI_NETFN_APP_REQUEST;
3673 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3674 msg.data = NULL;
3675 msg.data_len = 0;
3676 intf->null_user_handler = device_id_fetcher;
3677 i_ipmi_request(NULL,
3678 intf,
3679 &addr,
3680 0,
3681 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003682 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 &smi_msg,
3684 &recv_msg,
3685 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003686 intf->channels[0].address,
3687 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 0, 1); /* Don't retry, and don't wait. */
3689
3690 if (intf->local_event_generator) {
3691 /* Request the event receiver from the local MC. */
3692 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3693 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3694 msg.data = NULL;
3695 msg.data_len = 0;
3696 intf->null_user_handler = event_receiver_fetcher;
3697 i_ipmi_request(NULL,
3698 intf,
3699 &addr,
3700 0,
3701 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003702 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 &smi_msg,
3704 &recv_msg,
3705 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003706 intf->channels[0].address,
3707 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 0, 1); /* no retry, and no wait. */
3709 }
3710 intf->null_user_handler = NULL;
3711
3712 /* Validate the event receiver. The low bit must not
3713 be 1 (it must be a valid IPMB address), it cannot
3714 be zero, and it must not be my address. */
3715 if (((intf->event_receiver & 1) == 0)
3716 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003717 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 {
3719 /* The event receiver is valid, send an IPMB
3720 message. */
3721 ipmb = (struct ipmi_ipmb_addr *) &addr;
3722 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3723 ipmb->channel = 0; /* FIXME - is this right? */
3724 ipmb->lun = intf->event_receiver_lun;
3725 ipmb->slave_addr = intf->event_receiver;
3726 } else if (intf->local_sel_device) {
3727 /* The event receiver was not valid (or was
3728 me), but I am an SEL device, just dump it
3729 in my SEL. */
3730 si = (struct ipmi_system_interface_addr *) &addr;
3731 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3732 si->channel = IPMI_BMC_CHANNEL;
3733 si->lun = 0;
3734 } else
3735 continue; /* No where to send the event. */
3736
3737
3738 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
3739 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
3740 msg.data = data;
3741 msg.data_len = 16;
3742
3743 j = 0;
3744 while (*p) {
3745 int size = strlen(p);
3746
3747 if (size > 11)
3748 size = 11;
3749 data[0] = 0;
3750 data[1] = 0;
3751 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07003752 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 data[4] = j++; /* sequence # */
3754 /* Always give 11 bytes, so strncpy will fill
3755 it with zeroes for me. */
3756 strncpy(data+5, p, 11);
3757 p += size;
3758
3759 i_ipmi_request(NULL,
3760 intf,
3761 &addr,
3762 0,
3763 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003764 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 &smi_msg,
3766 &recv_msg,
3767 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003768 intf->channels[0].address,
3769 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 0, 1); /* no retry, and no wait. */
3771 }
3772 }
3773#endif /* CONFIG_IPMI_PANIC_STRING */
3774}
3775#endif /* CONFIG_IPMI_PANIC_EVENT */
3776
Lee Revellf18190b2006-06-26 18:30:00 +02003777static int has_panicked = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778
3779static int panic_event(struct notifier_block *this,
3780 unsigned long event,
3781 void *ptr)
3782{
3783 int i;
3784 ipmi_smi_t intf;
3785
Lee Revellf18190b2006-06-26 18:30:00 +02003786 if (has_panicked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 return NOTIFY_DONE;
Lee Revellf18190b2006-06-26 18:30:00 +02003788 has_panicked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789
3790 /* For every registered interface, set it to run to completion. */
Corey Minyarde8b33612005-09-06 15:18:45 -07003791 for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 intf = ipmi_interfaces[i];
Corey Minyard393d2cc2005-11-07 00:59:54 -08003793 if (IPMI_INVALID_INTERFACE(intf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 continue;
3795
3796 intf->handlers->set_run_to_completion(intf->send_info, 1);
3797 }
3798
3799#ifdef CONFIG_IPMI_PANIC_EVENT
3800 send_panic_events(ptr);
3801#endif
3802
3803 return NOTIFY_DONE;
3804}
3805
3806static struct notifier_block panic_block = {
3807 .notifier_call = panic_event,
3808 .next = NULL,
3809 .priority = 200 /* priority: INT_MAX >= x >= 0 */
3810};
3811
3812static int ipmi_init_msghandler(void)
3813{
3814 int i;
Corey Minyard50c812b2006-03-26 01:37:21 -08003815 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816
3817 if (initialized)
3818 return 0;
3819
Corey Minyard50c812b2006-03-26 01:37:21 -08003820 rv = driver_register(&ipmidriver);
3821 if (rv) {
3822 printk(KERN_ERR PFX "Could not register IPMI driver\n");
3823 return rv;
3824 }
3825
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003827 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828
Corey Minyard393d2cc2005-11-07 00:59:54 -08003829 for (i = 0; i < MAX_IPMI_INTERFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830 ipmi_interfaces[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831
Corey Minyard3b625942005-06-23 22:01:42 -07003832#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 proc_ipmi_root = proc_mkdir("ipmi", NULL);
3834 if (!proc_ipmi_root) {
3835 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
3836 return -ENOMEM;
3837 }
3838
3839 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07003840#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841
Corey Minyard409035e2006-06-28 04:26:53 -07003842 setup_timer(&ipmi_timer, ipmi_timeout, 0);
3843 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844
Alan Sterne041c682006-03-27 01:16:30 -08003845 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846
3847 initialized = 1;
3848
3849 return 0;
3850}
3851
3852static __init int ipmi_init_msghandler_mod(void)
3853{
3854 ipmi_init_msghandler();
3855 return 0;
3856}
3857
3858static __exit void cleanup_ipmi(void)
3859{
3860 int count;
3861
3862 if (!initialized)
3863 return;
3864
Alan Sterne041c682006-03-27 01:16:30 -08003865 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866
3867 /* This can't be called if any interfaces exist, so no worry about
3868 shutting down the interfaces. */
3869
3870 /* Tell the timer to stop, then wait for it to stop. This avoids
3871 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07003872 atomic_inc(&stop_operation);
3873 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874
Corey Minyard3b625942005-06-23 22:01:42 -07003875#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 remove_proc_entry(proc_ipmi_root->name, &proc_root);
Corey Minyard3b625942005-06-23 22:01:42 -07003877#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878
Corey Minyard50c812b2006-03-26 01:37:21 -08003879 driver_unregister(&ipmidriver);
3880
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 initialized = 0;
3882
3883 /* Check for buffer leaks. */
3884 count = atomic_read(&smi_msg_inuse_count);
3885 if (count != 0)
3886 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
3887 count);
3888 count = atomic_read(&recv_msg_inuse_count);
3889 if (count != 0)
3890 printk(KERN_WARNING PFX "recv message count %d at exit\n",
3891 count);
3892}
3893module_exit(cleanup_ipmi);
3894
3895module_init(ipmi_init_msghandler_mod);
3896MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07003897MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
3898MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
3899MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900
3901EXPORT_SYMBOL(ipmi_create_user);
3902EXPORT_SYMBOL(ipmi_destroy_user);
3903EXPORT_SYMBOL(ipmi_get_version);
3904EXPORT_SYMBOL(ipmi_request_settime);
3905EXPORT_SYMBOL(ipmi_request_supply_msgs);
3906EXPORT_SYMBOL(ipmi_register_smi);
3907EXPORT_SYMBOL(ipmi_unregister_smi);
3908EXPORT_SYMBOL(ipmi_register_for_cmd);
3909EXPORT_SYMBOL(ipmi_unregister_for_cmd);
3910EXPORT_SYMBOL(ipmi_smi_msg_received);
3911EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
3912EXPORT_SYMBOL(ipmi_alloc_smi_msg);
3913EXPORT_SYMBOL(ipmi_addr_length);
3914EXPORT_SYMBOL(ipmi_validate_addr);
3915EXPORT_SYMBOL(ipmi_set_gets_events);
3916EXPORT_SYMBOL(ipmi_smi_watcher_register);
3917EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
3918EXPORT_SYMBOL(ipmi_set_my_address);
3919EXPORT_SYMBOL(ipmi_get_my_address);
3920EXPORT_SYMBOL(ipmi_set_my_LUN);
3921EXPORT_SYMBOL(ipmi_get_my_LUN);
3922EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003924EXPORT_SYMBOL(ipmi_free_recv_msg);