blob: b75e2c549720b5ecd370df2eb000439fe239cce5 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/poll.h>
38#include <linux/spinlock.h>
Corey Minyardd6dfd132006-03-31 02:30:41 -080039#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/slab.h>
41#include <linux/ipmi.h>
42#include <linux/ipmi_smi.h>
43#include <linux/notifier.h>
44#include <linux/init.h>
45#include <linux/proc_fs.h>
Corey Minyard393d2cc2005-11-07 00:59:54 -080046#include <linux/rcupdate.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#define PFX "IPMI message handler: "
Corey Minyard1fdd75b2005-09-06 15:18:42 -070049
Corey Minyardb9675132006-12-06 20:41:02 -080050#define IPMI_DRIVER_VERSION "39.1"
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
53static int ipmi_init_msghandler(void);
54
Randy Dunlap0c8204b2006-12-10 02:19:06 -080055static int initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Corey Minyard3b625942005-06-23 22:01:42 -070057#ifdef CONFIG_PROC_FS
Randy Dunlap0c8204b2006-12-10 02:19:06 -080058static struct proc_dir_entry *proc_ipmi_root;
Corey Minyard3b625942005-06-23 22:01:42 -070059#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Corey Minyardb9675132006-12-06 20:41:02 -080061/* Remain in auto-maintenance mode for this amount of time (in ms). */
62#define IPMI_MAINTENANCE_MODE_TIMEOUT 30000
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#define MAX_EVENTS_IN_QUEUE 25
65
66/* Don't let a message sit in a queue forever, always time it with at lest
67 the max message timer. This is in milliseconds. */
68#define MAX_MSG_TIMEOUT 60000
69
Corey Minyard393d2cc2005-11-07 00:59:54 -080070
71/*
72 * The main "user" data structure.
73 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070074struct ipmi_user
75{
76 struct list_head link;
77
Corey Minyard393d2cc2005-11-07 00:59:54 -080078 /* Set to "0" when the user is destroyed. */
79 int valid;
80
81 struct kref refcount;
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 /* The upper layer that handles receive messages. */
84 struct ipmi_user_hndl *handler;
85 void *handler_data;
86
87 /* The interface this user is bound to. */
88 ipmi_smi_t intf;
89
90 /* Does this interface receive IPMI events? */
91 int gets_events;
92};
93
94struct cmd_rcvr
95{
96 struct list_head link;
97
98 ipmi_user_t user;
99 unsigned char netfn;
100 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -0700101 unsigned int chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800102
103 /*
104 * This is used to form a linked lised during mass deletion.
105 * Since this is in an RCU list, we cannot use the link above
106 * or change any data until the RCU period completes. So we
107 * use this next variable during mass deletion so we can have
108 * a list and don't have to wait and restart the search on
109 * every individual deletion of a command. */
110 struct cmd_rcvr *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111};
112
113struct seq_table
114{
115 unsigned int inuse : 1;
116 unsigned int broadcast : 1;
117
118 unsigned long timeout;
119 unsigned long orig_timeout;
120 unsigned int retries_left;
121
122 /* To verify on an incoming send message response that this is
123 the message that the response is for, we keep a sequence id
124 and increment it every time we send a message. */
125 long seqid;
126
127 /* This is held so we can properly respond to the message on a
128 timeout, and it is used to hold the temporary data for
129 retransmission, too. */
130 struct ipmi_recv_msg *recv_msg;
131};
132
133/* Store the information in a msgid (long) to allow us to find a
134 sequence table entry from the msgid. */
135#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
136
137#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
138 do { \
139 seq = ((msgid >> 26) & 0x3f); \
140 seqid = (msgid & 0x3fffff); \
Corey Minyarde8b33612005-09-06 15:18:45 -0700141 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
144
145struct ipmi_channel
146{
147 unsigned char medium;
148 unsigned char protocol;
Corey Minyardc14979b2005-09-06 15:18:38 -0700149
150 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
151 but may be changed by the user. */
152 unsigned char address;
153
154 /* My LUN. This should generally stay the SMS LUN, but just in
155 case... */
156 unsigned char lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157};
158
Corey Minyard3b625942005-06-23 22:01:42 -0700159#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160struct ipmi_proc_entry
161{
162 char *name;
163 struct ipmi_proc_entry *next;
164};
Corey Minyard3b625942005-06-23 22:01:42 -0700165#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
Corey Minyard50c812b2006-03-26 01:37:21 -0800167struct bmc_device
168{
169 struct platform_device *dev;
170 struct ipmi_device_id id;
171 unsigned char guid[16];
172 int guid_set;
173
174 struct kref refcount;
175
176 /* bmc device attributes */
177 struct device_attribute device_id_attr;
178 struct device_attribute provides_dev_sdrs_attr;
179 struct device_attribute revision_attr;
180 struct device_attribute firmware_rev_attr;
181 struct device_attribute version_attr;
182 struct device_attribute add_dev_support_attr;
183 struct device_attribute manufacturer_id_attr;
184 struct device_attribute product_id_attr;
185 struct device_attribute guid_attr;
186 struct device_attribute aux_firmware_rev_attr;
187};
188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189#define IPMI_IPMB_NUM_SEQ 64
Corey Minyardc14979b2005-09-06 15:18:38 -0700190#define IPMI_MAX_CHANNELS 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191struct ipmi_smi
192{
193 /* What interface number are we? */
194 int intf_num;
195
Corey Minyard393d2cc2005-11-07 00:59:54 -0800196 struct kref refcount;
197
Corey Minyardbca03242006-12-06 20:40:57 -0800198 /* Used for a list of interfaces. */
199 struct list_head link;
200
Corey Minyard393d2cc2005-11-07 00:59:54 -0800201 /* The list of upper layers that are using me. seq_lock
202 * protects this. */
203 struct list_head users;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Corey Minyardb2c03942006-12-06 20:41:00 -0800205 /* Information to supply to users. */
206 unsigned char ipmi_version_major;
207 unsigned char ipmi_version_minor;
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 /* Used for wake ups at startup. */
210 wait_queue_head_t waitq;
211
Corey Minyard50c812b2006-03-26 01:37:21 -0800212 struct bmc_device *bmc;
213 char *my_dev_name;
Corey Minyard759643b2006-12-06 20:40:59 -0800214 char *sysfs_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Corey Minyardb2c03942006-12-06 20:41:00 -0800216 /* This is the lower-layer's sender routine. Note that you
217 * must either be holding the ipmi_interfaces_mutex or be in
218 * an umpreemptible region to use this. You must fetch the
219 * value into a local variable and make sure it is not NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 struct ipmi_smi_handlers *handlers;
221 void *send_info;
222
Corey Minyard3b625942005-06-23 22:01:42 -0700223#ifdef CONFIG_PROC_FS
Corey Minyardac019152007-10-18 03:07:11 -0700224 /* A list of proc entries for this interface. */
225 struct mutex proc_entry_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 struct ipmi_proc_entry *proc_entries;
Corey Minyard3b625942005-06-23 22:01:42 -0700227#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
Corey Minyard50c812b2006-03-26 01:37:21 -0800229 /* Driver-model device for the system interface. */
230 struct device *si_dev;
231
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 /* A table of sequence numbers for this interface. We use the
233 sequence numbers for IPMB messages that go out of the
234 interface to match them up with their responses. A routine
235 is called periodically to time the items in this list. */
236 spinlock_t seq_lock;
237 struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
238 int curr_seq;
239
240 /* Messages that were delayed for some reason (out of memory,
241 for instance), will go in here to be processed later in a
242 periodic timer interrupt. */
243 spinlock_t waiting_msgs_lock;
244 struct list_head waiting_msgs;
245
246 /* The list of command receivers that are registered for commands
247 on this interface. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800248 struct mutex cmd_rcvrs_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 struct list_head cmd_rcvrs;
250
251 /* Events that were queues because no one was there to receive
252 them. */
253 spinlock_t events_lock; /* For dealing with event stuff. */
254 struct list_head waiting_events;
255 unsigned int waiting_events_count; /* How many events in queue? */
Corey Minyard87ebd062008-04-29 01:01:04 -0700256 char delivering_events;
257 char event_msg_printed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 /* The event receiver for my BMC, only really used at panic
260 shutdown as a place to store this. */
261 unsigned char event_receiver;
262 unsigned char event_receiver_lun;
263 unsigned char local_sel_device;
264 unsigned char local_event_generator;
265
Corey Minyardb9675132006-12-06 20:41:02 -0800266 /* For handling of maintenance mode. */
267 int maintenance_mode;
268 int maintenance_mode_enable;
269 int auto_maintenance_timeout;
270 spinlock_t maintenance_mode_lock; /* Used in a timer... */
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 /* A cheap hack, if this is non-null and a message to an
273 interface comes in with a NULL user, call this routine with
274 it. Note that the message will still be freed by the
275 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700276 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
278 /* When we are scanning the channels for an SMI, this will
279 tell which channel we are scanning. */
280 int curr_channel;
281
282 /* Channel information */
283 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
284
285 /* Proc FS stuff. */
286 struct proc_dir_entry *proc_dir;
287 char proc_dir_name[10];
288
289 spinlock_t counter_lock; /* For making counters atomic. */
290
291 /* Commands we got that were invalid. */
292 unsigned int sent_invalid_commands;
293
294 /* Commands we sent to the MC. */
295 unsigned int sent_local_commands;
296 /* Responses from the MC that were delivered to a user. */
297 unsigned int handled_local_responses;
298 /* Responses from the MC that were not delivered to a user. */
299 unsigned int unhandled_local_responses;
300
301 /* Commands we sent out to the IPMB bus. */
302 unsigned int sent_ipmb_commands;
303 /* Commands sent on the IPMB that had errors on the SEND CMD */
304 unsigned int sent_ipmb_command_errs;
305 /* Each retransmit increments this count. */
306 unsigned int retransmitted_ipmb_commands;
307 /* When a message times out (runs out of retransmits) this is
308 incremented. */
309 unsigned int timed_out_ipmb_commands;
310
311 /* This is like above, but for broadcasts. Broadcasts are
312 *not* included in the above count (they are expected to
313 time out). */
314 unsigned int timed_out_ipmb_broadcasts;
315
316 /* Responses I have sent to the IPMB bus. */
317 unsigned int sent_ipmb_responses;
318
319 /* The response was delivered to the user. */
320 unsigned int handled_ipmb_responses;
321 /* The response had invalid data in it. */
322 unsigned int invalid_ipmb_responses;
323 /* The response didn't have anyone waiting for it. */
324 unsigned int unhandled_ipmb_responses;
325
326 /* Commands we sent out to the IPMB bus. */
327 unsigned int sent_lan_commands;
328 /* Commands sent on the IPMB that had errors on the SEND CMD */
329 unsigned int sent_lan_command_errs;
330 /* Each retransmit increments this count. */
331 unsigned int retransmitted_lan_commands;
332 /* When a message times out (runs out of retransmits) this is
333 incremented. */
334 unsigned int timed_out_lan_commands;
335
336 /* Responses I have sent to the IPMB bus. */
337 unsigned int sent_lan_responses;
338
339 /* The response was delivered to the user. */
340 unsigned int handled_lan_responses;
341 /* The response had invalid data in it. */
342 unsigned int invalid_lan_responses;
343 /* The response didn't have anyone waiting for it. */
344 unsigned int unhandled_lan_responses;
345
346 /* The command was delivered to the user. */
347 unsigned int handled_commands;
348 /* The command had invalid data in it. */
349 unsigned int invalid_commands;
350 /* The command didn't have anyone waiting for it. */
351 unsigned int unhandled_commands;
352
353 /* Invalid data in an event. */
354 unsigned int invalid_events;
Konstantin Baydarov5956dce2008-04-29 01:01:03 -0700355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 /* Events that were received with the proper format. */
357 unsigned int events;
Konstantin Baydarov5956dce2008-04-29 01:01:03 -0700358
359 /*
360 * run_to_completion duplicate of smb_info, smi_info
361 * and ipmi_serial_info structures. Used to decrease numbers of
362 * parameters passed by "low" level IPMI code.
363 */
364 int run_to_completion;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365};
Corey Minyard50c812b2006-03-26 01:37:21 -0800366#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Corey Minyard50c812b2006-03-26 01:37:21 -0800368/**
369 * The driver model view of the IPMI messaging driver.
370 */
371static struct device_driver ipmidriver = {
372 .name = "ipmi",
373 .bus = &platform_bus_type
374};
375static DEFINE_MUTEX(ipmidriver_mutex);
376
Denis Chengbed97592008-02-06 01:37:35 -0800377static LIST_HEAD(ipmi_interfaces);
Corey Minyardbca03242006-12-06 20:40:57 -0800378static DEFINE_MUTEX(ipmi_interfaces_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380/* List of watchers that want to know when smi's are added and
381 deleted. */
Denis Chengbed97592008-02-06 01:37:35 -0800382static LIST_HEAD(smi_watchers);
Corey Minyardb2c03942006-12-06 20:41:00 -0800383static DEFINE_MUTEX(smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Corey Minyard393d2cc2005-11-07 00:59:54 -0800386static void free_recv_msg_list(struct list_head *q)
387{
388 struct ipmi_recv_msg *msg, *msg2;
389
390 list_for_each_entry_safe(msg, msg2, q, link) {
391 list_del(&msg->link);
392 ipmi_free_recv_msg(msg);
393 }
394}
395
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800396static void free_smi_msg_list(struct list_head *q)
397{
398 struct ipmi_smi_msg *msg, *msg2;
399
400 list_for_each_entry_safe(msg, msg2, q, link) {
401 list_del(&msg->link);
402 ipmi_free_smi_msg(msg);
403 }
404}
405
Corey Minyard393d2cc2005-11-07 00:59:54 -0800406static void clean_up_interface_data(ipmi_smi_t intf)
407{
408 int i;
409 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800410 struct list_head list;
411
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800412 free_smi_msg_list(&intf->waiting_msgs);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800413 free_recv_msg_list(&intf->waiting_events);
414
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800415 /*
416 * Wholesale remove all the entries from the list in the
417 * interface and wait for RCU to know that none are in use.
418 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800419 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800420 INIT_LIST_HEAD(&list);
421 list_splice_init_rcu(&intf->cmd_rcvrs, &list, synchronize_rcu);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800422 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800423
424 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
425 kfree(rcvr);
426
427 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
428 if ((intf->seq_table[i].inuse)
429 && (intf->seq_table[i].recv_msg))
430 {
431 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 }
433 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800434}
435
436static void intf_free(struct kref *ref)
437{
438 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
439
440 clean_up_interface_data(intf);
441 kfree(intf);
442}
443
Corey Minyardbca03242006-12-06 20:40:57 -0800444struct watcher_entry {
Corey Minyardb2c03942006-12-06 20:41:00 -0800445 int intf_num;
446 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800447 struct list_head link;
Corey Minyardbca03242006-12-06 20:40:57 -0800448};
449
Corey Minyard393d2cc2005-11-07 00:59:54 -0800450int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
451{
Corey Minyardbca03242006-12-06 20:40:57 -0800452 ipmi_smi_t intf;
Denis Chenge381d1c2008-02-06 01:37:39 -0800453 LIST_HEAD(to_deliver);
Corey Minyardbca03242006-12-06 20:40:57 -0800454 struct watcher_entry *e, *e2;
455
Corey Minyardb2c03942006-12-06 20:41:00 -0800456 mutex_lock(&smi_watchers_mutex);
457
Corey Minyardbca03242006-12-06 20:40:57 -0800458 mutex_lock(&ipmi_interfaces_mutex);
459
Corey Minyardb2c03942006-12-06 20:41:00 -0800460 /* Build a list of things to deliver. */
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800461 list_for_each_entry(intf, &ipmi_interfaces, link) {
Corey Minyardbca03242006-12-06 20:40:57 -0800462 if (intf->intf_num == -1)
463 continue;
464 e = kmalloc(sizeof(*e), GFP_KERNEL);
465 if (!e)
466 goto out_err;
Corey Minyardb2c03942006-12-06 20:41:00 -0800467 kref_get(&intf->refcount);
468 e->intf = intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800469 e->intf_num = intf->intf_num;
470 list_add_tail(&e->link, &to_deliver);
471 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800472
Corey Minyardb2c03942006-12-06 20:41:00 -0800473 /* We will succeed, so add it to the list. */
474 list_add(&watcher->link, &smi_watchers);
Corey Minyardbca03242006-12-06 20:40:57 -0800475
476 mutex_unlock(&ipmi_interfaces_mutex);
477
478 list_for_each_entry_safe(e, e2, &to_deliver, link) {
479 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800480 watcher->new_smi(e->intf_num, e->intf->si_dev);
481 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800482 kfree(e);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800483 }
Corey Minyardbca03242006-12-06 20:40:57 -0800484
Corey Minyardb2c03942006-12-06 20:41:00 -0800485 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 return 0;
Corey Minyardbca03242006-12-06 20:40:57 -0800488
489 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -0800490 mutex_unlock(&ipmi_interfaces_mutex);
491 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800492 list_for_each_entry_safe(e, e2, &to_deliver, link) {
493 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800494 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800495 kfree(e);
496 }
497 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498}
499
500int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
501{
Corey Minyardb2c03942006-12-06 20:41:00 -0800502 mutex_lock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 list_del(&(watcher->link));
Corey Minyardb2c03942006-12-06 20:41:00 -0800504 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 return 0;
506}
507
Corey Minyardb2c03942006-12-06 20:41:00 -0800508/*
509 * Must be called with smi_watchers_mutex held.
510 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511static void
Corey Minyard50c812b2006-03-26 01:37:21 -0800512call_smi_watchers(int i, struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
514 struct ipmi_smi_watcher *w;
515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 list_for_each_entry(w, &smi_watchers, link) {
517 if (try_module_get(w->owner)) {
Corey Minyard50c812b2006-03-26 01:37:21 -0800518 w->new_smi(i, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 module_put(w->owner);
520 }
521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522}
523
524static int
525ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
526{
527 if (addr1->addr_type != addr2->addr_type)
528 return 0;
529
530 if (addr1->channel != addr2->channel)
531 return 0;
532
533 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
534 struct ipmi_system_interface_addr *smi_addr1
535 = (struct ipmi_system_interface_addr *) addr1;
536 struct ipmi_system_interface_addr *smi_addr2
537 = (struct ipmi_system_interface_addr *) addr2;
538 return (smi_addr1->lun == smi_addr2->lun);
539 }
540
541 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
542 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
543 {
544 struct ipmi_ipmb_addr *ipmb_addr1
545 = (struct ipmi_ipmb_addr *) addr1;
546 struct ipmi_ipmb_addr *ipmb_addr2
547 = (struct ipmi_ipmb_addr *) addr2;
548
549 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
550 && (ipmb_addr1->lun == ipmb_addr2->lun));
551 }
552
553 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
554 struct ipmi_lan_addr *lan_addr1
555 = (struct ipmi_lan_addr *) addr1;
556 struct ipmi_lan_addr *lan_addr2
557 = (struct ipmi_lan_addr *) addr2;
558
559 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
560 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
561 && (lan_addr1->session_handle
562 == lan_addr2->session_handle)
563 && (lan_addr1->lun == lan_addr2->lun));
564 }
565
566 return 1;
567}
568
569int ipmi_validate_addr(struct ipmi_addr *addr, int len)
570{
571 if (len < sizeof(struct ipmi_system_interface_addr)) {
572 return -EINVAL;
573 }
574
575 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
576 if (addr->channel != IPMI_BMC_CHANNEL)
577 return -EINVAL;
578 return 0;
579 }
580
581 if ((addr->channel == IPMI_BMC_CHANNEL)
Jayachandran C12fc1d72006-02-03 03:04:51 -0800582 || (addr->channel >= IPMI_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 || (addr->channel < 0))
584 return -EINVAL;
585
586 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
587 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
588 {
589 if (len < sizeof(struct ipmi_ipmb_addr)) {
590 return -EINVAL;
591 }
592 return 0;
593 }
594
595 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
596 if (len < sizeof(struct ipmi_lan_addr)) {
597 return -EINVAL;
598 }
599 return 0;
600 }
601
602 return -EINVAL;
603}
604
605unsigned int ipmi_addr_length(int addr_type)
606{
607 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
608 return sizeof(struct ipmi_system_interface_addr);
609
610 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
611 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
612 {
613 return sizeof(struct ipmi_ipmb_addr);
614 }
615
616 if (addr_type == IPMI_LAN_ADDR_TYPE)
617 return sizeof(struct ipmi_lan_addr);
618
619 return 0;
620}
621
622static void deliver_response(struct ipmi_recv_msg *msg)
623{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800624 if (!msg->user) {
Corey Minyard56a55ec2005-09-06 15:18:42 -0700625 ipmi_smi_t intf = msg->user_msg_data;
626 unsigned long flags;
627
628 /* Special handling for NULL users. */
629 if (intf->null_user_handler) {
630 intf->null_user_handler(intf, msg);
631 spin_lock_irqsave(&intf->counter_lock, flags);
632 intf->handled_local_responses++;
633 spin_unlock_irqrestore(&intf->counter_lock, flags);
634 } else {
635 /* No handler, so give up. */
636 spin_lock_irqsave(&intf->counter_lock, flags);
637 intf->unhandled_local_responses++;
638 spin_unlock_irqrestore(&intf->counter_lock, flags);
639 }
640 ipmi_free_recv_msg(msg);
641 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800642 ipmi_user_t user = msg->user;
643 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645}
646
Corey Minyardb2c03942006-12-06 20:41:00 -0800647static void
648deliver_err_response(struct ipmi_recv_msg *msg, int err)
649{
650 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
651 msg->msg_data[0] = err;
652 msg->msg.netfn |= 1; /* Convert to a response. */
653 msg->msg.data_len = 1;
654 msg->msg.data = msg->msg_data;
655 deliver_response(msg);
656}
657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658/* Find the next sequence number not being used and add the given
659 message with the given timeout to the sequence table. This must be
660 called with the interface's seq_lock held. */
661static int intf_next_seq(ipmi_smi_t intf,
662 struct ipmi_recv_msg *recv_msg,
663 unsigned long timeout,
664 int retries,
665 int broadcast,
666 unsigned char *seq,
667 long *seqid)
668{
669 int rv = 0;
670 unsigned int i;
671
Corey Minyarde8b33612005-09-06 15:18:45 -0700672 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700674 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800676 if (!intf->seq_table[i].inuse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 break;
678 }
679
Corey Minyard8a3628d2006-03-31 02:30:40 -0800680 if (!intf->seq_table[i].inuse) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 intf->seq_table[i].recv_msg = recv_msg;
682
683 /* Start with the maximum timeout, when the send response
684 comes in we will start the real timer. */
685 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
686 intf->seq_table[i].orig_timeout = timeout;
687 intf->seq_table[i].retries_left = retries;
688 intf->seq_table[i].broadcast = broadcast;
689 intf->seq_table[i].inuse = 1;
690 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
691 *seq = i;
692 *seqid = intf->seq_table[i].seqid;
693 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
694 } else {
695 rv = -EAGAIN;
696 }
697
698 return rv;
699}
700
701/* Return the receive message for the given sequence number and
702 release the sequence number so it can be reused. Some other data
703 is passed in to be sure the message matches up correctly (to help
704 guard against message coming in after their timeout and the
705 sequence number being reused). */
706static int intf_find_seq(ipmi_smi_t intf,
707 unsigned char seq,
708 short channel,
709 unsigned char cmd,
710 unsigned char netfn,
711 struct ipmi_addr *addr,
712 struct ipmi_recv_msg **recv_msg)
713{
714 int rv = -ENODEV;
715 unsigned long flags;
716
717 if (seq >= IPMI_IPMB_NUM_SEQ)
718 return -EINVAL;
719
720 spin_lock_irqsave(&(intf->seq_lock), flags);
721 if (intf->seq_table[seq].inuse) {
722 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
723
724 if ((msg->addr.channel == channel)
725 && (msg->msg.cmd == cmd)
726 && (msg->msg.netfn == netfn)
727 && (ipmi_addr_equal(addr, &(msg->addr))))
728 {
729 *recv_msg = msg;
730 intf->seq_table[seq].inuse = 0;
731 rv = 0;
732 }
733 }
734 spin_unlock_irqrestore(&(intf->seq_lock), flags);
735
736 return rv;
737}
738
739
740/* Start the timer for a specific sequence table entry. */
741static int intf_start_seq_timer(ipmi_smi_t intf,
742 long msgid)
743{
744 int rv = -ENODEV;
745 unsigned long flags;
746 unsigned char seq;
747 unsigned long seqid;
748
749
750 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
751
752 spin_lock_irqsave(&(intf->seq_lock), flags);
753 /* We do this verification because the user can be deleted
754 while a message is outstanding. */
755 if ((intf->seq_table[seq].inuse)
756 && (intf->seq_table[seq].seqid == seqid))
757 {
758 struct seq_table *ent = &(intf->seq_table[seq]);
759 ent->timeout = ent->orig_timeout;
760 rv = 0;
761 }
762 spin_unlock_irqrestore(&(intf->seq_lock), flags);
763
764 return rv;
765}
766
767/* Got an error for the send message for a specific sequence number. */
768static int intf_err_seq(ipmi_smi_t intf,
769 long msgid,
770 unsigned int err)
771{
772 int rv = -ENODEV;
773 unsigned long flags;
774 unsigned char seq;
775 unsigned long seqid;
776 struct ipmi_recv_msg *msg = NULL;
777
778
779 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
780
781 spin_lock_irqsave(&(intf->seq_lock), flags);
782 /* We do this verification because the user can be deleted
783 while a message is outstanding. */
784 if ((intf->seq_table[seq].inuse)
785 && (intf->seq_table[seq].seqid == seqid))
786 {
787 struct seq_table *ent = &(intf->seq_table[seq]);
788
789 ent->inuse = 0;
790 msg = ent->recv_msg;
791 rv = 0;
792 }
793 spin_unlock_irqrestore(&(intf->seq_lock), flags);
794
Corey Minyardb2c03942006-12-06 20:41:00 -0800795 if (msg)
796 deliver_err_response(msg, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 return rv;
799}
800
801
802int ipmi_create_user(unsigned int if_num,
803 struct ipmi_user_hndl *handler,
804 void *handler_data,
805 ipmi_user_t *user)
806{
807 unsigned long flags;
808 ipmi_user_t new_user;
809 int rv = 0;
810 ipmi_smi_t intf;
811
812 /* There is no module usecount here, because it's not
813 required. Since this can only be used by and called from
814 other modules, they will implicitly use this module, and
815 thus this can't be removed unless the other modules are
816 removed. */
817
818 if (handler == NULL)
819 return -EINVAL;
820
821 /* Make sure the driver is actually initialized, this handles
822 problems with initialization order. */
823 if (!initialized) {
824 rv = ipmi_init_msghandler();
825 if (rv)
826 return rv;
827
828 /* The init code doesn't return an error if it was turned
829 off, but it won't initialize. Check that. */
830 if (!initialized)
831 return -ENODEV;
832 }
833
834 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800835 if (!new_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 return -ENOMEM;
837
Corey Minyardb2c03942006-12-06 20:41:00 -0800838 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800839 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
840 if (intf->intf_num == if_num)
841 goto found;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 }
Corey Minyardb2c03942006-12-06 20:41:00 -0800843 /* Not found, return an error */
Corey Minyardbca03242006-12-06 20:40:57 -0800844 rv = -EINVAL;
845 goto out_kfree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Corey Minyardbca03242006-12-06 20:40:57 -0800847 found:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800848 /* Note that each existing user holds a refcount to the interface. */
849 kref_get(&intf->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Corey Minyard393d2cc2005-11-07 00:59:54 -0800851 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 new_user->handler = handler;
853 new_user->handler_data = handler_data;
854 new_user->intf = intf;
855 new_user->gets_events = 0;
856
857 if (!try_module_get(intf->handlers->owner)) {
858 rv = -ENODEV;
Adrian Bunk5c98d292006-03-25 03:07:52 -0800859 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 }
861
862 if (intf->handlers->inc_usecount) {
863 rv = intf->handlers->inc_usecount(intf->send_info);
864 if (rv) {
865 module_put(intf->handlers->owner);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800866 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 }
868 }
869
Corey Minyardb2c03942006-12-06 20:41:00 -0800870 /* Hold the lock so intf->handlers is guaranteed to be good
871 * until now */
872 mutex_unlock(&ipmi_interfaces_mutex);
873
Corey Minyard393d2cc2005-11-07 00:59:54 -0800874 new_user->valid = 1;
875 spin_lock_irqsave(&intf->seq_lock, flags);
876 list_add_rcu(&new_user->link, &intf->users);
877 spin_unlock_irqrestore(&intf->seq_lock, flags);
878 *user = new_user;
879 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
Adrian Bunk5c98d292006-03-25 03:07:52 -0800881out_kref:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800882 kref_put(&intf->refcount, intf_free);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800883out_kfree:
Corey Minyardb2c03942006-12-06 20:41:00 -0800884 mutex_unlock(&ipmi_interfaces_mutex);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800885 kfree(new_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return rv;
887}
888
Corey Minyard393d2cc2005-11-07 00:59:54 -0800889static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800891 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893}
894
895int ipmi_destroy_user(ipmi_user_t user)
896{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800897 ipmi_smi_t intf = user->intf;
898 int i;
899 unsigned long flags;
900 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800901 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
Corey Minyard8a3628d2006-03-31 02:30:40 -0800903 user->valid = 0;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800904
905 /* Remove the user from the interface's sequence table. */
906 spin_lock_irqsave(&intf->seq_lock, flags);
907 list_del_rcu(&user->link);
908
909 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
910 if (intf->seq_table[i].inuse
911 && (intf->seq_table[i].recv_msg->user == user))
912 {
913 intf->seq_table[i].inuse = 0;
Corey Minyardb2c03942006-12-06 20:41:00 -0800914 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800917 spin_unlock_irqrestore(&intf->seq_lock, flags);
918
919 /*
920 * Remove the user from the command receiver's table. First
921 * we build a list of everything (not using the standard link,
922 * since other things may be using it till we do
923 * synchronize_rcu()) then free everything in that list.
924 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800925 mutex_lock(&intf->cmd_rcvrs_mutex);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800926 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800927 if (rcvr->user == user) {
928 list_del_rcu(&rcvr->link);
929 rcvr->next = rcvrs;
930 rcvrs = rcvr;
931 }
932 }
Corey Minyardd6dfd132006-03-31 02:30:41 -0800933 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800934 synchronize_rcu();
935 while (rcvrs) {
936 rcvr = rcvrs;
937 rcvrs = rcvr->next;
938 kfree(rcvr);
939 }
940
Corey Minyardb2c03942006-12-06 20:41:00 -0800941 mutex_lock(&ipmi_interfaces_mutex);
942 if (intf->handlers) {
943 module_put(intf->handlers->owner);
944 if (intf->handlers->dec_usecount)
945 intf->handlers->dec_usecount(intf->send_info);
946 }
947 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800948
949 kref_put(&intf->refcount, intf_free);
950
951 kref_put(&user->refcount, free_user);
952
Corey Minyard8a3628d2006-03-31 02:30:40 -0800953 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954}
955
956void ipmi_get_version(ipmi_user_t user,
957 unsigned char *major,
958 unsigned char *minor)
959{
Corey Minyardb2c03942006-12-06 20:41:00 -0800960 *major = user->intf->ipmi_version_major;
961 *minor = user->intf->ipmi_version_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962}
963
Corey Minyardc14979b2005-09-06 15:18:38 -0700964int ipmi_set_my_address(ipmi_user_t user,
965 unsigned int channel,
966 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
Corey Minyardc14979b2005-09-06 15:18:38 -0700968 if (channel >= IPMI_MAX_CHANNELS)
969 return -EINVAL;
970 user->intf->channels[channel].address = address;
971 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972}
973
Corey Minyardc14979b2005-09-06 15:18:38 -0700974int ipmi_get_my_address(ipmi_user_t user,
975 unsigned int channel,
976 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
Corey Minyardc14979b2005-09-06 15:18:38 -0700978 if (channel >= IPMI_MAX_CHANNELS)
979 return -EINVAL;
980 *address = user->intf->channels[channel].address;
981 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982}
983
Corey Minyardc14979b2005-09-06 15:18:38 -0700984int ipmi_set_my_LUN(ipmi_user_t user,
985 unsigned int channel,
986 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987{
Corey Minyardc14979b2005-09-06 15:18:38 -0700988 if (channel >= IPMI_MAX_CHANNELS)
989 return -EINVAL;
990 user->intf->channels[channel].lun = LUN & 0x3;
991 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992}
993
Corey Minyardc14979b2005-09-06 15:18:38 -0700994int ipmi_get_my_LUN(ipmi_user_t user,
995 unsigned int channel,
996 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997{
Corey Minyardc14979b2005-09-06 15:18:38 -0700998 if (channel >= IPMI_MAX_CHANNELS)
999 return -EINVAL;
1000 *address = user->intf->channels[channel].lun;
1001 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002}
1003
Corey Minyardb9675132006-12-06 20:41:02 -08001004int ipmi_get_maintenance_mode(ipmi_user_t user)
1005{
1006 int mode;
1007 unsigned long flags;
1008
1009 spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);
1010 mode = user->intf->maintenance_mode;
1011 spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);
1012
1013 return mode;
1014}
1015EXPORT_SYMBOL(ipmi_get_maintenance_mode);
1016
1017static void maintenance_mode_update(ipmi_smi_t intf)
1018{
1019 if (intf->handlers->set_maintenance_mode)
1020 intf->handlers->set_maintenance_mode(
1021 intf->send_info, intf->maintenance_mode_enable);
1022}
1023
1024int ipmi_set_maintenance_mode(ipmi_user_t user, int mode)
1025{
1026 int rv = 0;
1027 unsigned long flags;
1028 ipmi_smi_t intf = user->intf;
1029
1030 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1031 if (intf->maintenance_mode != mode) {
1032 switch (mode) {
1033 case IPMI_MAINTENANCE_MODE_AUTO:
1034 intf->maintenance_mode = mode;
1035 intf->maintenance_mode_enable
1036 = (intf->auto_maintenance_timeout > 0);
1037 break;
1038
1039 case IPMI_MAINTENANCE_MODE_OFF:
1040 intf->maintenance_mode = mode;
1041 intf->maintenance_mode_enable = 0;
1042 break;
1043
1044 case IPMI_MAINTENANCE_MODE_ON:
1045 intf->maintenance_mode = mode;
1046 intf->maintenance_mode_enable = 1;
1047 break;
1048
1049 default:
1050 rv = -EINVAL;
1051 goto out_unlock;
1052 }
1053
1054 maintenance_mode_update(intf);
1055 }
1056 out_unlock:
1057 spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);
1058
1059 return rv;
1060}
1061EXPORT_SYMBOL(ipmi_set_maintenance_mode);
1062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063int ipmi_set_gets_events(ipmi_user_t user, int val)
1064{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001065 unsigned long flags;
1066 ipmi_smi_t intf = user->intf;
1067 struct ipmi_recv_msg *msg, *msg2;
1068 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
Corey Minyard393d2cc2005-11-07 00:59:54 -08001070 INIT_LIST_HEAD(&msgs);
1071
1072 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 user->gets_events = val;
1074
Corey Minyardb2c03942006-12-06 20:41:00 -08001075 if (intf->delivering_events)
1076 /*
1077 * Another thread is delivering events for this, so
1078 * let it handle any new events.
1079 */
1080 goto out;
1081
1082 /* Deliver any queued events. */
1083 while (user->gets_events && !list_empty(&intf->waiting_events)) {
Akinobu Mita179e0912006-06-26 00:24:41 -07001084 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
1085 list_move_tail(&msg->link, &msgs);
Corey Minyard4791c032006-04-10 22:54:31 -07001086 intf->waiting_events_count = 0;
Corey Minyard87ebd062008-04-29 01:01:04 -07001087 if (intf->event_msg_printed) {
1088 printk(KERN_WARNING PFX "Event queue no longer"
1089 " full\n");
1090 intf->event_msg_printed = 0;
1091 }
Corey Minyardb2c03942006-12-06 20:41:00 -08001092
1093 intf->delivering_events = 1;
1094 spin_unlock_irqrestore(&intf->events_lock, flags);
1095
1096 list_for_each_entry_safe(msg, msg2, &msgs, link) {
1097 msg->user = user;
1098 kref_get(&user->refcount);
1099 deliver_response(msg);
1100 }
1101
1102 spin_lock_irqsave(&intf->events_lock, flags);
1103 intf->delivering_events = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08001105
Corey Minyardb2c03942006-12-06 20:41:00 -08001106 out:
Corey Minyard393d2cc2005-11-07 00:59:54 -08001107 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
1109 return 0;
1110}
1111
Corey Minyard393d2cc2005-11-07 00:59:54 -08001112static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
1113 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001114 unsigned char cmd,
1115 unsigned char chan)
Corey Minyard393d2cc2005-11-07 00:59:54 -08001116{
1117 struct cmd_rcvr *rcvr;
1118
1119 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyardc69c3122006-09-30 23:27:56 -07001120 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1121 && (rcvr->chans & (1 << chan)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08001122 return rcvr;
1123 }
1124 return NULL;
1125}
1126
Corey Minyardc69c3122006-09-30 23:27:56 -07001127static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
1128 unsigned char netfn,
1129 unsigned char cmd,
1130 unsigned int chans)
1131{
1132 struct cmd_rcvr *rcvr;
1133
1134 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
1135 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1136 && (rcvr->chans & chans))
1137 return 0;
1138 }
1139 return 1;
1140}
1141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142int ipmi_register_for_cmd(ipmi_user_t user,
1143 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001144 unsigned char cmd,
1145 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001147 ipmi_smi_t intf = user->intf;
1148 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001149 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
1151
1152 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -08001153 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001155 rcvr->cmd = cmd;
1156 rcvr->netfn = netfn;
Corey Minyardc69c3122006-09-30 23:27:56 -07001157 rcvr->chans = chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001158 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
Corey Minyardd6dfd132006-03-31 02:30:41 -08001160 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 /* Make sure the command/netfn is not already registered. */
Corey Minyardc69c3122006-09-30 23:27:56 -07001162 if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08001163 rv = -EBUSY;
1164 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 }
1166
Corey Minyard393d2cc2005-11-07 00:59:54 -08001167 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -07001168
Corey Minyard393d2cc2005-11-07 00:59:54 -08001169 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -08001170 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 if (rv)
1172 kfree(rcvr);
1173
1174 return rv;
1175}
1176
1177int ipmi_unregister_for_cmd(ipmi_user_t user,
1178 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001179 unsigned char cmd,
1180 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001182 ipmi_smi_t intf = user->intf;
1183 struct cmd_rcvr *rcvr;
Corey Minyardc69c3122006-09-30 23:27:56 -07001184 struct cmd_rcvr *rcvrs = NULL;
1185 int i, rv = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
Corey Minyardd6dfd132006-03-31 02:30:41 -08001187 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyardc69c3122006-09-30 23:27:56 -07001188 for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
1189 if (((1 << i) & chans) == 0)
1190 continue;
1191 rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
1192 if (rcvr == NULL)
1193 continue;
1194 if (rcvr->user == user) {
1195 rv = 0;
1196 rcvr->chans &= ~chans;
1197 if (rcvr->chans == 0) {
1198 list_del_rcu(&rcvr->link);
1199 rcvr->next = rcvrs;
1200 rcvrs = rcvr;
1201 }
1202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 }
Corey Minyardc69c3122006-09-30 23:27:56 -07001204 mutex_unlock(&intf->cmd_rcvrs_mutex);
1205 synchronize_rcu();
1206 while (rcvrs) {
1207 rcvr = rcvrs;
1208 rcvrs = rcvr->next;
1209 kfree(rcvr);
1210 }
1211 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212}
1213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214static unsigned char
1215ipmb_checksum(unsigned char *data, int size)
1216{
1217 unsigned char csum = 0;
1218
1219 for (; size > 0; size--, data++)
1220 csum += *data;
1221
1222 return -csum;
1223}
1224
1225static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1226 struct kernel_ipmi_msg *msg,
1227 struct ipmi_ipmb_addr *ipmb_addr,
1228 long msgid,
1229 unsigned char ipmb_seq,
1230 int broadcast,
1231 unsigned char source_address,
1232 unsigned char source_lun)
1233{
1234 int i = broadcast;
1235
1236 /* Format the IPMB header data. */
1237 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1238 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1239 smi_msg->data[2] = ipmb_addr->channel;
1240 if (broadcast)
1241 smi_msg->data[3] = 0;
1242 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1243 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1244 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1245 smi_msg->data[i+6] = source_address;
1246 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1247 smi_msg->data[i+8] = msg->cmd;
1248
1249 /* Now tack on the data to the message. */
1250 if (msg->data_len > 0)
1251 memcpy(&(smi_msg->data[i+9]), msg->data,
1252 msg->data_len);
1253 smi_msg->data_size = msg->data_len + 9;
1254
1255 /* Now calculate the checksum and tack it on. */
1256 smi_msg->data[i+smi_msg->data_size]
1257 = ipmb_checksum(&(smi_msg->data[i+6]),
1258 smi_msg->data_size-6);
1259
1260 /* Add on the checksum size and the offset from the
1261 broadcast. */
1262 smi_msg->data_size += 1 + i;
1263
1264 smi_msg->msgid = msgid;
1265}
1266
1267static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1268 struct kernel_ipmi_msg *msg,
1269 struct ipmi_lan_addr *lan_addr,
1270 long msgid,
1271 unsigned char ipmb_seq,
1272 unsigned char source_lun)
1273{
1274 /* Format the IPMB header data. */
1275 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1276 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1277 smi_msg->data[2] = lan_addr->channel;
1278 smi_msg->data[3] = lan_addr->session_handle;
1279 smi_msg->data[4] = lan_addr->remote_SWID;
1280 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1281 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1282 smi_msg->data[7] = lan_addr->local_SWID;
1283 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1284 smi_msg->data[9] = msg->cmd;
1285
1286 /* Now tack on the data to the message. */
1287 if (msg->data_len > 0)
1288 memcpy(&(smi_msg->data[10]), msg->data,
1289 msg->data_len);
1290 smi_msg->data_size = msg->data_len + 10;
1291
1292 /* Now calculate the checksum and tack it on. */
1293 smi_msg->data[smi_msg->data_size]
1294 = ipmb_checksum(&(smi_msg->data[7]),
1295 smi_msg->data_size-7);
1296
1297 /* Add on the checksum size and the offset from the
1298 broadcast. */
1299 smi_msg->data_size += 1;
1300
1301 smi_msg->msgid = msgid;
1302}
1303
1304/* Separate from ipmi_request so that the user does not have to be
1305 supplied in certain circumstances (mainly at panic time). If
1306 messages are supplied, they will be freed, even if an error
1307 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001308static int i_ipmi_request(ipmi_user_t user,
1309 ipmi_smi_t intf,
1310 struct ipmi_addr *addr,
1311 long msgid,
1312 struct kernel_ipmi_msg *msg,
1313 void *user_msg_data,
1314 void *supplied_smi,
1315 struct ipmi_recv_msg *supplied_recv,
1316 int priority,
1317 unsigned char source_address,
1318 unsigned char source_lun,
1319 int retries,
1320 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321{
Corey Minyardb2c03942006-12-06 20:41:00 -08001322 int rv = 0;
1323 struct ipmi_smi_msg *smi_msg;
1324 struct ipmi_recv_msg *recv_msg;
1325 unsigned long flags;
1326 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
1328
1329 if (supplied_recv) {
1330 recv_msg = supplied_recv;
1331 } else {
1332 recv_msg = ipmi_alloc_recv_msg();
1333 if (recv_msg == NULL) {
1334 return -ENOMEM;
1335 }
1336 }
1337 recv_msg->user_msg_data = user_msg_data;
1338
1339 if (supplied_smi) {
1340 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1341 } else {
1342 smi_msg = ipmi_alloc_smi_msg();
1343 if (smi_msg == NULL) {
1344 ipmi_free_recv_msg(recv_msg);
1345 return -ENOMEM;
1346 }
1347 }
1348
Corey Minyardb2c03942006-12-06 20:41:00 -08001349 rcu_read_lock();
1350 handlers = intf->handlers;
1351 if (!handlers) {
1352 rv = -ENODEV;
1353 goto out_err;
1354 }
1355
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001357 if (user)
1358 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 recv_msg->msgid = msgid;
1360 /* Store the message to send in the receive message so timeout
1361 responses can get the proper response data. */
1362 recv_msg->msg = *msg;
1363
1364 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1365 struct ipmi_system_interface_addr *smi_addr;
1366
1367 if (msg->netfn & 1) {
1368 /* Responses are not allowed to the SMI. */
1369 rv = -EINVAL;
1370 goto out_err;
1371 }
1372
1373 smi_addr = (struct ipmi_system_interface_addr *) addr;
1374 if (smi_addr->lun > 3) {
1375 spin_lock_irqsave(&intf->counter_lock, flags);
1376 intf->sent_invalid_commands++;
1377 spin_unlock_irqrestore(&intf->counter_lock, flags);
1378 rv = -EINVAL;
1379 goto out_err;
1380 }
1381
1382 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1383
1384 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1385 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1386 || (msg->cmd == IPMI_GET_MSG_CMD)
1387 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1388 {
1389 /* We don't let the user do these, since we manage
1390 the sequence numbers. */
1391 spin_lock_irqsave(&intf->counter_lock, flags);
1392 intf->sent_invalid_commands++;
1393 spin_unlock_irqrestore(&intf->counter_lock, flags);
1394 rv = -EINVAL;
1395 goto out_err;
1396 }
1397
Corey Minyardb9675132006-12-06 20:41:02 -08001398 if (((msg->netfn == IPMI_NETFN_APP_REQUEST)
1399 && ((msg->cmd == IPMI_COLD_RESET_CMD)
1400 || (msg->cmd == IPMI_WARM_RESET_CMD)))
1401 || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST))
1402 {
1403 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1404 intf->auto_maintenance_timeout
1405 = IPMI_MAINTENANCE_MODE_TIMEOUT;
1406 if (!intf->maintenance_mode
1407 && !intf->maintenance_mode_enable)
1408 {
1409 intf->maintenance_mode_enable = 1;
1410 maintenance_mode_update(intf);
1411 }
1412 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
1413 flags);
1414 }
1415
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1417 spin_lock_irqsave(&intf->counter_lock, flags);
1418 intf->sent_invalid_commands++;
1419 spin_unlock_irqrestore(&intf->counter_lock, flags);
1420 rv = -EMSGSIZE;
1421 goto out_err;
1422 }
1423
1424 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1425 smi_msg->data[1] = msg->cmd;
1426 smi_msg->msgid = msgid;
1427 smi_msg->user_data = recv_msg;
1428 if (msg->data_len > 0)
1429 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1430 smi_msg->data_size = msg->data_len + 2;
1431 spin_lock_irqsave(&intf->counter_lock, flags);
1432 intf->sent_local_commands++;
1433 spin_unlock_irqrestore(&intf->counter_lock, flags);
1434 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1435 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1436 {
1437 struct ipmi_ipmb_addr *ipmb_addr;
1438 unsigned char ipmb_seq;
1439 long seqid;
1440 int broadcast = 0;
1441
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001442 if (addr->channel >= IPMI_MAX_CHANNELS) {
1443 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 intf->sent_invalid_commands++;
1445 spin_unlock_irqrestore(&intf->counter_lock, flags);
1446 rv = -EINVAL;
1447 goto out_err;
1448 }
1449
1450 if (intf->channels[addr->channel].medium
1451 != IPMI_CHANNEL_MEDIUM_IPMB)
1452 {
1453 spin_lock_irqsave(&intf->counter_lock, flags);
1454 intf->sent_invalid_commands++;
1455 spin_unlock_irqrestore(&intf->counter_lock, flags);
1456 rv = -EINVAL;
1457 goto out_err;
1458 }
1459
1460 if (retries < 0) {
1461 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1462 retries = 0; /* Don't retry broadcasts. */
1463 else
1464 retries = 4;
1465 }
1466 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1467 /* Broadcasts add a zero at the beginning of the
1468 message, but otherwise is the same as an IPMB
1469 address. */
1470 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1471 broadcast = 1;
1472 }
1473
1474
1475 /* Default to 1 second retries. */
1476 if (retry_time_ms == 0)
1477 retry_time_ms = 1000;
1478
1479 /* 9 for the header and 1 for the checksum, plus
1480 possibly one for the broadcast. */
1481 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1482 spin_lock_irqsave(&intf->counter_lock, flags);
1483 intf->sent_invalid_commands++;
1484 spin_unlock_irqrestore(&intf->counter_lock, flags);
1485 rv = -EMSGSIZE;
1486 goto out_err;
1487 }
1488
1489 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1490 if (ipmb_addr->lun > 3) {
1491 spin_lock_irqsave(&intf->counter_lock, flags);
1492 intf->sent_invalid_commands++;
1493 spin_unlock_irqrestore(&intf->counter_lock, flags);
1494 rv = -EINVAL;
1495 goto out_err;
1496 }
1497
1498 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1499
1500 if (recv_msg->msg.netfn & 0x1) {
1501 /* It's a response, so use the user's sequence
1502 from msgid. */
1503 spin_lock_irqsave(&intf->counter_lock, flags);
1504 intf->sent_ipmb_responses++;
1505 spin_unlock_irqrestore(&intf->counter_lock, flags);
1506 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1507 msgid, broadcast,
1508 source_address, source_lun);
1509
1510 /* Save the receive message so we can use it
1511 to deliver the response. */
1512 smi_msg->user_data = recv_msg;
1513 } else {
1514 /* It's a command, so get a sequence for it. */
1515
1516 spin_lock_irqsave(&(intf->seq_lock), flags);
1517
1518 spin_lock(&intf->counter_lock);
1519 intf->sent_ipmb_commands++;
1520 spin_unlock(&intf->counter_lock);
1521
1522 /* Create a sequence number with a 1 second
1523 timeout and 4 retries. */
1524 rv = intf_next_seq(intf,
1525 recv_msg,
1526 retry_time_ms,
1527 retries,
1528 broadcast,
1529 &ipmb_seq,
1530 &seqid);
1531 if (rv) {
1532 /* We have used up all the sequence numbers,
1533 probably, so abort. */
1534 spin_unlock_irqrestore(&(intf->seq_lock),
1535 flags);
1536 goto out_err;
1537 }
1538
1539 /* Store the sequence number in the message,
1540 so that when the send message response
1541 comes back we can start the timer. */
1542 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1543 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1544 ipmb_seq, broadcast,
1545 source_address, source_lun);
1546
1547 /* Copy the message into the recv message data, so we
1548 can retransmit it later if necessary. */
1549 memcpy(recv_msg->msg_data, smi_msg->data,
1550 smi_msg->data_size);
1551 recv_msg->msg.data = recv_msg->msg_data;
1552 recv_msg->msg.data_len = smi_msg->data_size;
1553
1554 /* We don't unlock until here, because we need
1555 to copy the completed message into the
1556 recv_msg before we release the lock.
1557 Otherwise, race conditions may bite us. I
1558 know that's pretty paranoid, but I prefer
1559 to be correct. */
1560 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1561 }
1562 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1563 struct ipmi_lan_addr *lan_addr;
1564 unsigned char ipmb_seq;
1565 long seqid;
1566
Jayachandran C12fc1d72006-02-03 03:04:51 -08001567 if (addr->channel >= IPMI_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 spin_lock_irqsave(&intf->counter_lock, flags);
1569 intf->sent_invalid_commands++;
1570 spin_unlock_irqrestore(&intf->counter_lock, flags);
1571 rv = -EINVAL;
1572 goto out_err;
1573 }
1574
1575 if ((intf->channels[addr->channel].medium
1576 != IPMI_CHANNEL_MEDIUM_8023LAN)
1577 && (intf->channels[addr->channel].medium
1578 != IPMI_CHANNEL_MEDIUM_ASYNC))
1579 {
1580 spin_lock_irqsave(&intf->counter_lock, flags);
1581 intf->sent_invalid_commands++;
1582 spin_unlock_irqrestore(&intf->counter_lock, flags);
1583 rv = -EINVAL;
1584 goto out_err;
1585 }
1586
1587 retries = 4;
1588
1589 /* Default to 1 second retries. */
1590 if (retry_time_ms == 0)
1591 retry_time_ms = 1000;
1592
1593 /* 11 for the header and 1 for the checksum. */
1594 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1595 spin_lock_irqsave(&intf->counter_lock, flags);
1596 intf->sent_invalid_commands++;
1597 spin_unlock_irqrestore(&intf->counter_lock, flags);
1598 rv = -EMSGSIZE;
1599 goto out_err;
1600 }
1601
1602 lan_addr = (struct ipmi_lan_addr *) addr;
1603 if (lan_addr->lun > 3) {
1604 spin_lock_irqsave(&intf->counter_lock, flags);
1605 intf->sent_invalid_commands++;
1606 spin_unlock_irqrestore(&intf->counter_lock, flags);
1607 rv = -EINVAL;
1608 goto out_err;
1609 }
1610
1611 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1612
1613 if (recv_msg->msg.netfn & 0x1) {
1614 /* It's a response, so use the user's sequence
1615 from msgid. */
1616 spin_lock_irqsave(&intf->counter_lock, flags);
1617 intf->sent_lan_responses++;
1618 spin_unlock_irqrestore(&intf->counter_lock, flags);
1619 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1620 msgid, source_lun);
1621
1622 /* Save the receive message so we can use it
1623 to deliver the response. */
1624 smi_msg->user_data = recv_msg;
1625 } else {
1626 /* It's a command, so get a sequence for it. */
1627
1628 spin_lock_irqsave(&(intf->seq_lock), flags);
1629
1630 spin_lock(&intf->counter_lock);
1631 intf->sent_lan_commands++;
1632 spin_unlock(&intf->counter_lock);
1633
1634 /* Create a sequence number with a 1 second
1635 timeout and 4 retries. */
1636 rv = intf_next_seq(intf,
1637 recv_msg,
1638 retry_time_ms,
1639 retries,
1640 0,
1641 &ipmb_seq,
1642 &seqid);
1643 if (rv) {
1644 /* We have used up all the sequence numbers,
1645 probably, so abort. */
1646 spin_unlock_irqrestore(&(intf->seq_lock),
1647 flags);
1648 goto out_err;
1649 }
1650
1651 /* Store the sequence number in the message,
1652 so that when the send message response
1653 comes back we can start the timer. */
1654 format_lan_msg(smi_msg, msg, lan_addr,
1655 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1656 ipmb_seq, source_lun);
1657
1658 /* Copy the message into the recv message data, so we
1659 can retransmit it later if necessary. */
1660 memcpy(recv_msg->msg_data, smi_msg->data,
1661 smi_msg->data_size);
1662 recv_msg->msg.data = recv_msg->msg_data;
1663 recv_msg->msg.data_len = smi_msg->data_size;
1664
1665 /* We don't unlock until here, because we need
1666 to copy the completed message into the
1667 recv_msg before we release the lock.
1668 Otherwise, race conditions may bite us. I
1669 know that's pretty paranoid, but I prefer
1670 to be correct. */
1671 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1672 }
1673 } else {
1674 /* Unknown address type. */
1675 spin_lock_irqsave(&intf->counter_lock, flags);
1676 intf->sent_invalid_commands++;
1677 spin_unlock_irqrestore(&intf->counter_lock, flags);
1678 rv = -EINVAL;
1679 goto out_err;
1680 }
1681
1682#ifdef DEBUG_MSGING
1683 {
1684 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001685 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 printk(" %2.2x", smi_msg->data[m]);
1687 printk("\n");
1688 }
1689#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08001690
1691 handlers->sender(intf->send_info, smi_msg, priority);
1692 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
1694 return 0;
1695
1696 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -08001697 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 ipmi_free_smi_msg(smi_msg);
1699 ipmi_free_recv_msg(recv_msg);
1700 return rv;
1701}
1702
Corey Minyardc14979b2005-09-06 15:18:38 -07001703static int check_addr(ipmi_smi_t intf,
1704 struct ipmi_addr *addr,
1705 unsigned char *saddr,
1706 unsigned char *lun)
1707{
1708 if (addr->channel >= IPMI_MAX_CHANNELS)
1709 return -EINVAL;
1710 *lun = intf->channels[addr->channel].lun;
1711 *saddr = intf->channels[addr->channel].address;
1712 return 0;
1713}
1714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715int ipmi_request_settime(ipmi_user_t user,
1716 struct ipmi_addr *addr,
1717 long msgid,
1718 struct kernel_ipmi_msg *msg,
1719 void *user_msg_data,
1720 int priority,
1721 int retries,
1722 unsigned int retry_time_ms)
1723{
Corey Minyardc14979b2005-09-06 15:18:38 -07001724 unsigned char saddr, lun;
1725 int rv;
1726
Corey Minyard8a3628d2006-03-31 02:30:40 -08001727 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001728 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001729 rv = check_addr(user->intf, addr, &saddr, &lun);
1730 if (rv)
1731 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 return i_ipmi_request(user,
1733 user->intf,
1734 addr,
1735 msgid,
1736 msg,
1737 user_msg_data,
1738 NULL, NULL,
1739 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001740 saddr,
1741 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 retries,
1743 retry_time_ms);
1744}
1745
1746int ipmi_request_supply_msgs(ipmi_user_t user,
1747 struct ipmi_addr *addr,
1748 long msgid,
1749 struct kernel_ipmi_msg *msg,
1750 void *user_msg_data,
1751 void *supplied_smi,
1752 struct ipmi_recv_msg *supplied_recv,
1753 int priority)
1754{
Corey Minyardc14979b2005-09-06 15:18:38 -07001755 unsigned char saddr, lun;
1756 int rv;
1757
Corey Minyard8a3628d2006-03-31 02:30:40 -08001758 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001759 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001760 rv = check_addr(user->intf, addr, &saddr, &lun);
1761 if (rv)
1762 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 return i_ipmi_request(user,
1764 user->intf,
1765 addr,
1766 msgid,
1767 msg,
1768 user_msg_data,
1769 supplied_smi,
1770 supplied_recv,
1771 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001772 saddr,
1773 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 -1, 0);
1775}
1776
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001777#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778static int ipmb_file_read_proc(char *page, char **start, off_t off,
1779 int count, int *eof, void *data)
1780{
1781 char *out = (char *) page;
1782 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001783 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001784 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
Corey Minyarde8b33612005-09-06 15:18:45 -07001786 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001787 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1788 out[rv-1] = '\n'; /* Replace the final space with a newline */
1789 out[rv] = '\0';
1790 rv++;
1791 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792}
1793
1794static int version_file_read_proc(char *page, char **start, off_t off,
1795 int count, int *eof, void *data)
1796{
1797 char *out = (char *) page;
1798 ipmi_smi_t intf = data;
1799
1800 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001801 ipmi_version_major(&intf->bmc->id),
1802 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803}
1804
1805static int stat_file_read_proc(char *page, char **start, off_t off,
1806 int count, int *eof, void *data)
1807{
1808 char *out = (char *) page;
1809 ipmi_smi_t intf = data;
1810
1811 out += sprintf(out, "sent_invalid_commands: %d\n",
1812 intf->sent_invalid_commands);
1813 out += sprintf(out, "sent_local_commands: %d\n",
1814 intf->sent_local_commands);
1815 out += sprintf(out, "handled_local_responses: %d\n",
1816 intf->handled_local_responses);
1817 out += sprintf(out, "unhandled_local_responses: %d\n",
1818 intf->unhandled_local_responses);
1819 out += sprintf(out, "sent_ipmb_commands: %d\n",
1820 intf->sent_ipmb_commands);
1821 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1822 intf->sent_ipmb_command_errs);
1823 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1824 intf->retransmitted_ipmb_commands);
1825 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1826 intf->timed_out_ipmb_commands);
1827 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1828 intf->timed_out_ipmb_broadcasts);
1829 out += sprintf(out, "sent_ipmb_responses: %d\n",
1830 intf->sent_ipmb_responses);
1831 out += sprintf(out, "handled_ipmb_responses: %d\n",
1832 intf->handled_ipmb_responses);
1833 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1834 intf->invalid_ipmb_responses);
1835 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1836 intf->unhandled_ipmb_responses);
1837 out += sprintf(out, "sent_lan_commands: %d\n",
1838 intf->sent_lan_commands);
1839 out += sprintf(out, "sent_lan_command_errs: %d\n",
1840 intf->sent_lan_command_errs);
1841 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1842 intf->retransmitted_lan_commands);
1843 out += sprintf(out, "timed_out_lan_commands: %d\n",
1844 intf->timed_out_lan_commands);
1845 out += sprintf(out, "sent_lan_responses: %d\n",
1846 intf->sent_lan_responses);
1847 out += sprintf(out, "handled_lan_responses: %d\n",
1848 intf->handled_lan_responses);
1849 out += sprintf(out, "invalid_lan_responses: %d\n",
1850 intf->invalid_lan_responses);
1851 out += sprintf(out, "unhandled_lan_responses: %d\n",
1852 intf->unhandled_lan_responses);
1853 out += sprintf(out, "handled_commands: %d\n",
1854 intf->handled_commands);
1855 out += sprintf(out, "invalid_commands: %d\n",
1856 intf->invalid_commands);
1857 out += sprintf(out, "unhandled_commands: %d\n",
1858 intf->unhandled_commands);
1859 out += sprintf(out, "invalid_events: %d\n",
1860 intf->invalid_events);
1861 out += sprintf(out, "events: %d\n",
1862 intf->events);
1863
1864 return (out - ((char *) page));
1865}
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001866#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
1868int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1869 read_proc_t *read_proc, write_proc_t *write_proc,
1870 void *data, struct module *owner)
1871{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001873#ifdef CONFIG_PROC_FS
1874 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 struct ipmi_proc_entry *entry;
1876
1877 /* Create a list element. */
1878 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1879 if (!entry)
1880 return -ENOMEM;
1881 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1882 if (!entry->name) {
1883 kfree(entry);
1884 return -ENOMEM;
1885 }
1886 strcpy(entry->name, name);
1887
1888 file = create_proc_entry(name, 0, smi->proc_dir);
1889 if (!file) {
1890 kfree(entry->name);
1891 kfree(entry);
1892 rv = -ENOMEM;
1893 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 file->data = data;
1895 file->read_proc = read_proc;
1896 file->write_proc = write_proc;
1897 file->owner = owner;
1898
Corey Minyardac019152007-10-18 03:07:11 -07001899 mutex_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 /* Stick it on the list. */
1901 entry->next = smi->proc_entries;
1902 smi->proc_entries = entry;
Corey Minyardac019152007-10-18 03:07:11 -07001903 mutex_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 }
Corey Minyard3b625942005-06-23 22:01:42 -07001905#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906
1907 return rv;
1908}
1909
1910static int add_proc_entries(ipmi_smi_t smi, int num)
1911{
1912 int rv = 0;
1913
Corey Minyard3b625942005-06-23 22:01:42 -07001914#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 sprintf(smi->proc_dir_name, "%d", num);
1916 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1917 if (!smi->proc_dir)
1918 rv = -ENOMEM;
1919 else {
1920 smi->proc_dir->owner = THIS_MODULE;
1921 }
1922
1923 if (rv == 0)
1924 rv = ipmi_smi_add_proc_entry(smi, "stats",
1925 stat_file_read_proc, NULL,
1926 smi, THIS_MODULE);
1927
1928 if (rv == 0)
1929 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1930 ipmb_file_read_proc, NULL,
1931 smi, THIS_MODULE);
1932
1933 if (rv == 0)
1934 rv = ipmi_smi_add_proc_entry(smi, "version",
1935 version_file_read_proc, NULL,
1936 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001937#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938
1939 return rv;
1940}
1941
1942static void remove_proc_entries(ipmi_smi_t smi)
1943{
Corey Minyard3b625942005-06-23 22:01:42 -07001944#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 struct ipmi_proc_entry *entry;
1946
Corey Minyardac019152007-10-18 03:07:11 -07001947 mutex_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 while (smi->proc_entries) {
1949 entry = smi->proc_entries;
1950 smi->proc_entries = entry->next;
1951
1952 remove_proc_entry(entry->name, smi->proc_dir);
1953 kfree(entry->name);
1954 kfree(entry);
1955 }
Corey Minyardac019152007-10-18 03:07:11 -07001956 mutex_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001958#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959}
1960
Corey Minyard50c812b2006-03-26 01:37:21 -08001961static int __find_bmc_guid(struct device *dev, void *data)
1962{
1963 unsigned char *id = data;
1964 struct bmc_device *bmc = dev_get_drvdata(dev);
1965 return memcmp(bmc->guid, id, 16) == 0;
1966}
1967
1968static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1969 unsigned char *guid)
1970{
1971 struct device *dev;
1972
1973 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1974 if (dev)
1975 return dev_get_drvdata(dev);
1976 else
1977 return NULL;
1978}
1979
1980struct prod_dev_id {
1981 unsigned int product_id;
1982 unsigned char device_id;
1983};
1984
1985static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1986{
1987 struct prod_dev_id *id = data;
1988 struct bmc_device *bmc = dev_get_drvdata(dev);
1989
1990 return (bmc->id.product_id == id->product_id
Corey Minyard50c812b2006-03-26 01:37:21 -08001991 && bmc->id.device_id == id->device_id);
1992}
1993
1994static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1995 struct device_driver *drv,
Corey Minyardf0b55da2006-12-06 20:40:54 -08001996 unsigned int product_id, unsigned char device_id)
Corey Minyard50c812b2006-03-26 01:37:21 -08001997{
1998 struct prod_dev_id id = {
1999 .product_id = product_id,
2000 .device_id = device_id,
2001 };
2002 struct device *dev;
2003
2004 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
2005 if (dev)
2006 return dev_get_drvdata(dev);
2007 else
2008 return NULL;
2009}
2010
2011static ssize_t device_id_show(struct device *dev,
2012 struct device_attribute *attr,
2013 char *buf)
2014{
2015 struct bmc_device *bmc = dev_get_drvdata(dev);
2016
2017 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
2018}
2019
2020static ssize_t provides_dev_sdrs_show(struct device *dev,
2021 struct device_attribute *attr,
2022 char *buf)
2023{
2024 struct bmc_device *bmc = dev_get_drvdata(dev);
2025
2026 return snprintf(buf, 10, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002027 (bmc->id.device_revision & 0x80) >> 7);
Corey Minyard50c812b2006-03-26 01:37:21 -08002028}
2029
2030static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
2031 char *buf)
2032{
2033 struct bmc_device *bmc = dev_get_drvdata(dev);
2034
2035 return snprintf(buf, 20, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002036 bmc->id.device_revision & 0x0F);
Corey Minyard50c812b2006-03-26 01:37:21 -08002037}
2038
2039static ssize_t firmware_rev_show(struct device *dev,
2040 struct device_attribute *attr,
2041 char *buf)
2042{
2043 struct bmc_device *bmc = dev_get_drvdata(dev);
2044
2045 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
2046 bmc->id.firmware_revision_2);
2047}
2048
2049static ssize_t ipmi_version_show(struct device *dev,
2050 struct device_attribute *attr,
2051 char *buf)
2052{
2053 struct bmc_device *bmc = dev_get_drvdata(dev);
2054
2055 return snprintf(buf, 20, "%u.%u\n",
2056 ipmi_version_major(&bmc->id),
2057 ipmi_version_minor(&bmc->id));
2058}
2059
2060static ssize_t add_dev_support_show(struct device *dev,
2061 struct device_attribute *attr,
2062 char *buf)
2063{
2064 struct bmc_device *bmc = dev_get_drvdata(dev);
2065
2066 return snprintf(buf, 10, "0x%02x\n",
2067 bmc->id.additional_device_support);
2068}
2069
2070static ssize_t manufacturer_id_show(struct device *dev,
2071 struct device_attribute *attr,
2072 char *buf)
2073{
2074 struct bmc_device *bmc = dev_get_drvdata(dev);
2075
2076 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
2077}
2078
2079static ssize_t product_id_show(struct device *dev,
2080 struct device_attribute *attr,
2081 char *buf)
2082{
2083 struct bmc_device *bmc = dev_get_drvdata(dev);
2084
2085 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
2086}
2087
2088static ssize_t aux_firmware_rev_show(struct device *dev,
2089 struct device_attribute *attr,
2090 char *buf)
2091{
2092 struct bmc_device *bmc = dev_get_drvdata(dev);
2093
2094 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
2095 bmc->id.aux_firmware_revision[3],
2096 bmc->id.aux_firmware_revision[2],
2097 bmc->id.aux_firmware_revision[1],
2098 bmc->id.aux_firmware_revision[0]);
2099}
2100
2101static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
2102 char *buf)
2103{
2104 struct bmc_device *bmc = dev_get_drvdata(dev);
2105
2106 return snprintf(buf, 100, "%Lx%Lx\n",
2107 (long long) bmc->guid[0],
2108 (long long) bmc->guid[8]);
2109}
2110
Jeff Garzik5e593932006-10-11 01:22:21 -07002111static void remove_files(struct bmc_device *bmc)
Corey Minyard50c812b2006-03-26 01:37:21 -08002112{
Corey Minyardf0b55da2006-12-06 20:40:54 -08002113 if (!bmc->dev)
2114 return;
2115
Corey Minyard50c812b2006-03-26 01:37:21 -08002116 device_remove_file(&bmc->dev->dev,
2117 &bmc->device_id_attr);
2118 device_remove_file(&bmc->dev->dev,
2119 &bmc->provides_dev_sdrs_attr);
2120 device_remove_file(&bmc->dev->dev,
2121 &bmc->revision_attr);
2122 device_remove_file(&bmc->dev->dev,
2123 &bmc->firmware_rev_attr);
2124 device_remove_file(&bmc->dev->dev,
2125 &bmc->version_attr);
2126 device_remove_file(&bmc->dev->dev,
2127 &bmc->add_dev_support_attr);
2128 device_remove_file(&bmc->dev->dev,
2129 &bmc->manufacturer_id_attr);
2130 device_remove_file(&bmc->dev->dev,
2131 &bmc->product_id_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002132
Corey Minyard50c812b2006-03-26 01:37:21 -08002133 if (bmc->id.aux_firmware_revision_set)
2134 device_remove_file(&bmc->dev->dev,
2135 &bmc->aux_firmware_rev_attr);
2136 if (bmc->guid_set)
2137 device_remove_file(&bmc->dev->dev,
2138 &bmc->guid_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002139}
2140
2141static void
2142cleanup_bmc_device(struct kref *ref)
2143{
2144 struct bmc_device *bmc;
2145
2146 bmc = container_of(ref, struct bmc_device, refcount);
2147
2148 remove_files(bmc);
Corey Minyard1d5636c2006-12-10 02:19:08 -08002149 platform_device_unregister(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002150 kfree(bmc);
2151}
2152
2153static void ipmi_bmc_unregister(ipmi_smi_t intf)
2154{
2155 struct bmc_device *bmc = intf->bmc;
2156
Corey Minyard759643b2006-12-06 20:40:59 -08002157 if (intf->sysfs_name) {
2158 sysfs_remove_link(&intf->si_dev->kobj, intf->sysfs_name);
2159 kfree(intf->sysfs_name);
2160 intf->sysfs_name = NULL;
2161 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002162 if (intf->my_dev_name) {
2163 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
2164 kfree(intf->my_dev_name);
2165 intf->my_dev_name = NULL;
2166 }
2167
2168 mutex_lock(&ipmidriver_mutex);
2169 kref_put(&bmc->refcount, cleanup_bmc_device);
Corey Minyardf0b55da2006-12-06 20:40:54 -08002170 intf->bmc = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002171 mutex_unlock(&ipmidriver_mutex);
2172}
2173
Jeff Garzik5e593932006-10-11 01:22:21 -07002174static int create_files(struct bmc_device *bmc)
2175{
2176 int err;
2177
Corey Minyardf0b55da2006-12-06 20:40:54 -08002178 bmc->device_id_attr.attr.name = "device_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002179 bmc->device_id_attr.attr.mode = S_IRUGO;
2180 bmc->device_id_attr.show = device_id_show;
2181
2182 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002183 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2184 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2185
2186 bmc->revision_attr.attr.name = "revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002187 bmc->revision_attr.attr.mode = S_IRUGO;
2188 bmc->revision_attr.show = revision_show;
2189
2190 bmc->firmware_rev_attr.attr.name = "firmware_revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002191 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2192 bmc->firmware_rev_attr.show = firmware_rev_show;
2193
2194 bmc->version_attr.attr.name = "ipmi_version";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002195 bmc->version_attr.attr.mode = S_IRUGO;
2196 bmc->version_attr.show = ipmi_version_show;
2197
2198 bmc->add_dev_support_attr.attr.name = "additional_device_support";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002199 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2200 bmc->add_dev_support_attr.show = add_dev_support_show;
2201
2202 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002203 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2204 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2205
2206 bmc->product_id_attr.attr.name = "product_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002207 bmc->product_id_attr.attr.mode = S_IRUGO;
2208 bmc->product_id_attr.show = product_id_show;
2209
2210 bmc->guid_attr.attr.name = "guid";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002211 bmc->guid_attr.attr.mode = S_IRUGO;
2212 bmc->guid_attr.show = guid_show;
2213
2214 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002215 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2216 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2217
Jeff Garzik5e593932006-10-11 01:22:21 -07002218 err = device_create_file(&bmc->dev->dev,
2219 &bmc->device_id_attr);
2220 if (err) goto out;
2221 err = device_create_file(&bmc->dev->dev,
2222 &bmc->provides_dev_sdrs_attr);
2223 if (err) goto out_devid;
2224 err = device_create_file(&bmc->dev->dev,
2225 &bmc->revision_attr);
2226 if (err) goto out_sdrs;
2227 err = device_create_file(&bmc->dev->dev,
2228 &bmc->firmware_rev_attr);
2229 if (err) goto out_rev;
2230 err = device_create_file(&bmc->dev->dev,
2231 &bmc->version_attr);
2232 if (err) goto out_firm;
2233 err = device_create_file(&bmc->dev->dev,
2234 &bmc->add_dev_support_attr);
2235 if (err) goto out_version;
2236 err = device_create_file(&bmc->dev->dev,
2237 &bmc->manufacturer_id_attr);
2238 if (err) goto out_add_dev;
2239 err = device_create_file(&bmc->dev->dev,
2240 &bmc->product_id_attr);
2241 if (err) goto out_manu;
2242 if (bmc->id.aux_firmware_revision_set) {
2243 err = device_create_file(&bmc->dev->dev,
2244 &bmc->aux_firmware_rev_attr);
2245 if (err) goto out_prod_id;
2246 }
2247 if (bmc->guid_set) {
2248 err = device_create_file(&bmc->dev->dev,
2249 &bmc->guid_attr);
2250 if (err) goto out_aux_firm;
2251 }
2252
2253 return 0;
2254
2255out_aux_firm:
2256 if (bmc->id.aux_firmware_revision_set)
2257 device_remove_file(&bmc->dev->dev,
2258 &bmc->aux_firmware_rev_attr);
2259out_prod_id:
2260 device_remove_file(&bmc->dev->dev,
2261 &bmc->product_id_attr);
2262out_manu:
2263 device_remove_file(&bmc->dev->dev,
2264 &bmc->manufacturer_id_attr);
2265out_add_dev:
2266 device_remove_file(&bmc->dev->dev,
2267 &bmc->add_dev_support_attr);
2268out_version:
2269 device_remove_file(&bmc->dev->dev,
2270 &bmc->version_attr);
2271out_firm:
2272 device_remove_file(&bmc->dev->dev,
2273 &bmc->firmware_rev_attr);
2274out_rev:
2275 device_remove_file(&bmc->dev->dev,
2276 &bmc->revision_attr);
2277out_sdrs:
2278 device_remove_file(&bmc->dev->dev,
2279 &bmc->provides_dev_sdrs_attr);
2280out_devid:
2281 device_remove_file(&bmc->dev->dev,
2282 &bmc->device_id_attr);
2283out:
2284 return err;
2285}
2286
Corey Minyard759643b2006-12-06 20:40:59 -08002287static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
2288 const char *sysfs_name)
Corey Minyard50c812b2006-03-26 01:37:21 -08002289{
2290 int rv;
2291 struct bmc_device *bmc = intf->bmc;
2292 struct bmc_device *old_bmc;
2293 int size;
2294 char dummy[1];
2295
2296 mutex_lock(&ipmidriver_mutex);
2297
2298 /*
2299 * Try to find if there is an bmc_device struct
2300 * representing the interfaced BMC already
2301 */
2302 if (bmc->guid_set)
2303 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
2304 else
2305 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
2306 bmc->id.product_id,
2307 bmc->id.device_id);
2308
2309 /*
2310 * If there is already an bmc_device, free the new one,
2311 * otherwise register the new BMC device
2312 */
2313 if (old_bmc) {
2314 kfree(bmc);
2315 intf->bmc = old_bmc;
2316 bmc = old_bmc;
2317
2318 kref_get(&bmc->refcount);
2319 mutex_unlock(&ipmidriver_mutex);
2320
2321 printk(KERN_INFO
2322 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
2323 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2324 bmc->id.manufacturer_id,
2325 bmc->id.product_id,
2326 bmc->id.device_id);
2327 } else {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002328 char name[14];
2329 unsigned char orig_dev_id = bmc->id.device_id;
2330 int warn_printed = 0;
2331
2332 snprintf(name, sizeof(name),
2333 "ipmi_bmc.%4.4x", bmc->id.product_id);
2334
2335 while (ipmi_find_bmc_prod_dev_id(&ipmidriver,
2336 bmc->id.product_id,
Corey Minyard1d5636c2006-12-10 02:19:08 -08002337 bmc->id.device_id)) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002338 if (!warn_printed) {
2339 printk(KERN_WARNING PFX
2340 "This machine has two different BMCs"
2341 " with the same product id and device"
2342 " id. This is an error in the"
2343 " firmware, but incrementing the"
2344 " device id to work around the problem."
2345 " Prod ID = 0x%x, Dev ID = 0x%x\n",
2346 bmc->id.product_id, bmc->id.device_id);
2347 warn_printed = 1;
2348 }
2349 bmc->id.device_id++; /* Wraps at 255 */
2350 if (bmc->id.device_id == orig_dev_id) {
2351 printk(KERN_ERR PFX
2352 "Out of device ids!\n");
2353 break;
2354 }
2355 }
2356
2357 bmc->dev = platform_device_alloc(name, bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08002358 if (!bmc->dev) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002359 mutex_unlock(&ipmidriver_mutex);
Corey Minyard50c812b2006-03-26 01:37:21 -08002360 printk(KERN_ERR
2361 "ipmi_msghandler:"
2362 " Unable to allocate platform device\n");
2363 return -ENOMEM;
2364 }
2365 bmc->dev->dev.driver = &ipmidriver;
2366 dev_set_drvdata(&bmc->dev->dev, bmc);
2367 kref_init(&bmc->refcount);
2368
Zhang, Yanminb48f5452006-11-16 01:19:08 -08002369 rv = platform_device_add(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002370 mutex_unlock(&ipmidriver_mutex);
2371 if (rv) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002372 platform_device_put(bmc->dev);
2373 bmc->dev = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002374 printk(KERN_ERR
2375 "ipmi_msghandler:"
2376 " Unable to register bmc device: %d\n",
2377 rv);
2378 /* Don't go to out_err, you can only do that if
2379 the device is registered already. */
2380 return rv;
2381 }
2382
Jeff Garzik5e593932006-10-11 01:22:21 -07002383 rv = create_files(bmc);
2384 if (rv) {
2385 mutex_lock(&ipmidriver_mutex);
2386 platform_device_unregister(bmc->dev);
2387 mutex_unlock(&ipmidriver_mutex);
2388
2389 return rv;
2390 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002391
2392 printk(KERN_INFO
2393 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2394 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2395 bmc->id.manufacturer_id,
2396 bmc->id.product_id,
2397 bmc->id.device_id);
2398 }
2399
2400 /*
2401 * create symlink from system interface device to bmc device
2402 * and back.
2403 */
Corey Minyard759643b2006-12-06 20:40:59 -08002404 intf->sysfs_name = kstrdup(sysfs_name, GFP_KERNEL);
2405 if (!intf->sysfs_name) {
2406 rv = -ENOMEM;
2407 printk(KERN_ERR
2408 "ipmi_msghandler: allocate link to BMC: %d\n",
2409 rv);
2410 goto out_err;
2411 }
2412
Corey Minyard50c812b2006-03-26 01:37:21 -08002413 rv = sysfs_create_link(&intf->si_dev->kobj,
Corey Minyard759643b2006-12-06 20:40:59 -08002414 &bmc->dev->dev.kobj, intf->sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002415 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002416 kfree(intf->sysfs_name);
2417 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002418 printk(KERN_ERR
2419 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2420 rv);
2421 goto out_err;
2422 }
2423
Corey Minyard759643b2006-12-06 20:40:59 -08002424 size = snprintf(dummy, 0, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002425 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2426 if (!intf->my_dev_name) {
Corey Minyard759643b2006-12-06 20:40:59 -08002427 kfree(intf->sysfs_name);
2428 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002429 rv = -ENOMEM;
2430 printk(KERN_ERR
2431 "ipmi_msghandler: allocate link from BMC: %d\n",
2432 rv);
2433 goto out_err;
2434 }
Corey Minyard759643b2006-12-06 20:40:59 -08002435 snprintf(intf->my_dev_name, size+1, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002436
2437 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2438 intf->my_dev_name);
2439 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002440 kfree(intf->sysfs_name);
2441 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002442 kfree(intf->my_dev_name);
2443 intf->my_dev_name = NULL;
2444 printk(KERN_ERR
2445 "ipmi_msghandler:"
2446 " Unable to create symlink to bmc: %d\n",
2447 rv);
2448 goto out_err;
2449 }
2450
2451 return 0;
2452
2453out_err:
2454 ipmi_bmc_unregister(intf);
2455 return rv;
2456}
2457
2458static int
2459send_guid_cmd(ipmi_smi_t intf, int chan)
2460{
2461 struct kernel_ipmi_msg msg;
2462 struct ipmi_system_interface_addr si;
2463
2464 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2465 si.channel = IPMI_BMC_CHANNEL;
2466 si.lun = 0;
2467
2468 msg.netfn = IPMI_NETFN_APP_REQUEST;
2469 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2470 msg.data = NULL;
2471 msg.data_len = 0;
2472 return i_ipmi_request(NULL,
2473 intf,
2474 (struct ipmi_addr *) &si,
2475 0,
2476 &msg,
2477 intf,
2478 NULL,
2479 NULL,
2480 0,
2481 intf->channels[0].address,
2482 intf->channels[0].lun,
2483 -1, 0);
2484}
2485
2486static void
2487guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2488{
2489 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2490 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2491 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2492 /* Not for me */
2493 return;
2494
2495 if (msg->msg.data[0] != 0) {
2496 /* Error from getting the GUID, the BMC doesn't have one. */
2497 intf->bmc->guid_set = 0;
2498 goto out;
2499 }
2500
2501 if (msg->msg.data_len < 17) {
2502 intf->bmc->guid_set = 0;
2503 printk(KERN_WARNING PFX
2504 "guid_handler: The GUID response from the BMC was too"
2505 " short, it was %d but should have been 17. Assuming"
2506 " GUID is not available.\n",
2507 msg->msg.data_len);
2508 goto out;
2509 }
2510
2511 memcpy(intf->bmc->guid, msg->msg.data, 16);
2512 intf->bmc->guid_set = 1;
2513 out:
2514 wake_up(&intf->waitq);
2515}
2516
2517static void
2518get_guid(ipmi_smi_t intf)
2519{
2520 int rv;
2521
2522 intf->bmc->guid_set = 0x2;
2523 intf->null_user_handler = guid_handler;
2524 rv = send_guid_cmd(intf, 0);
2525 if (rv)
2526 /* Send failed, no GUID available. */
2527 intf->bmc->guid_set = 0;
2528 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2529 intf->null_user_handler = NULL;
2530}
2531
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532static int
2533send_channel_info_cmd(ipmi_smi_t intf, int chan)
2534{
2535 struct kernel_ipmi_msg msg;
2536 unsigned char data[1];
2537 struct ipmi_system_interface_addr si;
2538
2539 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2540 si.channel = IPMI_BMC_CHANNEL;
2541 si.lun = 0;
2542
2543 msg.netfn = IPMI_NETFN_APP_REQUEST;
2544 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2545 msg.data = data;
2546 msg.data_len = 1;
2547 data[0] = chan;
2548 return i_ipmi_request(NULL,
2549 intf,
2550 (struct ipmi_addr *) &si,
2551 0,
2552 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002553 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 NULL,
2555 NULL,
2556 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002557 intf->channels[0].address,
2558 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 -1, 0);
2560}
2561
2562static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002563channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564{
2565 int rv = 0;
2566 int chan;
2567
Corey Minyard56a55ec2005-09-06 15:18:42 -07002568 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2569 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2570 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 {
2572 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002573 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 /* Got an error from the channel, just go on. */
2575
Corey Minyard56a55ec2005-09-06 15:18:42 -07002576 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 /* If the MC does not support this
2578 command, that is legal. We just
2579 assume it has one IPMB at channel
2580 zero. */
2581 intf->channels[0].medium
2582 = IPMI_CHANNEL_MEDIUM_IPMB;
2583 intf->channels[0].protocol
2584 = IPMI_CHANNEL_PROTOCOL_IPMB;
2585 rv = -ENOSYS;
2586
2587 intf->curr_channel = IPMI_MAX_CHANNELS;
2588 wake_up(&intf->waitq);
2589 goto out;
2590 }
2591 goto next_channel;
2592 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002593 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 /* Message not big enough, just go on. */
2595 goto next_channel;
2596 }
2597 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002598 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2599 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600
2601 next_channel:
2602 intf->curr_channel++;
2603 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2604 wake_up(&intf->waitq);
2605 else
2606 rv = send_channel_info_cmd(intf, intf->curr_channel);
2607
2608 if (rv) {
2609 /* Got an error somehow, just give up. */
2610 intf->curr_channel = IPMI_MAX_CHANNELS;
2611 wake_up(&intf->waitq);
2612
2613 printk(KERN_WARNING PFX
2614 "Error sending channel information: %d\n",
2615 rv);
2616 }
2617 }
2618 out:
2619 return;
2620}
2621
Corey Minyardfcfa4722007-10-18 03:07:09 -07002622void ipmi_poll_interface(ipmi_user_t user)
2623{
2624 ipmi_smi_t intf = user->intf;
2625
2626 if (intf->handlers->poll)
2627 intf->handlers->poll(intf->send_info);
2628}
2629
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2631 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002632 struct ipmi_device_id *device_id,
2633 struct device *si_dev,
Corey Minyard759643b2006-12-06 20:40:59 -08002634 const char *sysfs_name,
Corey Minyard453823b2006-03-31 02:30:39 -08002635 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636{
2637 int i, j;
2638 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002639 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -08002640 ipmi_smi_t tintf;
Corey Minyardbca03242006-12-06 20:40:57 -08002641 struct list_head *link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 /* Make sure the driver is actually initialized, this handles
2644 problems with initialization order. */
2645 if (!initialized) {
2646 rv = ipmi_init_msghandler();
2647 if (rv)
2648 return rv;
2649 /* The init code doesn't return an error if it was turned
2650 off, but it won't initialize. Check that. */
2651 if (!initialized)
2652 return -ENODEV;
2653 }
2654
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07002655 intf = kzalloc(sizeof(*intf), GFP_KERNEL);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002656 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 return -ENOMEM;
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
Corey Minyardac019152007-10-18 03:07:11 -07002687 mutex_init(&intf->proc_entry_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002688#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++;
Corey Minyard87ebd062008-04-29 01:01:04 -07003270 } else if (!intf->event_msg_printed) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 /* There's too many things in the queue, discard this
3272 message. */
Corey Minyard87ebd062008-04-29 01:01:04 -07003273 printk(KERN_WARNING PFX "Event queue full, discarding"
3274 " incoming events\n");
3275 intf->event_msg_printed = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 }
3277
3278 out:
3279 spin_unlock_irqrestore(&(intf->events_lock), flags);
3280
3281 return rv;
3282}
3283
3284static int handle_bmc_rsp(ipmi_smi_t intf,
3285 struct ipmi_smi_msg *msg)
3286{
3287 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003289 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290
3291 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07003292 if (recv_msg == NULL)
3293 {
3294 printk(KERN_WARNING"IPMI message received with no owner. This\n"
3295 "could be because of a malformed message, or\n"
3296 "because of a hardware error. Contact your\n"
3297 "hardware vender for assistance\n");
3298 return 0;
3299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300
Corey Minyard393d2cc2005-11-07 00:59:54 -08003301 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003303 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07003304 /* The user for the message went away, so give up. */
3305 spin_lock_irqsave(&intf->counter_lock, flags);
3306 intf->unhandled_local_responses++;
3307 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 ipmi_free_recv_msg(recv_msg);
3309 } else {
3310 struct ipmi_system_interface_addr *smi_addr;
3311
3312 spin_lock_irqsave(&intf->counter_lock, flags);
3313 intf->handled_local_responses++;
3314 spin_unlock_irqrestore(&intf->counter_lock, flags);
3315 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3316 recv_msg->msgid = msg->msgid;
3317 smi_addr = ((struct ipmi_system_interface_addr *)
3318 &(recv_msg->addr));
3319 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3320 smi_addr->channel = IPMI_BMC_CHANNEL;
3321 smi_addr->lun = msg->rsp[0] & 3;
3322 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3323 recv_msg->msg.cmd = msg->rsp[1];
3324 memcpy(recv_msg->msg_data,
3325 &(msg->rsp[2]),
3326 msg->rsp_size - 2);
3327 recv_msg->msg.data = recv_msg->msg_data;
3328 recv_msg->msg.data_len = msg->rsp_size - 2;
3329 deliver_response(recv_msg);
3330 }
3331
3332 return 0;
3333}
3334
3335/* Handle a new message. Return 1 if the message should be requeued,
3336 0 if the message should be freed, or -1 if the message should not
3337 be freed or requeued. */
3338static int handle_new_recv_msg(ipmi_smi_t intf,
3339 struct ipmi_smi_msg *msg)
3340{
3341 int requeue;
3342 int chan;
3343
3344#ifdef DEBUG_MSGING
3345 int m;
3346 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07003347 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 printk(" %2.2x", msg->rsp[m]);
3349 printk("\n");
3350#endif
3351 if (msg->rsp_size < 2) {
3352 /* Message is too small to be correct. */
3353 printk(KERN_WARNING PFX "BMC returned to small a message"
3354 " for netfn %x cmd %x, got %d bytes\n",
3355 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3356
3357 /* Generate an error response for the message. */
3358 msg->rsp[0] = msg->data[0] | (1 << 2);
3359 msg->rsp[1] = msg->data[1];
3360 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3361 msg->rsp_size = 3;
3362 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3363 || (msg->rsp[1] != msg->data[1])) /* Command */
3364 {
3365 /* The response is not even marginally correct. */
3366 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3367 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3368 (msg->data[0] >> 2) | 1, msg->data[1],
3369 msg->rsp[0] >> 2, msg->rsp[1]);
3370
3371 /* Generate an error response for the message. */
3372 msg->rsp[0] = msg->data[0] | (1 << 2);
3373 msg->rsp[1] = msg->data[1];
3374 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3375 msg->rsp_size = 3;
3376 }
3377
3378 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3379 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3380 && (msg->user_data != NULL))
3381 {
3382 /* It's a response to a response we sent. For this we
3383 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003384 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385
3386 requeue = 0;
3387 if (msg->rsp_size < 2)
3388 /* Message is too small to be correct. */
3389 goto out;
3390
3391 chan = msg->data[2] & 0x0f;
3392 if (chan >= IPMI_MAX_CHANNELS)
3393 /* Invalid channel number */
3394 goto out;
3395
Corey Minyard393d2cc2005-11-07 00:59:54 -08003396 if (!recv_msg)
3397 goto out;
3398
3399 /* Make sure the user still exists. */
3400 if (!recv_msg->user || !recv_msg->user->valid)
3401 goto out;
3402
3403 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3404 recv_msg->msg.data = recv_msg->msg_data;
3405 recv_msg->msg.data_len = 1;
3406 recv_msg->msg_data[0] = msg->rsp[2];
3407 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3409 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3410 {
3411 /* It's from the receive queue. */
3412 chan = msg->rsp[3] & 0xf;
3413 if (chan >= IPMI_MAX_CHANNELS) {
3414 /* Invalid channel number */
3415 requeue = 0;
3416 goto out;
3417 }
3418
3419 switch (intf->channels[chan].medium) {
3420 case IPMI_CHANNEL_MEDIUM_IPMB:
3421 if (msg->rsp[4] & 0x04) {
3422 /* It's a response, so find the
3423 requesting message and send it up. */
3424 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3425 } else {
3426 /* It's a command to the SMS from some other
3427 entity. Handle that. */
3428 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3429 }
3430 break;
3431
3432 case IPMI_CHANNEL_MEDIUM_8023LAN:
3433 case IPMI_CHANNEL_MEDIUM_ASYNC:
3434 if (msg->rsp[6] & 0x04) {
3435 /* It's a response, so find the
3436 requesting message and send it up. */
3437 requeue = handle_lan_get_msg_rsp(intf, msg);
3438 } else {
3439 /* It's a command to the SMS from some other
3440 entity. Handle that. */
3441 requeue = handle_lan_get_msg_cmd(intf, msg);
3442 }
3443 break;
3444
3445 default:
3446 /* We don't handle the channel type, so just
3447 * free the message. */
3448 requeue = 0;
3449 }
3450
3451 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3452 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3453 {
3454 /* It's an asyncronous event. */
3455 requeue = handle_read_event_rsp(intf, msg);
3456 } else {
3457 /* It's a response from the local BMC. */
3458 requeue = handle_bmc_rsp(intf, msg);
3459 }
3460
3461 out:
3462 return requeue;
3463}
3464
3465/* Handle a new message from the lower layer. */
3466void ipmi_smi_msg_received(ipmi_smi_t intf,
3467 struct ipmi_smi_msg *msg)
3468{
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003469 unsigned long flags = 0; /* keep us warning-free. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 int rv;
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003471 int run_to_completion;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472
3473
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 if ((msg->data_size >= 2)
3475 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3476 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003477 && (msg->user_data == NULL))
3478 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 /* This is the local response to a command send, start
3480 the timer for these. The user_data will not be
3481 NULL if this is a response send, and we will let
3482 response sends just go through. */
3483
3484 /* Check for errors, if we get certain errors (ones
3485 that mean basically we can try again later), we
3486 ignore them and start the timer. Otherwise we
3487 report the error immediately. */
3488 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3489 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
Corey Minyard46d52b02006-11-08 17:44:55 -08003490 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
3491 && (msg->rsp[2] != IPMI_BUS_ERR)
3492 && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 {
3494 int chan = msg->rsp[3] & 0xf;
3495
3496 /* Got an error sending the message, handle it. */
3497 spin_lock_irqsave(&intf->counter_lock, flags);
3498 if (chan >= IPMI_MAX_CHANNELS)
3499 ; /* This shouldn't happen */
3500 else if ((intf->channels[chan].medium
3501 == IPMI_CHANNEL_MEDIUM_8023LAN)
3502 || (intf->channels[chan].medium
3503 == IPMI_CHANNEL_MEDIUM_ASYNC))
3504 intf->sent_lan_command_errs++;
3505 else
3506 intf->sent_ipmb_command_errs++;
3507 spin_unlock_irqrestore(&intf->counter_lock, flags);
3508 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3509 } else {
3510 /* The message was sent, start the timer. */
3511 intf_start_seq_timer(intf, msg->msgid);
3512 }
3513
3514 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003515 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 }
3517
3518 /* To preserve message order, if the list is not empty, we
3519 tack this message onto the end of the list. */
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003520 run_to_completion = intf->run_to_completion;
3521 if (!run_to_completion)
3522 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003523 if (!list_empty(&intf->waiting_msgs)) {
3524 list_add_tail(&msg->link, &intf->waiting_msgs);
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003525 if (!run_to_completion)
3526 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003527 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 }
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003529 if (!run_to_completion)
3530 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531
3532 rv = handle_new_recv_msg(intf, msg);
3533 if (rv > 0) {
3534 /* Could not handle the message now, just add it to a
3535 list to handle later. */
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003536 run_to_completion = intf->run_to_completion;
3537 if (!run_to_completion)
3538 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003539 list_add_tail(&msg->link, &intf->waiting_msgs);
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003540 if (!run_to_completion)
3541 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 } else if (rv == 0) {
3543 ipmi_free_smi_msg(msg);
3544 }
3545
Corey Minyard393d2cc2005-11-07 00:59:54 -08003546 out:
3547 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548}
3549
3550void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3551{
3552 ipmi_user_t user;
3553
Corey Minyard393d2cc2005-11-07 00:59:54 -08003554 rcu_read_lock();
3555 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003556 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 continue;
3558
3559 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3560 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003561 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562}
3563
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564
Corey Minyard882fe012005-05-01 08:59:12 -07003565static struct ipmi_smi_msg *
3566smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3567 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568{
Corey Minyard882fe012005-05-01 08:59:12 -07003569 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 if (!smi_msg)
3571 /* If we can't allocate the message, then just return, we
3572 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003573 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
3575 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3576 smi_msg->data_size = recv_msg->msg.data_len;
3577 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3578
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579#ifdef DEBUG_MSGING
3580 {
3581 int m;
3582 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003583 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 printk(" %2.2x", smi_msg->data[m]);
3585 printk("\n");
3586 }
3587#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003588 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589}
3590
Corey Minyard393d2cc2005-11-07 00:59:54 -08003591static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3592 struct list_head *timeouts, long timeout_period,
3593 int slot, unsigned long *flags)
3594{
Corey Minyardb2c03942006-12-06 20:41:00 -08003595 struct ipmi_recv_msg *msg;
3596 struct ipmi_smi_handlers *handlers;
3597
3598 if (intf->intf_num == -1)
3599 return;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003600
3601 if (!ent->inuse)
3602 return;
3603
3604 ent->timeout -= timeout_period;
3605 if (ent->timeout > 0)
3606 return;
3607
3608 if (ent->retries_left == 0) {
3609 /* The message has used all its retries. */
3610 ent->inuse = 0;
3611 msg = ent->recv_msg;
3612 list_add_tail(&msg->link, timeouts);
3613 spin_lock(&intf->counter_lock);
3614 if (ent->broadcast)
3615 intf->timed_out_ipmb_broadcasts++;
3616 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3617 intf->timed_out_lan_commands++;
3618 else
3619 intf->timed_out_ipmb_commands++;
3620 spin_unlock(&intf->counter_lock);
3621 } else {
3622 struct ipmi_smi_msg *smi_msg;
3623 /* More retries, send again. */
3624
3625 /* Start with the max timer, set to normal
3626 timer after the message is sent. */
3627 ent->timeout = MAX_MSG_TIMEOUT;
3628 ent->retries_left--;
3629 spin_lock(&intf->counter_lock);
3630 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3631 intf->retransmitted_lan_commands++;
3632 else
3633 intf->retransmitted_ipmb_commands++;
3634 spin_unlock(&intf->counter_lock);
3635
3636 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3637 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003638 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003639 return;
3640
3641 spin_unlock_irqrestore(&intf->seq_lock, *flags);
Corey Minyardb2c03942006-12-06 20:41:00 -08003642
Corey Minyard393d2cc2005-11-07 00:59:54 -08003643 /* Send the new message. We send with a zero
3644 * priority. It timed out, I doubt time is
3645 * that critical now, and high priority
3646 * messages are really only for messages to the
3647 * local MC, which don't get resent. */
Corey Minyardb2c03942006-12-06 20:41:00 -08003648 handlers = intf->handlers;
3649 if (handlers)
3650 intf->handlers->sender(intf->send_info,
3651 smi_msg, 0);
3652 else
3653 ipmi_free_smi_msg(smi_msg);
3654
Corey Minyard393d2cc2005-11-07 00:59:54 -08003655 spin_lock_irqsave(&intf->seq_lock, *flags);
3656 }
3657}
3658
3659static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660{
3661 ipmi_smi_t intf;
3662 struct list_head timeouts;
3663 struct ipmi_recv_msg *msg, *msg2;
3664 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3665 unsigned long flags;
Corey Minyardbca03242006-12-06 20:40:57 -08003666 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667
Corey Minyardbca03242006-12-06 20:40:57 -08003668 rcu_read_lock();
3669 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003671 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003672 list_for_each_entry_safe(smi_msg, smi_msg2,
3673 &intf->waiting_msgs, link) {
3674 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 list_del(&smi_msg->link);
3676 ipmi_free_smi_msg(smi_msg);
3677 } else {
3678 /* To preserve message order, quit if we
3679 can't handle a message. */
3680 break;
3681 }
3682 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003683 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684
3685 /* Go through the seq table and find any messages that
3686 have timed out, putting them in the timeouts
3687 list. */
David Barksdale41c57a82007-01-30 14:36:25 -08003688 INIT_LIST_HEAD(&timeouts);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003689 spin_lock_irqsave(&intf->seq_lock, flags);
Corey Minyardbca03242006-12-06 20:40:57 -08003690 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
3691 check_msg_timeout(intf, &(intf->seq_table[i]),
3692 &timeouts, timeout_period, i,
Corey Minyard393d2cc2005-11-07 00:59:54 -08003693 &flags);
3694 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695
Corey Minyard393d2cc2005-11-07 00:59:54 -08003696 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08003697 deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE);
Corey Minyardb9675132006-12-06 20:41:02 -08003698
3699 /*
3700 * Maintenance mode handling. Check the timeout
3701 * optimistically before we claim the lock. It may
3702 * mean a timeout gets missed occasionally, but that
3703 * only means the timeout gets extended by one period
3704 * in that case. No big deal, and it avoids the lock
3705 * most of the time.
3706 */
3707 if (intf->auto_maintenance_timeout > 0) {
3708 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
3709 if (intf->auto_maintenance_timeout > 0) {
3710 intf->auto_maintenance_timeout
3711 -= timeout_period;
3712 if (!intf->maintenance_mode
3713 && (intf->auto_maintenance_timeout <= 0))
3714 {
3715 intf->maintenance_mode_enable = 0;
3716 maintenance_mode_update(intf);
3717 }
3718 }
3719 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
3720 flags);
3721 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 }
Corey Minyardbca03242006-12-06 20:40:57 -08003723 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724}
3725
3726static void ipmi_request_event(void)
3727{
Corey Minyardb2c03942006-12-06 20:41:00 -08003728 ipmi_smi_t intf;
3729 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730
Corey Minyardbca03242006-12-06 20:40:57 -08003731 rcu_read_lock();
Corey Minyardb2c03942006-12-06 20:41:00 -08003732 /* Called from the timer, no need to check if handlers is
3733 * valid. */
3734 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb9675132006-12-06 20:41:02 -08003735 /* No event requests when in maintenance mode. */
3736 if (intf->maintenance_mode_enable)
3737 continue;
3738
Corey Minyardb2c03942006-12-06 20:41:00 -08003739 handlers = intf->handlers;
3740 if (handlers)
3741 handlers->request_events(intf->send_info);
3742 }
Corey Minyardbca03242006-12-06 20:40:57 -08003743 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744}
3745
3746static struct timer_list ipmi_timer;
3747
3748/* Call every ~100 ms. */
3749#define IPMI_TIMEOUT_TIME 100
3750
3751/* How many jiffies does it take to get to the timeout time. */
3752#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3753
3754/* Request events from the queue every second (this is the number of
3755 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3756 future, IPMI will add a way to know immediately if an event is in
3757 the queue and this silliness can go away. */
3758#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3759
Corey Minyard8f43f842005-06-23 22:01:40 -07003760static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3762
3763static void ipmi_timeout(unsigned long data)
3764{
Corey Minyard8f43f842005-06-23 22:01:40 -07003765 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767
3768 ticks_to_req_ev--;
3769 if (ticks_to_req_ev == 0) {
3770 ipmi_request_event();
3771 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3772 }
3773
3774 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3775
Corey Minyard8f43f842005-06-23 22:01:40 -07003776 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777}
3778
3779
3780static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3781static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3782
3783/* FIXME - convert these to slabs. */
3784static void free_smi_msg(struct ipmi_smi_msg *msg)
3785{
3786 atomic_dec(&smi_msg_inuse_count);
3787 kfree(msg);
3788}
3789
3790struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3791{
3792 struct ipmi_smi_msg *rv;
3793 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3794 if (rv) {
3795 rv->done = free_smi_msg;
3796 rv->user_data = NULL;
3797 atomic_inc(&smi_msg_inuse_count);
3798 }
3799 return rv;
3800}
3801
3802static void free_recv_msg(struct ipmi_recv_msg *msg)
3803{
3804 atomic_dec(&recv_msg_inuse_count);
3805 kfree(msg);
3806}
3807
3808struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3809{
3810 struct ipmi_recv_msg *rv;
3811
3812 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3813 if (rv) {
Corey Minyarda9eec552006-08-31 21:27:45 -07003814 rv->user = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 rv->done = free_recv_msg;
3816 atomic_inc(&recv_msg_inuse_count);
3817 }
3818 return rv;
3819}
3820
Corey Minyard393d2cc2005-11-07 00:59:54 -08003821void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3822{
3823 if (msg->user)
3824 kref_put(&msg->user->refcount, free_user);
3825 msg->done(msg);
3826}
3827
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828#ifdef CONFIG_IPMI_PANIC_EVENT
3829
3830static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3831{
3832}
3833
3834static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3835{
3836}
3837
3838#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003839static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003841 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3842 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3843 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3844 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 {
3846 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003847 intf->event_receiver = msg->msg.data[1];
3848 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 }
3850}
3851
Corey Minyard56a55ec2005-09-06 15:18:42 -07003852static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003854 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3855 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3856 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3857 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 {
3859 /* A get device id command, save if we are an event
3860 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003861 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3862 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 }
3864}
3865#endif
3866
3867static void send_panic_events(char *str)
3868{
3869 struct kernel_ipmi_msg msg;
3870 ipmi_smi_t intf;
3871 unsigned char data[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 struct ipmi_system_interface_addr *si;
3873 struct ipmi_addr addr;
3874 struct ipmi_smi_msg smi_msg;
3875 struct ipmi_recv_msg recv_msg;
3876
3877 si = (struct ipmi_system_interface_addr *) &addr;
3878 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3879 si->channel = IPMI_BMC_CHANNEL;
3880 si->lun = 0;
3881
3882 /* Fill in an event telling that we have failed. */
3883 msg.netfn = 0x04; /* Sensor or Event. */
3884 msg.cmd = 2; /* Platform event command. */
3885 msg.data = data;
3886 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003887 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 data[1] = 0x03; /* This is for IPMI 1.0. */
3889 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3890 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3891 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3892
3893 /* Put a few breadcrumbs in. Hopefully later we can add more things
3894 to make the panic events more useful. */
3895 if (str) {
3896 data[3] = str[0];
3897 data[6] = str[1];
3898 data[7] = str[2];
3899 }
3900
3901 smi_msg.done = dummy_smi_done_handler;
3902 recv_msg.done = dummy_recv_done_handler;
3903
3904 /* For every registered interface, send the event. */
Corey Minyardbca03242006-12-06 20:40:57 -08003905 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08003906 if (!intf->handlers)
3907 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 continue;
3909
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003910 intf->run_to_completion = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 /* Send the event announcing the panic. */
3912 intf->handlers->set_run_to_completion(intf->send_info, 1);
3913 i_ipmi_request(NULL,
3914 intf,
3915 &addr,
3916 0,
3917 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003918 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 &smi_msg,
3920 &recv_msg,
3921 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003922 intf->channels[0].address,
3923 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 0, 1); /* Don't retry, and don't wait. */
3925 }
3926
3927#ifdef CONFIG_IPMI_PANIC_STRING
3928 /* On every interface, dump a bunch of OEM event holding the
3929 string. */
3930 if (!str)
3931 return;
3932
Corey Minyardbca03242006-12-06 20:40:57 -08003933 /* For every registered interface, send the event. */
3934 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 char *p = str;
3936 struct ipmi_ipmb_addr *ipmb;
3937 int j;
3938
Corey Minyardbca03242006-12-06 20:40:57 -08003939 if (intf->intf_num == -1)
3940 /* Interface was not ready yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 continue;
3942
Corey Minyard78ba2fa2007-02-10 01:45:45 -08003943 /*
3944 * intf_num is used as an marker to tell if the
3945 * interface is valid. Thus we need a read barrier to
3946 * make sure data fetched before checking intf_num
3947 * won't be used.
3948 */
3949 smp_rmb();
3950
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 /* First job here is to figure out where to send the
3952 OEM events. There's no way in IPMI to send OEM
3953 events using an event send command, so we have to
3954 find the SEL to put them in and stick them in
3955 there. */
3956
3957 /* Get capabilities from the get device id. */
3958 intf->local_sel_device = 0;
3959 intf->local_event_generator = 0;
3960 intf->event_receiver = 0;
3961
3962 /* Request the device info from the local MC. */
3963 msg.netfn = IPMI_NETFN_APP_REQUEST;
3964 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3965 msg.data = NULL;
3966 msg.data_len = 0;
3967 intf->null_user_handler = device_id_fetcher;
3968 i_ipmi_request(NULL,
3969 intf,
3970 &addr,
3971 0,
3972 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003973 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 &smi_msg,
3975 &recv_msg,
3976 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003977 intf->channels[0].address,
3978 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 0, 1); /* Don't retry, and don't wait. */
3980
3981 if (intf->local_event_generator) {
3982 /* Request the event receiver from the local MC. */
3983 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3984 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3985 msg.data = NULL;
3986 msg.data_len = 0;
3987 intf->null_user_handler = event_receiver_fetcher;
3988 i_ipmi_request(NULL,
3989 intf,
3990 &addr,
3991 0,
3992 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003993 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 &smi_msg,
3995 &recv_msg,
3996 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003997 intf->channels[0].address,
3998 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 0, 1); /* no retry, and no wait. */
4000 }
4001 intf->null_user_handler = NULL;
4002
4003 /* Validate the event receiver. The low bit must not
4004 be 1 (it must be a valid IPMB address), it cannot
4005 be zero, and it must not be my address. */
4006 if (((intf->event_receiver & 1) == 0)
4007 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07004008 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 {
4010 /* The event receiver is valid, send an IPMB
4011 message. */
4012 ipmb = (struct ipmi_ipmb_addr *) &addr;
4013 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
4014 ipmb->channel = 0; /* FIXME - is this right? */
4015 ipmb->lun = intf->event_receiver_lun;
4016 ipmb->slave_addr = intf->event_receiver;
4017 } else if (intf->local_sel_device) {
4018 /* The event receiver was not valid (or was
4019 me), but I am an SEL device, just dump it
4020 in my SEL. */
4021 si = (struct ipmi_system_interface_addr *) &addr;
4022 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
4023 si->channel = IPMI_BMC_CHANNEL;
4024 si->lun = 0;
4025 } else
4026 continue; /* No where to send the event. */
4027
4028
4029 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
4030 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
4031 msg.data = data;
4032 msg.data_len = 16;
4033
4034 j = 0;
4035 while (*p) {
4036 int size = strlen(p);
4037
4038 if (size > 11)
4039 size = 11;
4040 data[0] = 0;
4041 data[1] = 0;
4042 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07004043 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 data[4] = j++; /* sequence # */
4045 /* Always give 11 bytes, so strncpy will fill
4046 it with zeroes for me. */
4047 strncpy(data+5, p, 11);
4048 p += size;
4049
4050 i_ipmi_request(NULL,
4051 intf,
4052 &addr,
4053 0,
4054 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07004055 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 &smi_msg,
4057 &recv_msg,
4058 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07004059 intf->channels[0].address,
4060 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 0, 1); /* no retry, and no wait. */
4062 }
4063 }
4064#endif /* CONFIG_IPMI_PANIC_STRING */
4065}
4066#endif /* CONFIG_IPMI_PANIC_EVENT */
4067
Randy Dunlap0c8204b2006-12-10 02:19:06 -08004068static int has_panicked;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069
4070static int panic_event(struct notifier_block *this,
4071 unsigned long event,
4072 void *ptr)
4073{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 ipmi_smi_t intf;
4075
Lee Revellf18190b2006-06-26 18:30:00 +02004076 if (has_panicked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 return NOTIFY_DONE;
Lee Revellf18190b2006-06-26 18:30:00 +02004078 has_panicked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079
4080 /* For every registered interface, set it to run to completion. */
Corey Minyardbca03242006-12-06 20:40:57 -08004081 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08004082 if (!intf->handlers)
4083 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 continue;
4085
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07004086 intf->run_to_completion = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 intf->handlers->set_run_to_completion(intf->send_info, 1);
4088 }
4089
4090#ifdef CONFIG_IPMI_PANIC_EVENT
4091 send_panic_events(ptr);
4092#endif
4093
4094 return NOTIFY_DONE;
4095}
4096
4097static struct notifier_block panic_block = {
4098 .notifier_call = panic_event,
4099 .next = NULL,
4100 .priority = 200 /* priority: INT_MAX >= x >= 0 */
4101};
4102
4103static int ipmi_init_msghandler(void)
4104{
Corey Minyard50c812b2006-03-26 01:37:21 -08004105 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106
4107 if (initialized)
4108 return 0;
4109
Corey Minyard50c812b2006-03-26 01:37:21 -08004110 rv = driver_register(&ipmidriver);
4111 if (rv) {
4112 printk(KERN_ERR PFX "Could not register IPMI driver\n");
4113 return rv;
4114 }
4115
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004117 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118
Corey Minyard3b625942005-06-23 22:01:42 -07004119#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 proc_ipmi_root = proc_mkdir("ipmi", NULL);
4121 if (!proc_ipmi_root) {
4122 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
4123 return -ENOMEM;
4124 }
4125
4126 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07004127#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128
Corey Minyard409035e2006-06-28 04:26:53 -07004129 setup_timer(&ipmi_timer, ipmi_timeout, 0);
4130 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131
Alan Sterne041c682006-03-27 01:16:30 -08004132 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133
4134 initialized = 1;
4135
4136 return 0;
4137}
4138
4139static __init int ipmi_init_msghandler_mod(void)
4140{
4141 ipmi_init_msghandler();
4142 return 0;
4143}
4144
4145static __exit void cleanup_ipmi(void)
4146{
4147 int count;
4148
4149 if (!initialized)
4150 return;
4151
Alan Sterne041c682006-03-27 01:16:30 -08004152 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153
4154 /* This can't be called if any interfaces exist, so no worry about
4155 shutting down the interfaces. */
4156
4157 /* Tell the timer to stop, then wait for it to stop. This avoids
4158 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07004159 atomic_inc(&stop_operation);
4160 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161
Corey Minyard3b625942005-06-23 22:01:42 -07004162#ifdef CONFIG_PROC_FS
Alexey Dobriyan3542ae42007-10-16 23:26:50 -07004163 remove_proc_entry(proc_ipmi_root->name, NULL);
Corey Minyard3b625942005-06-23 22:01:42 -07004164#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165
Corey Minyard50c812b2006-03-26 01:37:21 -08004166 driver_unregister(&ipmidriver);
4167
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 initialized = 0;
4169
4170 /* Check for buffer leaks. */
4171 count = atomic_read(&smi_msg_inuse_count);
4172 if (count != 0)
4173 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
4174 count);
4175 count = atomic_read(&recv_msg_inuse_count);
4176 if (count != 0)
4177 printk(KERN_WARNING PFX "recv message count %d at exit\n",
4178 count);
4179}
4180module_exit(cleanup_ipmi);
4181
4182module_init(ipmi_init_msghandler_mod);
4183MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004184MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
4185MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
4186MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187
4188EXPORT_SYMBOL(ipmi_create_user);
4189EXPORT_SYMBOL(ipmi_destroy_user);
4190EXPORT_SYMBOL(ipmi_get_version);
4191EXPORT_SYMBOL(ipmi_request_settime);
4192EXPORT_SYMBOL(ipmi_request_supply_msgs);
Corey Minyardfcfa4722007-10-18 03:07:09 -07004193EXPORT_SYMBOL(ipmi_poll_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194EXPORT_SYMBOL(ipmi_register_smi);
4195EXPORT_SYMBOL(ipmi_unregister_smi);
4196EXPORT_SYMBOL(ipmi_register_for_cmd);
4197EXPORT_SYMBOL(ipmi_unregister_for_cmd);
4198EXPORT_SYMBOL(ipmi_smi_msg_received);
4199EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
4200EXPORT_SYMBOL(ipmi_alloc_smi_msg);
4201EXPORT_SYMBOL(ipmi_addr_length);
4202EXPORT_SYMBOL(ipmi_validate_addr);
4203EXPORT_SYMBOL(ipmi_set_gets_events);
4204EXPORT_SYMBOL(ipmi_smi_watcher_register);
4205EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
4206EXPORT_SYMBOL(ipmi_set_my_address);
4207EXPORT_SYMBOL(ipmi_get_my_address);
4208EXPORT_SYMBOL(ipmi_set_my_LUN);
4209EXPORT_SYMBOL(ipmi_get_my_LUN);
4210EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Corey Minyard393d2cc2005-11-07 00:59:54 -08004211EXPORT_SYMBOL(ipmi_free_recv_msg);