blob: 5dc1265ce1d5b288c7049c9ecb305e72d223f618 [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 Minyardb2c03942006-12-06 20:41:00 -0800256 int delivering_events;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 /* The event receiver for my BMC, only really used at panic
259 shutdown as a place to store this. */
260 unsigned char event_receiver;
261 unsigned char event_receiver_lun;
262 unsigned char local_sel_device;
263 unsigned char local_event_generator;
264
Corey Minyardb9675132006-12-06 20:41:02 -0800265 /* For handling of maintenance mode. */
266 int maintenance_mode;
267 int maintenance_mode_enable;
268 int auto_maintenance_timeout;
269 spinlock_t maintenance_mode_lock; /* Used in a timer... */
270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 /* A cheap hack, if this is non-null and a message to an
272 interface comes in with a NULL user, call this routine with
273 it. Note that the message will still be freed by the
274 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700275 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
277 /* When we are scanning the channels for an SMI, this will
278 tell which channel we are scanning. */
279 int curr_channel;
280
281 /* Channel information */
282 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
283
284 /* Proc FS stuff. */
285 struct proc_dir_entry *proc_dir;
286 char proc_dir_name[10];
287
288 spinlock_t counter_lock; /* For making counters atomic. */
289
290 /* Commands we got that were invalid. */
291 unsigned int sent_invalid_commands;
292
293 /* Commands we sent to the MC. */
294 unsigned int sent_local_commands;
295 /* Responses from the MC that were delivered to a user. */
296 unsigned int handled_local_responses;
297 /* Responses from the MC that were not delivered to a user. */
298 unsigned int unhandled_local_responses;
299
300 /* Commands we sent out to the IPMB bus. */
301 unsigned int sent_ipmb_commands;
302 /* Commands sent on the IPMB that had errors on the SEND CMD */
303 unsigned int sent_ipmb_command_errs;
304 /* Each retransmit increments this count. */
305 unsigned int retransmitted_ipmb_commands;
306 /* When a message times out (runs out of retransmits) this is
307 incremented. */
308 unsigned int timed_out_ipmb_commands;
309
310 /* This is like above, but for broadcasts. Broadcasts are
311 *not* included in the above count (they are expected to
312 time out). */
313 unsigned int timed_out_ipmb_broadcasts;
314
315 /* Responses I have sent to the IPMB bus. */
316 unsigned int sent_ipmb_responses;
317
318 /* The response was delivered to the user. */
319 unsigned int handled_ipmb_responses;
320 /* The response had invalid data in it. */
321 unsigned int invalid_ipmb_responses;
322 /* The response didn't have anyone waiting for it. */
323 unsigned int unhandled_ipmb_responses;
324
325 /* Commands we sent out to the IPMB bus. */
326 unsigned int sent_lan_commands;
327 /* Commands sent on the IPMB that had errors on the SEND CMD */
328 unsigned int sent_lan_command_errs;
329 /* Each retransmit increments this count. */
330 unsigned int retransmitted_lan_commands;
331 /* When a message times out (runs out of retransmits) this is
332 incremented. */
333 unsigned int timed_out_lan_commands;
334
335 /* Responses I have sent to the IPMB bus. */
336 unsigned int sent_lan_responses;
337
338 /* The response was delivered to the user. */
339 unsigned int handled_lan_responses;
340 /* The response had invalid data in it. */
341 unsigned int invalid_lan_responses;
342 /* The response didn't have anyone waiting for it. */
343 unsigned int unhandled_lan_responses;
344
345 /* The command was delivered to the user. */
346 unsigned int handled_commands;
347 /* The command had invalid data in it. */
348 unsigned int invalid_commands;
349 /* The command didn't have anyone waiting for it. */
350 unsigned int unhandled_commands;
351
352 /* Invalid data in an event. */
353 unsigned int invalid_events;
354 /* Events that were received with the proper format. */
355 unsigned int events;
356};
Corey Minyard50c812b2006-03-26 01:37:21 -0800357#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Corey Minyard50c812b2006-03-26 01:37:21 -0800359/**
360 * The driver model view of the IPMI messaging driver.
361 */
362static struct device_driver ipmidriver = {
363 .name = "ipmi",
364 .bus = &platform_bus_type
365};
366static DEFINE_MUTEX(ipmidriver_mutex);
367
Corey Minyardbca03242006-12-06 20:40:57 -0800368static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces);
369static DEFINE_MUTEX(ipmi_interfaces_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371/* List of watchers that want to know when smi's are added and
372 deleted. */
373static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
Corey Minyardb2c03942006-12-06 20:41:00 -0800374static DEFINE_MUTEX(smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Corey Minyard393d2cc2005-11-07 00:59:54 -0800377static void free_recv_msg_list(struct list_head *q)
378{
379 struct ipmi_recv_msg *msg, *msg2;
380
381 list_for_each_entry_safe(msg, msg2, q, link) {
382 list_del(&msg->link);
383 ipmi_free_recv_msg(msg);
384 }
385}
386
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800387static void free_smi_msg_list(struct list_head *q)
388{
389 struct ipmi_smi_msg *msg, *msg2;
390
391 list_for_each_entry_safe(msg, msg2, q, link) {
392 list_del(&msg->link);
393 ipmi_free_smi_msg(msg);
394 }
395}
396
Corey Minyard393d2cc2005-11-07 00:59:54 -0800397static void clean_up_interface_data(ipmi_smi_t intf)
398{
399 int i;
400 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800401 struct list_head list;
402
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800403 free_smi_msg_list(&intf->waiting_msgs);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800404 free_recv_msg_list(&intf->waiting_events);
405
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800406 /*
407 * Wholesale remove all the entries from the list in the
408 * interface and wait for RCU to know that none are in use.
409 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800410 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800411 INIT_LIST_HEAD(&list);
412 list_splice_init_rcu(&intf->cmd_rcvrs, &list, synchronize_rcu);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800413 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800414
415 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
416 kfree(rcvr);
417
418 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
419 if ((intf->seq_table[i].inuse)
420 && (intf->seq_table[i].recv_msg))
421 {
422 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 }
424 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800425}
426
427static void intf_free(struct kref *ref)
428{
429 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
430
431 clean_up_interface_data(intf);
432 kfree(intf);
433}
434
Corey Minyardbca03242006-12-06 20:40:57 -0800435struct watcher_entry {
Corey Minyardb2c03942006-12-06 20:41:00 -0800436 int intf_num;
437 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800438 struct list_head link;
Corey Minyardbca03242006-12-06 20:40:57 -0800439};
440
Corey Minyard393d2cc2005-11-07 00:59:54 -0800441int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
442{
Corey Minyardbca03242006-12-06 20:40:57 -0800443 ipmi_smi_t intf;
444 struct list_head to_deliver = LIST_HEAD_INIT(to_deliver);
445 struct watcher_entry *e, *e2;
446
Corey Minyardb2c03942006-12-06 20:41:00 -0800447 mutex_lock(&smi_watchers_mutex);
448
Corey Minyardbca03242006-12-06 20:40:57 -0800449 mutex_lock(&ipmi_interfaces_mutex);
450
Corey Minyardb2c03942006-12-06 20:41:00 -0800451 /* Build a list of things to deliver. */
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800452 list_for_each_entry(intf, &ipmi_interfaces, link) {
Corey Minyardbca03242006-12-06 20:40:57 -0800453 if (intf->intf_num == -1)
454 continue;
455 e = kmalloc(sizeof(*e), GFP_KERNEL);
456 if (!e)
457 goto out_err;
Corey Minyardb2c03942006-12-06 20:41:00 -0800458 kref_get(&intf->refcount);
459 e->intf = intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800460 e->intf_num = intf->intf_num;
461 list_add_tail(&e->link, &to_deliver);
462 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800463
Corey Minyardb2c03942006-12-06 20:41:00 -0800464 /* We will succeed, so add it to the list. */
465 list_add(&watcher->link, &smi_watchers);
Corey Minyardbca03242006-12-06 20:40:57 -0800466
467 mutex_unlock(&ipmi_interfaces_mutex);
468
469 list_for_each_entry_safe(e, e2, &to_deliver, link) {
470 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800471 watcher->new_smi(e->intf_num, e->intf->si_dev);
472 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800473 kfree(e);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800474 }
Corey Minyardbca03242006-12-06 20:40:57 -0800475
Corey Minyardb2c03942006-12-06 20:41:00 -0800476 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 return 0;
Corey Minyardbca03242006-12-06 20:40:57 -0800479
480 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -0800481 mutex_unlock(&ipmi_interfaces_mutex);
482 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800483 list_for_each_entry_safe(e, e2, &to_deliver, link) {
484 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800485 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800486 kfree(e);
487 }
488 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489}
490
491int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
492{
Corey Minyardb2c03942006-12-06 20:41:00 -0800493 mutex_lock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 list_del(&(watcher->link));
Corey Minyardb2c03942006-12-06 20:41:00 -0800495 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 return 0;
497}
498
Corey Minyardb2c03942006-12-06 20:41:00 -0800499/*
500 * Must be called with smi_watchers_mutex held.
501 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502static void
Corey Minyard50c812b2006-03-26 01:37:21 -0800503call_smi_watchers(int i, struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504{
505 struct ipmi_smi_watcher *w;
506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 list_for_each_entry(w, &smi_watchers, link) {
508 if (try_module_get(w->owner)) {
Corey Minyard50c812b2006-03-26 01:37:21 -0800509 w->new_smi(i, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 module_put(w->owner);
511 }
512 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513}
514
515static int
516ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
517{
518 if (addr1->addr_type != addr2->addr_type)
519 return 0;
520
521 if (addr1->channel != addr2->channel)
522 return 0;
523
524 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
525 struct ipmi_system_interface_addr *smi_addr1
526 = (struct ipmi_system_interface_addr *) addr1;
527 struct ipmi_system_interface_addr *smi_addr2
528 = (struct ipmi_system_interface_addr *) addr2;
529 return (smi_addr1->lun == smi_addr2->lun);
530 }
531
532 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
533 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
534 {
535 struct ipmi_ipmb_addr *ipmb_addr1
536 = (struct ipmi_ipmb_addr *) addr1;
537 struct ipmi_ipmb_addr *ipmb_addr2
538 = (struct ipmi_ipmb_addr *) addr2;
539
540 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
541 && (ipmb_addr1->lun == ipmb_addr2->lun));
542 }
543
544 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
545 struct ipmi_lan_addr *lan_addr1
546 = (struct ipmi_lan_addr *) addr1;
547 struct ipmi_lan_addr *lan_addr2
548 = (struct ipmi_lan_addr *) addr2;
549
550 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
551 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
552 && (lan_addr1->session_handle
553 == lan_addr2->session_handle)
554 && (lan_addr1->lun == lan_addr2->lun));
555 }
556
557 return 1;
558}
559
560int ipmi_validate_addr(struct ipmi_addr *addr, int len)
561{
562 if (len < sizeof(struct ipmi_system_interface_addr)) {
563 return -EINVAL;
564 }
565
566 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
567 if (addr->channel != IPMI_BMC_CHANNEL)
568 return -EINVAL;
569 return 0;
570 }
571
572 if ((addr->channel == IPMI_BMC_CHANNEL)
Jayachandran C12fc1d72006-02-03 03:04:51 -0800573 || (addr->channel >= IPMI_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 || (addr->channel < 0))
575 return -EINVAL;
576
577 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
578 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
579 {
580 if (len < sizeof(struct ipmi_ipmb_addr)) {
581 return -EINVAL;
582 }
583 return 0;
584 }
585
586 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
587 if (len < sizeof(struct ipmi_lan_addr)) {
588 return -EINVAL;
589 }
590 return 0;
591 }
592
593 return -EINVAL;
594}
595
596unsigned int ipmi_addr_length(int addr_type)
597{
598 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
599 return sizeof(struct ipmi_system_interface_addr);
600
601 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
602 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
603 {
604 return sizeof(struct ipmi_ipmb_addr);
605 }
606
607 if (addr_type == IPMI_LAN_ADDR_TYPE)
608 return sizeof(struct ipmi_lan_addr);
609
610 return 0;
611}
612
613static void deliver_response(struct ipmi_recv_msg *msg)
614{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800615 if (!msg->user) {
Corey Minyard56a55ec2005-09-06 15:18:42 -0700616 ipmi_smi_t intf = msg->user_msg_data;
617 unsigned long flags;
618
619 /* Special handling for NULL users. */
620 if (intf->null_user_handler) {
621 intf->null_user_handler(intf, msg);
622 spin_lock_irqsave(&intf->counter_lock, flags);
623 intf->handled_local_responses++;
624 spin_unlock_irqrestore(&intf->counter_lock, flags);
625 } else {
626 /* No handler, so give up. */
627 spin_lock_irqsave(&intf->counter_lock, flags);
628 intf->unhandled_local_responses++;
629 spin_unlock_irqrestore(&intf->counter_lock, flags);
630 }
631 ipmi_free_recv_msg(msg);
632 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800633 ipmi_user_t user = msg->user;
634 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636}
637
Corey Minyardb2c03942006-12-06 20:41:00 -0800638static void
639deliver_err_response(struct ipmi_recv_msg *msg, int err)
640{
641 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
642 msg->msg_data[0] = err;
643 msg->msg.netfn |= 1; /* Convert to a response. */
644 msg->msg.data_len = 1;
645 msg->msg.data = msg->msg_data;
646 deliver_response(msg);
647}
648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649/* Find the next sequence number not being used and add the given
650 message with the given timeout to the sequence table. This must be
651 called with the interface's seq_lock held. */
652static int intf_next_seq(ipmi_smi_t intf,
653 struct ipmi_recv_msg *recv_msg,
654 unsigned long timeout,
655 int retries,
656 int broadcast,
657 unsigned char *seq,
658 long *seqid)
659{
660 int rv = 0;
661 unsigned int i;
662
Corey Minyarde8b33612005-09-06 15:18:45 -0700663 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700665 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800667 if (!intf->seq_table[i].inuse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 break;
669 }
670
Corey Minyard8a3628d2006-03-31 02:30:40 -0800671 if (!intf->seq_table[i].inuse) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 intf->seq_table[i].recv_msg = recv_msg;
673
674 /* Start with the maximum timeout, when the send response
675 comes in we will start the real timer. */
676 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
677 intf->seq_table[i].orig_timeout = timeout;
678 intf->seq_table[i].retries_left = retries;
679 intf->seq_table[i].broadcast = broadcast;
680 intf->seq_table[i].inuse = 1;
681 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
682 *seq = i;
683 *seqid = intf->seq_table[i].seqid;
684 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
685 } else {
686 rv = -EAGAIN;
687 }
688
689 return rv;
690}
691
692/* Return the receive message for the given sequence number and
693 release the sequence number so it can be reused. Some other data
694 is passed in to be sure the message matches up correctly (to help
695 guard against message coming in after their timeout and the
696 sequence number being reused). */
697static int intf_find_seq(ipmi_smi_t intf,
698 unsigned char seq,
699 short channel,
700 unsigned char cmd,
701 unsigned char netfn,
702 struct ipmi_addr *addr,
703 struct ipmi_recv_msg **recv_msg)
704{
705 int rv = -ENODEV;
706 unsigned long flags;
707
708 if (seq >= IPMI_IPMB_NUM_SEQ)
709 return -EINVAL;
710
711 spin_lock_irqsave(&(intf->seq_lock), flags);
712 if (intf->seq_table[seq].inuse) {
713 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
714
715 if ((msg->addr.channel == channel)
716 && (msg->msg.cmd == cmd)
717 && (msg->msg.netfn == netfn)
718 && (ipmi_addr_equal(addr, &(msg->addr))))
719 {
720 *recv_msg = msg;
721 intf->seq_table[seq].inuse = 0;
722 rv = 0;
723 }
724 }
725 spin_unlock_irqrestore(&(intf->seq_lock), flags);
726
727 return rv;
728}
729
730
731/* Start the timer for a specific sequence table entry. */
732static int intf_start_seq_timer(ipmi_smi_t intf,
733 long msgid)
734{
735 int rv = -ENODEV;
736 unsigned long flags;
737 unsigned char seq;
738 unsigned long seqid;
739
740
741 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
742
743 spin_lock_irqsave(&(intf->seq_lock), flags);
744 /* We do this verification because the user can be deleted
745 while a message is outstanding. */
746 if ((intf->seq_table[seq].inuse)
747 && (intf->seq_table[seq].seqid == seqid))
748 {
749 struct seq_table *ent = &(intf->seq_table[seq]);
750 ent->timeout = ent->orig_timeout;
751 rv = 0;
752 }
753 spin_unlock_irqrestore(&(intf->seq_lock), flags);
754
755 return rv;
756}
757
758/* Got an error for the send message for a specific sequence number. */
759static int intf_err_seq(ipmi_smi_t intf,
760 long msgid,
761 unsigned int err)
762{
763 int rv = -ENODEV;
764 unsigned long flags;
765 unsigned char seq;
766 unsigned long seqid;
767 struct ipmi_recv_msg *msg = NULL;
768
769
770 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
771
772 spin_lock_irqsave(&(intf->seq_lock), flags);
773 /* We do this verification because the user can be deleted
774 while a message is outstanding. */
775 if ((intf->seq_table[seq].inuse)
776 && (intf->seq_table[seq].seqid == seqid))
777 {
778 struct seq_table *ent = &(intf->seq_table[seq]);
779
780 ent->inuse = 0;
781 msg = ent->recv_msg;
782 rv = 0;
783 }
784 spin_unlock_irqrestore(&(intf->seq_lock), flags);
785
Corey Minyardb2c03942006-12-06 20:41:00 -0800786 if (msg)
787 deliver_err_response(msg, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 return rv;
790}
791
792
793int ipmi_create_user(unsigned int if_num,
794 struct ipmi_user_hndl *handler,
795 void *handler_data,
796 ipmi_user_t *user)
797{
798 unsigned long flags;
799 ipmi_user_t new_user;
800 int rv = 0;
801 ipmi_smi_t intf;
802
803 /* There is no module usecount here, because it's not
804 required. Since this can only be used by and called from
805 other modules, they will implicitly use this module, and
806 thus this can't be removed unless the other modules are
807 removed. */
808
809 if (handler == NULL)
810 return -EINVAL;
811
812 /* Make sure the driver is actually initialized, this handles
813 problems with initialization order. */
814 if (!initialized) {
815 rv = ipmi_init_msghandler();
816 if (rv)
817 return rv;
818
819 /* The init code doesn't return an error if it was turned
820 off, but it won't initialize. Check that. */
821 if (!initialized)
822 return -ENODEV;
823 }
824
825 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800826 if (!new_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 return -ENOMEM;
828
Corey Minyardb2c03942006-12-06 20:41:00 -0800829 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800830 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
831 if (intf->intf_num == if_num)
832 goto found;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
Corey Minyardb2c03942006-12-06 20:41:00 -0800834 /* Not found, return an error */
Corey Minyardbca03242006-12-06 20:40:57 -0800835 rv = -EINVAL;
836 goto out_kfree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Corey Minyardbca03242006-12-06 20:40:57 -0800838 found:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800839 /* Note that each existing user holds a refcount to the interface. */
840 kref_get(&intf->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
Corey Minyard393d2cc2005-11-07 00:59:54 -0800842 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 new_user->handler = handler;
844 new_user->handler_data = handler_data;
845 new_user->intf = intf;
846 new_user->gets_events = 0;
847
848 if (!try_module_get(intf->handlers->owner)) {
849 rv = -ENODEV;
Adrian Bunk5c98d292006-03-25 03:07:52 -0800850 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 }
852
853 if (intf->handlers->inc_usecount) {
854 rv = intf->handlers->inc_usecount(intf->send_info);
855 if (rv) {
856 module_put(intf->handlers->owner);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800857 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 }
859 }
860
Corey Minyardb2c03942006-12-06 20:41:00 -0800861 /* Hold the lock so intf->handlers is guaranteed to be good
862 * until now */
863 mutex_unlock(&ipmi_interfaces_mutex);
864
Corey Minyard393d2cc2005-11-07 00:59:54 -0800865 new_user->valid = 1;
866 spin_lock_irqsave(&intf->seq_lock, flags);
867 list_add_rcu(&new_user->link, &intf->users);
868 spin_unlock_irqrestore(&intf->seq_lock, flags);
869 *user = new_user;
870 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Adrian Bunk5c98d292006-03-25 03:07:52 -0800872out_kref:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800873 kref_put(&intf->refcount, intf_free);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800874out_kfree:
Corey Minyardb2c03942006-12-06 20:41:00 -0800875 mutex_unlock(&ipmi_interfaces_mutex);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800876 kfree(new_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 return rv;
878}
879
Corey Minyard393d2cc2005-11-07 00:59:54 -0800880static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800882 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884}
885
886int ipmi_destroy_user(ipmi_user_t user)
887{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800888 ipmi_smi_t intf = user->intf;
889 int i;
890 unsigned long flags;
891 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800892 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Corey Minyard8a3628d2006-03-31 02:30:40 -0800894 user->valid = 0;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800895
896 /* Remove the user from the interface's sequence table. */
897 spin_lock_irqsave(&intf->seq_lock, flags);
898 list_del_rcu(&user->link);
899
900 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
901 if (intf->seq_table[i].inuse
902 && (intf->seq_table[i].recv_msg->user == user))
903 {
904 intf->seq_table[i].inuse = 0;
Corey Minyardb2c03942006-12-06 20:41:00 -0800905 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800908 spin_unlock_irqrestore(&intf->seq_lock, flags);
909
910 /*
911 * Remove the user from the command receiver's table. First
912 * we build a list of everything (not using the standard link,
913 * since other things may be using it till we do
914 * synchronize_rcu()) then free everything in that list.
915 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800916 mutex_lock(&intf->cmd_rcvrs_mutex);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800917 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800918 if (rcvr->user == user) {
919 list_del_rcu(&rcvr->link);
920 rcvr->next = rcvrs;
921 rcvrs = rcvr;
922 }
923 }
Corey Minyardd6dfd132006-03-31 02:30:41 -0800924 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800925 synchronize_rcu();
926 while (rcvrs) {
927 rcvr = rcvrs;
928 rcvrs = rcvr->next;
929 kfree(rcvr);
930 }
931
Corey Minyardb2c03942006-12-06 20:41:00 -0800932 mutex_lock(&ipmi_interfaces_mutex);
933 if (intf->handlers) {
934 module_put(intf->handlers->owner);
935 if (intf->handlers->dec_usecount)
936 intf->handlers->dec_usecount(intf->send_info);
937 }
938 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800939
940 kref_put(&intf->refcount, intf_free);
941
942 kref_put(&user->refcount, free_user);
943
Corey Minyard8a3628d2006-03-31 02:30:40 -0800944 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945}
946
947void ipmi_get_version(ipmi_user_t user,
948 unsigned char *major,
949 unsigned char *minor)
950{
Corey Minyardb2c03942006-12-06 20:41:00 -0800951 *major = user->intf->ipmi_version_major;
952 *minor = user->intf->ipmi_version_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953}
954
Corey Minyardc14979b2005-09-06 15:18:38 -0700955int ipmi_set_my_address(ipmi_user_t user,
956 unsigned int channel,
957 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958{
Corey Minyardc14979b2005-09-06 15:18:38 -0700959 if (channel >= IPMI_MAX_CHANNELS)
960 return -EINVAL;
961 user->intf->channels[channel].address = address;
962 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963}
964
Corey Minyardc14979b2005-09-06 15:18:38 -0700965int ipmi_get_my_address(ipmi_user_t user,
966 unsigned int channel,
967 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
Corey Minyardc14979b2005-09-06 15:18:38 -0700969 if (channel >= IPMI_MAX_CHANNELS)
970 return -EINVAL;
971 *address = user->intf->channels[channel].address;
972 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973}
974
Corey Minyardc14979b2005-09-06 15:18:38 -0700975int ipmi_set_my_LUN(ipmi_user_t user,
976 unsigned int channel,
977 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978{
Corey Minyardc14979b2005-09-06 15:18:38 -0700979 if (channel >= IPMI_MAX_CHANNELS)
980 return -EINVAL;
981 user->intf->channels[channel].lun = LUN & 0x3;
982 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983}
984
Corey Minyardc14979b2005-09-06 15:18:38 -0700985int ipmi_get_my_LUN(ipmi_user_t user,
986 unsigned int channel,
987 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988{
Corey Minyardc14979b2005-09-06 15:18:38 -0700989 if (channel >= IPMI_MAX_CHANNELS)
990 return -EINVAL;
991 *address = user->intf->channels[channel].lun;
992 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993}
994
Corey Minyardb9675132006-12-06 20:41:02 -0800995int ipmi_get_maintenance_mode(ipmi_user_t user)
996{
997 int mode;
998 unsigned long flags;
999
1000 spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);
1001 mode = user->intf->maintenance_mode;
1002 spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);
1003
1004 return mode;
1005}
1006EXPORT_SYMBOL(ipmi_get_maintenance_mode);
1007
1008static void maintenance_mode_update(ipmi_smi_t intf)
1009{
1010 if (intf->handlers->set_maintenance_mode)
1011 intf->handlers->set_maintenance_mode(
1012 intf->send_info, intf->maintenance_mode_enable);
1013}
1014
1015int ipmi_set_maintenance_mode(ipmi_user_t user, int mode)
1016{
1017 int rv = 0;
1018 unsigned long flags;
1019 ipmi_smi_t intf = user->intf;
1020
1021 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1022 if (intf->maintenance_mode != mode) {
1023 switch (mode) {
1024 case IPMI_MAINTENANCE_MODE_AUTO:
1025 intf->maintenance_mode = mode;
1026 intf->maintenance_mode_enable
1027 = (intf->auto_maintenance_timeout > 0);
1028 break;
1029
1030 case IPMI_MAINTENANCE_MODE_OFF:
1031 intf->maintenance_mode = mode;
1032 intf->maintenance_mode_enable = 0;
1033 break;
1034
1035 case IPMI_MAINTENANCE_MODE_ON:
1036 intf->maintenance_mode = mode;
1037 intf->maintenance_mode_enable = 1;
1038 break;
1039
1040 default:
1041 rv = -EINVAL;
1042 goto out_unlock;
1043 }
1044
1045 maintenance_mode_update(intf);
1046 }
1047 out_unlock:
1048 spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);
1049
1050 return rv;
1051}
1052EXPORT_SYMBOL(ipmi_set_maintenance_mode);
1053
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054int ipmi_set_gets_events(ipmi_user_t user, int val)
1055{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001056 unsigned long flags;
1057 ipmi_smi_t intf = user->intf;
1058 struct ipmi_recv_msg *msg, *msg2;
1059 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Corey Minyard393d2cc2005-11-07 00:59:54 -08001061 INIT_LIST_HEAD(&msgs);
1062
1063 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 user->gets_events = val;
1065
Corey Minyardb2c03942006-12-06 20:41:00 -08001066 if (intf->delivering_events)
1067 /*
1068 * Another thread is delivering events for this, so
1069 * let it handle any new events.
1070 */
1071 goto out;
1072
1073 /* Deliver any queued events. */
1074 while (user->gets_events && !list_empty(&intf->waiting_events)) {
Akinobu Mita179e0912006-06-26 00:24:41 -07001075 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
1076 list_move_tail(&msg->link, &msgs);
Corey Minyard4791c032006-04-10 22:54:31 -07001077 intf->waiting_events_count = 0;
Corey Minyardb2c03942006-12-06 20:41:00 -08001078
1079 intf->delivering_events = 1;
1080 spin_unlock_irqrestore(&intf->events_lock, flags);
1081
1082 list_for_each_entry_safe(msg, msg2, &msgs, link) {
1083 msg->user = user;
1084 kref_get(&user->refcount);
1085 deliver_response(msg);
1086 }
1087
1088 spin_lock_irqsave(&intf->events_lock, flags);
1089 intf->delivering_events = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08001091
Corey Minyardb2c03942006-12-06 20:41:00 -08001092 out:
Corey Minyard393d2cc2005-11-07 00:59:54 -08001093 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
1095 return 0;
1096}
1097
Corey Minyard393d2cc2005-11-07 00:59:54 -08001098static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
1099 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001100 unsigned char cmd,
1101 unsigned char chan)
Corey Minyard393d2cc2005-11-07 00:59:54 -08001102{
1103 struct cmd_rcvr *rcvr;
1104
1105 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyardc69c3122006-09-30 23:27:56 -07001106 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1107 && (rcvr->chans & (1 << chan)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08001108 return rcvr;
1109 }
1110 return NULL;
1111}
1112
Corey Minyardc69c3122006-09-30 23:27:56 -07001113static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
1114 unsigned char netfn,
1115 unsigned char cmd,
1116 unsigned int chans)
1117{
1118 struct cmd_rcvr *rcvr;
1119
1120 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
1121 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1122 && (rcvr->chans & chans))
1123 return 0;
1124 }
1125 return 1;
1126}
1127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128int ipmi_register_for_cmd(ipmi_user_t user,
1129 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001130 unsigned char cmd,
1131 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001133 ipmi_smi_t intf = user->intf;
1134 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001135 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
1137
1138 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -08001139 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001141 rcvr->cmd = cmd;
1142 rcvr->netfn = netfn;
Corey Minyardc69c3122006-09-30 23:27:56 -07001143 rcvr->chans = chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001144 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Corey Minyardd6dfd132006-03-31 02:30:41 -08001146 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 /* Make sure the command/netfn is not already registered. */
Corey Minyardc69c3122006-09-30 23:27:56 -07001148 if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08001149 rv = -EBUSY;
1150 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 }
1152
Corey Minyard393d2cc2005-11-07 00:59:54 -08001153 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -07001154
Corey Minyard393d2cc2005-11-07 00:59:54 -08001155 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -08001156 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 if (rv)
1158 kfree(rcvr);
1159
1160 return rv;
1161}
1162
1163int ipmi_unregister_for_cmd(ipmi_user_t user,
1164 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001165 unsigned char cmd,
1166 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001168 ipmi_smi_t intf = user->intf;
1169 struct cmd_rcvr *rcvr;
Corey Minyardc69c3122006-09-30 23:27:56 -07001170 struct cmd_rcvr *rcvrs = NULL;
1171 int i, rv = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
Corey Minyardd6dfd132006-03-31 02:30:41 -08001173 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyardc69c3122006-09-30 23:27:56 -07001174 for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
1175 if (((1 << i) & chans) == 0)
1176 continue;
1177 rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
1178 if (rcvr == NULL)
1179 continue;
1180 if (rcvr->user == user) {
1181 rv = 0;
1182 rcvr->chans &= ~chans;
1183 if (rcvr->chans == 0) {
1184 list_del_rcu(&rcvr->link);
1185 rcvr->next = rcvrs;
1186 rcvrs = rcvr;
1187 }
1188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
Corey Minyardc69c3122006-09-30 23:27:56 -07001190 mutex_unlock(&intf->cmd_rcvrs_mutex);
1191 synchronize_rcu();
1192 while (rcvrs) {
1193 rcvr = rcvrs;
1194 rcvrs = rcvr->next;
1195 kfree(rcvr);
1196 }
1197 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198}
1199
1200void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
1201{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001202 ipmi_smi_t intf = user->intf;
Corey Minyardb2c03942006-12-06 20:41:00 -08001203 if (intf->handlers)
1204 intf->handlers->set_run_to_completion(intf->send_info, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205}
1206
1207static unsigned char
1208ipmb_checksum(unsigned char *data, int size)
1209{
1210 unsigned char csum = 0;
1211
1212 for (; size > 0; size--, data++)
1213 csum += *data;
1214
1215 return -csum;
1216}
1217
1218static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1219 struct kernel_ipmi_msg *msg,
1220 struct ipmi_ipmb_addr *ipmb_addr,
1221 long msgid,
1222 unsigned char ipmb_seq,
1223 int broadcast,
1224 unsigned char source_address,
1225 unsigned char source_lun)
1226{
1227 int i = broadcast;
1228
1229 /* Format the IPMB header data. */
1230 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1231 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1232 smi_msg->data[2] = ipmb_addr->channel;
1233 if (broadcast)
1234 smi_msg->data[3] = 0;
1235 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1236 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1237 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1238 smi_msg->data[i+6] = source_address;
1239 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1240 smi_msg->data[i+8] = msg->cmd;
1241
1242 /* Now tack on the data to the message. */
1243 if (msg->data_len > 0)
1244 memcpy(&(smi_msg->data[i+9]), msg->data,
1245 msg->data_len);
1246 smi_msg->data_size = msg->data_len + 9;
1247
1248 /* Now calculate the checksum and tack it on. */
1249 smi_msg->data[i+smi_msg->data_size]
1250 = ipmb_checksum(&(smi_msg->data[i+6]),
1251 smi_msg->data_size-6);
1252
1253 /* Add on the checksum size and the offset from the
1254 broadcast. */
1255 smi_msg->data_size += 1 + i;
1256
1257 smi_msg->msgid = msgid;
1258}
1259
1260static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1261 struct kernel_ipmi_msg *msg,
1262 struct ipmi_lan_addr *lan_addr,
1263 long msgid,
1264 unsigned char ipmb_seq,
1265 unsigned char source_lun)
1266{
1267 /* Format the IPMB header data. */
1268 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1269 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1270 smi_msg->data[2] = lan_addr->channel;
1271 smi_msg->data[3] = lan_addr->session_handle;
1272 smi_msg->data[4] = lan_addr->remote_SWID;
1273 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1274 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1275 smi_msg->data[7] = lan_addr->local_SWID;
1276 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1277 smi_msg->data[9] = msg->cmd;
1278
1279 /* Now tack on the data to the message. */
1280 if (msg->data_len > 0)
1281 memcpy(&(smi_msg->data[10]), msg->data,
1282 msg->data_len);
1283 smi_msg->data_size = msg->data_len + 10;
1284
1285 /* Now calculate the checksum and tack it on. */
1286 smi_msg->data[smi_msg->data_size]
1287 = ipmb_checksum(&(smi_msg->data[7]),
1288 smi_msg->data_size-7);
1289
1290 /* Add on the checksum size and the offset from the
1291 broadcast. */
1292 smi_msg->data_size += 1;
1293
1294 smi_msg->msgid = msgid;
1295}
1296
1297/* Separate from ipmi_request so that the user does not have to be
1298 supplied in certain circumstances (mainly at panic time). If
1299 messages are supplied, they will be freed, even if an error
1300 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001301static int i_ipmi_request(ipmi_user_t user,
1302 ipmi_smi_t intf,
1303 struct ipmi_addr *addr,
1304 long msgid,
1305 struct kernel_ipmi_msg *msg,
1306 void *user_msg_data,
1307 void *supplied_smi,
1308 struct ipmi_recv_msg *supplied_recv,
1309 int priority,
1310 unsigned char source_address,
1311 unsigned char source_lun,
1312 int retries,
1313 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314{
Corey Minyardb2c03942006-12-06 20:41:00 -08001315 int rv = 0;
1316 struct ipmi_smi_msg *smi_msg;
1317 struct ipmi_recv_msg *recv_msg;
1318 unsigned long flags;
1319 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
1321
1322 if (supplied_recv) {
1323 recv_msg = supplied_recv;
1324 } else {
1325 recv_msg = ipmi_alloc_recv_msg();
1326 if (recv_msg == NULL) {
1327 return -ENOMEM;
1328 }
1329 }
1330 recv_msg->user_msg_data = user_msg_data;
1331
1332 if (supplied_smi) {
1333 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1334 } else {
1335 smi_msg = ipmi_alloc_smi_msg();
1336 if (smi_msg == NULL) {
1337 ipmi_free_recv_msg(recv_msg);
1338 return -ENOMEM;
1339 }
1340 }
1341
Corey Minyardb2c03942006-12-06 20:41:00 -08001342 rcu_read_lock();
1343 handlers = intf->handlers;
1344 if (!handlers) {
1345 rv = -ENODEV;
1346 goto out_err;
1347 }
1348
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001350 if (user)
1351 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 recv_msg->msgid = msgid;
1353 /* Store the message to send in the receive message so timeout
1354 responses can get the proper response data. */
1355 recv_msg->msg = *msg;
1356
1357 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1358 struct ipmi_system_interface_addr *smi_addr;
1359
1360 if (msg->netfn & 1) {
1361 /* Responses are not allowed to the SMI. */
1362 rv = -EINVAL;
1363 goto out_err;
1364 }
1365
1366 smi_addr = (struct ipmi_system_interface_addr *) addr;
1367 if (smi_addr->lun > 3) {
1368 spin_lock_irqsave(&intf->counter_lock, flags);
1369 intf->sent_invalid_commands++;
1370 spin_unlock_irqrestore(&intf->counter_lock, flags);
1371 rv = -EINVAL;
1372 goto out_err;
1373 }
1374
1375 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1376
1377 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1378 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1379 || (msg->cmd == IPMI_GET_MSG_CMD)
1380 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1381 {
1382 /* We don't let the user do these, since we manage
1383 the sequence numbers. */
1384 spin_lock_irqsave(&intf->counter_lock, flags);
1385 intf->sent_invalid_commands++;
1386 spin_unlock_irqrestore(&intf->counter_lock, flags);
1387 rv = -EINVAL;
1388 goto out_err;
1389 }
1390
Corey Minyardb9675132006-12-06 20:41:02 -08001391 if (((msg->netfn == IPMI_NETFN_APP_REQUEST)
1392 && ((msg->cmd == IPMI_COLD_RESET_CMD)
1393 || (msg->cmd == IPMI_WARM_RESET_CMD)))
1394 || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST))
1395 {
1396 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1397 intf->auto_maintenance_timeout
1398 = IPMI_MAINTENANCE_MODE_TIMEOUT;
1399 if (!intf->maintenance_mode
1400 && !intf->maintenance_mode_enable)
1401 {
1402 intf->maintenance_mode_enable = 1;
1403 maintenance_mode_update(intf);
1404 }
1405 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
1406 flags);
1407 }
1408
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1410 spin_lock_irqsave(&intf->counter_lock, flags);
1411 intf->sent_invalid_commands++;
1412 spin_unlock_irqrestore(&intf->counter_lock, flags);
1413 rv = -EMSGSIZE;
1414 goto out_err;
1415 }
1416
1417 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1418 smi_msg->data[1] = msg->cmd;
1419 smi_msg->msgid = msgid;
1420 smi_msg->user_data = recv_msg;
1421 if (msg->data_len > 0)
1422 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1423 smi_msg->data_size = msg->data_len + 2;
1424 spin_lock_irqsave(&intf->counter_lock, flags);
1425 intf->sent_local_commands++;
1426 spin_unlock_irqrestore(&intf->counter_lock, flags);
1427 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1428 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1429 {
1430 struct ipmi_ipmb_addr *ipmb_addr;
1431 unsigned char ipmb_seq;
1432 long seqid;
1433 int broadcast = 0;
1434
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001435 if (addr->channel >= IPMI_MAX_CHANNELS) {
1436 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 intf->sent_invalid_commands++;
1438 spin_unlock_irqrestore(&intf->counter_lock, flags);
1439 rv = -EINVAL;
1440 goto out_err;
1441 }
1442
1443 if (intf->channels[addr->channel].medium
1444 != IPMI_CHANNEL_MEDIUM_IPMB)
1445 {
1446 spin_lock_irqsave(&intf->counter_lock, flags);
1447 intf->sent_invalid_commands++;
1448 spin_unlock_irqrestore(&intf->counter_lock, flags);
1449 rv = -EINVAL;
1450 goto out_err;
1451 }
1452
1453 if (retries < 0) {
1454 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1455 retries = 0; /* Don't retry broadcasts. */
1456 else
1457 retries = 4;
1458 }
1459 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1460 /* Broadcasts add a zero at the beginning of the
1461 message, but otherwise is the same as an IPMB
1462 address. */
1463 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1464 broadcast = 1;
1465 }
1466
1467
1468 /* Default to 1 second retries. */
1469 if (retry_time_ms == 0)
1470 retry_time_ms = 1000;
1471
1472 /* 9 for the header and 1 for the checksum, plus
1473 possibly one for the broadcast. */
1474 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1475 spin_lock_irqsave(&intf->counter_lock, flags);
1476 intf->sent_invalid_commands++;
1477 spin_unlock_irqrestore(&intf->counter_lock, flags);
1478 rv = -EMSGSIZE;
1479 goto out_err;
1480 }
1481
1482 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1483 if (ipmb_addr->lun > 3) {
1484 spin_lock_irqsave(&intf->counter_lock, flags);
1485 intf->sent_invalid_commands++;
1486 spin_unlock_irqrestore(&intf->counter_lock, flags);
1487 rv = -EINVAL;
1488 goto out_err;
1489 }
1490
1491 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1492
1493 if (recv_msg->msg.netfn & 0x1) {
1494 /* It's a response, so use the user's sequence
1495 from msgid. */
1496 spin_lock_irqsave(&intf->counter_lock, flags);
1497 intf->sent_ipmb_responses++;
1498 spin_unlock_irqrestore(&intf->counter_lock, flags);
1499 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1500 msgid, broadcast,
1501 source_address, source_lun);
1502
1503 /* Save the receive message so we can use it
1504 to deliver the response. */
1505 smi_msg->user_data = recv_msg;
1506 } else {
1507 /* It's a command, so get a sequence for it. */
1508
1509 spin_lock_irqsave(&(intf->seq_lock), flags);
1510
1511 spin_lock(&intf->counter_lock);
1512 intf->sent_ipmb_commands++;
1513 spin_unlock(&intf->counter_lock);
1514
1515 /* Create a sequence number with a 1 second
1516 timeout and 4 retries. */
1517 rv = intf_next_seq(intf,
1518 recv_msg,
1519 retry_time_ms,
1520 retries,
1521 broadcast,
1522 &ipmb_seq,
1523 &seqid);
1524 if (rv) {
1525 /* We have used up all the sequence numbers,
1526 probably, so abort. */
1527 spin_unlock_irqrestore(&(intf->seq_lock),
1528 flags);
1529 goto out_err;
1530 }
1531
1532 /* Store the sequence number in the message,
1533 so that when the send message response
1534 comes back we can start the timer. */
1535 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1536 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1537 ipmb_seq, broadcast,
1538 source_address, source_lun);
1539
1540 /* Copy the message into the recv message data, so we
1541 can retransmit it later if necessary. */
1542 memcpy(recv_msg->msg_data, smi_msg->data,
1543 smi_msg->data_size);
1544 recv_msg->msg.data = recv_msg->msg_data;
1545 recv_msg->msg.data_len = smi_msg->data_size;
1546
1547 /* We don't unlock until here, because we need
1548 to copy the completed message into the
1549 recv_msg before we release the lock.
1550 Otherwise, race conditions may bite us. I
1551 know that's pretty paranoid, but I prefer
1552 to be correct. */
1553 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1554 }
1555 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1556 struct ipmi_lan_addr *lan_addr;
1557 unsigned char ipmb_seq;
1558 long seqid;
1559
Jayachandran C12fc1d72006-02-03 03:04:51 -08001560 if (addr->channel >= IPMI_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 spin_lock_irqsave(&intf->counter_lock, flags);
1562 intf->sent_invalid_commands++;
1563 spin_unlock_irqrestore(&intf->counter_lock, flags);
1564 rv = -EINVAL;
1565 goto out_err;
1566 }
1567
1568 if ((intf->channels[addr->channel].medium
1569 != IPMI_CHANNEL_MEDIUM_8023LAN)
1570 && (intf->channels[addr->channel].medium
1571 != IPMI_CHANNEL_MEDIUM_ASYNC))
1572 {
1573 spin_lock_irqsave(&intf->counter_lock, flags);
1574 intf->sent_invalid_commands++;
1575 spin_unlock_irqrestore(&intf->counter_lock, flags);
1576 rv = -EINVAL;
1577 goto out_err;
1578 }
1579
1580 retries = 4;
1581
1582 /* Default to 1 second retries. */
1583 if (retry_time_ms == 0)
1584 retry_time_ms = 1000;
1585
1586 /* 11 for the header and 1 for the checksum. */
1587 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1588 spin_lock_irqsave(&intf->counter_lock, flags);
1589 intf->sent_invalid_commands++;
1590 spin_unlock_irqrestore(&intf->counter_lock, flags);
1591 rv = -EMSGSIZE;
1592 goto out_err;
1593 }
1594
1595 lan_addr = (struct ipmi_lan_addr *) addr;
1596 if (lan_addr->lun > 3) {
1597 spin_lock_irqsave(&intf->counter_lock, flags);
1598 intf->sent_invalid_commands++;
1599 spin_unlock_irqrestore(&intf->counter_lock, flags);
1600 rv = -EINVAL;
1601 goto out_err;
1602 }
1603
1604 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1605
1606 if (recv_msg->msg.netfn & 0x1) {
1607 /* It's a response, so use the user's sequence
1608 from msgid. */
1609 spin_lock_irqsave(&intf->counter_lock, flags);
1610 intf->sent_lan_responses++;
1611 spin_unlock_irqrestore(&intf->counter_lock, flags);
1612 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1613 msgid, source_lun);
1614
1615 /* Save the receive message so we can use it
1616 to deliver the response. */
1617 smi_msg->user_data = recv_msg;
1618 } else {
1619 /* It's a command, so get a sequence for it. */
1620
1621 spin_lock_irqsave(&(intf->seq_lock), flags);
1622
1623 spin_lock(&intf->counter_lock);
1624 intf->sent_lan_commands++;
1625 spin_unlock(&intf->counter_lock);
1626
1627 /* Create a sequence number with a 1 second
1628 timeout and 4 retries. */
1629 rv = intf_next_seq(intf,
1630 recv_msg,
1631 retry_time_ms,
1632 retries,
1633 0,
1634 &ipmb_seq,
1635 &seqid);
1636 if (rv) {
1637 /* We have used up all the sequence numbers,
1638 probably, so abort. */
1639 spin_unlock_irqrestore(&(intf->seq_lock),
1640 flags);
1641 goto out_err;
1642 }
1643
1644 /* Store the sequence number in the message,
1645 so that when the send message response
1646 comes back we can start the timer. */
1647 format_lan_msg(smi_msg, msg, lan_addr,
1648 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1649 ipmb_seq, source_lun);
1650
1651 /* Copy the message into the recv message data, so we
1652 can retransmit it later if necessary. */
1653 memcpy(recv_msg->msg_data, smi_msg->data,
1654 smi_msg->data_size);
1655 recv_msg->msg.data = recv_msg->msg_data;
1656 recv_msg->msg.data_len = smi_msg->data_size;
1657
1658 /* We don't unlock until here, because we need
1659 to copy the completed message into the
1660 recv_msg before we release the lock.
1661 Otherwise, race conditions may bite us. I
1662 know that's pretty paranoid, but I prefer
1663 to be correct. */
1664 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1665 }
1666 } else {
1667 /* Unknown address type. */
1668 spin_lock_irqsave(&intf->counter_lock, flags);
1669 intf->sent_invalid_commands++;
1670 spin_unlock_irqrestore(&intf->counter_lock, flags);
1671 rv = -EINVAL;
1672 goto out_err;
1673 }
1674
1675#ifdef DEBUG_MSGING
1676 {
1677 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001678 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 printk(" %2.2x", smi_msg->data[m]);
1680 printk("\n");
1681 }
1682#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08001683
1684 handlers->sender(intf->send_info, smi_msg, priority);
1685 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
1687 return 0;
1688
1689 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -08001690 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 ipmi_free_smi_msg(smi_msg);
1692 ipmi_free_recv_msg(recv_msg);
1693 return rv;
1694}
1695
Corey Minyardc14979b2005-09-06 15:18:38 -07001696static int check_addr(ipmi_smi_t intf,
1697 struct ipmi_addr *addr,
1698 unsigned char *saddr,
1699 unsigned char *lun)
1700{
1701 if (addr->channel >= IPMI_MAX_CHANNELS)
1702 return -EINVAL;
1703 *lun = intf->channels[addr->channel].lun;
1704 *saddr = intf->channels[addr->channel].address;
1705 return 0;
1706}
1707
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708int ipmi_request_settime(ipmi_user_t user,
1709 struct ipmi_addr *addr,
1710 long msgid,
1711 struct kernel_ipmi_msg *msg,
1712 void *user_msg_data,
1713 int priority,
1714 int retries,
1715 unsigned int retry_time_ms)
1716{
Corey Minyardc14979b2005-09-06 15:18:38 -07001717 unsigned char saddr, lun;
1718 int rv;
1719
Corey Minyard8a3628d2006-03-31 02:30:40 -08001720 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001721 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001722 rv = check_addr(user->intf, addr, &saddr, &lun);
1723 if (rv)
1724 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 return i_ipmi_request(user,
1726 user->intf,
1727 addr,
1728 msgid,
1729 msg,
1730 user_msg_data,
1731 NULL, NULL,
1732 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001733 saddr,
1734 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 retries,
1736 retry_time_ms);
1737}
1738
1739int ipmi_request_supply_msgs(ipmi_user_t user,
1740 struct ipmi_addr *addr,
1741 long msgid,
1742 struct kernel_ipmi_msg *msg,
1743 void *user_msg_data,
1744 void *supplied_smi,
1745 struct ipmi_recv_msg *supplied_recv,
1746 int priority)
1747{
Corey Minyardc14979b2005-09-06 15:18:38 -07001748 unsigned char saddr, lun;
1749 int rv;
1750
Corey Minyard8a3628d2006-03-31 02:30:40 -08001751 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001752 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001753 rv = check_addr(user->intf, addr, &saddr, &lun);
1754 if (rv)
1755 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 return i_ipmi_request(user,
1757 user->intf,
1758 addr,
1759 msgid,
1760 msg,
1761 user_msg_data,
1762 supplied_smi,
1763 supplied_recv,
1764 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001765 saddr,
1766 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 -1, 0);
1768}
1769
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001770#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771static int ipmb_file_read_proc(char *page, char **start, off_t off,
1772 int count, int *eof, void *data)
1773{
1774 char *out = (char *) page;
1775 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001776 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001777 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778
Corey Minyarde8b33612005-09-06 15:18:45 -07001779 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001780 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1781 out[rv-1] = '\n'; /* Replace the final space with a newline */
1782 out[rv] = '\0';
1783 rv++;
1784 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785}
1786
1787static int version_file_read_proc(char *page, char **start, off_t off,
1788 int count, int *eof, void *data)
1789{
1790 char *out = (char *) page;
1791 ipmi_smi_t intf = data;
1792
1793 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001794 ipmi_version_major(&intf->bmc->id),
1795 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796}
1797
1798static int stat_file_read_proc(char *page, char **start, off_t off,
1799 int count, int *eof, void *data)
1800{
1801 char *out = (char *) page;
1802 ipmi_smi_t intf = data;
1803
1804 out += sprintf(out, "sent_invalid_commands: %d\n",
1805 intf->sent_invalid_commands);
1806 out += sprintf(out, "sent_local_commands: %d\n",
1807 intf->sent_local_commands);
1808 out += sprintf(out, "handled_local_responses: %d\n",
1809 intf->handled_local_responses);
1810 out += sprintf(out, "unhandled_local_responses: %d\n",
1811 intf->unhandled_local_responses);
1812 out += sprintf(out, "sent_ipmb_commands: %d\n",
1813 intf->sent_ipmb_commands);
1814 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1815 intf->sent_ipmb_command_errs);
1816 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1817 intf->retransmitted_ipmb_commands);
1818 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1819 intf->timed_out_ipmb_commands);
1820 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1821 intf->timed_out_ipmb_broadcasts);
1822 out += sprintf(out, "sent_ipmb_responses: %d\n",
1823 intf->sent_ipmb_responses);
1824 out += sprintf(out, "handled_ipmb_responses: %d\n",
1825 intf->handled_ipmb_responses);
1826 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1827 intf->invalid_ipmb_responses);
1828 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1829 intf->unhandled_ipmb_responses);
1830 out += sprintf(out, "sent_lan_commands: %d\n",
1831 intf->sent_lan_commands);
1832 out += sprintf(out, "sent_lan_command_errs: %d\n",
1833 intf->sent_lan_command_errs);
1834 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1835 intf->retransmitted_lan_commands);
1836 out += sprintf(out, "timed_out_lan_commands: %d\n",
1837 intf->timed_out_lan_commands);
1838 out += sprintf(out, "sent_lan_responses: %d\n",
1839 intf->sent_lan_responses);
1840 out += sprintf(out, "handled_lan_responses: %d\n",
1841 intf->handled_lan_responses);
1842 out += sprintf(out, "invalid_lan_responses: %d\n",
1843 intf->invalid_lan_responses);
1844 out += sprintf(out, "unhandled_lan_responses: %d\n",
1845 intf->unhandled_lan_responses);
1846 out += sprintf(out, "handled_commands: %d\n",
1847 intf->handled_commands);
1848 out += sprintf(out, "invalid_commands: %d\n",
1849 intf->invalid_commands);
1850 out += sprintf(out, "unhandled_commands: %d\n",
1851 intf->unhandled_commands);
1852 out += sprintf(out, "invalid_events: %d\n",
1853 intf->invalid_events);
1854 out += sprintf(out, "events: %d\n",
1855 intf->events);
1856
1857 return (out - ((char *) page));
1858}
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001859#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
1861int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1862 read_proc_t *read_proc, write_proc_t *write_proc,
1863 void *data, struct module *owner)
1864{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001866#ifdef CONFIG_PROC_FS
1867 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 struct ipmi_proc_entry *entry;
1869
1870 /* Create a list element. */
1871 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1872 if (!entry)
1873 return -ENOMEM;
1874 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1875 if (!entry->name) {
1876 kfree(entry);
1877 return -ENOMEM;
1878 }
1879 strcpy(entry->name, name);
1880
1881 file = create_proc_entry(name, 0, smi->proc_dir);
1882 if (!file) {
1883 kfree(entry->name);
1884 kfree(entry);
1885 rv = -ENOMEM;
1886 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 file->data = data;
1888 file->read_proc = read_proc;
1889 file->write_proc = write_proc;
1890 file->owner = owner;
1891
Corey Minyardac019152007-10-18 03:07:11 -07001892 mutex_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 /* Stick it on the list. */
1894 entry->next = smi->proc_entries;
1895 smi->proc_entries = entry;
Corey Minyardac019152007-10-18 03:07:11 -07001896 mutex_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 }
Corey Minyard3b625942005-06-23 22:01:42 -07001898#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900 return rv;
1901}
1902
1903static int add_proc_entries(ipmi_smi_t smi, int num)
1904{
1905 int rv = 0;
1906
Corey Minyard3b625942005-06-23 22:01:42 -07001907#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 sprintf(smi->proc_dir_name, "%d", num);
1909 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1910 if (!smi->proc_dir)
1911 rv = -ENOMEM;
1912 else {
1913 smi->proc_dir->owner = THIS_MODULE;
1914 }
1915
1916 if (rv == 0)
1917 rv = ipmi_smi_add_proc_entry(smi, "stats",
1918 stat_file_read_proc, NULL,
1919 smi, THIS_MODULE);
1920
1921 if (rv == 0)
1922 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1923 ipmb_file_read_proc, NULL,
1924 smi, THIS_MODULE);
1925
1926 if (rv == 0)
1927 rv = ipmi_smi_add_proc_entry(smi, "version",
1928 version_file_read_proc, NULL,
1929 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001930#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931
1932 return rv;
1933}
1934
1935static void remove_proc_entries(ipmi_smi_t smi)
1936{
Corey Minyard3b625942005-06-23 22:01:42 -07001937#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 struct ipmi_proc_entry *entry;
1939
Corey Minyardac019152007-10-18 03:07:11 -07001940 mutex_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 while (smi->proc_entries) {
1942 entry = smi->proc_entries;
1943 smi->proc_entries = entry->next;
1944
1945 remove_proc_entry(entry->name, smi->proc_dir);
1946 kfree(entry->name);
1947 kfree(entry);
1948 }
Corey Minyardac019152007-10-18 03:07:11 -07001949 mutex_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001951#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952}
1953
Corey Minyard50c812b2006-03-26 01:37:21 -08001954static int __find_bmc_guid(struct device *dev, void *data)
1955{
1956 unsigned char *id = data;
1957 struct bmc_device *bmc = dev_get_drvdata(dev);
1958 return memcmp(bmc->guid, id, 16) == 0;
1959}
1960
1961static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1962 unsigned char *guid)
1963{
1964 struct device *dev;
1965
1966 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1967 if (dev)
1968 return dev_get_drvdata(dev);
1969 else
1970 return NULL;
1971}
1972
1973struct prod_dev_id {
1974 unsigned int product_id;
1975 unsigned char device_id;
1976};
1977
1978static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1979{
1980 struct prod_dev_id *id = data;
1981 struct bmc_device *bmc = dev_get_drvdata(dev);
1982
1983 return (bmc->id.product_id == id->product_id
Corey Minyard50c812b2006-03-26 01:37:21 -08001984 && bmc->id.device_id == id->device_id);
1985}
1986
1987static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1988 struct device_driver *drv,
Corey Minyardf0b55da2006-12-06 20:40:54 -08001989 unsigned int product_id, unsigned char device_id)
Corey Minyard50c812b2006-03-26 01:37:21 -08001990{
1991 struct prod_dev_id id = {
1992 .product_id = product_id,
1993 .device_id = device_id,
1994 };
1995 struct device *dev;
1996
1997 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
1998 if (dev)
1999 return dev_get_drvdata(dev);
2000 else
2001 return NULL;
2002}
2003
2004static ssize_t device_id_show(struct device *dev,
2005 struct device_attribute *attr,
2006 char *buf)
2007{
2008 struct bmc_device *bmc = dev_get_drvdata(dev);
2009
2010 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
2011}
2012
2013static ssize_t provides_dev_sdrs_show(struct device *dev,
2014 struct device_attribute *attr,
2015 char *buf)
2016{
2017 struct bmc_device *bmc = dev_get_drvdata(dev);
2018
2019 return snprintf(buf, 10, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002020 (bmc->id.device_revision & 0x80) >> 7);
Corey Minyard50c812b2006-03-26 01:37:21 -08002021}
2022
2023static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
2024 char *buf)
2025{
2026 struct bmc_device *bmc = dev_get_drvdata(dev);
2027
2028 return snprintf(buf, 20, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002029 bmc->id.device_revision & 0x0F);
Corey Minyard50c812b2006-03-26 01:37:21 -08002030}
2031
2032static ssize_t firmware_rev_show(struct device *dev,
2033 struct device_attribute *attr,
2034 char *buf)
2035{
2036 struct bmc_device *bmc = dev_get_drvdata(dev);
2037
2038 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
2039 bmc->id.firmware_revision_2);
2040}
2041
2042static ssize_t ipmi_version_show(struct device *dev,
2043 struct device_attribute *attr,
2044 char *buf)
2045{
2046 struct bmc_device *bmc = dev_get_drvdata(dev);
2047
2048 return snprintf(buf, 20, "%u.%u\n",
2049 ipmi_version_major(&bmc->id),
2050 ipmi_version_minor(&bmc->id));
2051}
2052
2053static ssize_t add_dev_support_show(struct device *dev,
2054 struct device_attribute *attr,
2055 char *buf)
2056{
2057 struct bmc_device *bmc = dev_get_drvdata(dev);
2058
2059 return snprintf(buf, 10, "0x%02x\n",
2060 bmc->id.additional_device_support);
2061}
2062
2063static ssize_t manufacturer_id_show(struct device *dev,
2064 struct device_attribute *attr,
2065 char *buf)
2066{
2067 struct bmc_device *bmc = dev_get_drvdata(dev);
2068
2069 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
2070}
2071
2072static ssize_t product_id_show(struct device *dev,
2073 struct device_attribute *attr,
2074 char *buf)
2075{
2076 struct bmc_device *bmc = dev_get_drvdata(dev);
2077
2078 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
2079}
2080
2081static ssize_t aux_firmware_rev_show(struct device *dev,
2082 struct device_attribute *attr,
2083 char *buf)
2084{
2085 struct bmc_device *bmc = dev_get_drvdata(dev);
2086
2087 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
2088 bmc->id.aux_firmware_revision[3],
2089 bmc->id.aux_firmware_revision[2],
2090 bmc->id.aux_firmware_revision[1],
2091 bmc->id.aux_firmware_revision[0]);
2092}
2093
2094static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
2095 char *buf)
2096{
2097 struct bmc_device *bmc = dev_get_drvdata(dev);
2098
2099 return snprintf(buf, 100, "%Lx%Lx\n",
2100 (long long) bmc->guid[0],
2101 (long long) bmc->guid[8]);
2102}
2103
Jeff Garzik5e593932006-10-11 01:22:21 -07002104static void remove_files(struct bmc_device *bmc)
Corey Minyard50c812b2006-03-26 01:37:21 -08002105{
Corey Minyardf0b55da2006-12-06 20:40:54 -08002106 if (!bmc->dev)
2107 return;
2108
Corey Minyard50c812b2006-03-26 01:37:21 -08002109 device_remove_file(&bmc->dev->dev,
2110 &bmc->device_id_attr);
2111 device_remove_file(&bmc->dev->dev,
2112 &bmc->provides_dev_sdrs_attr);
2113 device_remove_file(&bmc->dev->dev,
2114 &bmc->revision_attr);
2115 device_remove_file(&bmc->dev->dev,
2116 &bmc->firmware_rev_attr);
2117 device_remove_file(&bmc->dev->dev,
2118 &bmc->version_attr);
2119 device_remove_file(&bmc->dev->dev,
2120 &bmc->add_dev_support_attr);
2121 device_remove_file(&bmc->dev->dev,
2122 &bmc->manufacturer_id_attr);
2123 device_remove_file(&bmc->dev->dev,
2124 &bmc->product_id_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002125
Corey Minyard50c812b2006-03-26 01:37:21 -08002126 if (bmc->id.aux_firmware_revision_set)
2127 device_remove_file(&bmc->dev->dev,
2128 &bmc->aux_firmware_rev_attr);
2129 if (bmc->guid_set)
2130 device_remove_file(&bmc->dev->dev,
2131 &bmc->guid_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002132}
2133
2134static void
2135cleanup_bmc_device(struct kref *ref)
2136{
2137 struct bmc_device *bmc;
2138
2139 bmc = container_of(ref, struct bmc_device, refcount);
2140
2141 remove_files(bmc);
Corey Minyard1d5636c2006-12-10 02:19:08 -08002142 platform_device_unregister(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002143 kfree(bmc);
2144}
2145
2146static void ipmi_bmc_unregister(ipmi_smi_t intf)
2147{
2148 struct bmc_device *bmc = intf->bmc;
2149
Corey Minyard759643b2006-12-06 20:40:59 -08002150 if (intf->sysfs_name) {
2151 sysfs_remove_link(&intf->si_dev->kobj, intf->sysfs_name);
2152 kfree(intf->sysfs_name);
2153 intf->sysfs_name = NULL;
2154 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002155 if (intf->my_dev_name) {
2156 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
2157 kfree(intf->my_dev_name);
2158 intf->my_dev_name = NULL;
2159 }
2160
2161 mutex_lock(&ipmidriver_mutex);
2162 kref_put(&bmc->refcount, cleanup_bmc_device);
Corey Minyardf0b55da2006-12-06 20:40:54 -08002163 intf->bmc = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002164 mutex_unlock(&ipmidriver_mutex);
2165}
2166
Jeff Garzik5e593932006-10-11 01:22:21 -07002167static int create_files(struct bmc_device *bmc)
2168{
2169 int err;
2170
Corey Minyardf0b55da2006-12-06 20:40:54 -08002171 bmc->device_id_attr.attr.name = "device_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002172 bmc->device_id_attr.attr.mode = S_IRUGO;
2173 bmc->device_id_attr.show = device_id_show;
2174
2175 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002176 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2177 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2178
2179 bmc->revision_attr.attr.name = "revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002180 bmc->revision_attr.attr.mode = S_IRUGO;
2181 bmc->revision_attr.show = revision_show;
2182
2183 bmc->firmware_rev_attr.attr.name = "firmware_revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002184 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2185 bmc->firmware_rev_attr.show = firmware_rev_show;
2186
2187 bmc->version_attr.attr.name = "ipmi_version";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002188 bmc->version_attr.attr.mode = S_IRUGO;
2189 bmc->version_attr.show = ipmi_version_show;
2190
2191 bmc->add_dev_support_attr.attr.name = "additional_device_support";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002192 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2193 bmc->add_dev_support_attr.show = add_dev_support_show;
2194
2195 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002196 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2197 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2198
2199 bmc->product_id_attr.attr.name = "product_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002200 bmc->product_id_attr.attr.mode = S_IRUGO;
2201 bmc->product_id_attr.show = product_id_show;
2202
2203 bmc->guid_attr.attr.name = "guid";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002204 bmc->guid_attr.attr.mode = S_IRUGO;
2205 bmc->guid_attr.show = guid_show;
2206
2207 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002208 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2209 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2210
Jeff Garzik5e593932006-10-11 01:22:21 -07002211 err = device_create_file(&bmc->dev->dev,
2212 &bmc->device_id_attr);
2213 if (err) goto out;
2214 err = device_create_file(&bmc->dev->dev,
2215 &bmc->provides_dev_sdrs_attr);
2216 if (err) goto out_devid;
2217 err = device_create_file(&bmc->dev->dev,
2218 &bmc->revision_attr);
2219 if (err) goto out_sdrs;
2220 err = device_create_file(&bmc->dev->dev,
2221 &bmc->firmware_rev_attr);
2222 if (err) goto out_rev;
2223 err = device_create_file(&bmc->dev->dev,
2224 &bmc->version_attr);
2225 if (err) goto out_firm;
2226 err = device_create_file(&bmc->dev->dev,
2227 &bmc->add_dev_support_attr);
2228 if (err) goto out_version;
2229 err = device_create_file(&bmc->dev->dev,
2230 &bmc->manufacturer_id_attr);
2231 if (err) goto out_add_dev;
2232 err = device_create_file(&bmc->dev->dev,
2233 &bmc->product_id_attr);
2234 if (err) goto out_manu;
2235 if (bmc->id.aux_firmware_revision_set) {
2236 err = device_create_file(&bmc->dev->dev,
2237 &bmc->aux_firmware_rev_attr);
2238 if (err) goto out_prod_id;
2239 }
2240 if (bmc->guid_set) {
2241 err = device_create_file(&bmc->dev->dev,
2242 &bmc->guid_attr);
2243 if (err) goto out_aux_firm;
2244 }
2245
2246 return 0;
2247
2248out_aux_firm:
2249 if (bmc->id.aux_firmware_revision_set)
2250 device_remove_file(&bmc->dev->dev,
2251 &bmc->aux_firmware_rev_attr);
2252out_prod_id:
2253 device_remove_file(&bmc->dev->dev,
2254 &bmc->product_id_attr);
2255out_manu:
2256 device_remove_file(&bmc->dev->dev,
2257 &bmc->manufacturer_id_attr);
2258out_add_dev:
2259 device_remove_file(&bmc->dev->dev,
2260 &bmc->add_dev_support_attr);
2261out_version:
2262 device_remove_file(&bmc->dev->dev,
2263 &bmc->version_attr);
2264out_firm:
2265 device_remove_file(&bmc->dev->dev,
2266 &bmc->firmware_rev_attr);
2267out_rev:
2268 device_remove_file(&bmc->dev->dev,
2269 &bmc->revision_attr);
2270out_sdrs:
2271 device_remove_file(&bmc->dev->dev,
2272 &bmc->provides_dev_sdrs_attr);
2273out_devid:
2274 device_remove_file(&bmc->dev->dev,
2275 &bmc->device_id_attr);
2276out:
2277 return err;
2278}
2279
Corey Minyard759643b2006-12-06 20:40:59 -08002280static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
2281 const char *sysfs_name)
Corey Minyard50c812b2006-03-26 01:37:21 -08002282{
2283 int rv;
2284 struct bmc_device *bmc = intf->bmc;
2285 struct bmc_device *old_bmc;
2286 int size;
2287 char dummy[1];
2288
2289 mutex_lock(&ipmidriver_mutex);
2290
2291 /*
2292 * Try to find if there is an bmc_device struct
2293 * representing the interfaced BMC already
2294 */
2295 if (bmc->guid_set)
2296 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
2297 else
2298 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
2299 bmc->id.product_id,
2300 bmc->id.device_id);
2301
2302 /*
2303 * If there is already an bmc_device, free the new one,
2304 * otherwise register the new BMC device
2305 */
2306 if (old_bmc) {
2307 kfree(bmc);
2308 intf->bmc = old_bmc;
2309 bmc = old_bmc;
2310
2311 kref_get(&bmc->refcount);
2312 mutex_unlock(&ipmidriver_mutex);
2313
2314 printk(KERN_INFO
2315 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
2316 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2317 bmc->id.manufacturer_id,
2318 bmc->id.product_id,
2319 bmc->id.device_id);
2320 } else {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002321 char name[14];
2322 unsigned char orig_dev_id = bmc->id.device_id;
2323 int warn_printed = 0;
2324
2325 snprintf(name, sizeof(name),
2326 "ipmi_bmc.%4.4x", bmc->id.product_id);
2327
2328 while (ipmi_find_bmc_prod_dev_id(&ipmidriver,
2329 bmc->id.product_id,
Corey Minyard1d5636c2006-12-10 02:19:08 -08002330 bmc->id.device_id)) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002331 if (!warn_printed) {
2332 printk(KERN_WARNING PFX
2333 "This machine has two different BMCs"
2334 " with the same product id and device"
2335 " id. This is an error in the"
2336 " firmware, but incrementing the"
2337 " device id to work around the problem."
2338 " Prod ID = 0x%x, Dev ID = 0x%x\n",
2339 bmc->id.product_id, bmc->id.device_id);
2340 warn_printed = 1;
2341 }
2342 bmc->id.device_id++; /* Wraps at 255 */
2343 if (bmc->id.device_id == orig_dev_id) {
2344 printk(KERN_ERR PFX
2345 "Out of device ids!\n");
2346 break;
2347 }
2348 }
2349
2350 bmc->dev = platform_device_alloc(name, bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08002351 if (!bmc->dev) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002352 mutex_unlock(&ipmidriver_mutex);
Corey Minyard50c812b2006-03-26 01:37:21 -08002353 printk(KERN_ERR
2354 "ipmi_msghandler:"
2355 " Unable to allocate platform device\n");
2356 return -ENOMEM;
2357 }
2358 bmc->dev->dev.driver = &ipmidriver;
2359 dev_set_drvdata(&bmc->dev->dev, bmc);
2360 kref_init(&bmc->refcount);
2361
Zhang, Yanminb48f5452006-11-16 01:19:08 -08002362 rv = platform_device_add(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002363 mutex_unlock(&ipmidriver_mutex);
2364 if (rv) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002365 platform_device_put(bmc->dev);
2366 bmc->dev = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002367 printk(KERN_ERR
2368 "ipmi_msghandler:"
2369 " Unable to register bmc device: %d\n",
2370 rv);
2371 /* Don't go to out_err, you can only do that if
2372 the device is registered already. */
2373 return rv;
2374 }
2375
Jeff Garzik5e593932006-10-11 01:22:21 -07002376 rv = create_files(bmc);
2377 if (rv) {
2378 mutex_lock(&ipmidriver_mutex);
2379 platform_device_unregister(bmc->dev);
2380 mutex_unlock(&ipmidriver_mutex);
2381
2382 return rv;
2383 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002384
2385 printk(KERN_INFO
2386 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2387 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2388 bmc->id.manufacturer_id,
2389 bmc->id.product_id,
2390 bmc->id.device_id);
2391 }
2392
2393 /*
2394 * create symlink from system interface device to bmc device
2395 * and back.
2396 */
Corey Minyard759643b2006-12-06 20:40:59 -08002397 intf->sysfs_name = kstrdup(sysfs_name, GFP_KERNEL);
2398 if (!intf->sysfs_name) {
2399 rv = -ENOMEM;
2400 printk(KERN_ERR
2401 "ipmi_msghandler: allocate link to BMC: %d\n",
2402 rv);
2403 goto out_err;
2404 }
2405
Corey Minyard50c812b2006-03-26 01:37:21 -08002406 rv = sysfs_create_link(&intf->si_dev->kobj,
Corey Minyard759643b2006-12-06 20:40:59 -08002407 &bmc->dev->dev.kobj, intf->sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002408 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002409 kfree(intf->sysfs_name);
2410 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002411 printk(KERN_ERR
2412 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2413 rv);
2414 goto out_err;
2415 }
2416
Corey Minyard759643b2006-12-06 20:40:59 -08002417 size = snprintf(dummy, 0, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002418 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2419 if (!intf->my_dev_name) {
Corey Minyard759643b2006-12-06 20:40:59 -08002420 kfree(intf->sysfs_name);
2421 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002422 rv = -ENOMEM;
2423 printk(KERN_ERR
2424 "ipmi_msghandler: allocate link from BMC: %d\n",
2425 rv);
2426 goto out_err;
2427 }
Corey Minyard759643b2006-12-06 20:40:59 -08002428 snprintf(intf->my_dev_name, size+1, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002429
2430 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2431 intf->my_dev_name);
2432 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002433 kfree(intf->sysfs_name);
2434 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002435 kfree(intf->my_dev_name);
2436 intf->my_dev_name = NULL;
2437 printk(KERN_ERR
2438 "ipmi_msghandler:"
2439 " Unable to create symlink to bmc: %d\n",
2440 rv);
2441 goto out_err;
2442 }
2443
2444 return 0;
2445
2446out_err:
2447 ipmi_bmc_unregister(intf);
2448 return rv;
2449}
2450
2451static int
2452send_guid_cmd(ipmi_smi_t intf, int chan)
2453{
2454 struct kernel_ipmi_msg msg;
2455 struct ipmi_system_interface_addr si;
2456
2457 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2458 si.channel = IPMI_BMC_CHANNEL;
2459 si.lun = 0;
2460
2461 msg.netfn = IPMI_NETFN_APP_REQUEST;
2462 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2463 msg.data = NULL;
2464 msg.data_len = 0;
2465 return i_ipmi_request(NULL,
2466 intf,
2467 (struct ipmi_addr *) &si,
2468 0,
2469 &msg,
2470 intf,
2471 NULL,
2472 NULL,
2473 0,
2474 intf->channels[0].address,
2475 intf->channels[0].lun,
2476 -1, 0);
2477}
2478
2479static void
2480guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2481{
2482 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2483 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2484 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2485 /* Not for me */
2486 return;
2487
2488 if (msg->msg.data[0] != 0) {
2489 /* Error from getting the GUID, the BMC doesn't have one. */
2490 intf->bmc->guid_set = 0;
2491 goto out;
2492 }
2493
2494 if (msg->msg.data_len < 17) {
2495 intf->bmc->guid_set = 0;
2496 printk(KERN_WARNING PFX
2497 "guid_handler: The GUID response from the BMC was too"
2498 " short, it was %d but should have been 17. Assuming"
2499 " GUID is not available.\n",
2500 msg->msg.data_len);
2501 goto out;
2502 }
2503
2504 memcpy(intf->bmc->guid, msg->msg.data, 16);
2505 intf->bmc->guid_set = 1;
2506 out:
2507 wake_up(&intf->waitq);
2508}
2509
2510static void
2511get_guid(ipmi_smi_t intf)
2512{
2513 int rv;
2514
2515 intf->bmc->guid_set = 0x2;
2516 intf->null_user_handler = guid_handler;
2517 rv = send_guid_cmd(intf, 0);
2518 if (rv)
2519 /* Send failed, no GUID available. */
2520 intf->bmc->guid_set = 0;
2521 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2522 intf->null_user_handler = NULL;
2523}
2524
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525static int
2526send_channel_info_cmd(ipmi_smi_t intf, int chan)
2527{
2528 struct kernel_ipmi_msg msg;
2529 unsigned char data[1];
2530 struct ipmi_system_interface_addr si;
2531
2532 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2533 si.channel = IPMI_BMC_CHANNEL;
2534 si.lun = 0;
2535
2536 msg.netfn = IPMI_NETFN_APP_REQUEST;
2537 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2538 msg.data = data;
2539 msg.data_len = 1;
2540 data[0] = chan;
2541 return i_ipmi_request(NULL,
2542 intf,
2543 (struct ipmi_addr *) &si,
2544 0,
2545 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002546 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 NULL,
2548 NULL,
2549 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002550 intf->channels[0].address,
2551 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 -1, 0);
2553}
2554
2555static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002556channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557{
2558 int rv = 0;
2559 int chan;
2560
Corey Minyard56a55ec2005-09-06 15:18:42 -07002561 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2562 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2563 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 {
2565 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002566 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 /* Got an error from the channel, just go on. */
2568
Corey Minyard56a55ec2005-09-06 15:18:42 -07002569 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 /* If the MC does not support this
2571 command, that is legal. We just
2572 assume it has one IPMB at channel
2573 zero. */
2574 intf->channels[0].medium
2575 = IPMI_CHANNEL_MEDIUM_IPMB;
2576 intf->channels[0].protocol
2577 = IPMI_CHANNEL_PROTOCOL_IPMB;
2578 rv = -ENOSYS;
2579
2580 intf->curr_channel = IPMI_MAX_CHANNELS;
2581 wake_up(&intf->waitq);
2582 goto out;
2583 }
2584 goto next_channel;
2585 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002586 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 /* Message not big enough, just go on. */
2588 goto next_channel;
2589 }
2590 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002591 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2592 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
2594 next_channel:
2595 intf->curr_channel++;
2596 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2597 wake_up(&intf->waitq);
2598 else
2599 rv = send_channel_info_cmd(intf, intf->curr_channel);
2600
2601 if (rv) {
2602 /* Got an error somehow, just give up. */
2603 intf->curr_channel = IPMI_MAX_CHANNELS;
2604 wake_up(&intf->waitq);
2605
2606 printk(KERN_WARNING PFX
2607 "Error sending channel information: %d\n",
2608 rv);
2609 }
2610 }
2611 out:
2612 return;
2613}
2614
Corey Minyardfcfa4722007-10-18 03:07:09 -07002615void ipmi_poll_interface(ipmi_user_t user)
2616{
2617 ipmi_smi_t intf = user->intf;
2618
2619 if (intf->handlers->poll)
2620 intf->handlers->poll(intf->send_info);
2621}
2622
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2624 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002625 struct ipmi_device_id *device_id,
2626 struct device *si_dev,
Corey Minyard759643b2006-12-06 20:40:59 -08002627 const char *sysfs_name,
Corey Minyard453823b2006-03-31 02:30:39 -08002628 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629{
2630 int i, j;
2631 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002632 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -08002633 ipmi_smi_t tintf;
Corey Minyardbca03242006-12-06 20:40:57 -08002634 struct list_head *link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 /* Make sure the driver is actually initialized, this handles
2637 problems with initialization order. */
2638 if (!initialized) {
2639 rv = ipmi_init_msghandler();
2640 if (rv)
2641 return rv;
2642 /* The init code doesn't return an error if it was turned
2643 off, but it won't initialize. Check that. */
2644 if (!initialized)
2645 return -ENODEV;
2646 }
2647
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07002648 intf = kzalloc(sizeof(*intf), GFP_KERNEL);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002649 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 return -ENOMEM;
Corey Minyardb2c03942006-12-06 20:41:00 -08002651
2652 intf->ipmi_version_major = ipmi_version_major(device_id);
2653 intf->ipmi_version_minor = ipmi_version_minor(device_id);
2654
Corey Minyard50c812b2006-03-26 01:37:21 -08002655 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2656 if (!intf->bmc) {
2657 kfree(intf);
2658 return -ENOMEM;
2659 }
Corey Minyardbca03242006-12-06 20:40:57 -08002660 intf->intf_num = -1; /* Mark it invalid for now. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002661 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002662 intf->bmc->id = *device_id;
2663 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002664 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2665 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2666 intf->channels[j].lun = 2;
2667 }
2668 if (slave_addr != 0)
2669 intf->channels[0].address = slave_addr;
2670 INIT_LIST_HEAD(&intf->users);
2671 intf->handlers = handlers;
2672 intf->send_info = send_info;
2673 spin_lock_init(&intf->seq_lock);
2674 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2675 intf->seq_table[j].inuse = 0;
2676 intf->seq_table[j].seqid = 0;
2677 }
2678 intf->curr_seq = 0;
2679#ifdef CONFIG_PROC_FS
Corey Minyardac019152007-10-18 03:07:11 -07002680 mutex_init(&intf->proc_entry_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002681#endif
2682 spin_lock_init(&intf->waiting_msgs_lock);
2683 INIT_LIST_HEAD(&intf->waiting_msgs);
2684 spin_lock_init(&intf->events_lock);
2685 INIT_LIST_HEAD(&intf->waiting_events);
2686 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002687 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyardb9675132006-12-06 20:41:02 -08002688 spin_lock_init(&intf->maintenance_mode_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002689 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2690 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
Corey Minyard393d2cc2005-11-07 00:59:54 -08002692 spin_lock_init(&intf->counter_lock);
2693 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694
Corey Minyardb2c03942006-12-06 20:41:00 -08002695 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002696 mutex_lock(&ipmi_interfaces_mutex);
2697 /* Look for a hole in the numbers. */
2698 i = 0;
2699 link = &ipmi_interfaces;
2700 list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) {
2701 if (tintf->intf_num != i) {
2702 link = &tintf->link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 break;
2704 }
Corey Minyardbca03242006-12-06 20:40:57 -08002705 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 }
Corey Minyardbca03242006-12-06 20:40:57 -08002707 /* Add the new interface in numeric order. */
2708 if (i == 0)
2709 list_add_rcu(&intf->link, &ipmi_interfaces);
2710 else
2711 list_add_tail_rcu(&intf->link, link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
Corey Minyard453823b2006-03-31 02:30:39 -08002713 rv = handlers->start_processing(send_info, intf);
2714 if (rv)
2715 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002716
Corey Minyard50c812b2006-03-26 01:37:21 -08002717 get_guid(intf);
2718
Corey Minyardb2c03942006-12-06 20:41:00 -08002719 if ((intf->ipmi_version_major > 1)
2720 || ((intf->ipmi_version_major == 1)
2721 && (intf->ipmi_version_minor >= 5)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08002722 {
2723 /* Start scanning the channels to see what is
2724 available. */
2725 intf->null_user_handler = channel_handler;
2726 intf->curr_channel = 0;
2727 rv = send_channel_info_cmd(intf, 0);
2728 if (rv)
2729 goto out;
2730
2731 /* Wait for the channel info to be read. */
2732 wait_event(intf->waitq,
2733 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002734 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002735 } else {
2736 /* Assume a single IPMB channel at zero. */
2737 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2738 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740
2741 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002742 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
Corey Minyard759643b2006-12-06 20:40:59 -08002744 rv = ipmi_bmc_register(intf, i, sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002745
Corey Minyard393d2cc2005-11-07 00:59:54 -08002746 out:
2747 if (rv) {
2748 if (intf->proc_dir)
2749 remove_proc_entries(intf);
Corey Minyardb2c03942006-12-06 20:41:00 -08002750 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002751 list_del_rcu(&intf->link);
2752 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002753 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002754 synchronize_rcu();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002755 kref_put(&intf->refcount, intf_free);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002756 } else {
Corey Minyard78ba2fa2007-02-10 01:45:45 -08002757 /*
2758 * Keep memory order straight for RCU readers. Make
2759 * sure everything else is committed to memory before
2760 * setting intf_num to mark the interface valid.
2761 */
2762 smp_wmb();
Corey Minyardbca03242006-12-06 20:40:57 -08002763 intf->intf_num = i;
2764 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard78ba2fa2007-02-10 01:45:45 -08002765 /* After this point the interface is legal to use. */
Corey Minyard50c812b2006-03-26 01:37:21 -08002766 call_smi_watchers(i, intf->si_dev);
Corey Minyardb2c03942006-12-06 20:41:00 -08002767 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 }
2769
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 return rv;
2771}
2772
Corey Minyardb2c03942006-12-06 20:41:00 -08002773static void cleanup_smi_msgs(ipmi_smi_t intf)
2774{
2775 int i;
2776 struct seq_table *ent;
2777
2778 /* No need for locks, the interface is down. */
2779 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
2780 ent = &(intf->seq_table[i]);
2781 if (!ent->inuse)
2782 continue;
2783 deliver_err_response(ent->recv_msg, IPMI_ERR_UNSPECIFIED);
2784 }
2785}
2786
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787int ipmi_unregister_smi(ipmi_smi_t intf)
2788{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 struct ipmi_smi_watcher *w;
Corey Minyardb2c03942006-12-06 20:41:00 -08002790 int intf_num = intf->intf_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791
Corey Minyard50c812b2006-03-26 01:37:21 -08002792 ipmi_bmc_unregister(intf);
2793
Corey Minyardb2c03942006-12-06 20:41:00 -08002794 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002795 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002796 intf->intf_num = -1;
2797 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002798 list_del_rcu(&intf->link);
2799 mutex_unlock(&ipmi_interfaces_mutex);
2800 synchronize_rcu();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
Corey Minyardb2c03942006-12-06 20:41:00 -08002802 cleanup_smi_msgs(intf);
2803
Corey Minyard393d2cc2005-11-07 00:59:54 -08002804 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805
2806 /* Call all the watcher interfaces to tell them that
2807 an interface is gone. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002808 list_for_each_entry(w, &smi_watchers, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08002809 w->smi_gone(intf_num);
2810 mutex_unlock(&smi_watchers_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002811
Corey Minyard393d2cc2005-11-07 00:59:54 -08002812 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 return 0;
2814}
2815
2816static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2817 struct ipmi_smi_msg *msg)
2818{
2819 struct ipmi_ipmb_addr ipmb_addr;
2820 struct ipmi_recv_msg *recv_msg;
2821 unsigned long flags;
2822
2823
2824 /* This is 11, not 10, because the response must contain a
2825 * completion code. */
2826 if (msg->rsp_size < 11) {
2827 /* Message not big enough, just ignore it. */
2828 spin_lock_irqsave(&intf->counter_lock, flags);
2829 intf->invalid_ipmb_responses++;
2830 spin_unlock_irqrestore(&intf->counter_lock, flags);
2831 return 0;
2832 }
2833
2834 if (msg->rsp[2] != 0) {
2835 /* An error getting the response, just ignore it. */
2836 return 0;
2837 }
2838
2839 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
2840 ipmb_addr.slave_addr = msg->rsp[6];
2841 ipmb_addr.channel = msg->rsp[3] & 0x0f;
2842 ipmb_addr.lun = msg->rsp[7] & 3;
2843
2844 /* It's a response from a remote entity. Look up the sequence
2845 number and handle the response. */
2846 if (intf_find_seq(intf,
2847 msg->rsp[7] >> 2,
2848 msg->rsp[3] & 0x0f,
2849 msg->rsp[8],
2850 (msg->rsp[4] >> 2) & (~1),
2851 (struct ipmi_addr *) &(ipmb_addr),
2852 &recv_msg))
2853 {
2854 /* We were unable to find the sequence number,
2855 so just nuke the message. */
2856 spin_lock_irqsave(&intf->counter_lock, flags);
2857 intf->unhandled_ipmb_responses++;
2858 spin_unlock_irqrestore(&intf->counter_lock, flags);
2859 return 0;
2860 }
2861
2862 memcpy(recv_msg->msg_data,
2863 &(msg->rsp[9]),
2864 msg->rsp_size - 9);
2865 /* THe other fields matched, so no need to set them, except
2866 for netfn, which needs to be the response that was
2867 returned, not the request value. */
2868 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2869 recv_msg->msg.data = recv_msg->msg_data;
2870 recv_msg->msg.data_len = msg->rsp_size - 10;
2871 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2872 spin_lock_irqsave(&intf->counter_lock, flags);
2873 intf->handled_ipmb_responses++;
2874 spin_unlock_irqrestore(&intf->counter_lock, flags);
2875 deliver_response(recv_msg);
2876
2877 return 0;
2878}
2879
2880static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2881 struct ipmi_smi_msg *msg)
2882{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002883 struct cmd_rcvr *rcvr;
2884 int rv = 0;
2885 unsigned char netfn;
2886 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002887 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002888 ipmi_user_t user = NULL;
2889 struct ipmi_ipmb_addr *ipmb_addr;
2890 struct ipmi_recv_msg *recv_msg;
2891 unsigned long flags;
Corey Minyardb2c03942006-12-06 20:41:00 -08002892 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893
2894 if (msg->rsp_size < 10) {
2895 /* Message not big enough, just ignore it. */
2896 spin_lock_irqsave(&intf->counter_lock, flags);
2897 intf->invalid_commands++;
2898 spin_unlock_irqrestore(&intf->counter_lock, flags);
2899 return 0;
2900 }
2901
2902 if (msg->rsp[2] != 0) {
2903 /* An error getting the response, just ignore it. */
2904 return 0;
2905 }
2906
2907 netfn = msg->rsp[4] >> 2;
2908 cmd = msg->rsp[8];
Corey Minyardc69c3122006-09-30 23:27:56 -07002909 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002911 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002912 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002913 if (rcvr) {
2914 user = rcvr->user;
2915 kref_get(&user->refcount);
2916 } else
2917 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002918 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
2920 if (user == NULL) {
2921 /* We didn't find a user, deliver an error response. */
2922 spin_lock_irqsave(&intf->counter_lock, flags);
2923 intf->unhandled_commands++;
2924 spin_unlock_irqrestore(&intf->counter_lock, flags);
2925
2926 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2927 msg->data[1] = IPMI_SEND_MSG_CMD;
2928 msg->data[2] = msg->rsp[3];
2929 msg->data[3] = msg->rsp[6];
2930 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2931 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002932 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 /* rqseq/lun */
2934 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2935 msg->data[8] = msg->rsp[8]; /* cmd */
2936 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2937 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2938 msg->data_size = 11;
2939
2940#ifdef DEBUG_MSGING
2941 {
2942 int m;
2943 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002944 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 printk(" %2.2x", msg->data[m]);
2946 printk("\n");
2947 }
2948#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08002949 rcu_read_lock();
2950 handlers = intf->handlers;
2951 if (handlers) {
2952 handlers->sender(intf->send_info, msg, 0);
2953 /* We used the message, so return the value
2954 that causes it to not be freed or
2955 queued. */
2956 rv = -1;
2957 }
2958 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 } else {
2960 /* Deliver the message to the user. */
2961 spin_lock_irqsave(&intf->counter_lock, flags);
2962 intf->handled_commands++;
2963 spin_unlock_irqrestore(&intf->counter_lock, flags);
2964
2965 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002966 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 /* We couldn't allocate memory for the
2968 message, so requeue it for handling
2969 later. */
2970 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002971 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 } else {
2973 /* Extract the source address from the data. */
2974 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2975 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2976 ipmb_addr->slave_addr = msg->rsp[6];
2977 ipmb_addr->lun = msg->rsp[7] & 3;
2978 ipmb_addr->channel = msg->rsp[3] & 0xf;
2979
2980 /* Extract the rest of the message information
2981 from the IPMB header.*/
2982 recv_msg->user = user;
2983 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2984 recv_msg->msgid = msg->rsp[7] >> 2;
2985 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2986 recv_msg->msg.cmd = msg->rsp[8];
2987 recv_msg->msg.data = recv_msg->msg_data;
2988
2989 /* We chop off 10, not 9 bytes because the checksum
2990 at the end also needs to be removed. */
2991 recv_msg->msg.data_len = msg->rsp_size - 10;
2992 memcpy(recv_msg->msg_data,
2993 &(msg->rsp[9]),
2994 msg->rsp_size - 10);
2995 deliver_response(recv_msg);
2996 }
2997 }
2998
2999 return rv;
3000}
3001
3002static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
3003 struct ipmi_smi_msg *msg)
3004{
3005 struct ipmi_lan_addr lan_addr;
3006 struct ipmi_recv_msg *recv_msg;
3007 unsigned long flags;
3008
3009
3010 /* This is 13, not 12, because the response must contain a
3011 * completion code. */
3012 if (msg->rsp_size < 13) {
3013 /* Message not big enough, just ignore it. */
3014 spin_lock_irqsave(&intf->counter_lock, flags);
3015 intf->invalid_lan_responses++;
3016 spin_unlock_irqrestore(&intf->counter_lock, flags);
3017 return 0;
3018 }
3019
3020 if (msg->rsp[2] != 0) {
3021 /* An error getting the response, just ignore it. */
3022 return 0;
3023 }
3024
3025 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
3026 lan_addr.session_handle = msg->rsp[4];
3027 lan_addr.remote_SWID = msg->rsp[8];
3028 lan_addr.local_SWID = msg->rsp[5];
3029 lan_addr.channel = msg->rsp[3] & 0x0f;
3030 lan_addr.privilege = msg->rsp[3] >> 4;
3031 lan_addr.lun = msg->rsp[9] & 3;
3032
3033 /* It's a response from a remote entity. Look up the sequence
3034 number and handle the response. */
3035 if (intf_find_seq(intf,
3036 msg->rsp[9] >> 2,
3037 msg->rsp[3] & 0x0f,
3038 msg->rsp[10],
3039 (msg->rsp[6] >> 2) & (~1),
3040 (struct ipmi_addr *) &(lan_addr),
3041 &recv_msg))
3042 {
3043 /* We were unable to find the sequence number,
3044 so just nuke the message. */
3045 spin_lock_irqsave(&intf->counter_lock, flags);
3046 intf->unhandled_lan_responses++;
3047 spin_unlock_irqrestore(&intf->counter_lock, flags);
3048 return 0;
3049 }
3050
3051 memcpy(recv_msg->msg_data,
3052 &(msg->rsp[11]),
3053 msg->rsp_size - 11);
3054 /* The other fields matched, so no need to set them, except
3055 for netfn, which needs to be the response that was
3056 returned, not the request value. */
3057 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3058 recv_msg->msg.data = recv_msg->msg_data;
3059 recv_msg->msg.data_len = msg->rsp_size - 12;
3060 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3061 spin_lock_irqsave(&intf->counter_lock, flags);
3062 intf->handled_lan_responses++;
3063 spin_unlock_irqrestore(&intf->counter_lock, flags);
3064 deliver_response(recv_msg);
3065
3066 return 0;
3067}
3068
3069static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
3070 struct ipmi_smi_msg *msg)
3071{
Corey Minyard393d2cc2005-11-07 00:59:54 -08003072 struct cmd_rcvr *rcvr;
3073 int rv = 0;
3074 unsigned char netfn;
3075 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07003076 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003077 ipmi_user_t user = NULL;
3078 struct ipmi_lan_addr *lan_addr;
3079 struct ipmi_recv_msg *recv_msg;
3080 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081
3082 if (msg->rsp_size < 12) {
3083 /* Message not big enough, just ignore it. */
3084 spin_lock_irqsave(&intf->counter_lock, flags);
3085 intf->invalid_commands++;
3086 spin_unlock_irqrestore(&intf->counter_lock, flags);
3087 return 0;
3088 }
3089
3090 if (msg->rsp[2] != 0) {
3091 /* An error getting the response, just ignore it. */
3092 return 0;
3093 }
3094
3095 netfn = msg->rsp[6] >> 2;
3096 cmd = msg->rsp[10];
Corey Minyardc69c3122006-09-30 23:27:56 -07003097 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003099 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07003100 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003101 if (rcvr) {
3102 user = rcvr->user;
3103 kref_get(&user->refcount);
3104 } else
3105 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003106 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
3108 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003109 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 spin_lock_irqsave(&intf->counter_lock, flags);
3111 intf->unhandled_commands++;
3112 spin_unlock_irqrestore(&intf->counter_lock, flags);
3113
3114 rv = 0; /* Don't do anything with these messages, just
3115 allow them to be freed. */
3116 } else {
3117 /* Deliver the message to the user. */
3118 spin_lock_irqsave(&intf->counter_lock, flags);
3119 intf->handled_commands++;
3120 spin_unlock_irqrestore(&intf->counter_lock, flags);
3121
3122 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003123 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 /* We couldn't allocate memory for the
3125 message, so requeue it for handling
3126 later. */
3127 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003128 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 } else {
3130 /* Extract the source address from the data. */
3131 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
3132 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
3133 lan_addr->session_handle = msg->rsp[4];
3134 lan_addr->remote_SWID = msg->rsp[8];
3135 lan_addr->local_SWID = msg->rsp[5];
3136 lan_addr->lun = msg->rsp[9] & 3;
3137 lan_addr->channel = msg->rsp[3] & 0xf;
3138 lan_addr->privilege = msg->rsp[3] >> 4;
3139
3140 /* Extract the rest of the message information
3141 from the IPMB header.*/
3142 recv_msg->user = user;
3143 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
3144 recv_msg->msgid = msg->rsp[9] >> 2;
3145 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3146 recv_msg->msg.cmd = msg->rsp[10];
3147 recv_msg->msg.data = recv_msg->msg_data;
3148
3149 /* We chop off 12, not 11 bytes because the checksum
3150 at the end also needs to be removed. */
3151 recv_msg->msg.data_len = msg->rsp_size - 12;
3152 memcpy(recv_msg->msg_data,
3153 &(msg->rsp[11]),
3154 msg->rsp_size - 12);
3155 deliver_response(recv_msg);
3156 }
3157 }
3158
3159 return rv;
3160}
3161
3162static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
3163 struct ipmi_smi_msg *msg)
3164{
3165 struct ipmi_system_interface_addr *smi_addr;
3166
3167 recv_msg->msgid = 0;
3168 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
3169 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3170 smi_addr->channel = IPMI_BMC_CHANNEL;
3171 smi_addr->lun = msg->rsp[0] & 3;
3172 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
3173 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3174 recv_msg->msg.cmd = msg->rsp[1];
3175 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
3176 recv_msg->msg.data = recv_msg->msg_data;
3177 recv_msg->msg.data_len = msg->rsp_size - 3;
3178}
3179
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180static int handle_read_event_rsp(ipmi_smi_t intf,
3181 struct ipmi_smi_msg *msg)
3182{
3183 struct ipmi_recv_msg *recv_msg, *recv_msg2;
3184 struct list_head msgs;
3185 ipmi_user_t user;
3186 int rv = 0;
3187 int deliver_count = 0;
3188 unsigned long flags;
3189
3190 if (msg->rsp_size < 19) {
3191 /* Message is too small to be an IPMB event. */
3192 spin_lock_irqsave(&intf->counter_lock, flags);
3193 intf->invalid_events++;
3194 spin_unlock_irqrestore(&intf->counter_lock, flags);
3195 return 0;
3196 }
3197
3198 if (msg->rsp[2] != 0) {
3199 /* An error getting the event, just ignore it. */
3200 return 0;
3201 }
3202
3203 INIT_LIST_HEAD(&msgs);
3204
Corey Minyard393d2cc2005-11-07 00:59:54 -08003205 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206
3207 spin_lock(&intf->counter_lock);
3208 intf->events++;
3209 spin_unlock(&intf->counter_lock);
3210
3211 /* Allocate and fill in one message for every user that is getting
3212 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003213 rcu_read_lock();
3214 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003215 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 continue;
3217
3218 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003219 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003220 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003221 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
3222 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 list_del(&recv_msg->link);
3224 ipmi_free_recv_msg(recv_msg);
3225 }
3226 /* We couldn't allocate memory for the
3227 message, so requeue it for handling
3228 later. */
3229 rv = 1;
3230 goto out;
3231 }
3232
3233 deliver_count++;
3234
3235 copy_event_into_recv_msg(recv_msg, msg);
3236 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003237 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 list_add_tail(&(recv_msg->link), &msgs);
3239 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003240 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
3242 if (deliver_count) {
3243 /* Now deliver all the messages. */
3244 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
3245 list_del(&recv_msg->link);
3246 deliver_response(recv_msg);
3247 }
3248 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
3249 /* No one to receive the message, put it in queue if there's
3250 not already too many things in the queue. */
3251 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003252 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 /* We couldn't allocate memory for the
3254 message, so requeue it for handling
3255 later. */
3256 rv = 1;
3257 goto out;
3258 }
3259
3260 copy_event_into_recv_msg(recv_msg, msg);
3261 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
Corey Minyard4791c032006-04-10 22:54:31 -07003262 intf->waiting_events_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 } else {
3264 /* There's too many things in the queue, discard this
3265 message. */
3266 printk(KERN_WARNING PFX "Event queue full, discarding an"
3267 " incoming event\n");
3268 }
3269
3270 out:
3271 spin_unlock_irqrestore(&(intf->events_lock), flags);
3272
3273 return rv;
3274}
3275
3276static int handle_bmc_rsp(ipmi_smi_t intf,
3277 struct ipmi_smi_msg *msg)
3278{
3279 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003281 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
3283 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07003284 if (recv_msg == NULL)
3285 {
3286 printk(KERN_WARNING"IPMI message received with no owner. This\n"
3287 "could be because of a malformed message, or\n"
3288 "because of a hardware error. Contact your\n"
3289 "hardware vender for assistance\n");
3290 return 0;
3291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
Corey Minyard393d2cc2005-11-07 00:59:54 -08003293 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003295 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07003296 /* The user for the message went away, so give up. */
3297 spin_lock_irqsave(&intf->counter_lock, flags);
3298 intf->unhandled_local_responses++;
3299 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 ipmi_free_recv_msg(recv_msg);
3301 } else {
3302 struct ipmi_system_interface_addr *smi_addr;
3303
3304 spin_lock_irqsave(&intf->counter_lock, flags);
3305 intf->handled_local_responses++;
3306 spin_unlock_irqrestore(&intf->counter_lock, flags);
3307 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3308 recv_msg->msgid = msg->msgid;
3309 smi_addr = ((struct ipmi_system_interface_addr *)
3310 &(recv_msg->addr));
3311 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3312 smi_addr->channel = IPMI_BMC_CHANNEL;
3313 smi_addr->lun = msg->rsp[0] & 3;
3314 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3315 recv_msg->msg.cmd = msg->rsp[1];
3316 memcpy(recv_msg->msg_data,
3317 &(msg->rsp[2]),
3318 msg->rsp_size - 2);
3319 recv_msg->msg.data = recv_msg->msg_data;
3320 recv_msg->msg.data_len = msg->rsp_size - 2;
3321 deliver_response(recv_msg);
3322 }
3323
3324 return 0;
3325}
3326
3327/* Handle a new message. Return 1 if the message should be requeued,
3328 0 if the message should be freed, or -1 if the message should not
3329 be freed or requeued. */
3330static int handle_new_recv_msg(ipmi_smi_t intf,
3331 struct ipmi_smi_msg *msg)
3332{
3333 int requeue;
3334 int chan;
3335
3336#ifdef DEBUG_MSGING
3337 int m;
3338 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07003339 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 printk(" %2.2x", msg->rsp[m]);
3341 printk("\n");
3342#endif
3343 if (msg->rsp_size < 2) {
3344 /* Message is too small to be correct. */
3345 printk(KERN_WARNING PFX "BMC returned to small a message"
3346 " for netfn %x cmd %x, got %d bytes\n",
3347 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3348
3349 /* Generate an error response for the message. */
3350 msg->rsp[0] = msg->data[0] | (1 << 2);
3351 msg->rsp[1] = msg->data[1];
3352 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3353 msg->rsp_size = 3;
3354 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3355 || (msg->rsp[1] != msg->data[1])) /* Command */
3356 {
3357 /* The response is not even marginally correct. */
3358 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3359 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3360 (msg->data[0] >> 2) | 1, msg->data[1],
3361 msg->rsp[0] >> 2, msg->rsp[1]);
3362
3363 /* Generate an error response for the message. */
3364 msg->rsp[0] = msg->data[0] | (1 << 2);
3365 msg->rsp[1] = msg->data[1];
3366 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3367 msg->rsp_size = 3;
3368 }
3369
3370 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3371 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3372 && (msg->user_data != NULL))
3373 {
3374 /* It's a response to a response we sent. For this we
3375 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003376 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377
3378 requeue = 0;
3379 if (msg->rsp_size < 2)
3380 /* Message is too small to be correct. */
3381 goto out;
3382
3383 chan = msg->data[2] & 0x0f;
3384 if (chan >= IPMI_MAX_CHANNELS)
3385 /* Invalid channel number */
3386 goto out;
3387
Corey Minyard393d2cc2005-11-07 00:59:54 -08003388 if (!recv_msg)
3389 goto out;
3390
3391 /* Make sure the user still exists. */
3392 if (!recv_msg->user || !recv_msg->user->valid)
3393 goto out;
3394
3395 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3396 recv_msg->msg.data = recv_msg->msg_data;
3397 recv_msg->msg.data_len = 1;
3398 recv_msg->msg_data[0] = msg->rsp[2];
3399 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3401 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3402 {
3403 /* It's from the receive queue. */
3404 chan = msg->rsp[3] & 0xf;
3405 if (chan >= IPMI_MAX_CHANNELS) {
3406 /* Invalid channel number */
3407 requeue = 0;
3408 goto out;
3409 }
3410
3411 switch (intf->channels[chan].medium) {
3412 case IPMI_CHANNEL_MEDIUM_IPMB:
3413 if (msg->rsp[4] & 0x04) {
3414 /* It's a response, so find the
3415 requesting message and send it up. */
3416 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3417 } else {
3418 /* It's a command to the SMS from some other
3419 entity. Handle that. */
3420 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3421 }
3422 break;
3423
3424 case IPMI_CHANNEL_MEDIUM_8023LAN:
3425 case IPMI_CHANNEL_MEDIUM_ASYNC:
3426 if (msg->rsp[6] & 0x04) {
3427 /* It's a response, so find the
3428 requesting message and send it up. */
3429 requeue = handle_lan_get_msg_rsp(intf, msg);
3430 } else {
3431 /* It's a command to the SMS from some other
3432 entity. Handle that. */
3433 requeue = handle_lan_get_msg_cmd(intf, msg);
3434 }
3435 break;
3436
3437 default:
3438 /* We don't handle the channel type, so just
3439 * free the message. */
3440 requeue = 0;
3441 }
3442
3443 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3444 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3445 {
3446 /* It's an asyncronous event. */
3447 requeue = handle_read_event_rsp(intf, msg);
3448 } else {
3449 /* It's a response from the local BMC. */
3450 requeue = handle_bmc_rsp(intf, msg);
3451 }
3452
3453 out:
3454 return requeue;
3455}
3456
3457/* Handle a new message from the lower layer. */
3458void ipmi_smi_msg_received(ipmi_smi_t intf,
3459 struct ipmi_smi_msg *msg)
3460{
3461 unsigned long flags;
3462 int rv;
3463
3464
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 if ((msg->data_size >= 2)
3466 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3467 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003468 && (msg->user_data == NULL))
3469 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 /* This is the local response to a command send, start
3471 the timer for these. The user_data will not be
3472 NULL if this is a response send, and we will let
3473 response sends just go through. */
3474
3475 /* Check for errors, if we get certain errors (ones
3476 that mean basically we can try again later), we
3477 ignore them and start the timer. Otherwise we
3478 report the error immediately. */
3479 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3480 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
Corey Minyard46d52b02006-11-08 17:44:55 -08003481 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
3482 && (msg->rsp[2] != IPMI_BUS_ERR)
3483 && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 {
3485 int chan = msg->rsp[3] & 0xf;
3486
3487 /* Got an error sending the message, handle it. */
3488 spin_lock_irqsave(&intf->counter_lock, flags);
3489 if (chan >= IPMI_MAX_CHANNELS)
3490 ; /* This shouldn't happen */
3491 else if ((intf->channels[chan].medium
3492 == IPMI_CHANNEL_MEDIUM_8023LAN)
3493 || (intf->channels[chan].medium
3494 == IPMI_CHANNEL_MEDIUM_ASYNC))
3495 intf->sent_lan_command_errs++;
3496 else
3497 intf->sent_ipmb_command_errs++;
3498 spin_unlock_irqrestore(&intf->counter_lock, flags);
3499 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3500 } else {
3501 /* The message was sent, start the timer. */
3502 intf_start_seq_timer(intf, msg->msgid);
3503 }
3504
3505 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003506 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 }
3508
3509 /* To preserve message order, if the list is not empty, we
3510 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003511 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
3512 if (!list_empty(&intf->waiting_msgs)) {
3513 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003514 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003515 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003517 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
3519 rv = handle_new_recv_msg(intf, msg);
3520 if (rv > 0) {
3521 /* Could not handle the message now, just add it to a
3522 list to handle later. */
Hironobu Ishii177294d2005-11-11 08:12:21 -06003523 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003524 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003525 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 } else if (rv == 0) {
3527 ipmi_free_smi_msg(msg);
3528 }
3529
Corey Minyard393d2cc2005-11-07 00:59:54 -08003530 out:
3531 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532}
3533
3534void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3535{
3536 ipmi_user_t user;
3537
Corey Minyard393d2cc2005-11-07 00:59:54 -08003538 rcu_read_lock();
3539 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003540 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 continue;
3542
3543 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3544 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003545 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546}
3547
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548
Corey Minyard882fe012005-05-01 08:59:12 -07003549static struct ipmi_smi_msg *
3550smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3551 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552{
Corey Minyard882fe012005-05-01 08:59:12 -07003553 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 if (!smi_msg)
3555 /* If we can't allocate the message, then just return, we
3556 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003557 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
3559 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3560 smi_msg->data_size = recv_msg->msg.data_len;
3561 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3562
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563#ifdef DEBUG_MSGING
3564 {
3565 int m;
3566 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003567 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 printk(" %2.2x", smi_msg->data[m]);
3569 printk("\n");
3570 }
3571#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003572 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573}
3574
Corey Minyard393d2cc2005-11-07 00:59:54 -08003575static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3576 struct list_head *timeouts, long timeout_period,
3577 int slot, unsigned long *flags)
3578{
Corey Minyardb2c03942006-12-06 20:41:00 -08003579 struct ipmi_recv_msg *msg;
3580 struct ipmi_smi_handlers *handlers;
3581
3582 if (intf->intf_num == -1)
3583 return;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003584
3585 if (!ent->inuse)
3586 return;
3587
3588 ent->timeout -= timeout_period;
3589 if (ent->timeout > 0)
3590 return;
3591
3592 if (ent->retries_left == 0) {
3593 /* The message has used all its retries. */
3594 ent->inuse = 0;
3595 msg = ent->recv_msg;
3596 list_add_tail(&msg->link, timeouts);
3597 spin_lock(&intf->counter_lock);
3598 if (ent->broadcast)
3599 intf->timed_out_ipmb_broadcasts++;
3600 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3601 intf->timed_out_lan_commands++;
3602 else
3603 intf->timed_out_ipmb_commands++;
3604 spin_unlock(&intf->counter_lock);
3605 } else {
3606 struct ipmi_smi_msg *smi_msg;
3607 /* More retries, send again. */
3608
3609 /* Start with the max timer, set to normal
3610 timer after the message is sent. */
3611 ent->timeout = MAX_MSG_TIMEOUT;
3612 ent->retries_left--;
3613 spin_lock(&intf->counter_lock);
3614 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3615 intf->retransmitted_lan_commands++;
3616 else
3617 intf->retransmitted_ipmb_commands++;
3618 spin_unlock(&intf->counter_lock);
3619
3620 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3621 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003622 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003623 return;
3624
3625 spin_unlock_irqrestore(&intf->seq_lock, *flags);
Corey Minyardb2c03942006-12-06 20:41:00 -08003626
Corey Minyard393d2cc2005-11-07 00:59:54 -08003627 /* Send the new message. We send with a zero
3628 * priority. It timed out, I doubt time is
3629 * that critical now, and high priority
3630 * messages are really only for messages to the
3631 * local MC, which don't get resent. */
Corey Minyardb2c03942006-12-06 20:41:00 -08003632 handlers = intf->handlers;
3633 if (handlers)
3634 intf->handlers->sender(intf->send_info,
3635 smi_msg, 0);
3636 else
3637 ipmi_free_smi_msg(smi_msg);
3638
Corey Minyard393d2cc2005-11-07 00:59:54 -08003639 spin_lock_irqsave(&intf->seq_lock, *flags);
3640 }
3641}
3642
3643static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644{
3645 ipmi_smi_t intf;
3646 struct list_head timeouts;
3647 struct ipmi_recv_msg *msg, *msg2;
3648 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3649 unsigned long flags;
Corey Minyardbca03242006-12-06 20:40:57 -08003650 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651
Corey Minyardbca03242006-12-06 20:40:57 -08003652 rcu_read_lock();
3653 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003655 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003656 list_for_each_entry_safe(smi_msg, smi_msg2,
3657 &intf->waiting_msgs, link) {
3658 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 list_del(&smi_msg->link);
3660 ipmi_free_smi_msg(smi_msg);
3661 } else {
3662 /* To preserve message order, quit if we
3663 can't handle a message. */
3664 break;
3665 }
3666 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003667 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668
3669 /* Go through the seq table and find any messages that
3670 have timed out, putting them in the timeouts
3671 list. */
David Barksdale41c57a82007-01-30 14:36:25 -08003672 INIT_LIST_HEAD(&timeouts);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003673 spin_lock_irqsave(&intf->seq_lock, flags);
Corey Minyardbca03242006-12-06 20:40:57 -08003674 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
3675 check_msg_timeout(intf, &(intf->seq_table[i]),
3676 &timeouts, timeout_period, i,
Corey Minyard393d2cc2005-11-07 00:59:54 -08003677 &flags);
3678 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679
Corey Minyard393d2cc2005-11-07 00:59:54 -08003680 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08003681 deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE);
Corey Minyardb9675132006-12-06 20:41:02 -08003682
3683 /*
3684 * Maintenance mode handling. Check the timeout
3685 * optimistically before we claim the lock. It may
3686 * mean a timeout gets missed occasionally, but that
3687 * only means the timeout gets extended by one period
3688 * in that case. No big deal, and it avoids the lock
3689 * most of the time.
3690 */
3691 if (intf->auto_maintenance_timeout > 0) {
3692 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
3693 if (intf->auto_maintenance_timeout > 0) {
3694 intf->auto_maintenance_timeout
3695 -= timeout_period;
3696 if (!intf->maintenance_mode
3697 && (intf->auto_maintenance_timeout <= 0))
3698 {
3699 intf->maintenance_mode_enable = 0;
3700 maintenance_mode_update(intf);
3701 }
3702 }
3703 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
3704 flags);
3705 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 }
Corey Minyardbca03242006-12-06 20:40:57 -08003707 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708}
3709
3710static void ipmi_request_event(void)
3711{
Corey Minyardb2c03942006-12-06 20:41:00 -08003712 ipmi_smi_t intf;
3713 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714
Corey Minyardbca03242006-12-06 20:40:57 -08003715 rcu_read_lock();
Corey Minyardb2c03942006-12-06 20:41:00 -08003716 /* Called from the timer, no need to check if handlers is
3717 * valid. */
3718 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb9675132006-12-06 20:41:02 -08003719 /* No event requests when in maintenance mode. */
3720 if (intf->maintenance_mode_enable)
3721 continue;
3722
Corey Minyardb2c03942006-12-06 20:41:00 -08003723 handlers = intf->handlers;
3724 if (handlers)
3725 handlers->request_events(intf->send_info);
3726 }
Corey Minyardbca03242006-12-06 20:40:57 -08003727 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728}
3729
3730static struct timer_list ipmi_timer;
3731
3732/* Call every ~100 ms. */
3733#define IPMI_TIMEOUT_TIME 100
3734
3735/* How many jiffies does it take to get to the timeout time. */
3736#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3737
3738/* Request events from the queue every second (this is the number of
3739 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3740 future, IPMI will add a way to know immediately if an event is in
3741 the queue and this silliness can go away. */
3742#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3743
Corey Minyard8f43f842005-06-23 22:01:40 -07003744static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3746
3747static void ipmi_timeout(unsigned long data)
3748{
Corey Minyard8f43f842005-06-23 22:01:40 -07003749 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751
3752 ticks_to_req_ev--;
3753 if (ticks_to_req_ev == 0) {
3754 ipmi_request_event();
3755 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3756 }
3757
3758 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3759
Corey Minyard8f43f842005-06-23 22:01:40 -07003760 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761}
3762
3763
3764static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3765static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3766
3767/* FIXME - convert these to slabs. */
3768static void free_smi_msg(struct ipmi_smi_msg *msg)
3769{
3770 atomic_dec(&smi_msg_inuse_count);
3771 kfree(msg);
3772}
3773
3774struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3775{
3776 struct ipmi_smi_msg *rv;
3777 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3778 if (rv) {
3779 rv->done = free_smi_msg;
3780 rv->user_data = NULL;
3781 atomic_inc(&smi_msg_inuse_count);
3782 }
3783 return rv;
3784}
3785
3786static void free_recv_msg(struct ipmi_recv_msg *msg)
3787{
3788 atomic_dec(&recv_msg_inuse_count);
3789 kfree(msg);
3790}
3791
3792struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3793{
3794 struct ipmi_recv_msg *rv;
3795
3796 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3797 if (rv) {
Corey Minyarda9eec552006-08-31 21:27:45 -07003798 rv->user = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 rv->done = free_recv_msg;
3800 atomic_inc(&recv_msg_inuse_count);
3801 }
3802 return rv;
3803}
3804
Corey Minyard393d2cc2005-11-07 00:59:54 -08003805void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3806{
3807 if (msg->user)
3808 kref_put(&msg->user->refcount, free_user);
3809 msg->done(msg);
3810}
3811
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812#ifdef CONFIG_IPMI_PANIC_EVENT
3813
3814static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3815{
3816}
3817
3818static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3819{
3820}
3821
3822#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003823static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003825 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3826 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3827 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3828 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 {
3830 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003831 intf->event_receiver = msg->msg.data[1];
3832 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 }
3834}
3835
Corey Minyard56a55ec2005-09-06 15:18:42 -07003836static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003838 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3839 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3840 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3841 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 {
3843 /* A get device id command, save if we are an event
3844 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003845 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3846 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 }
3848}
3849#endif
3850
3851static void send_panic_events(char *str)
3852{
3853 struct kernel_ipmi_msg msg;
3854 ipmi_smi_t intf;
3855 unsigned char data[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 struct ipmi_system_interface_addr *si;
3857 struct ipmi_addr addr;
3858 struct ipmi_smi_msg smi_msg;
3859 struct ipmi_recv_msg recv_msg;
3860
3861 si = (struct ipmi_system_interface_addr *) &addr;
3862 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3863 si->channel = IPMI_BMC_CHANNEL;
3864 si->lun = 0;
3865
3866 /* Fill in an event telling that we have failed. */
3867 msg.netfn = 0x04; /* Sensor or Event. */
3868 msg.cmd = 2; /* Platform event command. */
3869 msg.data = data;
3870 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003871 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 data[1] = 0x03; /* This is for IPMI 1.0. */
3873 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3874 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3875 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3876
3877 /* Put a few breadcrumbs in. Hopefully later we can add more things
3878 to make the panic events more useful. */
3879 if (str) {
3880 data[3] = str[0];
3881 data[6] = str[1];
3882 data[7] = str[2];
3883 }
3884
3885 smi_msg.done = dummy_smi_done_handler;
3886 recv_msg.done = dummy_recv_done_handler;
3887
3888 /* For every registered interface, send the event. */
Corey Minyardbca03242006-12-06 20:40:57 -08003889 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08003890 if (!intf->handlers)
3891 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 continue;
3893
3894 /* Send the event announcing the panic. */
3895 intf->handlers->set_run_to_completion(intf->send_info, 1);
3896 i_ipmi_request(NULL,
3897 intf,
3898 &addr,
3899 0,
3900 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003901 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 &smi_msg,
3903 &recv_msg,
3904 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003905 intf->channels[0].address,
3906 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 0, 1); /* Don't retry, and don't wait. */
3908 }
3909
3910#ifdef CONFIG_IPMI_PANIC_STRING
3911 /* On every interface, dump a bunch of OEM event holding the
3912 string. */
3913 if (!str)
3914 return;
3915
Corey Minyardbca03242006-12-06 20:40:57 -08003916 /* For every registered interface, send the event. */
3917 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 char *p = str;
3919 struct ipmi_ipmb_addr *ipmb;
3920 int j;
3921
Corey Minyardbca03242006-12-06 20:40:57 -08003922 if (intf->intf_num == -1)
3923 /* Interface was not ready yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 continue;
3925
Corey Minyard78ba2fa2007-02-10 01:45:45 -08003926 /*
3927 * intf_num is used as an marker to tell if the
3928 * interface is valid. Thus we need a read barrier to
3929 * make sure data fetched before checking intf_num
3930 * won't be used.
3931 */
3932 smp_rmb();
3933
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 /* First job here is to figure out where to send the
3935 OEM events. There's no way in IPMI to send OEM
3936 events using an event send command, so we have to
3937 find the SEL to put them in and stick them in
3938 there. */
3939
3940 /* Get capabilities from the get device id. */
3941 intf->local_sel_device = 0;
3942 intf->local_event_generator = 0;
3943 intf->event_receiver = 0;
3944
3945 /* Request the device info from the local MC. */
3946 msg.netfn = IPMI_NETFN_APP_REQUEST;
3947 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3948 msg.data = NULL;
3949 msg.data_len = 0;
3950 intf->null_user_handler = device_id_fetcher;
3951 i_ipmi_request(NULL,
3952 intf,
3953 &addr,
3954 0,
3955 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003956 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 &smi_msg,
3958 &recv_msg,
3959 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003960 intf->channels[0].address,
3961 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 0, 1); /* Don't retry, and don't wait. */
3963
3964 if (intf->local_event_generator) {
3965 /* Request the event receiver from the local MC. */
3966 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3967 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3968 msg.data = NULL;
3969 msg.data_len = 0;
3970 intf->null_user_handler = event_receiver_fetcher;
3971 i_ipmi_request(NULL,
3972 intf,
3973 &addr,
3974 0,
3975 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003976 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 &smi_msg,
3978 &recv_msg,
3979 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003980 intf->channels[0].address,
3981 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 0, 1); /* no retry, and no wait. */
3983 }
3984 intf->null_user_handler = NULL;
3985
3986 /* Validate the event receiver. The low bit must not
3987 be 1 (it must be a valid IPMB address), it cannot
3988 be zero, and it must not be my address. */
3989 if (((intf->event_receiver & 1) == 0)
3990 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003991 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 {
3993 /* The event receiver is valid, send an IPMB
3994 message. */
3995 ipmb = (struct ipmi_ipmb_addr *) &addr;
3996 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3997 ipmb->channel = 0; /* FIXME - is this right? */
3998 ipmb->lun = intf->event_receiver_lun;
3999 ipmb->slave_addr = intf->event_receiver;
4000 } else if (intf->local_sel_device) {
4001 /* The event receiver was not valid (or was
4002 me), but I am an SEL device, just dump it
4003 in my SEL. */
4004 si = (struct ipmi_system_interface_addr *) &addr;
4005 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
4006 si->channel = IPMI_BMC_CHANNEL;
4007 si->lun = 0;
4008 } else
4009 continue; /* No where to send the event. */
4010
4011
4012 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
4013 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
4014 msg.data = data;
4015 msg.data_len = 16;
4016
4017 j = 0;
4018 while (*p) {
4019 int size = strlen(p);
4020
4021 if (size > 11)
4022 size = 11;
4023 data[0] = 0;
4024 data[1] = 0;
4025 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07004026 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 data[4] = j++; /* sequence # */
4028 /* Always give 11 bytes, so strncpy will fill
4029 it with zeroes for me. */
4030 strncpy(data+5, p, 11);
4031 p += size;
4032
4033 i_ipmi_request(NULL,
4034 intf,
4035 &addr,
4036 0,
4037 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07004038 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 &smi_msg,
4040 &recv_msg,
4041 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07004042 intf->channels[0].address,
4043 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 0, 1); /* no retry, and no wait. */
4045 }
4046 }
4047#endif /* CONFIG_IPMI_PANIC_STRING */
4048}
4049#endif /* CONFIG_IPMI_PANIC_EVENT */
4050
Randy Dunlap0c8204b2006-12-10 02:19:06 -08004051static int has_panicked;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052
4053static int panic_event(struct notifier_block *this,
4054 unsigned long event,
4055 void *ptr)
4056{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 ipmi_smi_t intf;
4058
Lee Revellf18190b2006-06-26 18:30:00 +02004059 if (has_panicked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 return NOTIFY_DONE;
Lee Revellf18190b2006-06-26 18:30:00 +02004061 has_panicked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062
4063 /* For every registered interface, set it to run to completion. */
Corey Minyardbca03242006-12-06 20:40:57 -08004064 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08004065 if (!intf->handlers)
4066 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 continue;
4068
4069 intf->handlers->set_run_to_completion(intf->send_info, 1);
4070 }
4071
4072#ifdef CONFIG_IPMI_PANIC_EVENT
4073 send_panic_events(ptr);
4074#endif
4075
4076 return NOTIFY_DONE;
4077}
4078
4079static struct notifier_block panic_block = {
4080 .notifier_call = panic_event,
4081 .next = NULL,
4082 .priority = 200 /* priority: INT_MAX >= x >= 0 */
4083};
4084
4085static int ipmi_init_msghandler(void)
4086{
Corey Minyard50c812b2006-03-26 01:37:21 -08004087 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088
4089 if (initialized)
4090 return 0;
4091
Corey Minyard50c812b2006-03-26 01:37:21 -08004092 rv = driver_register(&ipmidriver);
4093 if (rv) {
4094 printk(KERN_ERR PFX "Could not register IPMI driver\n");
4095 return rv;
4096 }
4097
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004099 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100
Corey Minyard3b625942005-06-23 22:01:42 -07004101#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 proc_ipmi_root = proc_mkdir("ipmi", NULL);
4103 if (!proc_ipmi_root) {
4104 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
4105 return -ENOMEM;
4106 }
4107
4108 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07004109#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110
Corey Minyard409035e2006-06-28 04:26:53 -07004111 setup_timer(&ipmi_timer, ipmi_timeout, 0);
4112 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113
Alan Sterne041c682006-03-27 01:16:30 -08004114 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115
4116 initialized = 1;
4117
4118 return 0;
4119}
4120
4121static __init int ipmi_init_msghandler_mod(void)
4122{
4123 ipmi_init_msghandler();
4124 return 0;
4125}
4126
4127static __exit void cleanup_ipmi(void)
4128{
4129 int count;
4130
4131 if (!initialized)
4132 return;
4133
Alan Sterne041c682006-03-27 01:16:30 -08004134 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135
4136 /* This can't be called if any interfaces exist, so no worry about
4137 shutting down the interfaces. */
4138
4139 /* Tell the timer to stop, then wait for it to stop. This avoids
4140 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07004141 atomic_inc(&stop_operation);
4142 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143
Corey Minyard3b625942005-06-23 22:01:42 -07004144#ifdef CONFIG_PROC_FS
Alexey Dobriyan3542ae42007-10-16 23:26:50 -07004145 remove_proc_entry(proc_ipmi_root->name, NULL);
Corey Minyard3b625942005-06-23 22:01:42 -07004146#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147
Corey Minyard50c812b2006-03-26 01:37:21 -08004148 driver_unregister(&ipmidriver);
4149
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 initialized = 0;
4151
4152 /* Check for buffer leaks. */
4153 count = atomic_read(&smi_msg_inuse_count);
4154 if (count != 0)
4155 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
4156 count);
4157 count = atomic_read(&recv_msg_inuse_count);
4158 if (count != 0)
4159 printk(KERN_WARNING PFX "recv message count %d at exit\n",
4160 count);
4161}
4162module_exit(cleanup_ipmi);
4163
4164module_init(ipmi_init_msghandler_mod);
4165MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004166MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
4167MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
4168MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169
4170EXPORT_SYMBOL(ipmi_create_user);
4171EXPORT_SYMBOL(ipmi_destroy_user);
4172EXPORT_SYMBOL(ipmi_get_version);
4173EXPORT_SYMBOL(ipmi_request_settime);
4174EXPORT_SYMBOL(ipmi_request_supply_msgs);
Corey Minyardfcfa4722007-10-18 03:07:09 -07004175EXPORT_SYMBOL(ipmi_poll_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176EXPORT_SYMBOL(ipmi_register_smi);
4177EXPORT_SYMBOL(ipmi_unregister_smi);
4178EXPORT_SYMBOL(ipmi_register_for_cmd);
4179EXPORT_SYMBOL(ipmi_unregister_for_cmd);
4180EXPORT_SYMBOL(ipmi_smi_msg_received);
4181EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
4182EXPORT_SYMBOL(ipmi_alloc_smi_msg);
4183EXPORT_SYMBOL(ipmi_addr_length);
4184EXPORT_SYMBOL(ipmi_validate_addr);
4185EXPORT_SYMBOL(ipmi_set_gets_events);
4186EXPORT_SYMBOL(ipmi_smi_watcher_register);
4187EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
4188EXPORT_SYMBOL(ipmi_set_my_address);
4189EXPORT_SYMBOL(ipmi_get_my_address);
4190EXPORT_SYMBOL(ipmi_set_my_LUN);
4191EXPORT_SYMBOL(ipmi_get_my_LUN);
4192EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08004194EXPORT_SYMBOL(ipmi_free_recv_msg);