blob: 230064ede08d9ade7c9fa26f3ce5e7f76127ccd6 [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 Minyardb9675132006-12-06 20:41:02 -080051#define IPMI_DRIVER_VERSION "39.1"
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
Randy Dunlap0c8204b2006-12-10 02:19:06 -080056static int initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Corey Minyard3b625942005-06-23 22:01:42 -070058#ifdef CONFIG_PROC_FS
Randy Dunlap0c8204b2006-12-10 02:19:06 -080059static struct proc_dir_entry *proc_ipmi_root;
Corey Minyard3b625942005-06-23 22:01:42 -070060#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Corey Minyardb9675132006-12-06 20:41:02 -080062/* Remain in auto-maintenance mode for this amount of time (in ms). */
63#define IPMI_MAINTENANCE_MODE_TIMEOUT 30000
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#define MAX_EVENTS_IN_QUEUE 25
66
67/* Don't let a message sit in a queue forever, always time it with at lest
68 the max message timer. This is in milliseconds. */
69#define MAX_MSG_TIMEOUT 60000
70
Corey Minyard393d2cc2005-11-07 00:59:54 -080071
72/*
73 * The main "user" data structure.
74 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070075struct ipmi_user
76{
77 struct list_head link;
78
Corey Minyard393d2cc2005-11-07 00:59:54 -080079 /* Set to "0" when the user is destroyed. */
80 int valid;
81
82 struct kref refcount;
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 /* The upper layer that handles receive messages. */
85 struct ipmi_user_hndl *handler;
86 void *handler_data;
87
88 /* The interface this user is bound to. */
89 ipmi_smi_t intf;
90
91 /* Does this interface receive IPMI events? */
92 int gets_events;
93};
94
95struct cmd_rcvr
96{
97 struct list_head link;
98
99 ipmi_user_t user;
100 unsigned char netfn;
101 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -0700102 unsigned int chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800103
104 /*
105 * This is used to form a linked lised during mass deletion.
106 * Since this is in an RCU list, we cannot use the link above
107 * or change any data until the RCU period completes. So we
108 * use this next variable during mass deletion so we can have
109 * a list and don't have to wait and restart the search on
110 * every individual deletion of a command. */
111 struct cmd_rcvr *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112};
113
114struct seq_table
115{
116 unsigned int inuse : 1;
117 unsigned int broadcast : 1;
118
119 unsigned long timeout;
120 unsigned long orig_timeout;
121 unsigned int retries_left;
122
123 /* To verify on an incoming send message response that this is
124 the message that the response is for, we keep a sequence id
125 and increment it every time we send a message. */
126 long seqid;
127
128 /* This is held so we can properly respond to the message on a
129 timeout, and it is used to hold the temporary data for
130 retransmission, too. */
131 struct ipmi_recv_msg *recv_msg;
132};
133
134/* Store the information in a msgid (long) to allow us to find a
135 sequence table entry from the msgid. */
136#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
137
138#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
139 do { \
140 seq = ((msgid >> 26) & 0x3f); \
141 seqid = (msgid & 0x3fffff); \
Corey Minyarde8b33612005-09-06 15:18:45 -0700142 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
145
146struct ipmi_channel
147{
148 unsigned char medium;
149 unsigned char protocol;
Corey Minyardc14979b2005-09-06 15:18:38 -0700150
151 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
152 but may be changed by the user. */
153 unsigned char address;
154
155 /* My LUN. This should generally stay the SMS LUN, but just in
156 case... */
157 unsigned char lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158};
159
Corey Minyard3b625942005-06-23 22:01:42 -0700160#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161struct ipmi_proc_entry
162{
163 char *name;
164 struct ipmi_proc_entry *next;
165};
Corey Minyard3b625942005-06-23 22:01:42 -0700166#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
Corey Minyard50c812b2006-03-26 01:37:21 -0800168struct bmc_device
169{
170 struct platform_device *dev;
171 struct ipmi_device_id id;
172 unsigned char guid[16];
173 int guid_set;
174
175 struct kref refcount;
176
177 /* bmc device attributes */
178 struct device_attribute device_id_attr;
179 struct device_attribute provides_dev_sdrs_attr;
180 struct device_attribute revision_attr;
181 struct device_attribute firmware_rev_attr;
182 struct device_attribute version_attr;
183 struct device_attribute add_dev_support_attr;
184 struct device_attribute manufacturer_id_attr;
185 struct device_attribute product_id_attr;
186 struct device_attribute guid_attr;
187 struct device_attribute aux_firmware_rev_attr;
188};
189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#define IPMI_IPMB_NUM_SEQ 64
Corey Minyardc14979b2005-09-06 15:18:38 -0700191#define IPMI_MAX_CHANNELS 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192struct ipmi_smi
193{
194 /* What interface number are we? */
195 int intf_num;
196
Corey Minyard393d2cc2005-11-07 00:59:54 -0800197 struct kref refcount;
198
Corey Minyardbca03242006-12-06 20:40:57 -0800199 /* Used for a list of interfaces. */
200 struct list_head link;
201
Corey Minyard393d2cc2005-11-07 00:59:54 -0800202 /* The list of upper layers that are using me. seq_lock
203 * protects this. */
204 struct list_head users;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Corey Minyardb2c03942006-12-06 20:41:00 -0800206 /* Information to supply to users. */
207 unsigned char ipmi_version_major;
208 unsigned char ipmi_version_minor;
209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 /* Used for wake ups at startup. */
211 wait_queue_head_t waitq;
212
Corey Minyard50c812b2006-03-26 01:37:21 -0800213 struct bmc_device *bmc;
214 char *my_dev_name;
Corey Minyard759643b2006-12-06 20:40:59 -0800215 char *sysfs_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Corey Minyardb2c03942006-12-06 20:41:00 -0800217 /* This is the lower-layer's sender routine. Note that you
218 * must either be holding the ipmi_interfaces_mutex or be in
219 * an umpreemptible region to use this. You must fetch the
220 * value into a local variable and make sure it is not NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 struct ipmi_smi_handlers *handlers;
222 void *send_info;
223
Corey Minyard3b625942005-06-23 22:01:42 -0700224#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 /* A list of proc entries for this interface. This does not
226 need a lock, only one thread creates it and only one thread
227 destroys it. */
Corey Minyard3b625942005-06-23 22:01:42 -0700228 spinlock_t proc_entry_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 struct ipmi_proc_entry *proc_entries;
Corey Minyard3b625942005-06-23 22:01:42 -0700230#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
Corey Minyard50c812b2006-03-26 01:37:21 -0800232 /* Driver-model device for the system interface. */
233 struct device *si_dev;
234
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 /* A table of sequence numbers for this interface. We use the
236 sequence numbers for IPMB messages that go out of the
237 interface to match them up with their responses. A routine
238 is called periodically to time the items in this list. */
239 spinlock_t seq_lock;
240 struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
241 int curr_seq;
242
243 /* Messages that were delayed for some reason (out of memory,
244 for instance), will go in here to be processed later in a
245 periodic timer interrupt. */
246 spinlock_t waiting_msgs_lock;
247 struct list_head waiting_msgs;
248
249 /* The list of command receivers that are registered for commands
250 on this interface. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800251 struct mutex cmd_rcvrs_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 struct list_head cmd_rcvrs;
253
254 /* Events that were queues because no one was there to receive
255 them. */
256 spinlock_t events_lock; /* For dealing with event stuff. */
257 struct list_head waiting_events;
258 unsigned int waiting_events_count; /* How many events in queue? */
Corey Minyardb2c03942006-12-06 20:41:00 -0800259 int delivering_events;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 /* The event receiver for my BMC, only really used at panic
262 shutdown as a place to store this. */
263 unsigned char event_receiver;
264 unsigned char event_receiver_lun;
265 unsigned char local_sel_device;
266 unsigned char local_event_generator;
267
Corey Minyardb9675132006-12-06 20:41:02 -0800268 /* For handling of maintenance mode. */
269 int maintenance_mode;
270 int maintenance_mode_enable;
271 int auto_maintenance_timeout;
272 spinlock_t maintenance_mode_lock; /* Used in a timer... */
273
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 /* A cheap hack, if this is non-null and a message to an
275 interface comes in with a NULL user, call this routine with
276 it. Note that the message will still be freed by the
277 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700278 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
280 /* When we are scanning the channels for an SMI, this will
281 tell which channel we are scanning. */
282 int curr_channel;
283
284 /* Channel information */
285 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
286
287 /* Proc FS stuff. */
288 struct proc_dir_entry *proc_dir;
289 char proc_dir_name[10];
290
291 spinlock_t counter_lock; /* For making counters atomic. */
292
293 /* Commands we got that were invalid. */
294 unsigned int sent_invalid_commands;
295
296 /* Commands we sent to the MC. */
297 unsigned int sent_local_commands;
298 /* Responses from the MC that were delivered to a user. */
299 unsigned int handled_local_responses;
300 /* Responses from the MC that were not delivered to a user. */
301 unsigned int unhandled_local_responses;
302
303 /* Commands we sent out to the IPMB bus. */
304 unsigned int sent_ipmb_commands;
305 /* Commands sent on the IPMB that had errors on the SEND CMD */
306 unsigned int sent_ipmb_command_errs;
307 /* Each retransmit increments this count. */
308 unsigned int retransmitted_ipmb_commands;
309 /* When a message times out (runs out of retransmits) this is
310 incremented. */
311 unsigned int timed_out_ipmb_commands;
312
313 /* This is like above, but for broadcasts. Broadcasts are
314 *not* included in the above count (they are expected to
315 time out). */
316 unsigned int timed_out_ipmb_broadcasts;
317
318 /* Responses I have sent to the IPMB bus. */
319 unsigned int sent_ipmb_responses;
320
321 /* The response was delivered to the user. */
322 unsigned int handled_ipmb_responses;
323 /* The response had invalid data in it. */
324 unsigned int invalid_ipmb_responses;
325 /* The response didn't have anyone waiting for it. */
326 unsigned int unhandled_ipmb_responses;
327
328 /* Commands we sent out to the IPMB bus. */
329 unsigned int sent_lan_commands;
330 /* Commands sent on the IPMB that had errors on the SEND CMD */
331 unsigned int sent_lan_command_errs;
332 /* Each retransmit increments this count. */
333 unsigned int retransmitted_lan_commands;
334 /* When a message times out (runs out of retransmits) this is
335 incremented. */
336 unsigned int timed_out_lan_commands;
337
338 /* Responses I have sent to the IPMB bus. */
339 unsigned int sent_lan_responses;
340
341 /* The response was delivered to the user. */
342 unsigned int handled_lan_responses;
343 /* The response had invalid data in it. */
344 unsigned int invalid_lan_responses;
345 /* The response didn't have anyone waiting for it. */
346 unsigned int unhandled_lan_responses;
347
348 /* The command was delivered to the user. */
349 unsigned int handled_commands;
350 /* The command had invalid data in it. */
351 unsigned int invalid_commands;
352 /* The command didn't have anyone waiting for it. */
353 unsigned int unhandled_commands;
354
355 /* Invalid data in an event. */
356 unsigned int invalid_events;
357 /* Events that were received with the proper format. */
358 unsigned int events;
359};
Corey Minyard50c812b2006-03-26 01:37:21 -0800360#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Corey Minyard50c812b2006-03-26 01:37:21 -0800362/**
363 * The driver model view of the IPMI messaging driver.
364 */
365static struct device_driver ipmidriver = {
366 .name = "ipmi",
367 .bus = &platform_bus_type
368};
369static DEFINE_MUTEX(ipmidriver_mutex);
370
Corey Minyardbca03242006-12-06 20:40:57 -0800371static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces);
372static DEFINE_MUTEX(ipmi_interfaces_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374/* List of watchers that want to know when smi's are added and
375 deleted. */
376static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
Corey Minyardb2c03942006-12-06 20:41:00 -0800377static DEFINE_MUTEX(smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Corey Minyard393d2cc2005-11-07 00:59:54 -0800380static void free_recv_msg_list(struct list_head *q)
381{
382 struct ipmi_recv_msg *msg, *msg2;
383
384 list_for_each_entry_safe(msg, msg2, q, link) {
385 list_del(&msg->link);
386 ipmi_free_recv_msg(msg);
387 }
388}
389
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800390static void free_smi_msg_list(struct list_head *q)
391{
392 struct ipmi_smi_msg *msg, *msg2;
393
394 list_for_each_entry_safe(msg, msg2, q, link) {
395 list_del(&msg->link);
396 ipmi_free_smi_msg(msg);
397 }
398}
399
Corey Minyard393d2cc2005-11-07 00:59:54 -0800400static void clean_up_interface_data(ipmi_smi_t intf)
401{
402 int i;
403 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800404 struct list_head list;
405
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800406 free_smi_msg_list(&intf->waiting_msgs);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800407 free_recv_msg_list(&intf->waiting_events);
408
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800409 /*
410 * Wholesale remove all the entries from the list in the
411 * interface and wait for RCU to know that none are in use.
412 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800413 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800414 INIT_LIST_HEAD(&list);
415 list_splice_init_rcu(&intf->cmd_rcvrs, &list, synchronize_rcu);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800416 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800417
418 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
419 kfree(rcvr);
420
421 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
422 if ((intf->seq_table[i].inuse)
423 && (intf->seq_table[i].recv_msg))
424 {
425 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 }
427 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800428}
429
430static void intf_free(struct kref *ref)
431{
432 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
433
434 clean_up_interface_data(intf);
435 kfree(intf);
436}
437
Corey Minyardbca03242006-12-06 20:40:57 -0800438struct watcher_entry {
Corey Minyardb2c03942006-12-06 20:41:00 -0800439 int intf_num;
440 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800441 struct list_head link;
Corey Minyardbca03242006-12-06 20:40:57 -0800442};
443
Corey Minyard393d2cc2005-11-07 00:59:54 -0800444int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
445{
Corey Minyardbca03242006-12-06 20:40:57 -0800446 ipmi_smi_t intf;
447 struct list_head to_deliver = LIST_HEAD_INIT(to_deliver);
448 struct watcher_entry *e, *e2;
449
Corey Minyardb2c03942006-12-06 20:41:00 -0800450 mutex_lock(&smi_watchers_mutex);
451
Corey Minyardbca03242006-12-06 20:40:57 -0800452 mutex_lock(&ipmi_interfaces_mutex);
453
Corey Minyardb2c03942006-12-06 20:41:00 -0800454 /* Build a list of things to deliver. */
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800455 list_for_each_entry(intf, &ipmi_interfaces, link) {
Corey Minyardbca03242006-12-06 20:40:57 -0800456 if (intf->intf_num == -1)
457 continue;
458 e = kmalloc(sizeof(*e), GFP_KERNEL);
459 if (!e)
460 goto out_err;
Corey Minyardb2c03942006-12-06 20:41:00 -0800461 kref_get(&intf->refcount);
462 e->intf = intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800463 e->intf_num = intf->intf_num;
464 list_add_tail(&e->link, &to_deliver);
465 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800466
Corey Minyardb2c03942006-12-06 20:41:00 -0800467 /* We will succeed, so add it to the list. */
468 list_add(&watcher->link, &smi_watchers);
Corey Minyardbca03242006-12-06 20:40:57 -0800469
470 mutex_unlock(&ipmi_interfaces_mutex);
471
472 list_for_each_entry_safe(e, e2, &to_deliver, link) {
473 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800474 watcher->new_smi(e->intf_num, e->intf->si_dev);
475 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800476 kfree(e);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800477 }
Corey Minyardbca03242006-12-06 20:40:57 -0800478
Corey Minyardb2c03942006-12-06 20:41:00 -0800479 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 return 0;
Corey Minyardbca03242006-12-06 20:40:57 -0800482
483 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -0800484 mutex_unlock(&ipmi_interfaces_mutex);
485 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800486 list_for_each_entry_safe(e, e2, &to_deliver, link) {
487 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800488 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800489 kfree(e);
490 }
491 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
494int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
495{
Corey Minyardb2c03942006-12-06 20:41:00 -0800496 mutex_lock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 list_del(&(watcher->link));
Corey Minyardb2c03942006-12-06 20:41:00 -0800498 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 return 0;
500}
501
Corey Minyardb2c03942006-12-06 20:41:00 -0800502/*
503 * Must be called with smi_watchers_mutex held.
504 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505static void
Corey Minyard50c812b2006-03-26 01:37:21 -0800506call_smi_watchers(int i, struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
508 struct ipmi_smi_watcher *w;
509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 list_for_each_entry(w, &smi_watchers, link) {
511 if (try_module_get(w->owner)) {
Corey Minyard50c812b2006-03-26 01:37:21 -0800512 w->new_smi(i, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 module_put(w->owner);
514 }
515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516}
517
518static int
519ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
520{
521 if (addr1->addr_type != addr2->addr_type)
522 return 0;
523
524 if (addr1->channel != addr2->channel)
525 return 0;
526
527 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
528 struct ipmi_system_interface_addr *smi_addr1
529 = (struct ipmi_system_interface_addr *) addr1;
530 struct ipmi_system_interface_addr *smi_addr2
531 = (struct ipmi_system_interface_addr *) addr2;
532 return (smi_addr1->lun == smi_addr2->lun);
533 }
534
535 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
536 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
537 {
538 struct ipmi_ipmb_addr *ipmb_addr1
539 = (struct ipmi_ipmb_addr *) addr1;
540 struct ipmi_ipmb_addr *ipmb_addr2
541 = (struct ipmi_ipmb_addr *) addr2;
542
543 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
544 && (ipmb_addr1->lun == ipmb_addr2->lun));
545 }
546
547 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
548 struct ipmi_lan_addr *lan_addr1
549 = (struct ipmi_lan_addr *) addr1;
550 struct ipmi_lan_addr *lan_addr2
551 = (struct ipmi_lan_addr *) addr2;
552
553 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
554 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
555 && (lan_addr1->session_handle
556 == lan_addr2->session_handle)
557 && (lan_addr1->lun == lan_addr2->lun));
558 }
559
560 return 1;
561}
562
563int ipmi_validate_addr(struct ipmi_addr *addr, int len)
564{
565 if (len < sizeof(struct ipmi_system_interface_addr)) {
566 return -EINVAL;
567 }
568
569 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
570 if (addr->channel != IPMI_BMC_CHANNEL)
571 return -EINVAL;
572 return 0;
573 }
574
575 if ((addr->channel == IPMI_BMC_CHANNEL)
Jayachandran C12fc1d72006-02-03 03:04:51 -0800576 || (addr->channel >= IPMI_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 || (addr->channel < 0))
578 return -EINVAL;
579
580 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
581 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
582 {
583 if (len < sizeof(struct ipmi_ipmb_addr)) {
584 return -EINVAL;
585 }
586 return 0;
587 }
588
589 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
590 if (len < sizeof(struct ipmi_lan_addr)) {
591 return -EINVAL;
592 }
593 return 0;
594 }
595
596 return -EINVAL;
597}
598
599unsigned int ipmi_addr_length(int addr_type)
600{
601 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
602 return sizeof(struct ipmi_system_interface_addr);
603
604 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
605 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
606 {
607 return sizeof(struct ipmi_ipmb_addr);
608 }
609
610 if (addr_type == IPMI_LAN_ADDR_TYPE)
611 return sizeof(struct ipmi_lan_addr);
612
613 return 0;
614}
615
616static void deliver_response(struct ipmi_recv_msg *msg)
617{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800618 if (!msg->user) {
Corey Minyard56a55ec2005-09-06 15:18:42 -0700619 ipmi_smi_t intf = msg->user_msg_data;
620 unsigned long flags;
621
622 /* Special handling for NULL users. */
623 if (intf->null_user_handler) {
624 intf->null_user_handler(intf, msg);
625 spin_lock_irqsave(&intf->counter_lock, flags);
626 intf->handled_local_responses++;
627 spin_unlock_irqrestore(&intf->counter_lock, flags);
628 } else {
629 /* No handler, so give up. */
630 spin_lock_irqsave(&intf->counter_lock, flags);
631 intf->unhandled_local_responses++;
632 spin_unlock_irqrestore(&intf->counter_lock, flags);
633 }
634 ipmi_free_recv_msg(msg);
635 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800636 ipmi_user_t user = msg->user;
637 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639}
640
Corey Minyardb2c03942006-12-06 20:41:00 -0800641static void
642deliver_err_response(struct ipmi_recv_msg *msg, int err)
643{
644 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
645 msg->msg_data[0] = err;
646 msg->msg.netfn |= 1; /* Convert to a response. */
647 msg->msg.data_len = 1;
648 msg->msg.data = msg->msg_data;
649 deliver_response(msg);
650}
651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652/* Find the next sequence number not being used and add the given
653 message with the given timeout to the sequence table. This must be
654 called with the interface's seq_lock held. */
655static int intf_next_seq(ipmi_smi_t intf,
656 struct ipmi_recv_msg *recv_msg,
657 unsigned long timeout,
658 int retries,
659 int broadcast,
660 unsigned char *seq,
661 long *seqid)
662{
663 int rv = 0;
664 unsigned int i;
665
Corey Minyarde8b33612005-09-06 15:18:45 -0700666 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700668 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800670 if (!intf->seq_table[i].inuse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 break;
672 }
673
Corey Minyard8a3628d2006-03-31 02:30:40 -0800674 if (!intf->seq_table[i].inuse) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 intf->seq_table[i].recv_msg = recv_msg;
676
677 /* Start with the maximum timeout, when the send response
678 comes in we will start the real timer. */
679 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
680 intf->seq_table[i].orig_timeout = timeout;
681 intf->seq_table[i].retries_left = retries;
682 intf->seq_table[i].broadcast = broadcast;
683 intf->seq_table[i].inuse = 1;
684 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
685 *seq = i;
686 *seqid = intf->seq_table[i].seqid;
687 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
688 } else {
689 rv = -EAGAIN;
690 }
691
692 return rv;
693}
694
695/* Return the receive message for the given sequence number and
696 release the sequence number so it can be reused. Some other data
697 is passed in to be sure the message matches up correctly (to help
698 guard against message coming in after their timeout and the
699 sequence number being reused). */
700static int intf_find_seq(ipmi_smi_t intf,
701 unsigned char seq,
702 short channel,
703 unsigned char cmd,
704 unsigned char netfn,
705 struct ipmi_addr *addr,
706 struct ipmi_recv_msg **recv_msg)
707{
708 int rv = -ENODEV;
709 unsigned long flags;
710
711 if (seq >= IPMI_IPMB_NUM_SEQ)
712 return -EINVAL;
713
714 spin_lock_irqsave(&(intf->seq_lock), flags);
715 if (intf->seq_table[seq].inuse) {
716 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
717
718 if ((msg->addr.channel == channel)
719 && (msg->msg.cmd == cmd)
720 && (msg->msg.netfn == netfn)
721 && (ipmi_addr_equal(addr, &(msg->addr))))
722 {
723 *recv_msg = msg;
724 intf->seq_table[seq].inuse = 0;
725 rv = 0;
726 }
727 }
728 spin_unlock_irqrestore(&(intf->seq_lock), flags);
729
730 return rv;
731}
732
733
734/* Start the timer for a specific sequence table entry. */
735static int intf_start_seq_timer(ipmi_smi_t intf,
736 long msgid)
737{
738 int rv = -ENODEV;
739 unsigned long flags;
740 unsigned char seq;
741 unsigned long seqid;
742
743
744 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
745
746 spin_lock_irqsave(&(intf->seq_lock), flags);
747 /* We do this verification because the user can be deleted
748 while a message is outstanding. */
749 if ((intf->seq_table[seq].inuse)
750 && (intf->seq_table[seq].seqid == seqid))
751 {
752 struct seq_table *ent = &(intf->seq_table[seq]);
753 ent->timeout = ent->orig_timeout;
754 rv = 0;
755 }
756 spin_unlock_irqrestore(&(intf->seq_lock), flags);
757
758 return rv;
759}
760
761/* Got an error for the send message for a specific sequence number. */
762static int intf_err_seq(ipmi_smi_t intf,
763 long msgid,
764 unsigned int err)
765{
766 int rv = -ENODEV;
767 unsigned long flags;
768 unsigned char seq;
769 unsigned long seqid;
770 struct ipmi_recv_msg *msg = NULL;
771
772
773 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
774
775 spin_lock_irqsave(&(intf->seq_lock), flags);
776 /* We do this verification because the user can be deleted
777 while a message is outstanding. */
778 if ((intf->seq_table[seq].inuse)
779 && (intf->seq_table[seq].seqid == seqid))
780 {
781 struct seq_table *ent = &(intf->seq_table[seq]);
782
783 ent->inuse = 0;
784 msg = ent->recv_msg;
785 rv = 0;
786 }
787 spin_unlock_irqrestore(&(intf->seq_lock), flags);
788
Corey Minyardb2c03942006-12-06 20:41:00 -0800789 if (msg)
790 deliver_err_response(msg, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
792 return rv;
793}
794
795
796int ipmi_create_user(unsigned int if_num,
797 struct ipmi_user_hndl *handler,
798 void *handler_data,
799 ipmi_user_t *user)
800{
801 unsigned long flags;
802 ipmi_user_t new_user;
803 int rv = 0;
804 ipmi_smi_t intf;
805
806 /* There is no module usecount here, because it's not
807 required. Since this can only be used by and called from
808 other modules, they will implicitly use this module, and
809 thus this can't be removed unless the other modules are
810 removed. */
811
812 if (handler == NULL)
813 return -EINVAL;
814
815 /* Make sure the driver is actually initialized, this handles
816 problems with initialization order. */
817 if (!initialized) {
818 rv = ipmi_init_msghandler();
819 if (rv)
820 return rv;
821
822 /* The init code doesn't return an error if it was turned
823 off, but it won't initialize. Check that. */
824 if (!initialized)
825 return -ENODEV;
826 }
827
828 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800829 if (!new_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 return -ENOMEM;
831
Corey Minyardb2c03942006-12-06 20:41:00 -0800832 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800833 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
834 if (intf->intf_num == if_num)
835 goto found;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 }
Corey Minyardb2c03942006-12-06 20:41:00 -0800837 /* Not found, return an error */
Corey Minyardbca03242006-12-06 20:40:57 -0800838 rv = -EINVAL;
839 goto out_kfree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Corey Minyardbca03242006-12-06 20:40:57 -0800841 found:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800842 /* Note that each existing user holds a refcount to the interface. */
843 kref_get(&intf->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
Corey Minyard393d2cc2005-11-07 00:59:54 -0800845 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 new_user->handler = handler;
847 new_user->handler_data = handler_data;
848 new_user->intf = intf;
849 new_user->gets_events = 0;
850
851 if (!try_module_get(intf->handlers->owner)) {
852 rv = -ENODEV;
Adrian Bunk5c98d292006-03-25 03:07:52 -0800853 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
855
856 if (intf->handlers->inc_usecount) {
857 rv = intf->handlers->inc_usecount(intf->send_info);
858 if (rv) {
859 module_put(intf->handlers->owner);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800860 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 }
862 }
863
Corey Minyardb2c03942006-12-06 20:41:00 -0800864 /* Hold the lock so intf->handlers is guaranteed to be good
865 * until now */
866 mutex_unlock(&ipmi_interfaces_mutex);
867
Corey Minyard393d2cc2005-11-07 00:59:54 -0800868 new_user->valid = 1;
869 spin_lock_irqsave(&intf->seq_lock, flags);
870 list_add_rcu(&new_user->link, &intf->users);
871 spin_unlock_irqrestore(&intf->seq_lock, flags);
872 *user = new_user;
873 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Adrian Bunk5c98d292006-03-25 03:07:52 -0800875out_kref:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800876 kref_put(&intf->refcount, intf_free);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800877out_kfree:
Corey Minyardb2c03942006-12-06 20:41:00 -0800878 mutex_unlock(&ipmi_interfaces_mutex);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800879 kfree(new_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 return rv;
881}
882
Corey Minyard393d2cc2005-11-07 00:59:54 -0800883static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800885 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887}
888
889int ipmi_destroy_user(ipmi_user_t user)
890{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800891 ipmi_smi_t intf = user->intf;
892 int i;
893 unsigned long flags;
894 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800895 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
Corey Minyard8a3628d2006-03-31 02:30:40 -0800897 user->valid = 0;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800898
899 /* Remove the user from the interface's sequence table. */
900 spin_lock_irqsave(&intf->seq_lock, flags);
901 list_del_rcu(&user->link);
902
903 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
904 if (intf->seq_table[i].inuse
905 && (intf->seq_table[i].recv_msg->user == user))
906 {
907 intf->seq_table[i].inuse = 0;
Corey Minyardb2c03942006-12-06 20:41:00 -0800908 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800911 spin_unlock_irqrestore(&intf->seq_lock, flags);
912
913 /*
914 * Remove the user from the command receiver's table. First
915 * we build a list of everything (not using the standard link,
916 * since other things may be using it till we do
917 * synchronize_rcu()) then free everything in that list.
918 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800919 mutex_lock(&intf->cmd_rcvrs_mutex);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800920 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800921 if (rcvr->user == user) {
922 list_del_rcu(&rcvr->link);
923 rcvr->next = rcvrs;
924 rcvrs = rcvr;
925 }
926 }
Corey Minyardd6dfd132006-03-31 02:30:41 -0800927 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800928 synchronize_rcu();
929 while (rcvrs) {
930 rcvr = rcvrs;
931 rcvrs = rcvr->next;
932 kfree(rcvr);
933 }
934
Corey Minyardb2c03942006-12-06 20:41:00 -0800935 mutex_lock(&ipmi_interfaces_mutex);
936 if (intf->handlers) {
937 module_put(intf->handlers->owner);
938 if (intf->handlers->dec_usecount)
939 intf->handlers->dec_usecount(intf->send_info);
940 }
941 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800942
943 kref_put(&intf->refcount, intf_free);
944
945 kref_put(&user->refcount, free_user);
946
Corey Minyard8a3628d2006-03-31 02:30:40 -0800947 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948}
949
950void ipmi_get_version(ipmi_user_t user,
951 unsigned char *major,
952 unsigned char *minor)
953{
Corey Minyardb2c03942006-12-06 20:41:00 -0800954 *major = user->intf->ipmi_version_major;
955 *minor = user->intf->ipmi_version_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956}
957
Corey Minyardc14979b2005-09-06 15:18:38 -0700958int ipmi_set_my_address(ipmi_user_t user,
959 unsigned int channel,
960 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961{
Corey Minyardc14979b2005-09-06 15:18:38 -0700962 if (channel >= IPMI_MAX_CHANNELS)
963 return -EINVAL;
964 user->intf->channels[channel].address = address;
965 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
967
Corey Minyardc14979b2005-09-06 15:18:38 -0700968int ipmi_get_my_address(ipmi_user_t user,
969 unsigned int channel,
970 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
Corey Minyardc14979b2005-09-06 15:18:38 -0700972 if (channel >= IPMI_MAX_CHANNELS)
973 return -EINVAL;
974 *address = user->intf->channels[channel].address;
975 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976}
977
Corey Minyardc14979b2005-09-06 15:18:38 -0700978int ipmi_set_my_LUN(ipmi_user_t user,
979 unsigned int channel,
980 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981{
Corey Minyardc14979b2005-09-06 15:18:38 -0700982 if (channel >= IPMI_MAX_CHANNELS)
983 return -EINVAL;
984 user->intf->channels[channel].lun = LUN & 0x3;
985 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986}
987
Corey Minyardc14979b2005-09-06 15:18:38 -0700988int ipmi_get_my_LUN(ipmi_user_t user,
989 unsigned int channel,
990 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991{
Corey Minyardc14979b2005-09-06 15:18:38 -0700992 if (channel >= IPMI_MAX_CHANNELS)
993 return -EINVAL;
994 *address = user->intf->channels[channel].lun;
995 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996}
997
Corey Minyardb9675132006-12-06 20:41:02 -0800998int ipmi_get_maintenance_mode(ipmi_user_t user)
999{
1000 int mode;
1001 unsigned long flags;
1002
1003 spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);
1004 mode = user->intf->maintenance_mode;
1005 spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);
1006
1007 return mode;
1008}
1009EXPORT_SYMBOL(ipmi_get_maintenance_mode);
1010
1011static void maintenance_mode_update(ipmi_smi_t intf)
1012{
1013 if (intf->handlers->set_maintenance_mode)
1014 intf->handlers->set_maintenance_mode(
1015 intf->send_info, intf->maintenance_mode_enable);
1016}
1017
1018int ipmi_set_maintenance_mode(ipmi_user_t user, int mode)
1019{
1020 int rv = 0;
1021 unsigned long flags;
1022 ipmi_smi_t intf = user->intf;
1023
1024 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1025 if (intf->maintenance_mode != mode) {
1026 switch (mode) {
1027 case IPMI_MAINTENANCE_MODE_AUTO:
1028 intf->maintenance_mode = mode;
1029 intf->maintenance_mode_enable
1030 = (intf->auto_maintenance_timeout > 0);
1031 break;
1032
1033 case IPMI_MAINTENANCE_MODE_OFF:
1034 intf->maintenance_mode = mode;
1035 intf->maintenance_mode_enable = 0;
1036 break;
1037
1038 case IPMI_MAINTENANCE_MODE_ON:
1039 intf->maintenance_mode = mode;
1040 intf->maintenance_mode_enable = 1;
1041 break;
1042
1043 default:
1044 rv = -EINVAL;
1045 goto out_unlock;
1046 }
1047
1048 maintenance_mode_update(intf);
1049 }
1050 out_unlock:
1051 spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);
1052
1053 return rv;
1054}
1055EXPORT_SYMBOL(ipmi_set_maintenance_mode);
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057int ipmi_set_gets_events(ipmi_user_t user, int val)
1058{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001059 unsigned long flags;
1060 ipmi_smi_t intf = user->intf;
1061 struct ipmi_recv_msg *msg, *msg2;
1062 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
Corey Minyard393d2cc2005-11-07 00:59:54 -08001064 INIT_LIST_HEAD(&msgs);
1065
1066 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 user->gets_events = val;
1068
Corey Minyardb2c03942006-12-06 20:41:00 -08001069 if (intf->delivering_events)
1070 /*
1071 * Another thread is delivering events for this, so
1072 * let it handle any new events.
1073 */
1074 goto out;
1075
1076 /* Deliver any queued events. */
1077 while (user->gets_events && !list_empty(&intf->waiting_events)) {
Akinobu Mita179e0912006-06-26 00:24:41 -07001078 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
1079 list_move_tail(&msg->link, &msgs);
Corey Minyard4791c032006-04-10 22:54:31 -07001080 intf->waiting_events_count = 0;
Corey Minyardb2c03942006-12-06 20:41:00 -08001081
1082 intf->delivering_events = 1;
1083 spin_unlock_irqrestore(&intf->events_lock, flags);
1084
1085 list_for_each_entry_safe(msg, msg2, &msgs, link) {
1086 msg->user = user;
1087 kref_get(&user->refcount);
1088 deliver_response(msg);
1089 }
1090
1091 spin_lock_irqsave(&intf->events_lock, flags);
1092 intf->delivering_events = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08001094
Corey Minyardb2c03942006-12-06 20:41:00 -08001095 out:
Corey Minyard393d2cc2005-11-07 00:59:54 -08001096 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
1098 return 0;
1099}
1100
Corey Minyard393d2cc2005-11-07 00:59:54 -08001101static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
1102 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001103 unsigned char cmd,
1104 unsigned char chan)
Corey Minyard393d2cc2005-11-07 00:59:54 -08001105{
1106 struct cmd_rcvr *rcvr;
1107
1108 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyardc69c3122006-09-30 23:27:56 -07001109 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1110 && (rcvr->chans & (1 << chan)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08001111 return rcvr;
1112 }
1113 return NULL;
1114}
1115
Corey Minyardc69c3122006-09-30 23:27:56 -07001116static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
1117 unsigned char netfn,
1118 unsigned char cmd,
1119 unsigned int chans)
1120{
1121 struct cmd_rcvr *rcvr;
1122
1123 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
1124 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1125 && (rcvr->chans & chans))
1126 return 0;
1127 }
1128 return 1;
1129}
1130
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131int ipmi_register_for_cmd(ipmi_user_t user,
1132 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001133 unsigned char cmd,
1134 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001136 ipmi_smi_t intf = user->intf;
1137 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001138 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
1140
1141 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -08001142 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001144 rcvr->cmd = cmd;
1145 rcvr->netfn = netfn;
Corey Minyardc69c3122006-09-30 23:27:56 -07001146 rcvr->chans = chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001147 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Corey Minyardd6dfd132006-03-31 02:30:41 -08001149 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 /* Make sure the command/netfn is not already registered. */
Corey Minyardc69c3122006-09-30 23:27:56 -07001151 if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08001152 rv = -EBUSY;
1153 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 }
1155
Corey Minyard393d2cc2005-11-07 00:59:54 -08001156 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -07001157
Corey Minyard393d2cc2005-11-07 00:59:54 -08001158 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -08001159 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (rv)
1161 kfree(rcvr);
1162
1163 return rv;
1164}
1165
1166int ipmi_unregister_for_cmd(ipmi_user_t user,
1167 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001168 unsigned char cmd,
1169 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001171 ipmi_smi_t intf = user->intf;
1172 struct cmd_rcvr *rcvr;
Corey Minyardc69c3122006-09-30 23:27:56 -07001173 struct cmd_rcvr *rcvrs = NULL;
1174 int i, rv = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
Corey Minyardd6dfd132006-03-31 02:30:41 -08001176 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyardc69c3122006-09-30 23:27:56 -07001177 for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
1178 if (((1 << i) & chans) == 0)
1179 continue;
1180 rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
1181 if (rcvr == NULL)
1182 continue;
1183 if (rcvr->user == user) {
1184 rv = 0;
1185 rcvr->chans &= ~chans;
1186 if (rcvr->chans == 0) {
1187 list_del_rcu(&rcvr->link);
1188 rcvr->next = rcvrs;
1189 rcvrs = rcvr;
1190 }
1191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 }
Corey Minyardc69c3122006-09-30 23:27:56 -07001193 mutex_unlock(&intf->cmd_rcvrs_mutex);
1194 synchronize_rcu();
1195 while (rcvrs) {
1196 rcvr = rcvrs;
1197 rcvrs = rcvr->next;
1198 kfree(rcvr);
1199 }
1200 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201}
1202
1203void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
1204{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001205 ipmi_smi_t intf = user->intf;
Corey Minyardb2c03942006-12-06 20:41:00 -08001206 if (intf->handlers)
1207 intf->handlers->set_run_to_completion(intf->send_info, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208}
1209
1210static unsigned char
1211ipmb_checksum(unsigned char *data, int size)
1212{
1213 unsigned char csum = 0;
1214
1215 for (; size > 0; size--, data++)
1216 csum += *data;
1217
1218 return -csum;
1219}
1220
1221static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1222 struct kernel_ipmi_msg *msg,
1223 struct ipmi_ipmb_addr *ipmb_addr,
1224 long msgid,
1225 unsigned char ipmb_seq,
1226 int broadcast,
1227 unsigned char source_address,
1228 unsigned char source_lun)
1229{
1230 int i = broadcast;
1231
1232 /* Format the IPMB header data. */
1233 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1234 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1235 smi_msg->data[2] = ipmb_addr->channel;
1236 if (broadcast)
1237 smi_msg->data[3] = 0;
1238 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1239 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1240 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1241 smi_msg->data[i+6] = source_address;
1242 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1243 smi_msg->data[i+8] = msg->cmd;
1244
1245 /* Now tack on the data to the message. */
1246 if (msg->data_len > 0)
1247 memcpy(&(smi_msg->data[i+9]), msg->data,
1248 msg->data_len);
1249 smi_msg->data_size = msg->data_len + 9;
1250
1251 /* Now calculate the checksum and tack it on. */
1252 smi_msg->data[i+smi_msg->data_size]
1253 = ipmb_checksum(&(smi_msg->data[i+6]),
1254 smi_msg->data_size-6);
1255
1256 /* Add on the checksum size and the offset from the
1257 broadcast. */
1258 smi_msg->data_size += 1 + i;
1259
1260 smi_msg->msgid = msgid;
1261}
1262
1263static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1264 struct kernel_ipmi_msg *msg,
1265 struct ipmi_lan_addr *lan_addr,
1266 long msgid,
1267 unsigned char ipmb_seq,
1268 unsigned char source_lun)
1269{
1270 /* Format the IPMB header data. */
1271 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1272 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1273 smi_msg->data[2] = lan_addr->channel;
1274 smi_msg->data[3] = lan_addr->session_handle;
1275 smi_msg->data[4] = lan_addr->remote_SWID;
1276 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1277 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1278 smi_msg->data[7] = lan_addr->local_SWID;
1279 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1280 smi_msg->data[9] = msg->cmd;
1281
1282 /* Now tack on the data to the message. */
1283 if (msg->data_len > 0)
1284 memcpy(&(smi_msg->data[10]), msg->data,
1285 msg->data_len);
1286 smi_msg->data_size = msg->data_len + 10;
1287
1288 /* Now calculate the checksum and tack it on. */
1289 smi_msg->data[smi_msg->data_size]
1290 = ipmb_checksum(&(smi_msg->data[7]),
1291 smi_msg->data_size-7);
1292
1293 /* Add on the checksum size and the offset from the
1294 broadcast. */
1295 smi_msg->data_size += 1;
1296
1297 smi_msg->msgid = msgid;
1298}
1299
1300/* Separate from ipmi_request so that the user does not have to be
1301 supplied in certain circumstances (mainly at panic time). If
1302 messages are supplied, they will be freed, even if an error
1303 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001304static int i_ipmi_request(ipmi_user_t user,
1305 ipmi_smi_t intf,
1306 struct ipmi_addr *addr,
1307 long msgid,
1308 struct kernel_ipmi_msg *msg,
1309 void *user_msg_data,
1310 void *supplied_smi,
1311 struct ipmi_recv_msg *supplied_recv,
1312 int priority,
1313 unsigned char source_address,
1314 unsigned char source_lun,
1315 int retries,
1316 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317{
Corey Minyardb2c03942006-12-06 20:41:00 -08001318 int rv = 0;
1319 struct ipmi_smi_msg *smi_msg;
1320 struct ipmi_recv_msg *recv_msg;
1321 unsigned long flags;
1322 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
1324
1325 if (supplied_recv) {
1326 recv_msg = supplied_recv;
1327 } else {
1328 recv_msg = ipmi_alloc_recv_msg();
1329 if (recv_msg == NULL) {
1330 return -ENOMEM;
1331 }
1332 }
1333 recv_msg->user_msg_data = user_msg_data;
1334
1335 if (supplied_smi) {
1336 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1337 } else {
1338 smi_msg = ipmi_alloc_smi_msg();
1339 if (smi_msg == NULL) {
1340 ipmi_free_recv_msg(recv_msg);
1341 return -ENOMEM;
1342 }
1343 }
1344
Corey Minyardb2c03942006-12-06 20:41:00 -08001345 rcu_read_lock();
1346 handlers = intf->handlers;
1347 if (!handlers) {
1348 rv = -ENODEV;
1349 goto out_err;
1350 }
1351
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001353 if (user)
1354 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 recv_msg->msgid = msgid;
1356 /* Store the message to send in the receive message so timeout
1357 responses can get the proper response data. */
1358 recv_msg->msg = *msg;
1359
1360 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1361 struct ipmi_system_interface_addr *smi_addr;
1362
1363 if (msg->netfn & 1) {
1364 /* Responses are not allowed to the SMI. */
1365 rv = -EINVAL;
1366 goto out_err;
1367 }
1368
1369 smi_addr = (struct ipmi_system_interface_addr *) addr;
1370 if (smi_addr->lun > 3) {
1371 spin_lock_irqsave(&intf->counter_lock, flags);
1372 intf->sent_invalid_commands++;
1373 spin_unlock_irqrestore(&intf->counter_lock, flags);
1374 rv = -EINVAL;
1375 goto out_err;
1376 }
1377
1378 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1379
1380 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1381 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1382 || (msg->cmd == IPMI_GET_MSG_CMD)
1383 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1384 {
1385 /* We don't let the user do these, since we manage
1386 the sequence numbers. */
1387 spin_lock_irqsave(&intf->counter_lock, flags);
1388 intf->sent_invalid_commands++;
1389 spin_unlock_irqrestore(&intf->counter_lock, flags);
1390 rv = -EINVAL;
1391 goto out_err;
1392 }
1393
Corey Minyardb9675132006-12-06 20:41:02 -08001394 if (((msg->netfn == IPMI_NETFN_APP_REQUEST)
1395 && ((msg->cmd == IPMI_COLD_RESET_CMD)
1396 || (msg->cmd == IPMI_WARM_RESET_CMD)))
1397 || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST))
1398 {
1399 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1400 intf->auto_maintenance_timeout
1401 = IPMI_MAINTENANCE_MODE_TIMEOUT;
1402 if (!intf->maintenance_mode
1403 && !intf->maintenance_mode_enable)
1404 {
1405 intf->maintenance_mode_enable = 1;
1406 maintenance_mode_update(intf);
1407 }
1408 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
1409 flags);
1410 }
1411
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1413 spin_lock_irqsave(&intf->counter_lock, flags);
1414 intf->sent_invalid_commands++;
1415 spin_unlock_irqrestore(&intf->counter_lock, flags);
1416 rv = -EMSGSIZE;
1417 goto out_err;
1418 }
1419
1420 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1421 smi_msg->data[1] = msg->cmd;
1422 smi_msg->msgid = msgid;
1423 smi_msg->user_data = recv_msg;
1424 if (msg->data_len > 0)
1425 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1426 smi_msg->data_size = msg->data_len + 2;
1427 spin_lock_irqsave(&intf->counter_lock, flags);
1428 intf->sent_local_commands++;
1429 spin_unlock_irqrestore(&intf->counter_lock, flags);
1430 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1431 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1432 {
1433 struct ipmi_ipmb_addr *ipmb_addr;
1434 unsigned char ipmb_seq;
1435 long seqid;
1436 int broadcast = 0;
1437
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001438 if (addr->channel >= IPMI_MAX_CHANNELS) {
1439 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 intf->sent_invalid_commands++;
1441 spin_unlock_irqrestore(&intf->counter_lock, flags);
1442 rv = -EINVAL;
1443 goto out_err;
1444 }
1445
1446 if (intf->channels[addr->channel].medium
1447 != IPMI_CHANNEL_MEDIUM_IPMB)
1448 {
1449 spin_lock_irqsave(&intf->counter_lock, flags);
1450 intf->sent_invalid_commands++;
1451 spin_unlock_irqrestore(&intf->counter_lock, flags);
1452 rv = -EINVAL;
1453 goto out_err;
1454 }
1455
1456 if (retries < 0) {
1457 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1458 retries = 0; /* Don't retry broadcasts. */
1459 else
1460 retries = 4;
1461 }
1462 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1463 /* Broadcasts add a zero at the beginning of the
1464 message, but otherwise is the same as an IPMB
1465 address. */
1466 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1467 broadcast = 1;
1468 }
1469
1470
1471 /* Default to 1 second retries. */
1472 if (retry_time_ms == 0)
1473 retry_time_ms = 1000;
1474
1475 /* 9 for the header and 1 for the checksum, plus
1476 possibly one for the broadcast. */
1477 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1478 spin_lock_irqsave(&intf->counter_lock, flags);
1479 intf->sent_invalid_commands++;
1480 spin_unlock_irqrestore(&intf->counter_lock, flags);
1481 rv = -EMSGSIZE;
1482 goto out_err;
1483 }
1484
1485 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1486 if (ipmb_addr->lun > 3) {
1487 spin_lock_irqsave(&intf->counter_lock, flags);
1488 intf->sent_invalid_commands++;
1489 spin_unlock_irqrestore(&intf->counter_lock, flags);
1490 rv = -EINVAL;
1491 goto out_err;
1492 }
1493
1494 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1495
1496 if (recv_msg->msg.netfn & 0x1) {
1497 /* It's a response, so use the user's sequence
1498 from msgid. */
1499 spin_lock_irqsave(&intf->counter_lock, flags);
1500 intf->sent_ipmb_responses++;
1501 spin_unlock_irqrestore(&intf->counter_lock, flags);
1502 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1503 msgid, broadcast,
1504 source_address, source_lun);
1505
1506 /* Save the receive message so we can use it
1507 to deliver the response. */
1508 smi_msg->user_data = recv_msg;
1509 } else {
1510 /* It's a command, so get a sequence for it. */
1511
1512 spin_lock_irqsave(&(intf->seq_lock), flags);
1513
1514 spin_lock(&intf->counter_lock);
1515 intf->sent_ipmb_commands++;
1516 spin_unlock(&intf->counter_lock);
1517
1518 /* Create a sequence number with a 1 second
1519 timeout and 4 retries. */
1520 rv = intf_next_seq(intf,
1521 recv_msg,
1522 retry_time_ms,
1523 retries,
1524 broadcast,
1525 &ipmb_seq,
1526 &seqid);
1527 if (rv) {
1528 /* We have used up all the sequence numbers,
1529 probably, so abort. */
1530 spin_unlock_irqrestore(&(intf->seq_lock),
1531 flags);
1532 goto out_err;
1533 }
1534
1535 /* Store the sequence number in the message,
1536 so that when the send message response
1537 comes back we can start the timer. */
1538 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1539 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1540 ipmb_seq, broadcast,
1541 source_address, source_lun);
1542
1543 /* Copy the message into the recv message data, so we
1544 can retransmit it later if necessary. */
1545 memcpy(recv_msg->msg_data, smi_msg->data,
1546 smi_msg->data_size);
1547 recv_msg->msg.data = recv_msg->msg_data;
1548 recv_msg->msg.data_len = smi_msg->data_size;
1549
1550 /* We don't unlock until here, because we need
1551 to copy the completed message into the
1552 recv_msg before we release the lock.
1553 Otherwise, race conditions may bite us. I
1554 know that's pretty paranoid, but I prefer
1555 to be correct. */
1556 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1557 }
1558 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1559 struct ipmi_lan_addr *lan_addr;
1560 unsigned char ipmb_seq;
1561 long seqid;
1562
Jayachandran C12fc1d72006-02-03 03:04:51 -08001563 if (addr->channel >= IPMI_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 spin_lock_irqsave(&intf->counter_lock, flags);
1565 intf->sent_invalid_commands++;
1566 spin_unlock_irqrestore(&intf->counter_lock, flags);
1567 rv = -EINVAL;
1568 goto out_err;
1569 }
1570
1571 if ((intf->channels[addr->channel].medium
1572 != IPMI_CHANNEL_MEDIUM_8023LAN)
1573 && (intf->channels[addr->channel].medium
1574 != IPMI_CHANNEL_MEDIUM_ASYNC))
1575 {
1576 spin_lock_irqsave(&intf->counter_lock, flags);
1577 intf->sent_invalid_commands++;
1578 spin_unlock_irqrestore(&intf->counter_lock, flags);
1579 rv = -EINVAL;
1580 goto out_err;
1581 }
1582
1583 retries = 4;
1584
1585 /* Default to 1 second retries. */
1586 if (retry_time_ms == 0)
1587 retry_time_ms = 1000;
1588
1589 /* 11 for the header and 1 for the checksum. */
1590 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1591 spin_lock_irqsave(&intf->counter_lock, flags);
1592 intf->sent_invalid_commands++;
1593 spin_unlock_irqrestore(&intf->counter_lock, flags);
1594 rv = -EMSGSIZE;
1595 goto out_err;
1596 }
1597
1598 lan_addr = (struct ipmi_lan_addr *) addr;
1599 if (lan_addr->lun > 3) {
1600 spin_lock_irqsave(&intf->counter_lock, flags);
1601 intf->sent_invalid_commands++;
1602 spin_unlock_irqrestore(&intf->counter_lock, flags);
1603 rv = -EINVAL;
1604 goto out_err;
1605 }
1606
1607 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1608
1609 if (recv_msg->msg.netfn & 0x1) {
1610 /* It's a response, so use the user's sequence
1611 from msgid. */
1612 spin_lock_irqsave(&intf->counter_lock, flags);
1613 intf->sent_lan_responses++;
1614 spin_unlock_irqrestore(&intf->counter_lock, flags);
1615 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1616 msgid, source_lun);
1617
1618 /* Save the receive message so we can use it
1619 to deliver the response. */
1620 smi_msg->user_data = recv_msg;
1621 } else {
1622 /* It's a command, so get a sequence for it. */
1623
1624 spin_lock_irqsave(&(intf->seq_lock), flags);
1625
1626 spin_lock(&intf->counter_lock);
1627 intf->sent_lan_commands++;
1628 spin_unlock(&intf->counter_lock);
1629
1630 /* Create a sequence number with a 1 second
1631 timeout and 4 retries. */
1632 rv = intf_next_seq(intf,
1633 recv_msg,
1634 retry_time_ms,
1635 retries,
1636 0,
1637 &ipmb_seq,
1638 &seqid);
1639 if (rv) {
1640 /* We have used up all the sequence numbers,
1641 probably, so abort. */
1642 spin_unlock_irqrestore(&(intf->seq_lock),
1643 flags);
1644 goto out_err;
1645 }
1646
1647 /* Store the sequence number in the message,
1648 so that when the send message response
1649 comes back we can start the timer. */
1650 format_lan_msg(smi_msg, msg, lan_addr,
1651 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1652 ipmb_seq, source_lun);
1653
1654 /* Copy the message into the recv message data, so we
1655 can retransmit it later if necessary. */
1656 memcpy(recv_msg->msg_data, smi_msg->data,
1657 smi_msg->data_size);
1658 recv_msg->msg.data = recv_msg->msg_data;
1659 recv_msg->msg.data_len = smi_msg->data_size;
1660
1661 /* We don't unlock until here, because we need
1662 to copy the completed message into the
1663 recv_msg before we release the lock.
1664 Otherwise, race conditions may bite us. I
1665 know that's pretty paranoid, but I prefer
1666 to be correct. */
1667 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1668 }
1669 } else {
1670 /* Unknown address type. */
1671 spin_lock_irqsave(&intf->counter_lock, flags);
1672 intf->sent_invalid_commands++;
1673 spin_unlock_irqrestore(&intf->counter_lock, flags);
1674 rv = -EINVAL;
1675 goto out_err;
1676 }
1677
1678#ifdef DEBUG_MSGING
1679 {
1680 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001681 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 printk(" %2.2x", smi_msg->data[m]);
1683 printk("\n");
1684 }
1685#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08001686
1687 handlers->sender(intf->send_info, smi_msg, priority);
1688 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
1690 return 0;
1691
1692 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -08001693 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 ipmi_free_smi_msg(smi_msg);
1695 ipmi_free_recv_msg(recv_msg);
1696 return rv;
1697}
1698
Corey Minyardc14979b2005-09-06 15:18:38 -07001699static int check_addr(ipmi_smi_t intf,
1700 struct ipmi_addr *addr,
1701 unsigned char *saddr,
1702 unsigned char *lun)
1703{
1704 if (addr->channel >= IPMI_MAX_CHANNELS)
1705 return -EINVAL;
1706 *lun = intf->channels[addr->channel].lun;
1707 *saddr = intf->channels[addr->channel].address;
1708 return 0;
1709}
1710
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711int ipmi_request_settime(ipmi_user_t user,
1712 struct ipmi_addr *addr,
1713 long msgid,
1714 struct kernel_ipmi_msg *msg,
1715 void *user_msg_data,
1716 int priority,
1717 int retries,
1718 unsigned int retry_time_ms)
1719{
Corey Minyardc14979b2005-09-06 15:18:38 -07001720 unsigned char saddr, lun;
1721 int rv;
1722
Corey Minyard8a3628d2006-03-31 02:30:40 -08001723 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001724 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001725 rv = check_addr(user->intf, addr, &saddr, &lun);
1726 if (rv)
1727 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 return i_ipmi_request(user,
1729 user->intf,
1730 addr,
1731 msgid,
1732 msg,
1733 user_msg_data,
1734 NULL, NULL,
1735 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001736 saddr,
1737 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 retries,
1739 retry_time_ms);
1740}
1741
1742int ipmi_request_supply_msgs(ipmi_user_t user,
1743 struct ipmi_addr *addr,
1744 long msgid,
1745 struct kernel_ipmi_msg *msg,
1746 void *user_msg_data,
1747 void *supplied_smi,
1748 struct ipmi_recv_msg *supplied_recv,
1749 int priority)
1750{
Corey Minyardc14979b2005-09-06 15:18:38 -07001751 unsigned char saddr, lun;
1752 int rv;
1753
Corey Minyard8a3628d2006-03-31 02:30:40 -08001754 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001755 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001756 rv = check_addr(user->intf, addr, &saddr, &lun);
1757 if (rv)
1758 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 return i_ipmi_request(user,
1760 user->intf,
1761 addr,
1762 msgid,
1763 msg,
1764 user_msg_data,
1765 supplied_smi,
1766 supplied_recv,
1767 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001768 saddr,
1769 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 -1, 0);
1771}
1772
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001773#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774static int ipmb_file_read_proc(char *page, char **start, off_t off,
1775 int count, int *eof, void *data)
1776{
1777 char *out = (char *) page;
1778 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001779 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001780 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
Corey Minyarde8b33612005-09-06 15:18:45 -07001782 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001783 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1784 out[rv-1] = '\n'; /* Replace the final space with a newline */
1785 out[rv] = '\0';
1786 rv++;
1787 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788}
1789
1790static int version_file_read_proc(char *page, char **start, off_t off,
1791 int count, int *eof, void *data)
1792{
1793 char *out = (char *) page;
1794 ipmi_smi_t intf = data;
1795
1796 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001797 ipmi_version_major(&intf->bmc->id),
1798 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799}
1800
1801static int stat_file_read_proc(char *page, char **start, off_t off,
1802 int count, int *eof, void *data)
1803{
1804 char *out = (char *) page;
1805 ipmi_smi_t intf = data;
1806
1807 out += sprintf(out, "sent_invalid_commands: %d\n",
1808 intf->sent_invalid_commands);
1809 out += sprintf(out, "sent_local_commands: %d\n",
1810 intf->sent_local_commands);
1811 out += sprintf(out, "handled_local_responses: %d\n",
1812 intf->handled_local_responses);
1813 out += sprintf(out, "unhandled_local_responses: %d\n",
1814 intf->unhandled_local_responses);
1815 out += sprintf(out, "sent_ipmb_commands: %d\n",
1816 intf->sent_ipmb_commands);
1817 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1818 intf->sent_ipmb_command_errs);
1819 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1820 intf->retransmitted_ipmb_commands);
1821 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1822 intf->timed_out_ipmb_commands);
1823 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1824 intf->timed_out_ipmb_broadcasts);
1825 out += sprintf(out, "sent_ipmb_responses: %d\n",
1826 intf->sent_ipmb_responses);
1827 out += sprintf(out, "handled_ipmb_responses: %d\n",
1828 intf->handled_ipmb_responses);
1829 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1830 intf->invalid_ipmb_responses);
1831 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1832 intf->unhandled_ipmb_responses);
1833 out += sprintf(out, "sent_lan_commands: %d\n",
1834 intf->sent_lan_commands);
1835 out += sprintf(out, "sent_lan_command_errs: %d\n",
1836 intf->sent_lan_command_errs);
1837 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1838 intf->retransmitted_lan_commands);
1839 out += sprintf(out, "timed_out_lan_commands: %d\n",
1840 intf->timed_out_lan_commands);
1841 out += sprintf(out, "sent_lan_responses: %d\n",
1842 intf->sent_lan_responses);
1843 out += sprintf(out, "handled_lan_responses: %d\n",
1844 intf->handled_lan_responses);
1845 out += sprintf(out, "invalid_lan_responses: %d\n",
1846 intf->invalid_lan_responses);
1847 out += sprintf(out, "unhandled_lan_responses: %d\n",
1848 intf->unhandled_lan_responses);
1849 out += sprintf(out, "handled_commands: %d\n",
1850 intf->handled_commands);
1851 out += sprintf(out, "invalid_commands: %d\n",
1852 intf->invalid_commands);
1853 out += sprintf(out, "unhandled_commands: %d\n",
1854 intf->unhandled_commands);
1855 out += sprintf(out, "invalid_events: %d\n",
1856 intf->invalid_events);
1857 out += sprintf(out, "events: %d\n",
1858 intf->events);
1859
1860 return (out - ((char *) page));
1861}
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001862#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863
1864int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1865 read_proc_t *read_proc, write_proc_t *write_proc,
1866 void *data, struct module *owner)
1867{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001869#ifdef CONFIG_PROC_FS
1870 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 struct ipmi_proc_entry *entry;
1872
1873 /* Create a list element. */
1874 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1875 if (!entry)
1876 return -ENOMEM;
1877 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1878 if (!entry->name) {
1879 kfree(entry);
1880 return -ENOMEM;
1881 }
1882 strcpy(entry->name, name);
1883
1884 file = create_proc_entry(name, 0, smi->proc_dir);
1885 if (!file) {
1886 kfree(entry->name);
1887 kfree(entry);
1888 rv = -ENOMEM;
1889 } else {
1890 file->nlink = 1;
1891 file->data = data;
1892 file->read_proc = read_proc;
1893 file->write_proc = write_proc;
1894 file->owner = owner;
1895
Corey Minyard3b625942005-06-23 22:01:42 -07001896 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 /* Stick it on the list. */
1898 entry->next = smi->proc_entries;
1899 smi->proc_entries = entry;
Corey Minyard3b625942005-06-23 22:01:42 -07001900 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 }
Corey Minyard3b625942005-06-23 22:01:42 -07001902#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
1904 return rv;
1905}
1906
1907static int add_proc_entries(ipmi_smi_t smi, int num)
1908{
1909 int rv = 0;
1910
Corey Minyard3b625942005-06-23 22:01:42 -07001911#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 sprintf(smi->proc_dir_name, "%d", num);
1913 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1914 if (!smi->proc_dir)
1915 rv = -ENOMEM;
1916 else {
1917 smi->proc_dir->owner = THIS_MODULE;
1918 }
1919
1920 if (rv == 0)
1921 rv = ipmi_smi_add_proc_entry(smi, "stats",
1922 stat_file_read_proc, NULL,
1923 smi, THIS_MODULE);
1924
1925 if (rv == 0)
1926 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1927 ipmb_file_read_proc, NULL,
1928 smi, THIS_MODULE);
1929
1930 if (rv == 0)
1931 rv = ipmi_smi_add_proc_entry(smi, "version",
1932 version_file_read_proc, NULL,
1933 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001934#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935
1936 return rv;
1937}
1938
1939static void remove_proc_entries(ipmi_smi_t smi)
1940{
Corey Minyard3b625942005-06-23 22:01:42 -07001941#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 struct ipmi_proc_entry *entry;
1943
Corey Minyard3b625942005-06-23 22:01:42 -07001944 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 while (smi->proc_entries) {
1946 entry = smi->proc_entries;
1947 smi->proc_entries = entry->next;
1948
1949 remove_proc_entry(entry->name, smi->proc_dir);
1950 kfree(entry->name);
1951 kfree(entry);
1952 }
Corey Minyard3b625942005-06-23 22:01:42 -07001953 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001955#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956}
1957
Corey Minyard50c812b2006-03-26 01:37:21 -08001958static int __find_bmc_guid(struct device *dev, void *data)
1959{
1960 unsigned char *id = data;
1961 struct bmc_device *bmc = dev_get_drvdata(dev);
1962 return memcmp(bmc->guid, id, 16) == 0;
1963}
1964
1965static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1966 unsigned char *guid)
1967{
1968 struct device *dev;
1969
1970 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1971 if (dev)
1972 return dev_get_drvdata(dev);
1973 else
1974 return NULL;
1975}
1976
1977struct prod_dev_id {
1978 unsigned int product_id;
1979 unsigned char device_id;
1980};
1981
1982static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1983{
1984 struct prod_dev_id *id = data;
1985 struct bmc_device *bmc = dev_get_drvdata(dev);
1986
1987 return (bmc->id.product_id == id->product_id
Corey Minyard50c812b2006-03-26 01:37:21 -08001988 && bmc->id.device_id == id->device_id);
1989}
1990
1991static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1992 struct device_driver *drv,
Corey Minyardf0b55da2006-12-06 20:40:54 -08001993 unsigned int product_id, unsigned char device_id)
Corey Minyard50c812b2006-03-26 01:37:21 -08001994{
1995 struct prod_dev_id id = {
1996 .product_id = product_id,
1997 .device_id = device_id,
1998 };
1999 struct device *dev;
2000
2001 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
2002 if (dev)
2003 return dev_get_drvdata(dev);
2004 else
2005 return NULL;
2006}
2007
2008static ssize_t device_id_show(struct device *dev,
2009 struct device_attribute *attr,
2010 char *buf)
2011{
2012 struct bmc_device *bmc = dev_get_drvdata(dev);
2013
2014 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
2015}
2016
2017static ssize_t provides_dev_sdrs_show(struct device *dev,
2018 struct device_attribute *attr,
2019 char *buf)
2020{
2021 struct bmc_device *bmc = dev_get_drvdata(dev);
2022
2023 return snprintf(buf, 10, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002024 (bmc->id.device_revision & 0x80) >> 7);
Corey Minyard50c812b2006-03-26 01:37:21 -08002025}
2026
2027static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
2028 char *buf)
2029{
2030 struct bmc_device *bmc = dev_get_drvdata(dev);
2031
2032 return snprintf(buf, 20, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002033 bmc->id.device_revision & 0x0F);
Corey Minyard50c812b2006-03-26 01:37:21 -08002034}
2035
2036static ssize_t firmware_rev_show(struct device *dev,
2037 struct device_attribute *attr,
2038 char *buf)
2039{
2040 struct bmc_device *bmc = dev_get_drvdata(dev);
2041
2042 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
2043 bmc->id.firmware_revision_2);
2044}
2045
2046static ssize_t ipmi_version_show(struct device *dev,
2047 struct device_attribute *attr,
2048 char *buf)
2049{
2050 struct bmc_device *bmc = dev_get_drvdata(dev);
2051
2052 return snprintf(buf, 20, "%u.%u\n",
2053 ipmi_version_major(&bmc->id),
2054 ipmi_version_minor(&bmc->id));
2055}
2056
2057static ssize_t add_dev_support_show(struct device *dev,
2058 struct device_attribute *attr,
2059 char *buf)
2060{
2061 struct bmc_device *bmc = dev_get_drvdata(dev);
2062
2063 return snprintf(buf, 10, "0x%02x\n",
2064 bmc->id.additional_device_support);
2065}
2066
2067static ssize_t manufacturer_id_show(struct device *dev,
2068 struct device_attribute *attr,
2069 char *buf)
2070{
2071 struct bmc_device *bmc = dev_get_drvdata(dev);
2072
2073 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
2074}
2075
2076static ssize_t product_id_show(struct device *dev,
2077 struct device_attribute *attr,
2078 char *buf)
2079{
2080 struct bmc_device *bmc = dev_get_drvdata(dev);
2081
2082 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
2083}
2084
2085static ssize_t aux_firmware_rev_show(struct device *dev,
2086 struct device_attribute *attr,
2087 char *buf)
2088{
2089 struct bmc_device *bmc = dev_get_drvdata(dev);
2090
2091 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
2092 bmc->id.aux_firmware_revision[3],
2093 bmc->id.aux_firmware_revision[2],
2094 bmc->id.aux_firmware_revision[1],
2095 bmc->id.aux_firmware_revision[0]);
2096}
2097
2098static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
2099 char *buf)
2100{
2101 struct bmc_device *bmc = dev_get_drvdata(dev);
2102
2103 return snprintf(buf, 100, "%Lx%Lx\n",
2104 (long long) bmc->guid[0],
2105 (long long) bmc->guid[8]);
2106}
2107
Jeff Garzik5e593932006-10-11 01:22:21 -07002108static void remove_files(struct bmc_device *bmc)
Corey Minyard50c812b2006-03-26 01:37:21 -08002109{
Corey Minyardf0b55da2006-12-06 20:40:54 -08002110 if (!bmc->dev)
2111 return;
2112
Corey Minyard50c812b2006-03-26 01:37:21 -08002113 device_remove_file(&bmc->dev->dev,
2114 &bmc->device_id_attr);
2115 device_remove_file(&bmc->dev->dev,
2116 &bmc->provides_dev_sdrs_attr);
2117 device_remove_file(&bmc->dev->dev,
2118 &bmc->revision_attr);
2119 device_remove_file(&bmc->dev->dev,
2120 &bmc->firmware_rev_attr);
2121 device_remove_file(&bmc->dev->dev,
2122 &bmc->version_attr);
2123 device_remove_file(&bmc->dev->dev,
2124 &bmc->add_dev_support_attr);
2125 device_remove_file(&bmc->dev->dev,
2126 &bmc->manufacturer_id_attr);
2127 device_remove_file(&bmc->dev->dev,
2128 &bmc->product_id_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002129
Corey Minyard50c812b2006-03-26 01:37:21 -08002130 if (bmc->id.aux_firmware_revision_set)
2131 device_remove_file(&bmc->dev->dev,
2132 &bmc->aux_firmware_rev_attr);
2133 if (bmc->guid_set)
2134 device_remove_file(&bmc->dev->dev,
2135 &bmc->guid_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002136}
2137
2138static void
2139cleanup_bmc_device(struct kref *ref)
2140{
2141 struct bmc_device *bmc;
2142
2143 bmc = container_of(ref, struct bmc_device, refcount);
2144
2145 remove_files(bmc);
Corey Minyard1d5636c2006-12-10 02:19:08 -08002146 platform_device_unregister(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002147 kfree(bmc);
2148}
2149
2150static void ipmi_bmc_unregister(ipmi_smi_t intf)
2151{
2152 struct bmc_device *bmc = intf->bmc;
2153
Corey Minyard759643b2006-12-06 20:40:59 -08002154 if (intf->sysfs_name) {
2155 sysfs_remove_link(&intf->si_dev->kobj, intf->sysfs_name);
2156 kfree(intf->sysfs_name);
2157 intf->sysfs_name = NULL;
2158 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002159 if (intf->my_dev_name) {
2160 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
2161 kfree(intf->my_dev_name);
2162 intf->my_dev_name = NULL;
2163 }
2164
2165 mutex_lock(&ipmidriver_mutex);
2166 kref_put(&bmc->refcount, cleanup_bmc_device);
Corey Minyardf0b55da2006-12-06 20:40:54 -08002167 intf->bmc = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002168 mutex_unlock(&ipmidriver_mutex);
2169}
2170
Jeff Garzik5e593932006-10-11 01:22:21 -07002171static int create_files(struct bmc_device *bmc)
2172{
2173 int err;
2174
Corey Minyardf0b55da2006-12-06 20:40:54 -08002175 bmc->device_id_attr.attr.name = "device_id";
2176 bmc->device_id_attr.attr.owner = THIS_MODULE;
2177 bmc->device_id_attr.attr.mode = S_IRUGO;
2178 bmc->device_id_attr.show = device_id_show;
2179
2180 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
2181 bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
2182 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2183 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2184
2185 bmc->revision_attr.attr.name = "revision";
2186 bmc->revision_attr.attr.owner = THIS_MODULE;
2187 bmc->revision_attr.attr.mode = S_IRUGO;
2188 bmc->revision_attr.show = revision_show;
2189
2190 bmc->firmware_rev_attr.attr.name = "firmware_revision";
2191 bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
2192 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2193 bmc->firmware_rev_attr.show = firmware_rev_show;
2194
2195 bmc->version_attr.attr.name = "ipmi_version";
2196 bmc->version_attr.attr.owner = THIS_MODULE;
2197 bmc->version_attr.attr.mode = S_IRUGO;
2198 bmc->version_attr.show = ipmi_version_show;
2199
2200 bmc->add_dev_support_attr.attr.name = "additional_device_support";
2201 bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
2202 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2203 bmc->add_dev_support_attr.show = add_dev_support_show;
2204
2205 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
2206 bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
2207 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2208 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2209
2210 bmc->product_id_attr.attr.name = "product_id";
2211 bmc->product_id_attr.attr.owner = THIS_MODULE;
2212 bmc->product_id_attr.attr.mode = S_IRUGO;
2213 bmc->product_id_attr.show = product_id_show;
2214
2215 bmc->guid_attr.attr.name = "guid";
2216 bmc->guid_attr.attr.owner = THIS_MODULE;
2217 bmc->guid_attr.attr.mode = S_IRUGO;
2218 bmc->guid_attr.show = guid_show;
2219
2220 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
2221 bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
2222 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2223 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2224
Jeff Garzik5e593932006-10-11 01:22:21 -07002225 err = device_create_file(&bmc->dev->dev,
2226 &bmc->device_id_attr);
2227 if (err) goto out;
2228 err = device_create_file(&bmc->dev->dev,
2229 &bmc->provides_dev_sdrs_attr);
2230 if (err) goto out_devid;
2231 err = device_create_file(&bmc->dev->dev,
2232 &bmc->revision_attr);
2233 if (err) goto out_sdrs;
2234 err = device_create_file(&bmc->dev->dev,
2235 &bmc->firmware_rev_attr);
2236 if (err) goto out_rev;
2237 err = device_create_file(&bmc->dev->dev,
2238 &bmc->version_attr);
2239 if (err) goto out_firm;
2240 err = device_create_file(&bmc->dev->dev,
2241 &bmc->add_dev_support_attr);
2242 if (err) goto out_version;
2243 err = device_create_file(&bmc->dev->dev,
2244 &bmc->manufacturer_id_attr);
2245 if (err) goto out_add_dev;
2246 err = device_create_file(&bmc->dev->dev,
2247 &bmc->product_id_attr);
2248 if (err) goto out_manu;
2249 if (bmc->id.aux_firmware_revision_set) {
2250 err = device_create_file(&bmc->dev->dev,
2251 &bmc->aux_firmware_rev_attr);
2252 if (err) goto out_prod_id;
2253 }
2254 if (bmc->guid_set) {
2255 err = device_create_file(&bmc->dev->dev,
2256 &bmc->guid_attr);
2257 if (err) goto out_aux_firm;
2258 }
2259
2260 return 0;
2261
2262out_aux_firm:
2263 if (bmc->id.aux_firmware_revision_set)
2264 device_remove_file(&bmc->dev->dev,
2265 &bmc->aux_firmware_rev_attr);
2266out_prod_id:
2267 device_remove_file(&bmc->dev->dev,
2268 &bmc->product_id_attr);
2269out_manu:
2270 device_remove_file(&bmc->dev->dev,
2271 &bmc->manufacturer_id_attr);
2272out_add_dev:
2273 device_remove_file(&bmc->dev->dev,
2274 &bmc->add_dev_support_attr);
2275out_version:
2276 device_remove_file(&bmc->dev->dev,
2277 &bmc->version_attr);
2278out_firm:
2279 device_remove_file(&bmc->dev->dev,
2280 &bmc->firmware_rev_attr);
2281out_rev:
2282 device_remove_file(&bmc->dev->dev,
2283 &bmc->revision_attr);
2284out_sdrs:
2285 device_remove_file(&bmc->dev->dev,
2286 &bmc->provides_dev_sdrs_attr);
2287out_devid:
2288 device_remove_file(&bmc->dev->dev,
2289 &bmc->device_id_attr);
2290out:
2291 return err;
2292}
2293
Corey Minyard759643b2006-12-06 20:40:59 -08002294static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
2295 const char *sysfs_name)
Corey Minyard50c812b2006-03-26 01:37:21 -08002296{
2297 int rv;
2298 struct bmc_device *bmc = intf->bmc;
2299 struct bmc_device *old_bmc;
2300 int size;
2301 char dummy[1];
2302
2303 mutex_lock(&ipmidriver_mutex);
2304
2305 /*
2306 * Try to find if there is an bmc_device struct
2307 * representing the interfaced BMC already
2308 */
2309 if (bmc->guid_set)
2310 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
2311 else
2312 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
2313 bmc->id.product_id,
2314 bmc->id.device_id);
2315
2316 /*
2317 * If there is already an bmc_device, free the new one,
2318 * otherwise register the new BMC device
2319 */
2320 if (old_bmc) {
2321 kfree(bmc);
2322 intf->bmc = old_bmc;
2323 bmc = old_bmc;
2324
2325 kref_get(&bmc->refcount);
2326 mutex_unlock(&ipmidriver_mutex);
2327
2328 printk(KERN_INFO
2329 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
2330 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2331 bmc->id.manufacturer_id,
2332 bmc->id.product_id,
2333 bmc->id.device_id);
2334 } else {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002335 char name[14];
2336 unsigned char orig_dev_id = bmc->id.device_id;
2337 int warn_printed = 0;
2338
2339 snprintf(name, sizeof(name),
2340 "ipmi_bmc.%4.4x", bmc->id.product_id);
2341
2342 while (ipmi_find_bmc_prod_dev_id(&ipmidriver,
2343 bmc->id.product_id,
Corey Minyard1d5636c2006-12-10 02:19:08 -08002344 bmc->id.device_id)) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002345 if (!warn_printed) {
2346 printk(KERN_WARNING PFX
2347 "This machine has two different BMCs"
2348 " with the same product id and device"
2349 " id. This is an error in the"
2350 " firmware, but incrementing the"
2351 " device id to work around the problem."
2352 " Prod ID = 0x%x, Dev ID = 0x%x\n",
2353 bmc->id.product_id, bmc->id.device_id);
2354 warn_printed = 1;
2355 }
2356 bmc->id.device_id++; /* Wraps at 255 */
2357 if (bmc->id.device_id == orig_dev_id) {
2358 printk(KERN_ERR PFX
2359 "Out of device ids!\n");
2360 break;
2361 }
2362 }
2363
2364 bmc->dev = platform_device_alloc(name, bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08002365 if (!bmc->dev) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002366 mutex_unlock(&ipmidriver_mutex);
Corey Minyard50c812b2006-03-26 01:37:21 -08002367 printk(KERN_ERR
2368 "ipmi_msghandler:"
2369 " Unable to allocate platform device\n");
2370 return -ENOMEM;
2371 }
2372 bmc->dev->dev.driver = &ipmidriver;
2373 dev_set_drvdata(&bmc->dev->dev, bmc);
2374 kref_init(&bmc->refcount);
2375
Zhang, Yanminb48f5452006-11-16 01:19:08 -08002376 rv = platform_device_add(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002377 mutex_unlock(&ipmidriver_mutex);
2378 if (rv) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002379 platform_device_put(bmc->dev);
2380 bmc->dev = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002381 printk(KERN_ERR
2382 "ipmi_msghandler:"
2383 " Unable to register bmc device: %d\n",
2384 rv);
2385 /* Don't go to out_err, you can only do that if
2386 the device is registered already. */
2387 return rv;
2388 }
2389
Jeff Garzik5e593932006-10-11 01:22:21 -07002390 rv = create_files(bmc);
2391 if (rv) {
2392 mutex_lock(&ipmidriver_mutex);
2393 platform_device_unregister(bmc->dev);
2394 mutex_unlock(&ipmidriver_mutex);
2395
2396 return rv;
2397 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002398
2399 printk(KERN_INFO
2400 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2401 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2402 bmc->id.manufacturer_id,
2403 bmc->id.product_id,
2404 bmc->id.device_id);
2405 }
2406
2407 /*
2408 * create symlink from system interface device to bmc device
2409 * and back.
2410 */
Corey Minyard759643b2006-12-06 20:40:59 -08002411 intf->sysfs_name = kstrdup(sysfs_name, GFP_KERNEL);
2412 if (!intf->sysfs_name) {
2413 rv = -ENOMEM;
2414 printk(KERN_ERR
2415 "ipmi_msghandler: allocate link to BMC: %d\n",
2416 rv);
2417 goto out_err;
2418 }
2419
Corey Minyard50c812b2006-03-26 01:37:21 -08002420 rv = sysfs_create_link(&intf->si_dev->kobj,
Corey Minyard759643b2006-12-06 20:40:59 -08002421 &bmc->dev->dev.kobj, intf->sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002422 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002423 kfree(intf->sysfs_name);
2424 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002425 printk(KERN_ERR
2426 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2427 rv);
2428 goto out_err;
2429 }
2430
Corey Minyard759643b2006-12-06 20:40:59 -08002431 size = snprintf(dummy, 0, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002432 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2433 if (!intf->my_dev_name) {
Corey Minyard759643b2006-12-06 20:40:59 -08002434 kfree(intf->sysfs_name);
2435 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002436 rv = -ENOMEM;
2437 printk(KERN_ERR
2438 "ipmi_msghandler: allocate link from BMC: %d\n",
2439 rv);
2440 goto out_err;
2441 }
Corey Minyard759643b2006-12-06 20:40:59 -08002442 snprintf(intf->my_dev_name, size+1, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002443
2444 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2445 intf->my_dev_name);
2446 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002447 kfree(intf->sysfs_name);
2448 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002449 kfree(intf->my_dev_name);
2450 intf->my_dev_name = NULL;
2451 printk(KERN_ERR
2452 "ipmi_msghandler:"
2453 " Unable to create symlink to bmc: %d\n",
2454 rv);
2455 goto out_err;
2456 }
2457
2458 return 0;
2459
2460out_err:
2461 ipmi_bmc_unregister(intf);
2462 return rv;
2463}
2464
2465static int
2466send_guid_cmd(ipmi_smi_t intf, int chan)
2467{
2468 struct kernel_ipmi_msg msg;
2469 struct ipmi_system_interface_addr si;
2470
2471 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2472 si.channel = IPMI_BMC_CHANNEL;
2473 si.lun = 0;
2474
2475 msg.netfn = IPMI_NETFN_APP_REQUEST;
2476 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2477 msg.data = NULL;
2478 msg.data_len = 0;
2479 return i_ipmi_request(NULL,
2480 intf,
2481 (struct ipmi_addr *) &si,
2482 0,
2483 &msg,
2484 intf,
2485 NULL,
2486 NULL,
2487 0,
2488 intf->channels[0].address,
2489 intf->channels[0].lun,
2490 -1, 0);
2491}
2492
2493static void
2494guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2495{
2496 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2497 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2498 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2499 /* Not for me */
2500 return;
2501
2502 if (msg->msg.data[0] != 0) {
2503 /* Error from getting the GUID, the BMC doesn't have one. */
2504 intf->bmc->guid_set = 0;
2505 goto out;
2506 }
2507
2508 if (msg->msg.data_len < 17) {
2509 intf->bmc->guid_set = 0;
2510 printk(KERN_WARNING PFX
2511 "guid_handler: The GUID response from the BMC was too"
2512 " short, it was %d but should have been 17. Assuming"
2513 " GUID is not available.\n",
2514 msg->msg.data_len);
2515 goto out;
2516 }
2517
2518 memcpy(intf->bmc->guid, msg->msg.data, 16);
2519 intf->bmc->guid_set = 1;
2520 out:
2521 wake_up(&intf->waitq);
2522}
2523
2524static void
2525get_guid(ipmi_smi_t intf)
2526{
2527 int rv;
2528
2529 intf->bmc->guid_set = 0x2;
2530 intf->null_user_handler = guid_handler;
2531 rv = send_guid_cmd(intf, 0);
2532 if (rv)
2533 /* Send failed, no GUID available. */
2534 intf->bmc->guid_set = 0;
2535 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2536 intf->null_user_handler = NULL;
2537}
2538
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539static int
2540send_channel_info_cmd(ipmi_smi_t intf, int chan)
2541{
2542 struct kernel_ipmi_msg msg;
2543 unsigned char data[1];
2544 struct ipmi_system_interface_addr si;
2545
2546 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2547 si.channel = IPMI_BMC_CHANNEL;
2548 si.lun = 0;
2549
2550 msg.netfn = IPMI_NETFN_APP_REQUEST;
2551 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2552 msg.data = data;
2553 msg.data_len = 1;
2554 data[0] = chan;
2555 return i_ipmi_request(NULL,
2556 intf,
2557 (struct ipmi_addr *) &si,
2558 0,
2559 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002560 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 NULL,
2562 NULL,
2563 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002564 intf->channels[0].address,
2565 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 -1, 0);
2567}
2568
2569static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002570channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571{
2572 int rv = 0;
2573 int chan;
2574
Corey Minyard56a55ec2005-09-06 15:18:42 -07002575 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2576 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2577 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 {
2579 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002580 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 /* Got an error from the channel, just go on. */
2582
Corey Minyard56a55ec2005-09-06 15:18:42 -07002583 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 /* If the MC does not support this
2585 command, that is legal. We just
2586 assume it has one IPMB at channel
2587 zero. */
2588 intf->channels[0].medium
2589 = IPMI_CHANNEL_MEDIUM_IPMB;
2590 intf->channels[0].protocol
2591 = IPMI_CHANNEL_PROTOCOL_IPMB;
2592 rv = -ENOSYS;
2593
2594 intf->curr_channel = IPMI_MAX_CHANNELS;
2595 wake_up(&intf->waitq);
2596 goto out;
2597 }
2598 goto next_channel;
2599 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002600 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 /* Message not big enough, just go on. */
2602 goto next_channel;
2603 }
2604 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002605 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2606 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
2608 next_channel:
2609 intf->curr_channel++;
2610 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2611 wake_up(&intf->waitq);
2612 else
2613 rv = send_channel_info_cmd(intf, intf->curr_channel);
2614
2615 if (rv) {
2616 /* Got an error somehow, just give up. */
2617 intf->curr_channel = IPMI_MAX_CHANNELS;
2618 wake_up(&intf->waitq);
2619
2620 printk(KERN_WARNING PFX
2621 "Error sending channel information: %d\n",
2622 rv);
2623 }
2624 }
2625 out:
2626 return;
2627}
2628
2629int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2630 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002631 struct ipmi_device_id *device_id,
2632 struct device *si_dev,
Corey Minyard759643b2006-12-06 20:40:59 -08002633 const char *sysfs_name,
Corey Minyard453823b2006-03-31 02:30:39 -08002634 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635{
2636 int i, j;
2637 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002638 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -08002639 ipmi_smi_t tintf;
Corey Minyardbca03242006-12-06 20:40:57 -08002640 struct list_head *link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 /* Make sure the driver is actually initialized, this handles
2643 problems with initialization order. */
2644 if (!initialized) {
2645 rv = ipmi_init_msghandler();
2646 if (rv)
2647 return rv;
2648 /* The init code doesn't return an error if it was turned
2649 off, but it won't initialize. Check that. */
2650 if (!initialized)
2651 return -ENODEV;
2652 }
2653
Corey Minyard393d2cc2005-11-07 00:59:54 -08002654 intf = kmalloc(sizeof(*intf), GFP_KERNEL);
2655 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002657 memset(intf, 0, sizeof(*intf));
Corey Minyardb2c03942006-12-06 20:41:00 -08002658
2659 intf->ipmi_version_major = ipmi_version_major(device_id);
2660 intf->ipmi_version_minor = ipmi_version_minor(device_id);
2661
Corey Minyard50c812b2006-03-26 01:37:21 -08002662 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2663 if (!intf->bmc) {
2664 kfree(intf);
2665 return -ENOMEM;
2666 }
Corey Minyardbca03242006-12-06 20:40:57 -08002667 intf->intf_num = -1; /* Mark it invalid for now. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002668 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002669 intf->bmc->id = *device_id;
2670 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002671 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2672 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2673 intf->channels[j].lun = 2;
2674 }
2675 if (slave_addr != 0)
2676 intf->channels[0].address = slave_addr;
2677 INIT_LIST_HEAD(&intf->users);
2678 intf->handlers = handlers;
2679 intf->send_info = send_info;
2680 spin_lock_init(&intf->seq_lock);
2681 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2682 intf->seq_table[j].inuse = 0;
2683 intf->seq_table[j].seqid = 0;
2684 }
2685 intf->curr_seq = 0;
2686#ifdef CONFIG_PROC_FS
2687 spin_lock_init(&intf->proc_entry_lock);
2688#endif
2689 spin_lock_init(&intf->waiting_msgs_lock);
2690 INIT_LIST_HEAD(&intf->waiting_msgs);
2691 spin_lock_init(&intf->events_lock);
2692 INIT_LIST_HEAD(&intf->waiting_events);
2693 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002694 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyardb9675132006-12-06 20:41:02 -08002695 spin_lock_init(&intf->maintenance_mode_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002696 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2697 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698
Corey Minyard393d2cc2005-11-07 00:59:54 -08002699 spin_lock_init(&intf->counter_lock);
2700 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Corey Minyardb2c03942006-12-06 20:41:00 -08002702 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002703 mutex_lock(&ipmi_interfaces_mutex);
2704 /* Look for a hole in the numbers. */
2705 i = 0;
2706 link = &ipmi_interfaces;
2707 list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) {
2708 if (tintf->intf_num != i) {
2709 link = &tintf->link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 break;
2711 }
Corey Minyardbca03242006-12-06 20:40:57 -08002712 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 }
Corey Minyardbca03242006-12-06 20:40:57 -08002714 /* Add the new interface in numeric order. */
2715 if (i == 0)
2716 list_add_rcu(&intf->link, &ipmi_interfaces);
2717 else
2718 list_add_tail_rcu(&intf->link, link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719
Corey Minyard453823b2006-03-31 02:30:39 -08002720 rv = handlers->start_processing(send_info, intf);
2721 if (rv)
2722 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002723
Corey Minyard50c812b2006-03-26 01:37:21 -08002724 get_guid(intf);
2725
Corey Minyardb2c03942006-12-06 20:41:00 -08002726 if ((intf->ipmi_version_major > 1)
2727 || ((intf->ipmi_version_major == 1)
2728 && (intf->ipmi_version_minor >= 5)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08002729 {
2730 /* Start scanning the channels to see what is
2731 available. */
2732 intf->null_user_handler = channel_handler;
2733 intf->curr_channel = 0;
2734 rv = send_channel_info_cmd(intf, 0);
2735 if (rv)
2736 goto out;
2737
2738 /* Wait for the channel info to be read. */
2739 wait_event(intf->waitq,
2740 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002741 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002742 } else {
2743 /* Assume a single IPMB channel at zero. */
2744 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2745 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
2748 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002749 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
Corey Minyard759643b2006-12-06 20:40:59 -08002751 rv = ipmi_bmc_register(intf, i, sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002752
Corey Minyard393d2cc2005-11-07 00:59:54 -08002753 out:
2754 if (rv) {
2755 if (intf->proc_dir)
2756 remove_proc_entries(intf);
Corey Minyardb2c03942006-12-06 20:41:00 -08002757 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002758 list_del_rcu(&intf->link);
2759 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002760 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002761 synchronize_rcu();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002762 kref_put(&intf->refcount, intf_free);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002763 } else {
Corey Minyard78ba2fa2007-02-10 01:45:45 -08002764 /*
2765 * Keep memory order straight for RCU readers. Make
2766 * sure everything else is committed to memory before
2767 * setting intf_num to mark the interface valid.
2768 */
2769 smp_wmb();
Corey Minyardbca03242006-12-06 20:40:57 -08002770 intf->intf_num = i;
2771 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard78ba2fa2007-02-10 01:45:45 -08002772 /* After this point the interface is legal to use. */
Corey Minyard50c812b2006-03-26 01:37:21 -08002773 call_smi_watchers(i, intf->si_dev);
Corey Minyardb2c03942006-12-06 20:41:00 -08002774 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 }
2776
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 return rv;
2778}
2779
Corey Minyardb2c03942006-12-06 20:41:00 -08002780static void cleanup_smi_msgs(ipmi_smi_t intf)
2781{
2782 int i;
2783 struct seq_table *ent;
2784
2785 /* No need for locks, the interface is down. */
2786 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
2787 ent = &(intf->seq_table[i]);
2788 if (!ent->inuse)
2789 continue;
2790 deliver_err_response(ent->recv_msg, IPMI_ERR_UNSPECIFIED);
2791 }
2792}
2793
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794int ipmi_unregister_smi(ipmi_smi_t intf)
2795{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 struct ipmi_smi_watcher *w;
Corey Minyardb2c03942006-12-06 20:41:00 -08002797 int intf_num = intf->intf_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
Corey Minyard50c812b2006-03-26 01:37:21 -08002799 ipmi_bmc_unregister(intf);
2800
Corey Minyardb2c03942006-12-06 20:41:00 -08002801 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002802 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002803 intf->intf_num = -1;
2804 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002805 list_del_rcu(&intf->link);
2806 mutex_unlock(&ipmi_interfaces_mutex);
2807 synchronize_rcu();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
Corey Minyardb2c03942006-12-06 20:41:00 -08002809 cleanup_smi_msgs(intf);
2810
Corey Minyard393d2cc2005-11-07 00:59:54 -08002811 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812
2813 /* Call all the watcher interfaces to tell them that
2814 an interface is gone. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002815 list_for_each_entry(w, &smi_watchers, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08002816 w->smi_gone(intf_num);
2817 mutex_unlock(&smi_watchers_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002818
Corey Minyard393d2cc2005-11-07 00:59:54 -08002819 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 return 0;
2821}
2822
2823static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2824 struct ipmi_smi_msg *msg)
2825{
2826 struct ipmi_ipmb_addr ipmb_addr;
2827 struct ipmi_recv_msg *recv_msg;
2828 unsigned long flags;
2829
2830
2831 /* This is 11, not 10, because the response must contain a
2832 * completion code. */
2833 if (msg->rsp_size < 11) {
2834 /* Message not big enough, just ignore it. */
2835 spin_lock_irqsave(&intf->counter_lock, flags);
2836 intf->invalid_ipmb_responses++;
2837 spin_unlock_irqrestore(&intf->counter_lock, flags);
2838 return 0;
2839 }
2840
2841 if (msg->rsp[2] != 0) {
2842 /* An error getting the response, just ignore it. */
2843 return 0;
2844 }
2845
2846 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
2847 ipmb_addr.slave_addr = msg->rsp[6];
2848 ipmb_addr.channel = msg->rsp[3] & 0x0f;
2849 ipmb_addr.lun = msg->rsp[7] & 3;
2850
2851 /* It's a response from a remote entity. Look up the sequence
2852 number and handle the response. */
2853 if (intf_find_seq(intf,
2854 msg->rsp[7] >> 2,
2855 msg->rsp[3] & 0x0f,
2856 msg->rsp[8],
2857 (msg->rsp[4] >> 2) & (~1),
2858 (struct ipmi_addr *) &(ipmb_addr),
2859 &recv_msg))
2860 {
2861 /* We were unable to find the sequence number,
2862 so just nuke the message. */
2863 spin_lock_irqsave(&intf->counter_lock, flags);
2864 intf->unhandled_ipmb_responses++;
2865 spin_unlock_irqrestore(&intf->counter_lock, flags);
2866 return 0;
2867 }
2868
2869 memcpy(recv_msg->msg_data,
2870 &(msg->rsp[9]),
2871 msg->rsp_size - 9);
2872 /* THe other fields matched, so no need to set them, except
2873 for netfn, which needs to be the response that was
2874 returned, not the request value. */
2875 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2876 recv_msg->msg.data = recv_msg->msg_data;
2877 recv_msg->msg.data_len = msg->rsp_size - 10;
2878 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2879 spin_lock_irqsave(&intf->counter_lock, flags);
2880 intf->handled_ipmb_responses++;
2881 spin_unlock_irqrestore(&intf->counter_lock, flags);
2882 deliver_response(recv_msg);
2883
2884 return 0;
2885}
2886
2887static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2888 struct ipmi_smi_msg *msg)
2889{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002890 struct cmd_rcvr *rcvr;
2891 int rv = 0;
2892 unsigned char netfn;
2893 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002894 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002895 ipmi_user_t user = NULL;
2896 struct ipmi_ipmb_addr *ipmb_addr;
2897 struct ipmi_recv_msg *recv_msg;
2898 unsigned long flags;
Corey Minyardb2c03942006-12-06 20:41:00 -08002899 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900
2901 if (msg->rsp_size < 10) {
2902 /* Message not big enough, just ignore it. */
2903 spin_lock_irqsave(&intf->counter_lock, flags);
2904 intf->invalid_commands++;
2905 spin_unlock_irqrestore(&intf->counter_lock, flags);
2906 return 0;
2907 }
2908
2909 if (msg->rsp[2] != 0) {
2910 /* An error getting the response, just ignore it. */
2911 return 0;
2912 }
2913
2914 netfn = msg->rsp[4] >> 2;
2915 cmd = msg->rsp[8];
Corey Minyardc69c3122006-09-30 23:27:56 -07002916 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002918 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002919 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002920 if (rcvr) {
2921 user = rcvr->user;
2922 kref_get(&user->refcount);
2923 } else
2924 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002925 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926
2927 if (user == NULL) {
2928 /* We didn't find a user, deliver an error response. */
2929 spin_lock_irqsave(&intf->counter_lock, flags);
2930 intf->unhandled_commands++;
2931 spin_unlock_irqrestore(&intf->counter_lock, flags);
2932
2933 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2934 msg->data[1] = IPMI_SEND_MSG_CMD;
2935 msg->data[2] = msg->rsp[3];
2936 msg->data[3] = msg->rsp[6];
2937 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2938 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002939 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 /* rqseq/lun */
2941 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2942 msg->data[8] = msg->rsp[8]; /* cmd */
2943 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2944 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2945 msg->data_size = 11;
2946
2947#ifdef DEBUG_MSGING
2948 {
2949 int m;
2950 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002951 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 printk(" %2.2x", msg->data[m]);
2953 printk("\n");
2954 }
2955#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08002956 rcu_read_lock();
2957 handlers = intf->handlers;
2958 if (handlers) {
2959 handlers->sender(intf->send_info, msg, 0);
2960 /* We used the message, so return the value
2961 that causes it to not be freed or
2962 queued. */
2963 rv = -1;
2964 }
2965 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 } else {
2967 /* Deliver the message to the user. */
2968 spin_lock_irqsave(&intf->counter_lock, flags);
2969 intf->handled_commands++;
2970 spin_unlock_irqrestore(&intf->counter_lock, flags);
2971
2972 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002973 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 /* We couldn't allocate memory for the
2975 message, so requeue it for handling
2976 later. */
2977 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002978 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 } else {
2980 /* Extract the source address from the data. */
2981 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2982 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2983 ipmb_addr->slave_addr = msg->rsp[6];
2984 ipmb_addr->lun = msg->rsp[7] & 3;
2985 ipmb_addr->channel = msg->rsp[3] & 0xf;
2986
2987 /* Extract the rest of the message information
2988 from the IPMB header.*/
2989 recv_msg->user = user;
2990 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2991 recv_msg->msgid = msg->rsp[7] >> 2;
2992 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2993 recv_msg->msg.cmd = msg->rsp[8];
2994 recv_msg->msg.data = recv_msg->msg_data;
2995
2996 /* We chop off 10, not 9 bytes because the checksum
2997 at the end also needs to be removed. */
2998 recv_msg->msg.data_len = msg->rsp_size - 10;
2999 memcpy(recv_msg->msg_data,
3000 &(msg->rsp[9]),
3001 msg->rsp_size - 10);
3002 deliver_response(recv_msg);
3003 }
3004 }
3005
3006 return rv;
3007}
3008
3009static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
3010 struct ipmi_smi_msg *msg)
3011{
3012 struct ipmi_lan_addr lan_addr;
3013 struct ipmi_recv_msg *recv_msg;
3014 unsigned long flags;
3015
3016
3017 /* This is 13, not 12, because the response must contain a
3018 * completion code. */
3019 if (msg->rsp_size < 13) {
3020 /* Message not big enough, just ignore it. */
3021 spin_lock_irqsave(&intf->counter_lock, flags);
3022 intf->invalid_lan_responses++;
3023 spin_unlock_irqrestore(&intf->counter_lock, flags);
3024 return 0;
3025 }
3026
3027 if (msg->rsp[2] != 0) {
3028 /* An error getting the response, just ignore it. */
3029 return 0;
3030 }
3031
3032 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
3033 lan_addr.session_handle = msg->rsp[4];
3034 lan_addr.remote_SWID = msg->rsp[8];
3035 lan_addr.local_SWID = msg->rsp[5];
3036 lan_addr.channel = msg->rsp[3] & 0x0f;
3037 lan_addr.privilege = msg->rsp[3] >> 4;
3038 lan_addr.lun = msg->rsp[9] & 3;
3039
3040 /* It's a response from a remote entity. Look up the sequence
3041 number and handle the response. */
3042 if (intf_find_seq(intf,
3043 msg->rsp[9] >> 2,
3044 msg->rsp[3] & 0x0f,
3045 msg->rsp[10],
3046 (msg->rsp[6] >> 2) & (~1),
3047 (struct ipmi_addr *) &(lan_addr),
3048 &recv_msg))
3049 {
3050 /* We were unable to find the sequence number,
3051 so just nuke the message. */
3052 spin_lock_irqsave(&intf->counter_lock, flags);
3053 intf->unhandled_lan_responses++;
3054 spin_unlock_irqrestore(&intf->counter_lock, flags);
3055 return 0;
3056 }
3057
3058 memcpy(recv_msg->msg_data,
3059 &(msg->rsp[11]),
3060 msg->rsp_size - 11);
3061 /* The other fields matched, so no need to set them, except
3062 for netfn, which needs to be the response that was
3063 returned, not the request value. */
3064 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3065 recv_msg->msg.data = recv_msg->msg_data;
3066 recv_msg->msg.data_len = msg->rsp_size - 12;
3067 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3068 spin_lock_irqsave(&intf->counter_lock, flags);
3069 intf->handled_lan_responses++;
3070 spin_unlock_irqrestore(&intf->counter_lock, flags);
3071 deliver_response(recv_msg);
3072
3073 return 0;
3074}
3075
3076static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
3077 struct ipmi_smi_msg *msg)
3078{
Corey Minyard393d2cc2005-11-07 00:59:54 -08003079 struct cmd_rcvr *rcvr;
3080 int rv = 0;
3081 unsigned char netfn;
3082 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07003083 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003084 ipmi_user_t user = NULL;
3085 struct ipmi_lan_addr *lan_addr;
3086 struct ipmi_recv_msg *recv_msg;
3087 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088
3089 if (msg->rsp_size < 12) {
3090 /* Message not big enough, just ignore it. */
3091 spin_lock_irqsave(&intf->counter_lock, flags);
3092 intf->invalid_commands++;
3093 spin_unlock_irqrestore(&intf->counter_lock, flags);
3094 return 0;
3095 }
3096
3097 if (msg->rsp[2] != 0) {
3098 /* An error getting the response, just ignore it. */
3099 return 0;
3100 }
3101
3102 netfn = msg->rsp[6] >> 2;
3103 cmd = msg->rsp[10];
Corey Minyardc69c3122006-09-30 23:27:56 -07003104 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003106 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07003107 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003108 if (rcvr) {
3109 user = rcvr->user;
3110 kref_get(&user->refcount);
3111 } else
3112 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003113 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
3115 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003116 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 spin_lock_irqsave(&intf->counter_lock, flags);
3118 intf->unhandled_commands++;
3119 spin_unlock_irqrestore(&intf->counter_lock, flags);
3120
3121 rv = 0; /* Don't do anything with these messages, just
3122 allow them to be freed. */
3123 } else {
3124 /* Deliver the message to the user. */
3125 spin_lock_irqsave(&intf->counter_lock, flags);
3126 intf->handled_commands++;
3127 spin_unlock_irqrestore(&intf->counter_lock, flags);
3128
3129 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003130 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 /* We couldn't allocate memory for the
3132 message, so requeue it for handling
3133 later. */
3134 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003135 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 } else {
3137 /* Extract the source address from the data. */
3138 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
3139 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
3140 lan_addr->session_handle = msg->rsp[4];
3141 lan_addr->remote_SWID = msg->rsp[8];
3142 lan_addr->local_SWID = msg->rsp[5];
3143 lan_addr->lun = msg->rsp[9] & 3;
3144 lan_addr->channel = msg->rsp[3] & 0xf;
3145 lan_addr->privilege = msg->rsp[3] >> 4;
3146
3147 /* Extract the rest of the message information
3148 from the IPMB header.*/
3149 recv_msg->user = user;
3150 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
3151 recv_msg->msgid = msg->rsp[9] >> 2;
3152 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3153 recv_msg->msg.cmd = msg->rsp[10];
3154 recv_msg->msg.data = recv_msg->msg_data;
3155
3156 /* We chop off 12, not 11 bytes because the checksum
3157 at the end also needs to be removed. */
3158 recv_msg->msg.data_len = msg->rsp_size - 12;
3159 memcpy(recv_msg->msg_data,
3160 &(msg->rsp[11]),
3161 msg->rsp_size - 12);
3162 deliver_response(recv_msg);
3163 }
3164 }
3165
3166 return rv;
3167}
3168
3169static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
3170 struct ipmi_smi_msg *msg)
3171{
3172 struct ipmi_system_interface_addr *smi_addr;
3173
3174 recv_msg->msgid = 0;
3175 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
3176 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3177 smi_addr->channel = IPMI_BMC_CHANNEL;
3178 smi_addr->lun = msg->rsp[0] & 3;
3179 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
3180 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3181 recv_msg->msg.cmd = msg->rsp[1];
3182 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
3183 recv_msg->msg.data = recv_msg->msg_data;
3184 recv_msg->msg.data_len = msg->rsp_size - 3;
3185}
3186
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187static int handle_read_event_rsp(ipmi_smi_t intf,
3188 struct ipmi_smi_msg *msg)
3189{
3190 struct ipmi_recv_msg *recv_msg, *recv_msg2;
3191 struct list_head msgs;
3192 ipmi_user_t user;
3193 int rv = 0;
3194 int deliver_count = 0;
3195 unsigned long flags;
3196
3197 if (msg->rsp_size < 19) {
3198 /* Message is too small to be an IPMB event. */
3199 spin_lock_irqsave(&intf->counter_lock, flags);
3200 intf->invalid_events++;
3201 spin_unlock_irqrestore(&intf->counter_lock, flags);
3202 return 0;
3203 }
3204
3205 if (msg->rsp[2] != 0) {
3206 /* An error getting the event, just ignore it. */
3207 return 0;
3208 }
3209
3210 INIT_LIST_HEAD(&msgs);
3211
Corey Minyard393d2cc2005-11-07 00:59:54 -08003212 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
3214 spin_lock(&intf->counter_lock);
3215 intf->events++;
3216 spin_unlock(&intf->counter_lock);
3217
3218 /* Allocate and fill in one message for every user that is getting
3219 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003220 rcu_read_lock();
3221 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003222 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 continue;
3224
3225 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003226 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003227 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003228 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
3229 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 list_del(&recv_msg->link);
3231 ipmi_free_recv_msg(recv_msg);
3232 }
3233 /* We couldn't allocate memory for the
3234 message, so requeue it for handling
3235 later. */
3236 rv = 1;
3237 goto out;
3238 }
3239
3240 deliver_count++;
3241
3242 copy_event_into_recv_msg(recv_msg, msg);
3243 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003244 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 list_add_tail(&(recv_msg->link), &msgs);
3246 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003247 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248
3249 if (deliver_count) {
3250 /* Now deliver all the messages. */
3251 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
3252 list_del(&recv_msg->link);
3253 deliver_response(recv_msg);
3254 }
3255 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
3256 /* No one to receive the message, put it in queue if there's
3257 not already too many things in the queue. */
3258 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003259 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 /* We couldn't allocate memory for the
3261 message, so requeue it for handling
3262 later. */
3263 rv = 1;
3264 goto out;
3265 }
3266
3267 copy_event_into_recv_msg(recv_msg, msg);
3268 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
Corey Minyard4791c032006-04-10 22:54:31 -07003269 intf->waiting_events_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 } else {
3271 /* There's too many things in the queue, discard this
3272 message. */
3273 printk(KERN_WARNING PFX "Event queue full, discarding an"
3274 " incoming event\n");
3275 }
3276
3277 out:
3278 spin_unlock_irqrestore(&(intf->events_lock), flags);
3279
3280 return rv;
3281}
3282
3283static int handle_bmc_rsp(ipmi_smi_t intf,
3284 struct ipmi_smi_msg *msg)
3285{
3286 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003288 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289
3290 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07003291 if (recv_msg == NULL)
3292 {
3293 printk(KERN_WARNING"IPMI message received with no owner. This\n"
3294 "could be because of a malformed message, or\n"
3295 "because of a hardware error. Contact your\n"
3296 "hardware vender for assistance\n");
3297 return 0;
3298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299
Corey Minyard393d2cc2005-11-07 00:59:54 -08003300 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003302 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07003303 /* The user for the message went away, so give up. */
3304 spin_lock_irqsave(&intf->counter_lock, flags);
3305 intf->unhandled_local_responses++;
3306 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 ipmi_free_recv_msg(recv_msg);
3308 } else {
3309 struct ipmi_system_interface_addr *smi_addr;
3310
3311 spin_lock_irqsave(&intf->counter_lock, flags);
3312 intf->handled_local_responses++;
3313 spin_unlock_irqrestore(&intf->counter_lock, flags);
3314 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3315 recv_msg->msgid = msg->msgid;
3316 smi_addr = ((struct ipmi_system_interface_addr *)
3317 &(recv_msg->addr));
3318 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3319 smi_addr->channel = IPMI_BMC_CHANNEL;
3320 smi_addr->lun = msg->rsp[0] & 3;
3321 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3322 recv_msg->msg.cmd = msg->rsp[1];
3323 memcpy(recv_msg->msg_data,
3324 &(msg->rsp[2]),
3325 msg->rsp_size - 2);
3326 recv_msg->msg.data = recv_msg->msg_data;
3327 recv_msg->msg.data_len = msg->rsp_size - 2;
3328 deliver_response(recv_msg);
3329 }
3330
3331 return 0;
3332}
3333
3334/* Handle a new message. Return 1 if the message should be requeued,
3335 0 if the message should be freed, or -1 if the message should not
3336 be freed or requeued. */
3337static int handle_new_recv_msg(ipmi_smi_t intf,
3338 struct ipmi_smi_msg *msg)
3339{
3340 int requeue;
3341 int chan;
3342
3343#ifdef DEBUG_MSGING
3344 int m;
3345 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07003346 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 printk(" %2.2x", msg->rsp[m]);
3348 printk("\n");
3349#endif
3350 if (msg->rsp_size < 2) {
3351 /* Message is too small to be correct. */
3352 printk(KERN_WARNING PFX "BMC returned to small a message"
3353 " for netfn %x cmd %x, got %d bytes\n",
3354 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3355
3356 /* Generate an error response for the message. */
3357 msg->rsp[0] = msg->data[0] | (1 << 2);
3358 msg->rsp[1] = msg->data[1];
3359 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3360 msg->rsp_size = 3;
3361 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3362 || (msg->rsp[1] != msg->data[1])) /* Command */
3363 {
3364 /* The response is not even marginally correct. */
3365 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3366 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3367 (msg->data[0] >> 2) | 1, msg->data[1],
3368 msg->rsp[0] >> 2, msg->rsp[1]);
3369
3370 /* Generate an error response for the message. */
3371 msg->rsp[0] = msg->data[0] | (1 << 2);
3372 msg->rsp[1] = msg->data[1];
3373 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3374 msg->rsp_size = 3;
3375 }
3376
3377 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3378 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3379 && (msg->user_data != NULL))
3380 {
3381 /* It's a response to a response we sent. For this we
3382 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003383 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384
3385 requeue = 0;
3386 if (msg->rsp_size < 2)
3387 /* Message is too small to be correct. */
3388 goto out;
3389
3390 chan = msg->data[2] & 0x0f;
3391 if (chan >= IPMI_MAX_CHANNELS)
3392 /* Invalid channel number */
3393 goto out;
3394
Corey Minyard393d2cc2005-11-07 00:59:54 -08003395 if (!recv_msg)
3396 goto out;
3397
3398 /* Make sure the user still exists. */
3399 if (!recv_msg->user || !recv_msg->user->valid)
3400 goto out;
3401
3402 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3403 recv_msg->msg.data = recv_msg->msg_data;
3404 recv_msg->msg.data_len = 1;
3405 recv_msg->msg_data[0] = msg->rsp[2];
3406 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3408 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3409 {
3410 /* It's from the receive queue. */
3411 chan = msg->rsp[3] & 0xf;
3412 if (chan >= IPMI_MAX_CHANNELS) {
3413 /* Invalid channel number */
3414 requeue = 0;
3415 goto out;
3416 }
3417
3418 switch (intf->channels[chan].medium) {
3419 case IPMI_CHANNEL_MEDIUM_IPMB:
3420 if (msg->rsp[4] & 0x04) {
3421 /* It's a response, so find the
3422 requesting message and send it up. */
3423 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3424 } else {
3425 /* It's a command to the SMS from some other
3426 entity. Handle that. */
3427 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3428 }
3429 break;
3430
3431 case IPMI_CHANNEL_MEDIUM_8023LAN:
3432 case IPMI_CHANNEL_MEDIUM_ASYNC:
3433 if (msg->rsp[6] & 0x04) {
3434 /* It's a response, so find the
3435 requesting message and send it up. */
3436 requeue = handle_lan_get_msg_rsp(intf, msg);
3437 } else {
3438 /* It's a command to the SMS from some other
3439 entity. Handle that. */
3440 requeue = handle_lan_get_msg_cmd(intf, msg);
3441 }
3442 break;
3443
3444 default:
3445 /* We don't handle the channel type, so just
3446 * free the message. */
3447 requeue = 0;
3448 }
3449
3450 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3451 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3452 {
3453 /* It's an asyncronous event. */
3454 requeue = handle_read_event_rsp(intf, msg);
3455 } else {
3456 /* It's a response from the local BMC. */
3457 requeue = handle_bmc_rsp(intf, msg);
3458 }
3459
3460 out:
3461 return requeue;
3462}
3463
3464/* Handle a new message from the lower layer. */
3465void ipmi_smi_msg_received(ipmi_smi_t intf,
3466 struct ipmi_smi_msg *msg)
3467{
3468 unsigned long flags;
3469 int rv;
3470
3471
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 if ((msg->data_size >= 2)
3473 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3474 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003475 && (msg->user_data == NULL))
3476 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 /* This is the local response to a command send, start
3478 the timer for these. The user_data will not be
3479 NULL if this is a response send, and we will let
3480 response sends just go through. */
3481
3482 /* Check for errors, if we get certain errors (ones
3483 that mean basically we can try again later), we
3484 ignore them and start the timer. Otherwise we
3485 report the error immediately. */
3486 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3487 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
Corey Minyard46d52b02006-11-08 17:44:55 -08003488 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
3489 && (msg->rsp[2] != IPMI_BUS_ERR)
3490 && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 {
3492 int chan = msg->rsp[3] & 0xf;
3493
3494 /* Got an error sending the message, handle it. */
3495 spin_lock_irqsave(&intf->counter_lock, flags);
3496 if (chan >= IPMI_MAX_CHANNELS)
3497 ; /* This shouldn't happen */
3498 else if ((intf->channels[chan].medium
3499 == IPMI_CHANNEL_MEDIUM_8023LAN)
3500 || (intf->channels[chan].medium
3501 == IPMI_CHANNEL_MEDIUM_ASYNC))
3502 intf->sent_lan_command_errs++;
3503 else
3504 intf->sent_ipmb_command_errs++;
3505 spin_unlock_irqrestore(&intf->counter_lock, flags);
3506 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3507 } else {
3508 /* The message was sent, start the timer. */
3509 intf_start_seq_timer(intf, msg->msgid);
3510 }
3511
3512 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003513 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 }
3515
3516 /* To preserve message order, if the list is not empty, we
3517 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003518 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
3519 if (!list_empty(&intf->waiting_msgs)) {
3520 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003521 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003522 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003524 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
3526 rv = handle_new_recv_msg(intf, msg);
3527 if (rv > 0) {
3528 /* Could not handle the message now, just add it to a
3529 list to handle later. */
Hironobu Ishii177294d2005-11-11 08:12:21 -06003530 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003531 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003532 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 } else if (rv == 0) {
3534 ipmi_free_smi_msg(msg);
3535 }
3536
Corey Minyard393d2cc2005-11-07 00:59:54 -08003537 out:
3538 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539}
3540
3541void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3542{
3543 ipmi_user_t user;
3544
Corey Minyard393d2cc2005-11-07 00:59:54 -08003545 rcu_read_lock();
3546 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003547 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548 continue;
3549
3550 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3551 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003552 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553}
3554
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555
Corey Minyard882fe012005-05-01 08:59:12 -07003556static struct ipmi_smi_msg *
3557smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3558 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559{
Corey Minyard882fe012005-05-01 08:59:12 -07003560 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 if (!smi_msg)
3562 /* If we can't allocate the message, then just return, we
3563 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003564 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565
3566 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3567 smi_msg->data_size = recv_msg->msg.data_len;
3568 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3569
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570#ifdef DEBUG_MSGING
3571 {
3572 int m;
3573 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003574 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 printk(" %2.2x", smi_msg->data[m]);
3576 printk("\n");
3577 }
3578#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003579 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580}
3581
Corey Minyard393d2cc2005-11-07 00:59:54 -08003582static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3583 struct list_head *timeouts, long timeout_period,
3584 int slot, unsigned long *flags)
3585{
Corey Minyardb2c03942006-12-06 20:41:00 -08003586 struct ipmi_recv_msg *msg;
3587 struct ipmi_smi_handlers *handlers;
3588
3589 if (intf->intf_num == -1)
3590 return;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003591
3592 if (!ent->inuse)
3593 return;
3594
3595 ent->timeout -= timeout_period;
3596 if (ent->timeout > 0)
3597 return;
3598
3599 if (ent->retries_left == 0) {
3600 /* The message has used all its retries. */
3601 ent->inuse = 0;
3602 msg = ent->recv_msg;
3603 list_add_tail(&msg->link, timeouts);
3604 spin_lock(&intf->counter_lock);
3605 if (ent->broadcast)
3606 intf->timed_out_ipmb_broadcasts++;
3607 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3608 intf->timed_out_lan_commands++;
3609 else
3610 intf->timed_out_ipmb_commands++;
3611 spin_unlock(&intf->counter_lock);
3612 } else {
3613 struct ipmi_smi_msg *smi_msg;
3614 /* More retries, send again. */
3615
3616 /* Start with the max timer, set to normal
3617 timer after the message is sent. */
3618 ent->timeout = MAX_MSG_TIMEOUT;
3619 ent->retries_left--;
3620 spin_lock(&intf->counter_lock);
3621 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3622 intf->retransmitted_lan_commands++;
3623 else
3624 intf->retransmitted_ipmb_commands++;
3625 spin_unlock(&intf->counter_lock);
3626
3627 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3628 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003629 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003630 return;
3631
3632 spin_unlock_irqrestore(&intf->seq_lock, *flags);
Corey Minyardb2c03942006-12-06 20:41:00 -08003633
Corey Minyard393d2cc2005-11-07 00:59:54 -08003634 /* Send the new message. We send with a zero
3635 * priority. It timed out, I doubt time is
3636 * that critical now, and high priority
3637 * messages are really only for messages to the
3638 * local MC, which don't get resent. */
Corey Minyardb2c03942006-12-06 20:41:00 -08003639 handlers = intf->handlers;
3640 if (handlers)
3641 intf->handlers->sender(intf->send_info,
3642 smi_msg, 0);
3643 else
3644 ipmi_free_smi_msg(smi_msg);
3645
Corey Minyard393d2cc2005-11-07 00:59:54 -08003646 spin_lock_irqsave(&intf->seq_lock, *flags);
3647 }
3648}
3649
3650static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651{
3652 ipmi_smi_t intf;
3653 struct list_head timeouts;
3654 struct ipmi_recv_msg *msg, *msg2;
3655 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3656 unsigned long flags;
Corey Minyardbca03242006-12-06 20:40:57 -08003657 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658
Corey Minyardbca03242006-12-06 20:40:57 -08003659 rcu_read_lock();
3660 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003662 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003663 list_for_each_entry_safe(smi_msg, smi_msg2,
3664 &intf->waiting_msgs, link) {
3665 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 list_del(&smi_msg->link);
3667 ipmi_free_smi_msg(smi_msg);
3668 } else {
3669 /* To preserve message order, quit if we
3670 can't handle a message. */
3671 break;
3672 }
3673 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003674 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675
3676 /* Go through the seq table and find any messages that
3677 have timed out, putting them in the timeouts
3678 list. */
David Barksdale41c57a82007-01-30 14:36:25 -08003679 INIT_LIST_HEAD(&timeouts);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003680 spin_lock_irqsave(&intf->seq_lock, flags);
Corey Minyardbca03242006-12-06 20:40:57 -08003681 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
3682 check_msg_timeout(intf, &(intf->seq_table[i]),
3683 &timeouts, timeout_period, i,
Corey Minyard393d2cc2005-11-07 00:59:54 -08003684 &flags);
3685 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686
Corey Minyard393d2cc2005-11-07 00:59:54 -08003687 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08003688 deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE);
Corey Minyardb9675132006-12-06 20:41:02 -08003689
3690 /*
3691 * Maintenance mode handling. Check the timeout
3692 * optimistically before we claim the lock. It may
3693 * mean a timeout gets missed occasionally, but that
3694 * only means the timeout gets extended by one period
3695 * in that case. No big deal, and it avoids the lock
3696 * most of the time.
3697 */
3698 if (intf->auto_maintenance_timeout > 0) {
3699 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
3700 if (intf->auto_maintenance_timeout > 0) {
3701 intf->auto_maintenance_timeout
3702 -= timeout_period;
3703 if (!intf->maintenance_mode
3704 && (intf->auto_maintenance_timeout <= 0))
3705 {
3706 intf->maintenance_mode_enable = 0;
3707 maintenance_mode_update(intf);
3708 }
3709 }
3710 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
3711 flags);
3712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 }
Corey Minyardbca03242006-12-06 20:40:57 -08003714 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715}
3716
3717static void ipmi_request_event(void)
3718{
Corey Minyardb2c03942006-12-06 20:41:00 -08003719 ipmi_smi_t intf;
3720 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721
Corey Minyardbca03242006-12-06 20:40:57 -08003722 rcu_read_lock();
Corey Minyardb2c03942006-12-06 20:41:00 -08003723 /* Called from the timer, no need to check if handlers is
3724 * valid. */
3725 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb9675132006-12-06 20:41:02 -08003726 /* No event requests when in maintenance mode. */
3727 if (intf->maintenance_mode_enable)
3728 continue;
3729
Corey Minyardb2c03942006-12-06 20:41:00 -08003730 handlers = intf->handlers;
3731 if (handlers)
3732 handlers->request_events(intf->send_info);
3733 }
Corey Minyardbca03242006-12-06 20:40:57 -08003734 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735}
3736
3737static struct timer_list ipmi_timer;
3738
3739/* Call every ~100 ms. */
3740#define IPMI_TIMEOUT_TIME 100
3741
3742/* How many jiffies does it take to get to the timeout time. */
3743#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3744
3745/* Request events from the queue every second (this is the number of
3746 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3747 future, IPMI will add a way to know immediately if an event is in
3748 the queue and this silliness can go away. */
3749#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3750
Corey Minyard8f43f842005-06-23 22:01:40 -07003751static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3753
3754static void ipmi_timeout(unsigned long data)
3755{
Corey Minyard8f43f842005-06-23 22:01:40 -07003756 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758
3759 ticks_to_req_ev--;
3760 if (ticks_to_req_ev == 0) {
3761 ipmi_request_event();
3762 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3763 }
3764
3765 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3766
Corey Minyard8f43f842005-06-23 22:01:40 -07003767 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768}
3769
3770
3771static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3772static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3773
3774/* FIXME - convert these to slabs. */
3775static void free_smi_msg(struct ipmi_smi_msg *msg)
3776{
3777 atomic_dec(&smi_msg_inuse_count);
3778 kfree(msg);
3779}
3780
3781struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3782{
3783 struct ipmi_smi_msg *rv;
3784 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3785 if (rv) {
3786 rv->done = free_smi_msg;
3787 rv->user_data = NULL;
3788 atomic_inc(&smi_msg_inuse_count);
3789 }
3790 return rv;
3791}
3792
3793static void free_recv_msg(struct ipmi_recv_msg *msg)
3794{
3795 atomic_dec(&recv_msg_inuse_count);
3796 kfree(msg);
3797}
3798
3799struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3800{
3801 struct ipmi_recv_msg *rv;
3802
3803 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3804 if (rv) {
Corey Minyarda9eec552006-08-31 21:27:45 -07003805 rv->user = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 rv->done = free_recv_msg;
3807 atomic_inc(&recv_msg_inuse_count);
3808 }
3809 return rv;
3810}
3811
Corey Minyard393d2cc2005-11-07 00:59:54 -08003812void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3813{
3814 if (msg->user)
3815 kref_put(&msg->user->refcount, free_user);
3816 msg->done(msg);
3817}
3818
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819#ifdef CONFIG_IPMI_PANIC_EVENT
3820
3821static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3822{
3823}
3824
3825static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3826{
3827}
3828
3829#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003830static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003832 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3833 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3834 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3835 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 {
3837 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003838 intf->event_receiver = msg->msg.data[1];
3839 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 }
3841}
3842
Corey Minyard56a55ec2005-09-06 15:18:42 -07003843static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003845 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3846 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3847 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3848 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 {
3850 /* A get device id command, save if we are an event
3851 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003852 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3853 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 }
3855}
3856#endif
3857
3858static void send_panic_events(char *str)
3859{
3860 struct kernel_ipmi_msg msg;
3861 ipmi_smi_t intf;
3862 unsigned char data[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 struct ipmi_system_interface_addr *si;
3864 struct ipmi_addr addr;
3865 struct ipmi_smi_msg smi_msg;
3866 struct ipmi_recv_msg recv_msg;
3867
3868 si = (struct ipmi_system_interface_addr *) &addr;
3869 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3870 si->channel = IPMI_BMC_CHANNEL;
3871 si->lun = 0;
3872
3873 /* Fill in an event telling that we have failed. */
3874 msg.netfn = 0x04; /* Sensor or Event. */
3875 msg.cmd = 2; /* Platform event command. */
3876 msg.data = data;
3877 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003878 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 data[1] = 0x03; /* This is for IPMI 1.0. */
3880 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3881 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3882 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3883
3884 /* Put a few breadcrumbs in. Hopefully later we can add more things
3885 to make the panic events more useful. */
3886 if (str) {
3887 data[3] = str[0];
3888 data[6] = str[1];
3889 data[7] = str[2];
3890 }
3891
3892 smi_msg.done = dummy_smi_done_handler;
3893 recv_msg.done = dummy_recv_done_handler;
3894
3895 /* For every registered interface, send the event. */
Corey Minyardbca03242006-12-06 20:40:57 -08003896 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08003897 if (!intf->handlers)
3898 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 continue;
3900
3901 /* Send the event announcing the panic. */
3902 intf->handlers->set_run_to_completion(intf->send_info, 1);
3903 i_ipmi_request(NULL,
3904 intf,
3905 &addr,
3906 0,
3907 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003908 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 &smi_msg,
3910 &recv_msg,
3911 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003912 intf->channels[0].address,
3913 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 0, 1); /* Don't retry, and don't wait. */
3915 }
3916
3917#ifdef CONFIG_IPMI_PANIC_STRING
3918 /* On every interface, dump a bunch of OEM event holding the
3919 string. */
3920 if (!str)
3921 return;
3922
Corey Minyardbca03242006-12-06 20:40:57 -08003923 /* For every registered interface, send the event. */
3924 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 char *p = str;
3926 struct ipmi_ipmb_addr *ipmb;
3927 int j;
3928
Corey Minyardbca03242006-12-06 20:40:57 -08003929 if (intf->intf_num == -1)
3930 /* Interface was not ready yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 continue;
3932
Corey Minyard78ba2fa2007-02-10 01:45:45 -08003933 /*
3934 * intf_num is used as an marker to tell if the
3935 * interface is valid. Thus we need a read barrier to
3936 * make sure data fetched before checking intf_num
3937 * won't be used.
3938 */
3939 smp_rmb();
3940
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 /* First job here is to figure out where to send the
3942 OEM events. There's no way in IPMI to send OEM
3943 events using an event send command, so we have to
3944 find the SEL to put them in and stick them in
3945 there. */
3946
3947 /* Get capabilities from the get device id. */
3948 intf->local_sel_device = 0;
3949 intf->local_event_generator = 0;
3950 intf->event_receiver = 0;
3951
3952 /* Request the device info from the local MC. */
3953 msg.netfn = IPMI_NETFN_APP_REQUEST;
3954 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3955 msg.data = NULL;
3956 msg.data_len = 0;
3957 intf->null_user_handler = device_id_fetcher;
3958 i_ipmi_request(NULL,
3959 intf,
3960 &addr,
3961 0,
3962 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003963 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 &smi_msg,
3965 &recv_msg,
3966 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003967 intf->channels[0].address,
3968 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 0, 1); /* Don't retry, and don't wait. */
3970
3971 if (intf->local_event_generator) {
3972 /* Request the event receiver from the local MC. */
3973 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3974 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3975 msg.data = NULL;
3976 msg.data_len = 0;
3977 intf->null_user_handler = event_receiver_fetcher;
3978 i_ipmi_request(NULL,
3979 intf,
3980 &addr,
3981 0,
3982 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003983 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 &smi_msg,
3985 &recv_msg,
3986 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003987 intf->channels[0].address,
3988 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 0, 1); /* no retry, and no wait. */
3990 }
3991 intf->null_user_handler = NULL;
3992
3993 /* Validate the event receiver. The low bit must not
3994 be 1 (it must be a valid IPMB address), it cannot
3995 be zero, and it must not be my address. */
3996 if (((intf->event_receiver & 1) == 0)
3997 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003998 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 {
4000 /* The event receiver is valid, send an IPMB
4001 message. */
4002 ipmb = (struct ipmi_ipmb_addr *) &addr;
4003 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
4004 ipmb->channel = 0; /* FIXME - is this right? */
4005 ipmb->lun = intf->event_receiver_lun;
4006 ipmb->slave_addr = intf->event_receiver;
4007 } else if (intf->local_sel_device) {
4008 /* The event receiver was not valid (or was
4009 me), but I am an SEL device, just dump it
4010 in my SEL. */
4011 si = (struct ipmi_system_interface_addr *) &addr;
4012 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
4013 si->channel = IPMI_BMC_CHANNEL;
4014 si->lun = 0;
4015 } else
4016 continue; /* No where to send the event. */
4017
4018
4019 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
4020 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
4021 msg.data = data;
4022 msg.data_len = 16;
4023
4024 j = 0;
4025 while (*p) {
4026 int size = strlen(p);
4027
4028 if (size > 11)
4029 size = 11;
4030 data[0] = 0;
4031 data[1] = 0;
4032 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07004033 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 data[4] = j++; /* sequence # */
4035 /* Always give 11 bytes, so strncpy will fill
4036 it with zeroes for me. */
4037 strncpy(data+5, p, 11);
4038 p += size;
4039
4040 i_ipmi_request(NULL,
4041 intf,
4042 &addr,
4043 0,
4044 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07004045 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 &smi_msg,
4047 &recv_msg,
4048 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07004049 intf->channels[0].address,
4050 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 0, 1); /* no retry, and no wait. */
4052 }
4053 }
4054#endif /* CONFIG_IPMI_PANIC_STRING */
4055}
4056#endif /* CONFIG_IPMI_PANIC_EVENT */
4057
Randy Dunlap0c8204b2006-12-10 02:19:06 -08004058static int has_panicked;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059
4060static int panic_event(struct notifier_block *this,
4061 unsigned long event,
4062 void *ptr)
4063{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 ipmi_smi_t intf;
4065
Lee Revellf18190b2006-06-26 18:30:00 +02004066 if (has_panicked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 return NOTIFY_DONE;
Lee Revellf18190b2006-06-26 18:30:00 +02004068 has_panicked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069
4070 /* For every registered interface, set it to run to completion. */
Corey Minyardbca03242006-12-06 20:40:57 -08004071 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08004072 if (!intf->handlers)
4073 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 continue;
4075
4076 intf->handlers->set_run_to_completion(intf->send_info, 1);
4077 }
4078
4079#ifdef CONFIG_IPMI_PANIC_EVENT
4080 send_panic_events(ptr);
4081#endif
4082
4083 return NOTIFY_DONE;
4084}
4085
4086static struct notifier_block panic_block = {
4087 .notifier_call = panic_event,
4088 .next = NULL,
4089 .priority = 200 /* priority: INT_MAX >= x >= 0 */
4090};
4091
4092static int ipmi_init_msghandler(void)
4093{
Corey Minyard50c812b2006-03-26 01:37:21 -08004094 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095
4096 if (initialized)
4097 return 0;
4098
Corey Minyard50c812b2006-03-26 01:37:21 -08004099 rv = driver_register(&ipmidriver);
4100 if (rv) {
4101 printk(KERN_ERR PFX "Could not register IPMI driver\n");
4102 return rv;
4103 }
4104
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004106 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107
Corey Minyard3b625942005-06-23 22:01:42 -07004108#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 proc_ipmi_root = proc_mkdir("ipmi", NULL);
4110 if (!proc_ipmi_root) {
4111 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
4112 return -ENOMEM;
4113 }
4114
4115 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07004116#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117
Corey Minyard409035e2006-06-28 04:26:53 -07004118 setup_timer(&ipmi_timer, ipmi_timeout, 0);
4119 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120
Alan Sterne041c682006-03-27 01:16:30 -08004121 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122
4123 initialized = 1;
4124
4125 return 0;
4126}
4127
4128static __init int ipmi_init_msghandler_mod(void)
4129{
4130 ipmi_init_msghandler();
4131 return 0;
4132}
4133
4134static __exit void cleanup_ipmi(void)
4135{
4136 int count;
4137
4138 if (!initialized)
4139 return;
4140
Alan Sterne041c682006-03-27 01:16:30 -08004141 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
4143 /* This can't be called if any interfaces exist, so no worry about
4144 shutting down the interfaces. */
4145
4146 /* Tell the timer to stop, then wait for it to stop. This avoids
4147 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07004148 atomic_inc(&stop_operation);
4149 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Corey Minyard3b625942005-06-23 22:01:42 -07004151#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 remove_proc_entry(proc_ipmi_root->name, &proc_root);
Corey Minyard3b625942005-06-23 22:01:42 -07004153#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154
Corey Minyard50c812b2006-03-26 01:37:21 -08004155 driver_unregister(&ipmidriver);
4156
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 initialized = 0;
4158
4159 /* Check for buffer leaks. */
4160 count = atomic_read(&smi_msg_inuse_count);
4161 if (count != 0)
4162 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
4163 count);
4164 count = atomic_read(&recv_msg_inuse_count);
4165 if (count != 0)
4166 printk(KERN_WARNING PFX "recv message count %d at exit\n",
4167 count);
4168}
4169module_exit(cleanup_ipmi);
4170
4171module_init(ipmi_init_msghandler_mod);
4172MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004173MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
4174MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
4175MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176
4177EXPORT_SYMBOL(ipmi_create_user);
4178EXPORT_SYMBOL(ipmi_destroy_user);
4179EXPORT_SYMBOL(ipmi_get_version);
4180EXPORT_SYMBOL(ipmi_request_settime);
4181EXPORT_SYMBOL(ipmi_request_supply_msgs);
4182EXPORT_SYMBOL(ipmi_register_smi);
4183EXPORT_SYMBOL(ipmi_unregister_smi);
4184EXPORT_SYMBOL(ipmi_register_for_cmd);
4185EXPORT_SYMBOL(ipmi_unregister_for_cmd);
4186EXPORT_SYMBOL(ipmi_smi_msg_received);
4187EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
4188EXPORT_SYMBOL(ipmi_alloc_smi_msg);
4189EXPORT_SYMBOL(ipmi_addr_length);
4190EXPORT_SYMBOL(ipmi_validate_addr);
4191EXPORT_SYMBOL(ipmi_set_gets_events);
4192EXPORT_SYMBOL(ipmi_smi_watcher_register);
4193EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
4194EXPORT_SYMBOL(ipmi_set_my_address);
4195EXPORT_SYMBOL(ipmi_get_my_address);
4196EXPORT_SYMBOL(ipmi_set_my_LUN);
4197EXPORT_SYMBOL(ipmi_get_my_LUN);
4198EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08004200EXPORT_SYMBOL(ipmi_free_recv_msg);