blob: 8b71f5638b60e3220b90e1d33a472a3944e94c03 [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;
Konstantin Baydarov5956dce2008-04-29 01:01:03 -0700354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 /* Events that were received with the proper format. */
356 unsigned int events;
Konstantin Baydarov5956dce2008-04-29 01:01:03 -0700357
358 /*
359 * run_to_completion duplicate of smb_info, smi_info
360 * and ipmi_serial_info structures. Used to decrease numbers of
361 * parameters passed by "low" level IPMI code.
362 */
363 int run_to_completion;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364};
Corey Minyard50c812b2006-03-26 01:37:21 -0800365#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Corey Minyard50c812b2006-03-26 01:37:21 -0800367/**
368 * The driver model view of the IPMI messaging driver.
369 */
370static struct device_driver ipmidriver = {
371 .name = "ipmi",
372 .bus = &platform_bus_type
373};
374static DEFINE_MUTEX(ipmidriver_mutex);
375
Denis Chengbed97592008-02-06 01:37:35 -0800376static LIST_HEAD(ipmi_interfaces);
Corey Minyardbca03242006-12-06 20:40:57 -0800377static DEFINE_MUTEX(ipmi_interfaces_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379/* List of watchers that want to know when smi's are added and
380 deleted. */
Denis Chengbed97592008-02-06 01:37:35 -0800381static LIST_HEAD(smi_watchers);
Corey Minyardb2c03942006-12-06 20:41:00 -0800382static DEFINE_MUTEX(smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Corey Minyard393d2cc2005-11-07 00:59:54 -0800385static void free_recv_msg_list(struct list_head *q)
386{
387 struct ipmi_recv_msg *msg, *msg2;
388
389 list_for_each_entry_safe(msg, msg2, q, link) {
390 list_del(&msg->link);
391 ipmi_free_recv_msg(msg);
392 }
393}
394
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800395static void free_smi_msg_list(struct list_head *q)
396{
397 struct ipmi_smi_msg *msg, *msg2;
398
399 list_for_each_entry_safe(msg, msg2, q, link) {
400 list_del(&msg->link);
401 ipmi_free_smi_msg(msg);
402 }
403}
404
Corey Minyard393d2cc2005-11-07 00:59:54 -0800405static void clean_up_interface_data(ipmi_smi_t intf)
406{
407 int i;
408 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800409 struct list_head list;
410
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800411 free_smi_msg_list(&intf->waiting_msgs);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800412 free_recv_msg_list(&intf->waiting_events);
413
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800414 /*
415 * Wholesale remove all the entries from the list in the
416 * interface and wait for RCU to know that none are in use.
417 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800418 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800419 INIT_LIST_HEAD(&list);
420 list_splice_init_rcu(&intf->cmd_rcvrs, &list, synchronize_rcu);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800421 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800422
423 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
424 kfree(rcvr);
425
426 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
427 if ((intf->seq_table[i].inuse)
428 && (intf->seq_table[i].recv_msg))
429 {
430 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 }
432 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800433}
434
435static void intf_free(struct kref *ref)
436{
437 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
438
439 clean_up_interface_data(intf);
440 kfree(intf);
441}
442
Corey Minyardbca03242006-12-06 20:40:57 -0800443struct watcher_entry {
Corey Minyardb2c03942006-12-06 20:41:00 -0800444 int intf_num;
445 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800446 struct list_head link;
Corey Minyardbca03242006-12-06 20:40:57 -0800447};
448
Corey Minyard393d2cc2005-11-07 00:59:54 -0800449int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
450{
Corey Minyardbca03242006-12-06 20:40:57 -0800451 ipmi_smi_t intf;
Denis Chenge381d1c2008-02-06 01:37:39 -0800452 LIST_HEAD(to_deliver);
Corey Minyardbca03242006-12-06 20:40:57 -0800453 struct watcher_entry *e, *e2;
454
Corey Minyardb2c03942006-12-06 20:41:00 -0800455 mutex_lock(&smi_watchers_mutex);
456
Corey Minyardbca03242006-12-06 20:40:57 -0800457 mutex_lock(&ipmi_interfaces_mutex);
458
Corey Minyardb2c03942006-12-06 20:41:00 -0800459 /* Build a list of things to deliver. */
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800460 list_for_each_entry(intf, &ipmi_interfaces, link) {
Corey Minyardbca03242006-12-06 20:40:57 -0800461 if (intf->intf_num == -1)
462 continue;
463 e = kmalloc(sizeof(*e), GFP_KERNEL);
464 if (!e)
465 goto out_err;
Corey Minyardb2c03942006-12-06 20:41:00 -0800466 kref_get(&intf->refcount);
467 e->intf = intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800468 e->intf_num = intf->intf_num;
469 list_add_tail(&e->link, &to_deliver);
470 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800471
Corey Minyardb2c03942006-12-06 20:41:00 -0800472 /* We will succeed, so add it to the list. */
473 list_add(&watcher->link, &smi_watchers);
Corey Minyardbca03242006-12-06 20:40:57 -0800474
475 mutex_unlock(&ipmi_interfaces_mutex);
476
477 list_for_each_entry_safe(e, e2, &to_deliver, link) {
478 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800479 watcher->new_smi(e->intf_num, e->intf->si_dev);
480 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800481 kfree(e);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800482 }
Corey Minyardbca03242006-12-06 20:40:57 -0800483
Corey Minyardb2c03942006-12-06 20:41:00 -0800484 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 return 0;
Corey Minyardbca03242006-12-06 20:40:57 -0800487
488 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -0800489 mutex_unlock(&ipmi_interfaces_mutex);
490 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800491 list_for_each_entry_safe(e, e2, &to_deliver, link) {
492 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800493 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800494 kfree(e);
495 }
496 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498
499int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
500{
Corey Minyardb2c03942006-12-06 20:41:00 -0800501 mutex_lock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 list_del(&(watcher->link));
Corey Minyardb2c03942006-12-06 20:41:00 -0800503 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 return 0;
505}
506
Corey Minyardb2c03942006-12-06 20:41:00 -0800507/*
508 * Must be called with smi_watchers_mutex held.
509 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510static void
Corey Minyard50c812b2006-03-26 01:37:21 -0800511call_smi_watchers(int i, struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
513 struct ipmi_smi_watcher *w;
514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 list_for_each_entry(w, &smi_watchers, link) {
516 if (try_module_get(w->owner)) {
Corey Minyard50c812b2006-03-26 01:37:21 -0800517 w->new_smi(i, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 module_put(w->owner);
519 }
520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521}
522
523static int
524ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
525{
526 if (addr1->addr_type != addr2->addr_type)
527 return 0;
528
529 if (addr1->channel != addr2->channel)
530 return 0;
531
532 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
533 struct ipmi_system_interface_addr *smi_addr1
534 = (struct ipmi_system_interface_addr *) addr1;
535 struct ipmi_system_interface_addr *smi_addr2
536 = (struct ipmi_system_interface_addr *) addr2;
537 return (smi_addr1->lun == smi_addr2->lun);
538 }
539
540 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
541 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
542 {
543 struct ipmi_ipmb_addr *ipmb_addr1
544 = (struct ipmi_ipmb_addr *) addr1;
545 struct ipmi_ipmb_addr *ipmb_addr2
546 = (struct ipmi_ipmb_addr *) addr2;
547
548 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
549 && (ipmb_addr1->lun == ipmb_addr2->lun));
550 }
551
552 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
553 struct ipmi_lan_addr *lan_addr1
554 = (struct ipmi_lan_addr *) addr1;
555 struct ipmi_lan_addr *lan_addr2
556 = (struct ipmi_lan_addr *) addr2;
557
558 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
559 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
560 && (lan_addr1->session_handle
561 == lan_addr2->session_handle)
562 && (lan_addr1->lun == lan_addr2->lun));
563 }
564
565 return 1;
566}
567
568int ipmi_validate_addr(struct ipmi_addr *addr, int len)
569{
570 if (len < sizeof(struct ipmi_system_interface_addr)) {
571 return -EINVAL;
572 }
573
574 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
575 if (addr->channel != IPMI_BMC_CHANNEL)
576 return -EINVAL;
577 return 0;
578 }
579
580 if ((addr->channel == IPMI_BMC_CHANNEL)
Jayachandran C12fc1d72006-02-03 03:04:51 -0800581 || (addr->channel >= IPMI_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 || (addr->channel < 0))
583 return -EINVAL;
584
585 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
586 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
587 {
588 if (len < sizeof(struct ipmi_ipmb_addr)) {
589 return -EINVAL;
590 }
591 return 0;
592 }
593
594 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
595 if (len < sizeof(struct ipmi_lan_addr)) {
596 return -EINVAL;
597 }
598 return 0;
599 }
600
601 return -EINVAL;
602}
603
604unsigned int ipmi_addr_length(int addr_type)
605{
606 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
607 return sizeof(struct ipmi_system_interface_addr);
608
609 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
610 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
611 {
612 return sizeof(struct ipmi_ipmb_addr);
613 }
614
615 if (addr_type == IPMI_LAN_ADDR_TYPE)
616 return sizeof(struct ipmi_lan_addr);
617
618 return 0;
619}
620
621static void deliver_response(struct ipmi_recv_msg *msg)
622{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800623 if (!msg->user) {
Corey Minyard56a55ec2005-09-06 15:18:42 -0700624 ipmi_smi_t intf = msg->user_msg_data;
625 unsigned long flags;
626
627 /* Special handling for NULL users. */
628 if (intf->null_user_handler) {
629 intf->null_user_handler(intf, msg);
630 spin_lock_irqsave(&intf->counter_lock, flags);
631 intf->handled_local_responses++;
632 spin_unlock_irqrestore(&intf->counter_lock, flags);
633 } else {
634 /* No handler, so give up. */
635 spin_lock_irqsave(&intf->counter_lock, flags);
636 intf->unhandled_local_responses++;
637 spin_unlock_irqrestore(&intf->counter_lock, flags);
638 }
639 ipmi_free_recv_msg(msg);
640 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800641 ipmi_user_t user = msg->user;
642 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644}
645
Corey Minyardb2c03942006-12-06 20:41:00 -0800646static void
647deliver_err_response(struct ipmi_recv_msg *msg, int err)
648{
649 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
650 msg->msg_data[0] = err;
651 msg->msg.netfn |= 1; /* Convert to a response. */
652 msg->msg.data_len = 1;
653 msg->msg.data = msg->msg_data;
654 deliver_response(msg);
655}
656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657/* Find the next sequence number not being used and add the given
658 message with the given timeout to the sequence table. This must be
659 called with the interface's seq_lock held. */
660static int intf_next_seq(ipmi_smi_t intf,
661 struct ipmi_recv_msg *recv_msg,
662 unsigned long timeout,
663 int retries,
664 int broadcast,
665 unsigned char *seq,
666 long *seqid)
667{
668 int rv = 0;
669 unsigned int i;
670
Corey Minyarde8b33612005-09-06 15:18:45 -0700671 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700673 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800675 if (!intf->seq_table[i].inuse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 break;
677 }
678
Corey Minyard8a3628d2006-03-31 02:30:40 -0800679 if (!intf->seq_table[i].inuse) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 intf->seq_table[i].recv_msg = recv_msg;
681
682 /* Start with the maximum timeout, when the send response
683 comes in we will start the real timer. */
684 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
685 intf->seq_table[i].orig_timeout = timeout;
686 intf->seq_table[i].retries_left = retries;
687 intf->seq_table[i].broadcast = broadcast;
688 intf->seq_table[i].inuse = 1;
689 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
690 *seq = i;
691 *seqid = intf->seq_table[i].seqid;
692 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
693 } else {
694 rv = -EAGAIN;
695 }
696
697 return rv;
698}
699
700/* Return the receive message for the given sequence number and
701 release the sequence number so it can be reused. Some other data
702 is passed in to be sure the message matches up correctly (to help
703 guard against message coming in after their timeout and the
704 sequence number being reused). */
705static int intf_find_seq(ipmi_smi_t intf,
706 unsigned char seq,
707 short channel,
708 unsigned char cmd,
709 unsigned char netfn,
710 struct ipmi_addr *addr,
711 struct ipmi_recv_msg **recv_msg)
712{
713 int rv = -ENODEV;
714 unsigned long flags;
715
716 if (seq >= IPMI_IPMB_NUM_SEQ)
717 return -EINVAL;
718
719 spin_lock_irqsave(&(intf->seq_lock), flags);
720 if (intf->seq_table[seq].inuse) {
721 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
722
723 if ((msg->addr.channel == channel)
724 && (msg->msg.cmd == cmd)
725 && (msg->msg.netfn == netfn)
726 && (ipmi_addr_equal(addr, &(msg->addr))))
727 {
728 *recv_msg = msg;
729 intf->seq_table[seq].inuse = 0;
730 rv = 0;
731 }
732 }
733 spin_unlock_irqrestore(&(intf->seq_lock), flags);
734
735 return rv;
736}
737
738
739/* Start the timer for a specific sequence table entry. */
740static int intf_start_seq_timer(ipmi_smi_t intf,
741 long msgid)
742{
743 int rv = -ENODEV;
744 unsigned long flags;
745 unsigned char seq;
746 unsigned long seqid;
747
748
749 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
750
751 spin_lock_irqsave(&(intf->seq_lock), flags);
752 /* We do this verification because the user can be deleted
753 while a message is outstanding. */
754 if ((intf->seq_table[seq].inuse)
755 && (intf->seq_table[seq].seqid == seqid))
756 {
757 struct seq_table *ent = &(intf->seq_table[seq]);
758 ent->timeout = ent->orig_timeout;
759 rv = 0;
760 }
761 spin_unlock_irqrestore(&(intf->seq_lock), flags);
762
763 return rv;
764}
765
766/* Got an error for the send message for a specific sequence number. */
767static int intf_err_seq(ipmi_smi_t intf,
768 long msgid,
769 unsigned int err)
770{
771 int rv = -ENODEV;
772 unsigned long flags;
773 unsigned char seq;
774 unsigned long seqid;
775 struct ipmi_recv_msg *msg = NULL;
776
777
778 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
779
780 spin_lock_irqsave(&(intf->seq_lock), flags);
781 /* We do this verification because the user can be deleted
782 while a message is outstanding. */
783 if ((intf->seq_table[seq].inuse)
784 && (intf->seq_table[seq].seqid == seqid))
785 {
786 struct seq_table *ent = &(intf->seq_table[seq]);
787
788 ent->inuse = 0;
789 msg = ent->recv_msg;
790 rv = 0;
791 }
792 spin_unlock_irqrestore(&(intf->seq_lock), flags);
793
Corey Minyardb2c03942006-12-06 20:41:00 -0800794 if (msg)
795 deliver_err_response(msg, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797 return rv;
798}
799
800
801int ipmi_create_user(unsigned int if_num,
802 struct ipmi_user_hndl *handler,
803 void *handler_data,
804 ipmi_user_t *user)
805{
806 unsigned long flags;
807 ipmi_user_t new_user;
808 int rv = 0;
809 ipmi_smi_t intf;
810
811 /* There is no module usecount here, because it's not
812 required. Since this can only be used by and called from
813 other modules, they will implicitly use this module, and
814 thus this can't be removed unless the other modules are
815 removed. */
816
817 if (handler == NULL)
818 return -EINVAL;
819
820 /* Make sure the driver is actually initialized, this handles
821 problems with initialization order. */
822 if (!initialized) {
823 rv = ipmi_init_msghandler();
824 if (rv)
825 return rv;
826
827 /* The init code doesn't return an error if it was turned
828 off, but it won't initialize. Check that. */
829 if (!initialized)
830 return -ENODEV;
831 }
832
833 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800834 if (!new_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 return -ENOMEM;
836
Corey Minyardb2c03942006-12-06 20:41:00 -0800837 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800838 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
839 if (intf->intf_num == if_num)
840 goto found;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 }
Corey Minyardb2c03942006-12-06 20:41:00 -0800842 /* Not found, return an error */
Corey Minyardbca03242006-12-06 20:40:57 -0800843 rv = -EINVAL;
844 goto out_kfree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Corey Minyardbca03242006-12-06 20:40:57 -0800846 found:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800847 /* Note that each existing user holds a refcount to the interface. */
848 kref_get(&intf->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Corey Minyard393d2cc2005-11-07 00:59:54 -0800850 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 new_user->handler = handler;
852 new_user->handler_data = handler_data;
853 new_user->intf = intf;
854 new_user->gets_events = 0;
855
856 if (!try_module_get(intf->handlers->owner)) {
857 rv = -ENODEV;
Adrian Bunk5c98d292006-03-25 03:07:52 -0800858 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 }
860
861 if (intf->handlers->inc_usecount) {
862 rv = intf->handlers->inc_usecount(intf->send_info);
863 if (rv) {
864 module_put(intf->handlers->owner);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800865 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 }
867 }
868
Corey Minyardb2c03942006-12-06 20:41:00 -0800869 /* Hold the lock so intf->handlers is guaranteed to be good
870 * until now */
871 mutex_unlock(&ipmi_interfaces_mutex);
872
Corey Minyard393d2cc2005-11-07 00:59:54 -0800873 new_user->valid = 1;
874 spin_lock_irqsave(&intf->seq_lock, flags);
875 list_add_rcu(&new_user->link, &intf->users);
876 spin_unlock_irqrestore(&intf->seq_lock, flags);
877 *user = new_user;
878 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
Adrian Bunk5c98d292006-03-25 03:07:52 -0800880out_kref:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800881 kref_put(&intf->refcount, intf_free);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800882out_kfree:
Corey Minyardb2c03942006-12-06 20:41:00 -0800883 mutex_unlock(&ipmi_interfaces_mutex);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800884 kfree(new_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 return rv;
886}
887
Corey Minyard393d2cc2005-11-07 00:59:54 -0800888static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800890 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892}
893
894int ipmi_destroy_user(ipmi_user_t user)
895{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800896 ipmi_smi_t intf = user->intf;
897 int i;
898 unsigned long flags;
899 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800900 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Corey Minyard8a3628d2006-03-31 02:30:40 -0800902 user->valid = 0;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800903
904 /* Remove the user from the interface's sequence table. */
905 spin_lock_irqsave(&intf->seq_lock, flags);
906 list_del_rcu(&user->link);
907
908 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
909 if (intf->seq_table[i].inuse
910 && (intf->seq_table[i].recv_msg->user == user))
911 {
912 intf->seq_table[i].inuse = 0;
Corey Minyardb2c03942006-12-06 20:41:00 -0800913 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800914 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800916 spin_unlock_irqrestore(&intf->seq_lock, flags);
917
918 /*
919 * Remove the user from the command receiver's table. First
920 * we build a list of everything (not using the standard link,
921 * since other things may be using it till we do
922 * synchronize_rcu()) then free everything in that list.
923 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800924 mutex_lock(&intf->cmd_rcvrs_mutex);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800925 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800926 if (rcvr->user == user) {
927 list_del_rcu(&rcvr->link);
928 rcvr->next = rcvrs;
929 rcvrs = rcvr;
930 }
931 }
Corey Minyardd6dfd132006-03-31 02:30:41 -0800932 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800933 synchronize_rcu();
934 while (rcvrs) {
935 rcvr = rcvrs;
936 rcvrs = rcvr->next;
937 kfree(rcvr);
938 }
939
Corey Minyardb2c03942006-12-06 20:41:00 -0800940 mutex_lock(&ipmi_interfaces_mutex);
941 if (intf->handlers) {
942 module_put(intf->handlers->owner);
943 if (intf->handlers->dec_usecount)
944 intf->handlers->dec_usecount(intf->send_info);
945 }
946 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800947
948 kref_put(&intf->refcount, intf_free);
949
950 kref_put(&user->refcount, free_user);
951
Corey Minyard8a3628d2006-03-31 02:30:40 -0800952 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953}
954
955void ipmi_get_version(ipmi_user_t user,
956 unsigned char *major,
957 unsigned char *minor)
958{
Corey Minyardb2c03942006-12-06 20:41:00 -0800959 *major = user->intf->ipmi_version_major;
960 *minor = user->intf->ipmi_version_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961}
962
Corey Minyardc14979b2005-09-06 15:18:38 -0700963int ipmi_set_my_address(ipmi_user_t user,
964 unsigned int channel,
965 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966{
Corey Minyardc14979b2005-09-06 15:18:38 -0700967 if (channel >= IPMI_MAX_CHANNELS)
968 return -EINVAL;
969 user->intf->channels[channel].address = address;
970 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971}
972
Corey Minyardc14979b2005-09-06 15:18:38 -0700973int ipmi_get_my_address(ipmi_user_t user,
974 unsigned int channel,
975 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976{
Corey Minyardc14979b2005-09-06 15:18:38 -0700977 if (channel >= IPMI_MAX_CHANNELS)
978 return -EINVAL;
979 *address = user->intf->channels[channel].address;
980 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981}
982
Corey Minyardc14979b2005-09-06 15:18:38 -0700983int ipmi_set_my_LUN(ipmi_user_t user,
984 unsigned int channel,
985 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
Corey Minyardc14979b2005-09-06 15:18:38 -0700987 if (channel >= IPMI_MAX_CHANNELS)
988 return -EINVAL;
989 user->intf->channels[channel].lun = LUN & 0x3;
990 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991}
992
Corey Minyardc14979b2005-09-06 15:18:38 -0700993int ipmi_get_my_LUN(ipmi_user_t user,
994 unsigned int channel,
995 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996{
Corey Minyardc14979b2005-09-06 15:18:38 -0700997 if (channel >= IPMI_MAX_CHANNELS)
998 return -EINVAL;
999 *address = user->intf->channels[channel].lun;
1000 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001}
1002
Corey Minyardb9675132006-12-06 20:41:02 -08001003int ipmi_get_maintenance_mode(ipmi_user_t user)
1004{
1005 int mode;
1006 unsigned long flags;
1007
1008 spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);
1009 mode = user->intf->maintenance_mode;
1010 spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);
1011
1012 return mode;
1013}
1014EXPORT_SYMBOL(ipmi_get_maintenance_mode);
1015
1016static void maintenance_mode_update(ipmi_smi_t intf)
1017{
1018 if (intf->handlers->set_maintenance_mode)
1019 intf->handlers->set_maintenance_mode(
1020 intf->send_info, intf->maintenance_mode_enable);
1021}
1022
1023int ipmi_set_maintenance_mode(ipmi_user_t user, int mode)
1024{
1025 int rv = 0;
1026 unsigned long flags;
1027 ipmi_smi_t intf = user->intf;
1028
1029 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1030 if (intf->maintenance_mode != mode) {
1031 switch (mode) {
1032 case IPMI_MAINTENANCE_MODE_AUTO:
1033 intf->maintenance_mode = mode;
1034 intf->maintenance_mode_enable
1035 = (intf->auto_maintenance_timeout > 0);
1036 break;
1037
1038 case IPMI_MAINTENANCE_MODE_OFF:
1039 intf->maintenance_mode = mode;
1040 intf->maintenance_mode_enable = 0;
1041 break;
1042
1043 case IPMI_MAINTENANCE_MODE_ON:
1044 intf->maintenance_mode = mode;
1045 intf->maintenance_mode_enable = 1;
1046 break;
1047
1048 default:
1049 rv = -EINVAL;
1050 goto out_unlock;
1051 }
1052
1053 maintenance_mode_update(intf);
1054 }
1055 out_unlock:
1056 spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);
1057
1058 return rv;
1059}
1060EXPORT_SYMBOL(ipmi_set_maintenance_mode);
1061
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062int ipmi_set_gets_events(ipmi_user_t user, int val)
1063{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001064 unsigned long flags;
1065 ipmi_smi_t intf = user->intf;
1066 struct ipmi_recv_msg *msg, *msg2;
1067 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
Corey Minyard393d2cc2005-11-07 00:59:54 -08001069 INIT_LIST_HEAD(&msgs);
1070
1071 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 user->gets_events = val;
1073
Corey Minyardb2c03942006-12-06 20:41:00 -08001074 if (intf->delivering_events)
1075 /*
1076 * Another thread is delivering events for this, so
1077 * let it handle any new events.
1078 */
1079 goto out;
1080
1081 /* Deliver any queued events. */
1082 while (user->gets_events && !list_empty(&intf->waiting_events)) {
Akinobu Mita179e0912006-06-26 00:24:41 -07001083 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
1084 list_move_tail(&msg->link, &msgs);
Corey Minyard4791c032006-04-10 22:54:31 -07001085 intf->waiting_events_count = 0;
Corey Minyardb2c03942006-12-06 20:41:00 -08001086
1087 intf->delivering_events = 1;
1088 spin_unlock_irqrestore(&intf->events_lock, flags);
1089
1090 list_for_each_entry_safe(msg, msg2, &msgs, link) {
1091 msg->user = user;
1092 kref_get(&user->refcount);
1093 deliver_response(msg);
1094 }
1095
1096 spin_lock_irqsave(&intf->events_lock, flags);
1097 intf->delivering_events = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08001099
Corey Minyardb2c03942006-12-06 20:41:00 -08001100 out:
Corey Minyard393d2cc2005-11-07 00:59:54 -08001101 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103 return 0;
1104}
1105
Corey Minyard393d2cc2005-11-07 00:59:54 -08001106static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
1107 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001108 unsigned char cmd,
1109 unsigned char chan)
Corey Minyard393d2cc2005-11-07 00:59:54 -08001110{
1111 struct cmd_rcvr *rcvr;
1112
1113 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyardc69c3122006-09-30 23:27:56 -07001114 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1115 && (rcvr->chans & (1 << chan)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08001116 return rcvr;
1117 }
1118 return NULL;
1119}
1120
Corey Minyardc69c3122006-09-30 23:27:56 -07001121static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
1122 unsigned char netfn,
1123 unsigned char cmd,
1124 unsigned int chans)
1125{
1126 struct cmd_rcvr *rcvr;
1127
1128 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
1129 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1130 && (rcvr->chans & chans))
1131 return 0;
1132 }
1133 return 1;
1134}
1135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136int ipmi_register_for_cmd(ipmi_user_t user,
1137 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001138 unsigned char cmd,
1139 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001141 ipmi_smi_t intf = user->intf;
1142 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001143 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
1145
1146 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -08001147 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001149 rcvr->cmd = cmd;
1150 rcvr->netfn = netfn;
Corey Minyardc69c3122006-09-30 23:27:56 -07001151 rcvr->chans = chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001152 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
Corey Minyardd6dfd132006-03-31 02:30:41 -08001154 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 /* Make sure the command/netfn is not already registered. */
Corey Minyardc69c3122006-09-30 23:27:56 -07001156 if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08001157 rv = -EBUSY;
1158 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
1160
Corey Minyard393d2cc2005-11-07 00:59:54 -08001161 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -07001162
Corey Minyard393d2cc2005-11-07 00:59:54 -08001163 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -08001164 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 if (rv)
1166 kfree(rcvr);
1167
1168 return rv;
1169}
1170
1171int ipmi_unregister_for_cmd(ipmi_user_t user,
1172 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001173 unsigned char cmd,
1174 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001176 ipmi_smi_t intf = user->intf;
1177 struct cmd_rcvr *rcvr;
Corey Minyardc69c3122006-09-30 23:27:56 -07001178 struct cmd_rcvr *rcvrs = NULL;
1179 int i, rv = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
Corey Minyardd6dfd132006-03-31 02:30:41 -08001181 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyardc69c3122006-09-30 23:27:56 -07001182 for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
1183 if (((1 << i) & chans) == 0)
1184 continue;
1185 rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
1186 if (rcvr == NULL)
1187 continue;
1188 if (rcvr->user == user) {
1189 rv = 0;
1190 rcvr->chans &= ~chans;
1191 if (rcvr->chans == 0) {
1192 list_del_rcu(&rcvr->link);
1193 rcvr->next = rcvrs;
1194 rcvrs = rcvr;
1195 }
1196 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 }
Corey Minyardc69c3122006-09-30 23:27:56 -07001198 mutex_unlock(&intf->cmd_rcvrs_mutex);
1199 synchronize_rcu();
1200 while (rcvrs) {
1201 rcvr = rcvrs;
1202 rcvrs = rcvr->next;
1203 kfree(rcvr);
1204 }
1205 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206}
1207
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208static unsigned char
1209ipmb_checksum(unsigned char *data, int size)
1210{
1211 unsigned char csum = 0;
1212
1213 for (; size > 0; size--, data++)
1214 csum += *data;
1215
1216 return -csum;
1217}
1218
1219static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1220 struct kernel_ipmi_msg *msg,
1221 struct ipmi_ipmb_addr *ipmb_addr,
1222 long msgid,
1223 unsigned char ipmb_seq,
1224 int broadcast,
1225 unsigned char source_address,
1226 unsigned char source_lun)
1227{
1228 int i = broadcast;
1229
1230 /* Format the IPMB header data. */
1231 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1232 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1233 smi_msg->data[2] = ipmb_addr->channel;
1234 if (broadcast)
1235 smi_msg->data[3] = 0;
1236 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1237 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1238 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1239 smi_msg->data[i+6] = source_address;
1240 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1241 smi_msg->data[i+8] = msg->cmd;
1242
1243 /* Now tack on the data to the message. */
1244 if (msg->data_len > 0)
1245 memcpy(&(smi_msg->data[i+9]), msg->data,
1246 msg->data_len);
1247 smi_msg->data_size = msg->data_len + 9;
1248
1249 /* Now calculate the checksum and tack it on. */
1250 smi_msg->data[i+smi_msg->data_size]
1251 = ipmb_checksum(&(smi_msg->data[i+6]),
1252 smi_msg->data_size-6);
1253
1254 /* Add on the checksum size and the offset from the
1255 broadcast. */
1256 smi_msg->data_size += 1 + i;
1257
1258 smi_msg->msgid = msgid;
1259}
1260
1261static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1262 struct kernel_ipmi_msg *msg,
1263 struct ipmi_lan_addr *lan_addr,
1264 long msgid,
1265 unsigned char ipmb_seq,
1266 unsigned char source_lun)
1267{
1268 /* Format the IPMB header data. */
1269 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1270 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1271 smi_msg->data[2] = lan_addr->channel;
1272 smi_msg->data[3] = lan_addr->session_handle;
1273 smi_msg->data[4] = lan_addr->remote_SWID;
1274 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1275 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1276 smi_msg->data[7] = lan_addr->local_SWID;
1277 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1278 smi_msg->data[9] = msg->cmd;
1279
1280 /* Now tack on the data to the message. */
1281 if (msg->data_len > 0)
1282 memcpy(&(smi_msg->data[10]), msg->data,
1283 msg->data_len);
1284 smi_msg->data_size = msg->data_len + 10;
1285
1286 /* Now calculate the checksum and tack it on. */
1287 smi_msg->data[smi_msg->data_size]
1288 = ipmb_checksum(&(smi_msg->data[7]),
1289 smi_msg->data_size-7);
1290
1291 /* Add on the checksum size and the offset from the
1292 broadcast. */
1293 smi_msg->data_size += 1;
1294
1295 smi_msg->msgid = msgid;
1296}
1297
1298/* Separate from ipmi_request so that the user does not have to be
1299 supplied in certain circumstances (mainly at panic time). If
1300 messages are supplied, they will be freed, even if an error
1301 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001302static int i_ipmi_request(ipmi_user_t user,
1303 ipmi_smi_t intf,
1304 struct ipmi_addr *addr,
1305 long msgid,
1306 struct kernel_ipmi_msg *msg,
1307 void *user_msg_data,
1308 void *supplied_smi,
1309 struct ipmi_recv_msg *supplied_recv,
1310 int priority,
1311 unsigned char source_address,
1312 unsigned char source_lun,
1313 int retries,
1314 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315{
Corey Minyardb2c03942006-12-06 20:41:00 -08001316 int rv = 0;
1317 struct ipmi_smi_msg *smi_msg;
1318 struct ipmi_recv_msg *recv_msg;
1319 unsigned long flags;
1320 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
1322
1323 if (supplied_recv) {
1324 recv_msg = supplied_recv;
1325 } else {
1326 recv_msg = ipmi_alloc_recv_msg();
1327 if (recv_msg == NULL) {
1328 return -ENOMEM;
1329 }
1330 }
1331 recv_msg->user_msg_data = user_msg_data;
1332
1333 if (supplied_smi) {
1334 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1335 } else {
1336 smi_msg = ipmi_alloc_smi_msg();
1337 if (smi_msg == NULL) {
1338 ipmi_free_recv_msg(recv_msg);
1339 return -ENOMEM;
1340 }
1341 }
1342
Corey Minyardb2c03942006-12-06 20:41:00 -08001343 rcu_read_lock();
1344 handlers = intf->handlers;
1345 if (!handlers) {
1346 rv = -ENODEV;
1347 goto out_err;
1348 }
1349
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001351 if (user)
1352 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 recv_msg->msgid = msgid;
1354 /* Store the message to send in the receive message so timeout
1355 responses can get the proper response data. */
1356 recv_msg->msg = *msg;
1357
1358 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1359 struct ipmi_system_interface_addr *smi_addr;
1360
1361 if (msg->netfn & 1) {
1362 /* Responses are not allowed to the SMI. */
1363 rv = -EINVAL;
1364 goto out_err;
1365 }
1366
1367 smi_addr = (struct ipmi_system_interface_addr *) addr;
1368 if (smi_addr->lun > 3) {
1369 spin_lock_irqsave(&intf->counter_lock, flags);
1370 intf->sent_invalid_commands++;
1371 spin_unlock_irqrestore(&intf->counter_lock, flags);
1372 rv = -EINVAL;
1373 goto out_err;
1374 }
1375
1376 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1377
1378 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1379 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1380 || (msg->cmd == IPMI_GET_MSG_CMD)
1381 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1382 {
1383 /* We don't let the user do these, since we manage
1384 the sequence numbers. */
1385 spin_lock_irqsave(&intf->counter_lock, flags);
1386 intf->sent_invalid_commands++;
1387 spin_unlock_irqrestore(&intf->counter_lock, flags);
1388 rv = -EINVAL;
1389 goto out_err;
1390 }
1391
Corey Minyardb9675132006-12-06 20:41:02 -08001392 if (((msg->netfn == IPMI_NETFN_APP_REQUEST)
1393 && ((msg->cmd == IPMI_COLD_RESET_CMD)
1394 || (msg->cmd == IPMI_WARM_RESET_CMD)))
1395 || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST))
1396 {
1397 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1398 intf->auto_maintenance_timeout
1399 = IPMI_MAINTENANCE_MODE_TIMEOUT;
1400 if (!intf->maintenance_mode
1401 && !intf->maintenance_mode_enable)
1402 {
1403 intf->maintenance_mode_enable = 1;
1404 maintenance_mode_update(intf);
1405 }
1406 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
1407 flags);
1408 }
1409
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1411 spin_lock_irqsave(&intf->counter_lock, flags);
1412 intf->sent_invalid_commands++;
1413 spin_unlock_irqrestore(&intf->counter_lock, flags);
1414 rv = -EMSGSIZE;
1415 goto out_err;
1416 }
1417
1418 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1419 smi_msg->data[1] = msg->cmd;
1420 smi_msg->msgid = msgid;
1421 smi_msg->user_data = recv_msg;
1422 if (msg->data_len > 0)
1423 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1424 smi_msg->data_size = msg->data_len + 2;
1425 spin_lock_irqsave(&intf->counter_lock, flags);
1426 intf->sent_local_commands++;
1427 spin_unlock_irqrestore(&intf->counter_lock, flags);
1428 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1429 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1430 {
1431 struct ipmi_ipmb_addr *ipmb_addr;
1432 unsigned char ipmb_seq;
1433 long seqid;
1434 int broadcast = 0;
1435
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001436 if (addr->channel >= IPMI_MAX_CHANNELS) {
1437 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 intf->sent_invalid_commands++;
1439 spin_unlock_irqrestore(&intf->counter_lock, flags);
1440 rv = -EINVAL;
1441 goto out_err;
1442 }
1443
1444 if (intf->channels[addr->channel].medium
1445 != IPMI_CHANNEL_MEDIUM_IPMB)
1446 {
1447 spin_lock_irqsave(&intf->counter_lock, flags);
1448 intf->sent_invalid_commands++;
1449 spin_unlock_irqrestore(&intf->counter_lock, flags);
1450 rv = -EINVAL;
1451 goto out_err;
1452 }
1453
1454 if (retries < 0) {
1455 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1456 retries = 0; /* Don't retry broadcasts. */
1457 else
1458 retries = 4;
1459 }
1460 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1461 /* Broadcasts add a zero at the beginning of the
1462 message, but otherwise is the same as an IPMB
1463 address. */
1464 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1465 broadcast = 1;
1466 }
1467
1468
1469 /* Default to 1 second retries. */
1470 if (retry_time_ms == 0)
1471 retry_time_ms = 1000;
1472
1473 /* 9 for the header and 1 for the checksum, plus
1474 possibly one for the broadcast. */
1475 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1476 spin_lock_irqsave(&intf->counter_lock, flags);
1477 intf->sent_invalid_commands++;
1478 spin_unlock_irqrestore(&intf->counter_lock, flags);
1479 rv = -EMSGSIZE;
1480 goto out_err;
1481 }
1482
1483 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1484 if (ipmb_addr->lun > 3) {
1485 spin_lock_irqsave(&intf->counter_lock, flags);
1486 intf->sent_invalid_commands++;
1487 spin_unlock_irqrestore(&intf->counter_lock, flags);
1488 rv = -EINVAL;
1489 goto out_err;
1490 }
1491
1492 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1493
1494 if (recv_msg->msg.netfn & 0x1) {
1495 /* It's a response, so use the user's sequence
1496 from msgid. */
1497 spin_lock_irqsave(&intf->counter_lock, flags);
1498 intf->sent_ipmb_responses++;
1499 spin_unlock_irqrestore(&intf->counter_lock, flags);
1500 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1501 msgid, broadcast,
1502 source_address, source_lun);
1503
1504 /* Save the receive message so we can use it
1505 to deliver the response. */
1506 smi_msg->user_data = recv_msg;
1507 } else {
1508 /* It's a command, so get a sequence for it. */
1509
1510 spin_lock_irqsave(&(intf->seq_lock), flags);
1511
1512 spin_lock(&intf->counter_lock);
1513 intf->sent_ipmb_commands++;
1514 spin_unlock(&intf->counter_lock);
1515
1516 /* Create a sequence number with a 1 second
1517 timeout and 4 retries. */
1518 rv = intf_next_seq(intf,
1519 recv_msg,
1520 retry_time_ms,
1521 retries,
1522 broadcast,
1523 &ipmb_seq,
1524 &seqid);
1525 if (rv) {
1526 /* We have used up all the sequence numbers,
1527 probably, so abort. */
1528 spin_unlock_irqrestore(&(intf->seq_lock),
1529 flags);
1530 goto out_err;
1531 }
1532
1533 /* Store the sequence number in the message,
1534 so that when the send message response
1535 comes back we can start the timer. */
1536 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1537 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1538 ipmb_seq, broadcast,
1539 source_address, source_lun);
1540
1541 /* Copy the message into the recv message data, so we
1542 can retransmit it later if necessary. */
1543 memcpy(recv_msg->msg_data, smi_msg->data,
1544 smi_msg->data_size);
1545 recv_msg->msg.data = recv_msg->msg_data;
1546 recv_msg->msg.data_len = smi_msg->data_size;
1547
1548 /* We don't unlock until here, because we need
1549 to copy the completed message into the
1550 recv_msg before we release the lock.
1551 Otherwise, race conditions may bite us. I
1552 know that's pretty paranoid, but I prefer
1553 to be correct. */
1554 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1555 }
1556 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1557 struct ipmi_lan_addr *lan_addr;
1558 unsigned char ipmb_seq;
1559 long seqid;
1560
Jayachandran C12fc1d72006-02-03 03:04:51 -08001561 if (addr->channel >= IPMI_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 spin_lock_irqsave(&intf->counter_lock, flags);
1563 intf->sent_invalid_commands++;
1564 spin_unlock_irqrestore(&intf->counter_lock, flags);
1565 rv = -EINVAL;
1566 goto out_err;
1567 }
1568
1569 if ((intf->channels[addr->channel].medium
1570 != IPMI_CHANNEL_MEDIUM_8023LAN)
1571 && (intf->channels[addr->channel].medium
1572 != IPMI_CHANNEL_MEDIUM_ASYNC))
1573 {
1574 spin_lock_irqsave(&intf->counter_lock, flags);
1575 intf->sent_invalid_commands++;
1576 spin_unlock_irqrestore(&intf->counter_lock, flags);
1577 rv = -EINVAL;
1578 goto out_err;
1579 }
1580
1581 retries = 4;
1582
1583 /* Default to 1 second retries. */
1584 if (retry_time_ms == 0)
1585 retry_time_ms = 1000;
1586
1587 /* 11 for the header and 1 for the checksum. */
1588 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1589 spin_lock_irqsave(&intf->counter_lock, flags);
1590 intf->sent_invalid_commands++;
1591 spin_unlock_irqrestore(&intf->counter_lock, flags);
1592 rv = -EMSGSIZE;
1593 goto out_err;
1594 }
1595
1596 lan_addr = (struct ipmi_lan_addr *) addr;
1597 if (lan_addr->lun > 3) {
1598 spin_lock_irqsave(&intf->counter_lock, flags);
1599 intf->sent_invalid_commands++;
1600 spin_unlock_irqrestore(&intf->counter_lock, flags);
1601 rv = -EINVAL;
1602 goto out_err;
1603 }
1604
1605 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1606
1607 if (recv_msg->msg.netfn & 0x1) {
1608 /* It's a response, so use the user's sequence
1609 from msgid. */
1610 spin_lock_irqsave(&intf->counter_lock, flags);
1611 intf->sent_lan_responses++;
1612 spin_unlock_irqrestore(&intf->counter_lock, flags);
1613 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1614 msgid, source_lun);
1615
1616 /* Save the receive message so we can use it
1617 to deliver the response. */
1618 smi_msg->user_data = recv_msg;
1619 } else {
1620 /* It's a command, so get a sequence for it. */
1621
1622 spin_lock_irqsave(&(intf->seq_lock), flags);
1623
1624 spin_lock(&intf->counter_lock);
1625 intf->sent_lan_commands++;
1626 spin_unlock(&intf->counter_lock);
1627
1628 /* Create a sequence number with a 1 second
1629 timeout and 4 retries. */
1630 rv = intf_next_seq(intf,
1631 recv_msg,
1632 retry_time_ms,
1633 retries,
1634 0,
1635 &ipmb_seq,
1636 &seqid);
1637 if (rv) {
1638 /* We have used up all the sequence numbers,
1639 probably, so abort. */
1640 spin_unlock_irqrestore(&(intf->seq_lock),
1641 flags);
1642 goto out_err;
1643 }
1644
1645 /* Store the sequence number in the message,
1646 so that when the send message response
1647 comes back we can start the timer. */
1648 format_lan_msg(smi_msg, msg, lan_addr,
1649 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1650 ipmb_seq, source_lun);
1651
1652 /* Copy the message into the recv message data, so we
1653 can retransmit it later if necessary. */
1654 memcpy(recv_msg->msg_data, smi_msg->data,
1655 smi_msg->data_size);
1656 recv_msg->msg.data = recv_msg->msg_data;
1657 recv_msg->msg.data_len = smi_msg->data_size;
1658
1659 /* We don't unlock until here, because we need
1660 to copy the completed message into the
1661 recv_msg before we release the lock.
1662 Otherwise, race conditions may bite us. I
1663 know that's pretty paranoid, but I prefer
1664 to be correct. */
1665 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1666 }
1667 } else {
1668 /* Unknown address type. */
1669 spin_lock_irqsave(&intf->counter_lock, flags);
1670 intf->sent_invalid_commands++;
1671 spin_unlock_irqrestore(&intf->counter_lock, flags);
1672 rv = -EINVAL;
1673 goto out_err;
1674 }
1675
1676#ifdef DEBUG_MSGING
1677 {
1678 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001679 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 printk(" %2.2x", smi_msg->data[m]);
1681 printk("\n");
1682 }
1683#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08001684
1685 handlers->sender(intf->send_info, smi_msg, priority);
1686 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688 return 0;
1689
1690 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -08001691 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 ipmi_free_smi_msg(smi_msg);
1693 ipmi_free_recv_msg(recv_msg);
1694 return rv;
1695}
1696
Corey Minyardc14979b2005-09-06 15:18:38 -07001697static int check_addr(ipmi_smi_t intf,
1698 struct ipmi_addr *addr,
1699 unsigned char *saddr,
1700 unsigned char *lun)
1701{
1702 if (addr->channel >= IPMI_MAX_CHANNELS)
1703 return -EINVAL;
1704 *lun = intf->channels[addr->channel].lun;
1705 *saddr = intf->channels[addr->channel].address;
1706 return 0;
1707}
1708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709int ipmi_request_settime(ipmi_user_t user,
1710 struct ipmi_addr *addr,
1711 long msgid,
1712 struct kernel_ipmi_msg *msg,
1713 void *user_msg_data,
1714 int priority,
1715 int retries,
1716 unsigned int retry_time_ms)
1717{
Corey Minyardc14979b2005-09-06 15:18:38 -07001718 unsigned char saddr, lun;
1719 int rv;
1720
Corey Minyard8a3628d2006-03-31 02:30:40 -08001721 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001722 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001723 rv = check_addr(user->intf, addr, &saddr, &lun);
1724 if (rv)
1725 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 return i_ipmi_request(user,
1727 user->intf,
1728 addr,
1729 msgid,
1730 msg,
1731 user_msg_data,
1732 NULL, NULL,
1733 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001734 saddr,
1735 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 retries,
1737 retry_time_ms);
1738}
1739
1740int ipmi_request_supply_msgs(ipmi_user_t user,
1741 struct ipmi_addr *addr,
1742 long msgid,
1743 struct kernel_ipmi_msg *msg,
1744 void *user_msg_data,
1745 void *supplied_smi,
1746 struct ipmi_recv_msg *supplied_recv,
1747 int priority)
1748{
Corey Minyardc14979b2005-09-06 15:18:38 -07001749 unsigned char saddr, lun;
1750 int rv;
1751
Corey Minyard8a3628d2006-03-31 02:30:40 -08001752 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001753 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001754 rv = check_addr(user->intf, addr, &saddr, &lun);
1755 if (rv)
1756 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 return i_ipmi_request(user,
1758 user->intf,
1759 addr,
1760 msgid,
1761 msg,
1762 user_msg_data,
1763 supplied_smi,
1764 supplied_recv,
1765 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001766 saddr,
1767 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 -1, 0);
1769}
1770
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001771#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772static int ipmb_file_read_proc(char *page, char **start, off_t off,
1773 int count, int *eof, void *data)
1774{
1775 char *out = (char *) page;
1776 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001777 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001778 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
Corey Minyarde8b33612005-09-06 15:18:45 -07001780 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001781 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1782 out[rv-1] = '\n'; /* Replace the final space with a newline */
1783 out[rv] = '\0';
1784 rv++;
1785 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786}
1787
1788static int version_file_read_proc(char *page, char **start, off_t off,
1789 int count, int *eof, void *data)
1790{
1791 char *out = (char *) page;
1792 ipmi_smi_t intf = data;
1793
1794 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001795 ipmi_version_major(&intf->bmc->id),
1796 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797}
1798
1799static int stat_file_read_proc(char *page, char **start, off_t off,
1800 int count, int *eof, void *data)
1801{
1802 char *out = (char *) page;
1803 ipmi_smi_t intf = data;
1804
1805 out += sprintf(out, "sent_invalid_commands: %d\n",
1806 intf->sent_invalid_commands);
1807 out += sprintf(out, "sent_local_commands: %d\n",
1808 intf->sent_local_commands);
1809 out += sprintf(out, "handled_local_responses: %d\n",
1810 intf->handled_local_responses);
1811 out += sprintf(out, "unhandled_local_responses: %d\n",
1812 intf->unhandled_local_responses);
1813 out += sprintf(out, "sent_ipmb_commands: %d\n",
1814 intf->sent_ipmb_commands);
1815 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1816 intf->sent_ipmb_command_errs);
1817 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1818 intf->retransmitted_ipmb_commands);
1819 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1820 intf->timed_out_ipmb_commands);
1821 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1822 intf->timed_out_ipmb_broadcasts);
1823 out += sprintf(out, "sent_ipmb_responses: %d\n",
1824 intf->sent_ipmb_responses);
1825 out += sprintf(out, "handled_ipmb_responses: %d\n",
1826 intf->handled_ipmb_responses);
1827 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1828 intf->invalid_ipmb_responses);
1829 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1830 intf->unhandled_ipmb_responses);
1831 out += sprintf(out, "sent_lan_commands: %d\n",
1832 intf->sent_lan_commands);
1833 out += sprintf(out, "sent_lan_command_errs: %d\n",
1834 intf->sent_lan_command_errs);
1835 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1836 intf->retransmitted_lan_commands);
1837 out += sprintf(out, "timed_out_lan_commands: %d\n",
1838 intf->timed_out_lan_commands);
1839 out += sprintf(out, "sent_lan_responses: %d\n",
1840 intf->sent_lan_responses);
1841 out += sprintf(out, "handled_lan_responses: %d\n",
1842 intf->handled_lan_responses);
1843 out += sprintf(out, "invalid_lan_responses: %d\n",
1844 intf->invalid_lan_responses);
1845 out += sprintf(out, "unhandled_lan_responses: %d\n",
1846 intf->unhandled_lan_responses);
1847 out += sprintf(out, "handled_commands: %d\n",
1848 intf->handled_commands);
1849 out += sprintf(out, "invalid_commands: %d\n",
1850 intf->invalid_commands);
1851 out += sprintf(out, "unhandled_commands: %d\n",
1852 intf->unhandled_commands);
1853 out += sprintf(out, "invalid_events: %d\n",
1854 intf->invalid_events);
1855 out += sprintf(out, "events: %d\n",
1856 intf->events);
1857
1858 return (out - ((char *) page));
1859}
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001860#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
1862int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1863 read_proc_t *read_proc, write_proc_t *write_proc,
1864 void *data, struct module *owner)
1865{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001867#ifdef CONFIG_PROC_FS
1868 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 struct ipmi_proc_entry *entry;
1870
1871 /* Create a list element. */
1872 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1873 if (!entry)
1874 return -ENOMEM;
1875 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1876 if (!entry->name) {
1877 kfree(entry);
1878 return -ENOMEM;
1879 }
1880 strcpy(entry->name, name);
1881
1882 file = create_proc_entry(name, 0, smi->proc_dir);
1883 if (!file) {
1884 kfree(entry->name);
1885 kfree(entry);
1886 rv = -ENOMEM;
1887 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 file->data = data;
1889 file->read_proc = read_proc;
1890 file->write_proc = write_proc;
1891 file->owner = owner;
1892
Corey Minyardac019152007-10-18 03:07:11 -07001893 mutex_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 /* Stick it on the list. */
1895 entry->next = smi->proc_entries;
1896 smi->proc_entries = entry;
Corey Minyardac019152007-10-18 03:07:11 -07001897 mutex_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 }
Corey Minyard3b625942005-06-23 22:01:42 -07001899#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
1901 return rv;
1902}
1903
1904static int add_proc_entries(ipmi_smi_t smi, int num)
1905{
1906 int rv = 0;
1907
Corey Minyard3b625942005-06-23 22:01:42 -07001908#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 sprintf(smi->proc_dir_name, "%d", num);
1910 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1911 if (!smi->proc_dir)
1912 rv = -ENOMEM;
1913 else {
1914 smi->proc_dir->owner = THIS_MODULE;
1915 }
1916
1917 if (rv == 0)
1918 rv = ipmi_smi_add_proc_entry(smi, "stats",
1919 stat_file_read_proc, NULL,
1920 smi, THIS_MODULE);
1921
1922 if (rv == 0)
1923 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1924 ipmb_file_read_proc, NULL,
1925 smi, THIS_MODULE);
1926
1927 if (rv == 0)
1928 rv = ipmi_smi_add_proc_entry(smi, "version",
1929 version_file_read_proc, NULL,
1930 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001931#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
1933 return rv;
1934}
1935
1936static void remove_proc_entries(ipmi_smi_t smi)
1937{
Corey Minyard3b625942005-06-23 22:01:42 -07001938#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 struct ipmi_proc_entry *entry;
1940
Corey Minyardac019152007-10-18 03:07:11 -07001941 mutex_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 while (smi->proc_entries) {
1943 entry = smi->proc_entries;
1944 smi->proc_entries = entry->next;
1945
1946 remove_proc_entry(entry->name, smi->proc_dir);
1947 kfree(entry->name);
1948 kfree(entry);
1949 }
Corey Minyardac019152007-10-18 03:07:11 -07001950 mutex_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001952#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953}
1954
Corey Minyard50c812b2006-03-26 01:37:21 -08001955static int __find_bmc_guid(struct device *dev, void *data)
1956{
1957 unsigned char *id = data;
1958 struct bmc_device *bmc = dev_get_drvdata(dev);
1959 return memcmp(bmc->guid, id, 16) == 0;
1960}
1961
1962static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1963 unsigned char *guid)
1964{
1965 struct device *dev;
1966
1967 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1968 if (dev)
1969 return dev_get_drvdata(dev);
1970 else
1971 return NULL;
1972}
1973
1974struct prod_dev_id {
1975 unsigned int product_id;
1976 unsigned char device_id;
1977};
1978
1979static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1980{
1981 struct prod_dev_id *id = data;
1982 struct bmc_device *bmc = dev_get_drvdata(dev);
1983
1984 return (bmc->id.product_id == id->product_id
Corey Minyard50c812b2006-03-26 01:37:21 -08001985 && bmc->id.device_id == id->device_id);
1986}
1987
1988static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1989 struct device_driver *drv,
Corey Minyardf0b55da2006-12-06 20:40:54 -08001990 unsigned int product_id, unsigned char device_id)
Corey Minyard50c812b2006-03-26 01:37:21 -08001991{
1992 struct prod_dev_id id = {
1993 .product_id = product_id,
1994 .device_id = device_id,
1995 };
1996 struct device *dev;
1997
1998 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
1999 if (dev)
2000 return dev_get_drvdata(dev);
2001 else
2002 return NULL;
2003}
2004
2005static ssize_t device_id_show(struct device *dev,
2006 struct device_attribute *attr,
2007 char *buf)
2008{
2009 struct bmc_device *bmc = dev_get_drvdata(dev);
2010
2011 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
2012}
2013
2014static ssize_t provides_dev_sdrs_show(struct device *dev,
2015 struct device_attribute *attr,
2016 char *buf)
2017{
2018 struct bmc_device *bmc = dev_get_drvdata(dev);
2019
2020 return snprintf(buf, 10, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002021 (bmc->id.device_revision & 0x80) >> 7);
Corey Minyard50c812b2006-03-26 01:37:21 -08002022}
2023
2024static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
2025 char *buf)
2026{
2027 struct bmc_device *bmc = dev_get_drvdata(dev);
2028
2029 return snprintf(buf, 20, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002030 bmc->id.device_revision & 0x0F);
Corey Minyard50c812b2006-03-26 01:37:21 -08002031}
2032
2033static ssize_t firmware_rev_show(struct device *dev,
2034 struct device_attribute *attr,
2035 char *buf)
2036{
2037 struct bmc_device *bmc = dev_get_drvdata(dev);
2038
2039 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
2040 bmc->id.firmware_revision_2);
2041}
2042
2043static ssize_t ipmi_version_show(struct device *dev,
2044 struct device_attribute *attr,
2045 char *buf)
2046{
2047 struct bmc_device *bmc = dev_get_drvdata(dev);
2048
2049 return snprintf(buf, 20, "%u.%u\n",
2050 ipmi_version_major(&bmc->id),
2051 ipmi_version_minor(&bmc->id));
2052}
2053
2054static ssize_t add_dev_support_show(struct device *dev,
2055 struct device_attribute *attr,
2056 char *buf)
2057{
2058 struct bmc_device *bmc = dev_get_drvdata(dev);
2059
2060 return snprintf(buf, 10, "0x%02x\n",
2061 bmc->id.additional_device_support);
2062}
2063
2064static ssize_t manufacturer_id_show(struct device *dev,
2065 struct device_attribute *attr,
2066 char *buf)
2067{
2068 struct bmc_device *bmc = dev_get_drvdata(dev);
2069
2070 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
2071}
2072
2073static ssize_t product_id_show(struct device *dev,
2074 struct device_attribute *attr,
2075 char *buf)
2076{
2077 struct bmc_device *bmc = dev_get_drvdata(dev);
2078
2079 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
2080}
2081
2082static ssize_t aux_firmware_rev_show(struct device *dev,
2083 struct device_attribute *attr,
2084 char *buf)
2085{
2086 struct bmc_device *bmc = dev_get_drvdata(dev);
2087
2088 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
2089 bmc->id.aux_firmware_revision[3],
2090 bmc->id.aux_firmware_revision[2],
2091 bmc->id.aux_firmware_revision[1],
2092 bmc->id.aux_firmware_revision[0]);
2093}
2094
2095static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
2096 char *buf)
2097{
2098 struct bmc_device *bmc = dev_get_drvdata(dev);
2099
2100 return snprintf(buf, 100, "%Lx%Lx\n",
2101 (long long) bmc->guid[0],
2102 (long long) bmc->guid[8]);
2103}
2104
Jeff Garzik5e593932006-10-11 01:22:21 -07002105static void remove_files(struct bmc_device *bmc)
Corey Minyard50c812b2006-03-26 01:37:21 -08002106{
Corey Minyardf0b55da2006-12-06 20:40:54 -08002107 if (!bmc->dev)
2108 return;
2109
Corey Minyard50c812b2006-03-26 01:37:21 -08002110 device_remove_file(&bmc->dev->dev,
2111 &bmc->device_id_attr);
2112 device_remove_file(&bmc->dev->dev,
2113 &bmc->provides_dev_sdrs_attr);
2114 device_remove_file(&bmc->dev->dev,
2115 &bmc->revision_attr);
2116 device_remove_file(&bmc->dev->dev,
2117 &bmc->firmware_rev_attr);
2118 device_remove_file(&bmc->dev->dev,
2119 &bmc->version_attr);
2120 device_remove_file(&bmc->dev->dev,
2121 &bmc->add_dev_support_attr);
2122 device_remove_file(&bmc->dev->dev,
2123 &bmc->manufacturer_id_attr);
2124 device_remove_file(&bmc->dev->dev,
2125 &bmc->product_id_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002126
Corey Minyard50c812b2006-03-26 01:37:21 -08002127 if (bmc->id.aux_firmware_revision_set)
2128 device_remove_file(&bmc->dev->dev,
2129 &bmc->aux_firmware_rev_attr);
2130 if (bmc->guid_set)
2131 device_remove_file(&bmc->dev->dev,
2132 &bmc->guid_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002133}
2134
2135static void
2136cleanup_bmc_device(struct kref *ref)
2137{
2138 struct bmc_device *bmc;
2139
2140 bmc = container_of(ref, struct bmc_device, refcount);
2141
2142 remove_files(bmc);
Corey Minyard1d5636c2006-12-10 02:19:08 -08002143 platform_device_unregister(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002144 kfree(bmc);
2145}
2146
2147static void ipmi_bmc_unregister(ipmi_smi_t intf)
2148{
2149 struct bmc_device *bmc = intf->bmc;
2150
Corey Minyard759643b2006-12-06 20:40:59 -08002151 if (intf->sysfs_name) {
2152 sysfs_remove_link(&intf->si_dev->kobj, intf->sysfs_name);
2153 kfree(intf->sysfs_name);
2154 intf->sysfs_name = NULL;
2155 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002156 if (intf->my_dev_name) {
2157 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
2158 kfree(intf->my_dev_name);
2159 intf->my_dev_name = NULL;
2160 }
2161
2162 mutex_lock(&ipmidriver_mutex);
2163 kref_put(&bmc->refcount, cleanup_bmc_device);
Corey Minyardf0b55da2006-12-06 20:40:54 -08002164 intf->bmc = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002165 mutex_unlock(&ipmidriver_mutex);
2166}
2167
Jeff Garzik5e593932006-10-11 01:22:21 -07002168static int create_files(struct bmc_device *bmc)
2169{
2170 int err;
2171
Corey Minyardf0b55da2006-12-06 20:40:54 -08002172 bmc->device_id_attr.attr.name = "device_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002173 bmc->device_id_attr.attr.mode = S_IRUGO;
2174 bmc->device_id_attr.show = device_id_show;
2175
2176 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002177 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2178 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2179
2180 bmc->revision_attr.attr.name = "revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002181 bmc->revision_attr.attr.mode = S_IRUGO;
2182 bmc->revision_attr.show = revision_show;
2183
2184 bmc->firmware_rev_attr.attr.name = "firmware_revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002185 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2186 bmc->firmware_rev_attr.show = firmware_rev_show;
2187
2188 bmc->version_attr.attr.name = "ipmi_version";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002189 bmc->version_attr.attr.mode = S_IRUGO;
2190 bmc->version_attr.show = ipmi_version_show;
2191
2192 bmc->add_dev_support_attr.attr.name = "additional_device_support";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002193 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2194 bmc->add_dev_support_attr.show = add_dev_support_show;
2195
2196 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002197 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2198 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2199
2200 bmc->product_id_attr.attr.name = "product_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002201 bmc->product_id_attr.attr.mode = S_IRUGO;
2202 bmc->product_id_attr.show = product_id_show;
2203
2204 bmc->guid_attr.attr.name = "guid";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002205 bmc->guid_attr.attr.mode = S_IRUGO;
2206 bmc->guid_attr.show = guid_show;
2207
2208 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002209 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2210 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2211
Jeff Garzik5e593932006-10-11 01:22:21 -07002212 err = device_create_file(&bmc->dev->dev,
2213 &bmc->device_id_attr);
2214 if (err) goto out;
2215 err = device_create_file(&bmc->dev->dev,
2216 &bmc->provides_dev_sdrs_attr);
2217 if (err) goto out_devid;
2218 err = device_create_file(&bmc->dev->dev,
2219 &bmc->revision_attr);
2220 if (err) goto out_sdrs;
2221 err = device_create_file(&bmc->dev->dev,
2222 &bmc->firmware_rev_attr);
2223 if (err) goto out_rev;
2224 err = device_create_file(&bmc->dev->dev,
2225 &bmc->version_attr);
2226 if (err) goto out_firm;
2227 err = device_create_file(&bmc->dev->dev,
2228 &bmc->add_dev_support_attr);
2229 if (err) goto out_version;
2230 err = device_create_file(&bmc->dev->dev,
2231 &bmc->manufacturer_id_attr);
2232 if (err) goto out_add_dev;
2233 err = device_create_file(&bmc->dev->dev,
2234 &bmc->product_id_attr);
2235 if (err) goto out_manu;
2236 if (bmc->id.aux_firmware_revision_set) {
2237 err = device_create_file(&bmc->dev->dev,
2238 &bmc->aux_firmware_rev_attr);
2239 if (err) goto out_prod_id;
2240 }
2241 if (bmc->guid_set) {
2242 err = device_create_file(&bmc->dev->dev,
2243 &bmc->guid_attr);
2244 if (err) goto out_aux_firm;
2245 }
2246
2247 return 0;
2248
2249out_aux_firm:
2250 if (bmc->id.aux_firmware_revision_set)
2251 device_remove_file(&bmc->dev->dev,
2252 &bmc->aux_firmware_rev_attr);
2253out_prod_id:
2254 device_remove_file(&bmc->dev->dev,
2255 &bmc->product_id_attr);
2256out_manu:
2257 device_remove_file(&bmc->dev->dev,
2258 &bmc->manufacturer_id_attr);
2259out_add_dev:
2260 device_remove_file(&bmc->dev->dev,
2261 &bmc->add_dev_support_attr);
2262out_version:
2263 device_remove_file(&bmc->dev->dev,
2264 &bmc->version_attr);
2265out_firm:
2266 device_remove_file(&bmc->dev->dev,
2267 &bmc->firmware_rev_attr);
2268out_rev:
2269 device_remove_file(&bmc->dev->dev,
2270 &bmc->revision_attr);
2271out_sdrs:
2272 device_remove_file(&bmc->dev->dev,
2273 &bmc->provides_dev_sdrs_attr);
2274out_devid:
2275 device_remove_file(&bmc->dev->dev,
2276 &bmc->device_id_attr);
2277out:
2278 return err;
2279}
2280
Corey Minyard759643b2006-12-06 20:40:59 -08002281static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
2282 const char *sysfs_name)
Corey Minyard50c812b2006-03-26 01:37:21 -08002283{
2284 int rv;
2285 struct bmc_device *bmc = intf->bmc;
2286 struct bmc_device *old_bmc;
2287 int size;
2288 char dummy[1];
2289
2290 mutex_lock(&ipmidriver_mutex);
2291
2292 /*
2293 * Try to find if there is an bmc_device struct
2294 * representing the interfaced BMC already
2295 */
2296 if (bmc->guid_set)
2297 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
2298 else
2299 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
2300 bmc->id.product_id,
2301 bmc->id.device_id);
2302
2303 /*
2304 * If there is already an bmc_device, free the new one,
2305 * otherwise register the new BMC device
2306 */
2307 if (old_bmc) {
2308 kfree(bmc);
2309 intf->bmc = old_bmc;
2310 bmc = old_bmc;
2311
2312 kref_get(&bmc->refcount);
2313 mutex_unlock(&ipmidriver_mutex);
2314
2315 printk(KERN_INFO
2316 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
2317 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2318 bmc->id.manufacturer_id,
2319 bmc->id.product_id,
2320 bmc->id.device_id);
2321 } else {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002322 char name[14];
2323 unsigned char orig_dev_id = bmc->id.device_id;
2324 int warn_printed = 0;
2325
2326 snprintf(name, sizeof(name),
2327 "ipmi_bmc.%4.4x", bmc->id.product_id);
2328
2329 while (ipmi_find_bmc_prod_dev_id(&ipmidriver,
2330 bmc->id.product_id,
Corey Minyard1d5636c2006-12-10 02:19:08 -08002331 bmc->id.device_id)) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002332 if (!warn_printed) {
2333 printk(KERN_WARNING PFX
2334 "This machine has two different BMCs"
2335 " with the same product id and device"
2336 " id. This is an error in the"
2337 " firmware, but incrementing the"
2338 " device id to work around the problem."
2339 " Prod ID = 0x%x, Dev ID = 0x%x\n",
2340 bmc->id.product_id, bmc->id.device_id);
2341 warn_printed = 1;
2342 }
2343 bmc->id.device_id++; /* Wraps at 255 */
2344 if (bmc->id.device_id == orig_dev_id) {
2345 printk(KERN_ERR PFX
2346 "Out of device ids!\n");
2347 break;
2348 }
2349 }
2350
2351 bmc->dev = platform_device_alloc(name, bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08002352 if (!bmc->dev) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002353 mutex_unlock(&ipmidriver_mutex);
Corey Minyard50c812b2006-03-26 01:37:21 -08002354 printk(KERN_ERR
2355 "ipmi_msghandler:"
2356 " Unable to allocate platform device\n");
2357 return -ENOMEM;
2358 }
2359 bmc->dev->dev.driver = &ipmidriver;
2360 dev_set_drvdata(&bmc->dev->dev, bmc);
2361 kref_init(&bmc->refcount);
2362
Zhang, Yanminb48f5452006-11-16 01:19:08 -08002363 rv = platform_device_add(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002364 mutex_unlock(&ipmidriver_mutex);
2365 if (rv) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002366 platform_device_put(bmc->dev);
2367 bmc->dev = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002368 printk(KERN_ERR
2369 "ipmi_msghandler:"
2370 " Unable to register bmc device: %d\n",
2371 rv);
2372 /* Don't go to out_err, you can only do that if
2373 the device is registered already. */
2374 return rv;
2375 }
2376
Jeff Garzik5e593932006-10-11 01:22:21 -07002377 rv = create_files(bmc);
2378 if (rv) {
2379 mutex_lock(&ipmidriver_mutex);
2380 platform_device_unregister(bmc->dev);
2381 mutex_unlock(&ipmidriver_mutex);
2382
2383 return rv;
2384 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002385
2386 printk(KERN_INFO
2387 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2388 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2389 bmc->id.manufacturer_id,
2390 bmc->id.product_id,
2391 bmc->id.device_id);
2392 }
2393
2394 /*
2395 * create symlink from system interface device to bmc device
2396 * and back.
2397 */
Corey Minyard759643b2006-12-06 20:40:59 -08002398 intf->sysfs_name = kstrdup(sysfs_name, GFP_KERNEL);
2399 if (!intf->sysfs_name) {
2400 rv = -ENOMEM;
2401 printk(KERN_ERR
2402 "ipmi_msghandler: allocate link to BMC: %d\n",
2403 rv);
2404 goto out_err;
2405 }
2406
Corey Minyard50c812b2006-03-26 01:37:21 -08002407 rv = sysfs_create_link(&intf->si_dev->kobj,
Corey Minyard759643b2006-12-06 20:40:59 -08002408 &bmc->dev->dev.kobj, intf->sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002409 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002410 kfree(intf->sysfs_name);
2411 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002412 printk(KERN_ERR
2413 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2414 rv);
2415 goto out_err;
2416 }
2417
Corey Minyard759643b2006-12-06 20:40:59 -08002418 size = snprintf(dummy, 0, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002419 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2420 if (!intf->my_dev_name) {
Corey Minyard759643b2006-12-06 20:40:59 -08002421 kfree(intf->sysfs_name);
2422 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002423 rv = -ENOMEM;
2424 printk(KERN_ERR
2425 "ipmi_msghandler: allocate link from BMC: %d\n",
2426 rv);
2427 goto out_err;
2428 }
Corey Minyard759643b2006-12-06 20:40:59 -08002429 snprintf(intf->my_dev_name, size+1, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002430
2431 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2432 intf->my_dev_name);
2433 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002434 kfree(intf->sysfs_name);
2435 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002436 kfree(intf->my_dev_name);
2437 intf->my_dev_name = NULL;
2438 printk(KERN_ERR
2439 "ipmi_msghandler:"
2440 " Unable to create symlink to bmc: %d\n",
2441 rv);
2442 goto out_err;
2443 }
2444
2445 return 0;
2446
2447out_err:
2448 ipmi_bmc_unregister(intf);
2449 return rv;
2450}
2451
2452static int
2453send_guid_cmd(ipmi_smi_t intf, int chan)
2454{
2455 struct kernel_ipmi_msg msg;
2456 struct ipmi_system_interface_addr si;
2457
2458 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2459 si.channel = IPMI_BMC_CHANNEL;
2460 si.lun = 0;
2461
2462 msg.netfn = IPMI_NETFN_APP_REQUEST;
2463 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2464 msg.data = NULL;
2465 msg.data_len = 0;
2466 return i_ipmi_request(NULL,
2467 intf,
2468 (struct ipmi_addr *) &si,
2469 0,
2470 &msg,
2471 intf,
2472 NULL,
2473 NULL,
2474 0,
2475 intf->channels[0].address,
2476 intf->channels[0].lun,
2477 -1, 0);
2478}
2479
2480static void
2481guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2482{
2483 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2484 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2485 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2486 /* Not for me */
2487 return;
2488
2489 if (msg->msg.data[0] != 0) {
2490 /* Error from getting the GUID, the BMC doesn't have one. */
2491 intf->bmc->guid_set = 0;
2492 goto out;
2493 }
2494
2495 if (msg->msg.data_len < 17) {
2496 intf->bmc->guid_set = 0;
2497 printk(KERN_WARNING PFX
2498 "guid_handler: The GUID response from the BMC was too"
2499 " short, it was %d but should have been 17. Assuming"
2500 " GUID is not available.\n",
2501 msg->msg.data_len);
2502 goto out;
2503 }
2504
2505 memcpy(intf->bmc->guid, msg->msg.data, 16);
2506 intf->bmc->guid_set = 1;
2507 out:
2508 wake_up(&intf->waitq);
2509}
2510
2511static void
2512get_guid(ipmi_smi_t intf)
2513{
2514 int rv;
2515
2516 intf->bmc->guid_set = 0x2;
2517 intf->null_user_handler = guid_handler;
2518 rv = send_guid_cmd(intf, 0);
2519 if (rv)
2520 /* Send failed, no GUID available. */
2521 intf->bmc->guid_set = 0;
2522 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2523 intf->null_user_handler = NULL;
2524}
2525
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526static int
2527send_channel_info_cmd(ipmi_smi_t intf, int chan)
2528{
2529 struct kernel_ipmi_msg msg;
2530 unsigned char data[1];
2531 struct ipmi_system_interface_addr si;
2532
2533 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2534 si.channel = IPMI_BMC_CHANNEL;
2535 si.lun = 0;
2536
2537 msg.netfn = IPMI_NETFN_APP_REQUEST;
2538 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2539 msg.data = data;
2540 msg.data_len = 1;
2541 data[0] = chan;
2542 return i_ipmi_request(NULL,
2543 intf,
2544 (struct ipmi_addr *) &si,
2545 0,
2546 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002547 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 NULL,
2549 NULL,
2550 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002551 intf->channels[0].address,
2552 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 -1, 0);
2554}
2555
2556static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002557channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558{
2559 int rv = 0;
2560 int chan;
2561
Corey Minyard56a55ec2005-09-06 15:18:42 -07002562 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2563 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2564 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 {
2566 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002567 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 /* Got an error from the channel, just go on. */
2569
Corey Minyard56a55ec2005-09-06 15:18:42 -07002570 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 /* If the MC does not support this
2572 command, that is legal. We just
2573 assume it has one IPMB at channel
2574 zero. */
2575 intf->channels[0].medium
2576 = IPMI_CHANNEL_MEDIUM_IPMB;
2577 intf->channels[0].protocol
2578 = IPMI_CHANNEL_PROTOCOL_IPMB;
2579 rv = -ENOSYS;
2580
2581 intf->curr_channel = IPMI_MAX_CHANNELS;
2582 wake_up(&intf->waitq);
2583 goto out;
2584 }
2585 goto next_channel;
2586 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002587 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 /* Message not big enough, just go on. */
2589 goto next_channel;
2590 }
2591 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002592 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2593 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594
2595 next_channel:
2596 intf->curr_channel++;
2597 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2598 wake_up(&intf->waitq);
2599 else
2600 rv = send_channel_info_cmd(intf, intf->curr_channel);
2601
2602 if (rv) {
2603 /* Got an error somehow, just give up. */
2604 intf->curr_channel = IPMI_MAX_CHANNELS;
2605 wake_up(&intf->waitq);
2606
2607 printk(KERN_WARNING PFX
2608 "Error sending channel information: %d\n",
2609 rv);
2610 }
2611 }
2612 out:
2613 return;
2614}
2615
Corey Minyardfcfa4722007-10-18 03:07:09 -07002616void ipmi_poll_interface(ipmi_user_t user)
2617{
2618 ipmi_smi_t intf = user->intf;
2619
2620 if (intf->handlers->poll)
2621 intf->handlers->poll(intf->send_info);
2622}
2623
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2625 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002626 struct ipmi_device_id *device_id,
2627 struct device *si_dev,
Corey Minyard759643b2006-12-06 20:40:59 -08002628 const char *sysfs_name,
Corey Minyard453823b2006-03-31 02:30:39 -08002629 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630{
2631 int i, j;
2632 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002633 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -08002634 ipmi_smi_t tintf;
Corey Minyardbca03242006-12-06 20:40:57 -08002635 struct list_head *link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 /* Make sure the driver is actually initialized, this handles
2638 problems with initialization order. */
2639 if (!initialized) {
2640 rv = ipmi_init_msghandler();
2641 if (rv)
2642 return rv;
2643 /* The init code doesn't return an error if it was turned
2644 off, but it won't initialize. Check that. */
2645 if (!initialized)
2646 return -ENODEV;
2647 }
2648
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07002649 intf = kzalloc(sizeof(*intf), GFP_KERNEL);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002650 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 return -ENOMEM;
Corey Minyardb2c03942006-12-06 20:41:00 -08002652
2653 intf->ipmi_version_major = ipmi_version_major(device_id);
2654 intf->ipmi_version_minor = ipmi_version_minor(device_id);
2655
Corey Minyard50c812b2006-03-26 01:37:21 -08002656 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2657 if (!intf->bmc) {
2658 kfree(intf);
2659 return -ENOMEM;
2660 }
Corey Minyardbca03242006-12-06 20:40:57 -08002661 intf->intf_num = -1; /* Mark it invalid for now. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002662 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002663 intf->bmc->id = *device_id;
2664 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002665 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2666 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2667 intf->channels[j].lun = 2;
2668 }
2669 if (slave_addr != 0)
2670 intf->channels[0].address = slave_addr;
2671 INIT_LIST_HEAD(&intf->users);
2672 intf->handlers = handlers;
2673 intf->send_info = send_info;
2674 spin_lock_init(&intf->seq_lock);
2675 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2676 intf->seq_table[j].inuse = 0;
2677 intf->seq_table[j].seqid = 0;
2678 }
2679 intf->curr_seq = 0;
2680#ifdef CONFIG_PROC_FS
Corey Minyardac019152007-10-18 03:07:11 -07002681 mutex_init(&intf->proc_entry_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002682#endif
2683 spin_lock_init(&intf->waiting_msgs_lock);
2684 INIT_LIST_HEAD(&intf->waiting_msgs);
2685 spin_lock_init(&intf->events_lock);
2686 INIT_LIST_HEAD(&intf->waiting_events);
2687 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002688 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyardb9675132006-12-06 20:41:02 -08002689 spin_lock_init(&intf->maintenance_mode_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002690 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2691 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
Corey Minyard393d2cc2005-11-07 00:59:54 -08002693 spin_lock_init(&intf->counter_lock);
2694 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
Corey Minyardb2c03942006-12-06 20:41:00 -08002696 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002697 mutex_lock(&ipmi_interfaces_mutex);
2698 /* Look for a hole in the numbers. */
2699 i = 0;
2700 link = &ipmi_interfaces;
2701 list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) {
2702 if (tintf->intf_num != i) {
2703 link = &tintf->link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 break;
2705 }
Corey Minyardbca03242006-12-06 20:40:57 -08002706 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 }
Corey Minyardbca03242006-12-06 20:40:57 -08002708 /* Add the new interface in numeric order. */
2709 if (i == 0)
2710 list_add_rcu(&intf->link, &ipmi_interfaces);
2711 else
2712 list_add_tail_rcu(&intf->link, link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713
Corey Minyard453823b2006-03-31 02:30:39 -08002714 rv = handlers->start_processing(send_info, intf);
2715 if (rv)
2716 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002717
Corey Minyard50c812b2006-03-26 01:37:21 -08002718 get_guid(intf);
2719
Corey Minyardb2c03942006-12-06 20:41:00 -08002720 if ((intf->ipmi_version_major > 1)
2721 || ((intf->ipmi_version_major == 1)
2722 && (intf->ipmi_version_minor >= 5)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08002723 {
2724 /* Start scanning the channels to see what is
2725 available. */
2726 intf->null_user_handler = channel_handler;
2727 intf->curr_channel = 0;
2728 rv = send_channel_info_cmd(intf, 0);
2729 if (rv)
2730 goto out;
2731
2732 /* Wait for the channel info to be read. */
2733 wait_event(intf->waitq,
2734 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002735 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002736 } else {
2737 /* Assume a single IPMB channel at zero. */
2738 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2739 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741
2742 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002743 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744
Corey Minyard759643b2006-12-06 20:40:59 -08002745 rv = ipmi_bmc_register(intf, i, sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002746
Corey Minyard393d2cc2005-11-07 00:59:54 -08002747 out:
2748 if (rv) {
2749 if (intf->proc_dir)
2750 remove_proc_entries(intf);
Corey Minyardb2c03942006-12-06 20:41:00 -08002751 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002752 list_del_rcu(&intf->link);
2753 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002754 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002755 synchronize_rcu();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002756 kref_put(&intf->refcount, intf_free);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002757 } else {
Corey Minyard78ba2fa2007-02-10 01:45:45 -08002758 /*
2759 * Keep memory order straight for RCU readers. Make
2760 * sure everything else is committed to memory before
2761 * setting intf_num to mark the interface valid.
2762 */
2763 smp_wmb();
Corey Minyardbca03242006-12-06 20:40:57 -08002764 intf->intf_num = i;
2765 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard78ba2fa2007-02-10 01:45:45 -08002766 /* After this point the interface is legal to use. */
Corey Minyard50c812b2006-03-26 01:37:21 -08002767 call_smi_watchers(i, intf->si_dev);
Corey Minyardb2c03942006-12-06 20:41:00 -08002768 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 }
2770
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 return rv;
2772}
2773
Corey Minyardb2c03942006-12-06 20:41:00 -08002774static void cleanup_smi_msgs(ipmi_smi_t intf)
2775{
2776 int i;
2777 struct seq_table *ent;
2778
2779 /* No need for locks, the interface is down. */
2780 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
2781 ent = &(intf->seq_table[i]);
2782 if (!ent->inuse)
2783 continue;
2784 deliver_err_response(ent->recv_msg, IPMI_ERR_UNSPECIFIED);
2785 }
2786}
2787
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788int ipmi_unregister_smi(ipmi_smi_t intf)
2789{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 struct ipmi_smi_watcher *w;
Corey Minyardb2c03942006-12-06 20:41:00 -08002791 int intf_num = intf->intf_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
Corey Minyard50c812b2006-03-26 01:37:21 -08002793 ipmi_bmc_unregister(intf);
2794
Corey Minyardb2c03942006-12-06 20:41:00 -08002795 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002796 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002797 intf->intf_num = -1;
2798 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002799 list_del_rcu(&intf->link);
2800 mutex_unlock(&ipmi_interfaces_mutex);
2801 synchronize_rcu();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
Corey Minyardb2c03942006-12-06 20:41:00 -08002803 cleanup_smi_msgs(intf);
2804
Corey Minyard393d2cc2005-11-07 00:59:54 -08002805 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806
2807 /* Call all the watcher interfaces to tell them that
2808 an interface is gone. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002809 list_for_each_entry(w, &smi_watchers, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08002810 w->smi_gone(intf_num);
2811 mutex_unlock(&smi_watchers_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002812
Corey Minyard393d2cc2005-11-07 00:59:54 -08002813 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 return 0;
2815}
2816
2817static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2818 struct ipmi_smi_msg *msg)
2819{
2820 struct ipmi_ipmb_addr ipmb_addr;
2821 struct ipmi_recv_msg *recv_msg;
2822 unsigned long flags;
2823
2824
2825 /* This is 11, not 10, because the response must contain a
2826 * completion code. */
2827 if (msg->rsp_size < 11) {
2828 /* Message not big enough, just ignore it. */
2829 spin_lock_irqsave(&intf->counter_lock, flags);
2830 intf->invalid_ipmb_responses++;
2831 spin_unlock_irqrestore(&intf->counter_lock, flags);
2832 return 0;
2833 }
2834
2835 if (msg->rsp[2] != 0) {
2836 /* An error getting the response, just ignore it. */
2837 return 0;
2838 }
2839
2840 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
2841 ipmb_addr.slave_addr = msg->rsp[6];
2842 ipmb_addr.channel = msg->rsp[3] & 0x0f;
2843 ipmb_addr.lun = msg->rsp[7] & 3;
2844
2845 /* It's a response from a remote entity. Look up the sequence
2846 number and handle the response. */
2847 if (intf_find_seq(intf,
2848 msg->rsp[7] >> 2,
2849 msg->rsp[3] & 0x0f,
2850 msg->rsp[8],
2851 (msg->rsp[4] >> 2) & (~1),
2852 (struct ipmi_addr *) &(ipmb_addr),
2853 &recv_msg))
2854 {
2855 /* We were unable to find the sequence number,
2856 so just nuke the message. */
2857 spin_lock_irqsave(&intf->counter_lock, flags);
2858 intf->unhandled_ipmb_responses++;
2859 spin_unlock_irqrestore(&intf->counter_lock, flags);
2860 return 0;
2861 }
2862
2863 memcpy(recv_msg->msg_data,
2864 &(msg->rsp[9]),
2865 msg->rsp_size - 9);
2866 /* THe other fields matched, so no need to set them, except
2867 for netfn, which needs to be the response that was
2868 returned, not the request value. */
2869 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2870 recv_msg->msg.data = recv_msg->msg_data;
2871 recv_msg->msg.data_len = msg->rsp_size - 10;
2872 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2873 spin_lock_irqsave(&intf->counter_lock, flags);
2874 intf->handled_ipmb_responses++;
2875 spin_unlock_irqrestore(&intf->counter_lock, flags);
2876 deliver_response(recv_msg);
2877
2878 return 0;
2879}
2880
2881static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2882 struct ipmi_smi_msg *msg)
2883{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002884 struct cmd_rcvr *rcvr;
2885 int rv = 0;
2886 unsigned char netfn;
2887 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002888 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002889 ipmi_user_t user = NULL;
2890 struct ipmi_ipmb_addr *ipmb_addr;
2891 struct ipmi_recv_msg *recv_msg;
2892 unsigned long flags;
Corey Minyardb2c03942006-12-06 20:41:00 -08002893 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
2895 if (msg->rsp_size < 10) {
2896 /* Message not big enough, just ignore it. */
2897 spin_lock_irqsave(&intf->counter_lock, flags);
2898 intf->invalid_commands++;
2899 spin_unlock_irqrestore(&intf->counter_lock, flags);
2900 return 0;
2901 }
2902
2903 if (msg->rsp[2] != 0) {
2904 /* An error getting the response, just ignore it. */
2905 return 0;
2906 }
2907
2908 netfn = msg->rsp[4] >> 2;
2909 cmd = msg->rsp[8];
Corey Minyardc69c3122006-09-30 23:27:56 -07002910 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002912 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002913 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002914 if (rcvr) {
2915 user = rcvr->user;
2916 kref_get(&user->refcount);
2917 } else
2918 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002919 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920
2921 if (user == NULL) {
2922 /* We didn't find a user, deliver an error response. */
2923 spin_lock_irqsave(&intf->counter_lock, flags);
2924 intf->unhandled_commands++;
2925 spin_unlock_irqrestore(&intf->counter_lock, flags);
2926
2927 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2928 msg->data[1] = IPMI_SEND_MSG_CMD;
2929 msg->data[2] = msg->rsp[3];
2930 msg->data[3] = msg->rsp[6];
2931 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2932 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002933 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 /* rqseq/lun */
2935 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2936 msg->data[8] = msg->rsp[8]; /* cmd */
2937 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2938 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2939 msg->data_size = 11;
2940
2941#ifdef DEBUG_MSGING
2942 {
2943 int m;
2944 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002945 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 printk(" %2.2x", msg->data[m]);
2947 printk("\n");
2948 }
2949#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08002950 rcu_read_lock();
2951 handlers = intf->handlers;
2952 if (handlers) {
2953 handlers->sender(intf->send_info, msg, 0);
2954 /* We used the message, so return the value
2955 that causes it to not be freed or
2956 queued. */
2957 rv = -1;
2958 }
2959 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 } else {
2961 /* Deliver the message to the user. */
2962 spin_lock_irqsave(&intf->counter_lock, flags);
2963 intf->handled_commands++;
2964 spin_unlock_irqrestore(&intf->counter_lock, flags);
2965
2966 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002967 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 /* We couldn't allocate memory for the
2969 message, so requeue it for handling
2970 later. */
2971 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002972 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 } else {
2974 /* Extract the source address from the data. */
2975 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2976 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2977 ipmb_addr->slave_addr = msg->rsp[6];
2978 ipmb_addr->lun = msg->rsp[7] & 3;
2979 ipmb_addr->channel = msg->rsp[3] & 0xf;
2980
2981 /* Extract the rest of the message information
2982 from the IPMB header.*/
2983 recv_msg->user = user;
2984 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2985 recv_msg->msgid = msg->rsp[7] >> 2;
2986 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2987 recv_msg->msg.cmd = msg->rsp[8];
2988 recv_msg->msg.data = recv_msg->msg_data;
2989
2990 /* We chop off 10, not 9 bytes because the checksum
2991 at the end also needs to be removed. */
2992 recv_msg->msg.data_len = msg->rsp_size - 10;
2993 memcpy(recv_msg->msg_data,
2994 &(msg->rsp[9]),
2995 msg->rsp_size - 10);
2996 deliver_response(recv_msg);
2997 }
2998 }
2999
3000 return rv;
3001}
3002
3003static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
3004 struct ipmi_smi_msg *msg)
3005{
3006 struct ipmi_lan_addr lan_addr;
3007 struct ipmi_recv_msg *recv_msg;
3008 unsigned long flags;
3009
3010
3011 /* This is 13, not 12, because the response must contain a
3012 * completion code. */
3013 if (msg->rsp_size < 13) {
3014 /* Message not big enough, just ignore it. */
3015 spin_lock_irqsave(&intf->counter_lock, flags);
3016 intf->invalid_lan_responses++;
3017 spin_unlock_irqrestore(&intf->counter_lock, flags);
3018 return 0;
3019 }
3020
3021 if (msg->rsp[2] != 0) {
3022 /* An error getting the response, just ignore it. */
3023 return 0;
3024 }
3025
3026 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
3027 lan_addr.session_handle = msg->rsp[4];
3028 lan_addr.remote_SWID = msg->rsp[8];
3029 lan_addr.local_SWID = msg->rsp[5];
3030 lan_addr.channel = msg->rsp[3] & 0x0f;
3031 lan_addr.privilege = msg->rsp[3] >> 4;
3032 lan_addr.lun = msg->rsp[9] & 3;
3033
3034 /* It's a response from a remote entity. Look up the sequence
3035 number and handle the response. */
3036 if (intf_find_seq(intf,
3037 msg->rsp[9] >> 2,
3038 msg->rsp[3] & 0x0f,
3039 msg->rsp[10],
3040 (msg->rsp[6] >> 2) & (~1),
3041 (struct ipmi_addr *) &(lan_addr),
3042 &recv_msg))
3043 {
3044 /* We were unable to find the sequence number,
3045 so just nuke the message. */
3046 spin_lock_irqsave(&intf->counter_lock, flags);
3047 intf->unhandled_lan_responses++;
3048 spin_unlock_irqrestore(&intf->counter_lock, flags);
3049 return 0;
3050 }
3051
3052 memcpy(recv_msg->msg_data,
3053 &(msg->rsp[11]),
3054 msg->rsp_size - 11);
3055 /* The other fields matched, so no need to set them, except
3056 for netfn, which needs to be the response that was
3057 returned, not the request value. */
3058 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3059 recv_msg->msg.data = recv_msg->msg_data;
3060 recv_msg->msg.data_len = msg->rsp_size - 12;
3061 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3062 spin_lock_irqsave(&intf->counter_lock, flags);
3063 intf->handled_lan_responses++;
3064 spin_unlock_irqrestore(&intf->counter_lock, flags);
3065 deliver_response(recv_msg);
3066
3067 return 0;
3068}
3069
3070static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
3071 struct ipmi_smi_msg *msg)
3072{
Corey Minyard393d2cc2005-11-07 00:59:54 -08003073 struct cmd_rcvr *rcvr;
3074 int rv = 0;
3075 unsigned char netfn;
3076 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07003077 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003078 ipmi_user_t user = NULL;
3079 struct ipmi_lan_addr *lan_addr;
3080 struct ipmi_recv_msg *recv_msg;
3081 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082
3083 if (msg->rsp_size < 12) {
3084 /* Message not big enough, just ignore it. */
3085 spin_lock_irqsave(&intf->counter_lock, flags);
3086 intf->invalid_commands++;
3087 spin_unlock_irqrestore(&intf->counter_lock, flags);
3088 return 0;
3089 }
3090
3091 if (msg->rsp[2] != 0) {
3092 /* An error getting the response, just ignore it. */
3093 return 0;
3094 }
3095
3096 netfn = msg->rsp[6] >> 2;
3097 cmd = msg->rsp[10];
Corey Minyardc69c3122006-09-30 23:27:56 -07003098 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003100 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07003101 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003102 if (rcvr) {
3103 user = rcvr->user;
3104 kref_get(&user->refcount);
3105 } else
3106 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003107 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108
3109 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003110 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 spin_lock_irqsave(&intf->counter_lock, flags);
3112 intf->unhandled_commands++;
3113 spin_unlock_irqrestore(&intf->counter_lock, flags);
3114
3115 rv = 0; /* Don't do anything with these messages, just
3116 allow them to be freed. */
3117 } else {
3118 /* Deliver the message to the user. */
3119 spin_lock_irqsave(&intf->counter_lock, flags);
3120 intf->handled_commands++;
3121 spin_unlock_irqrestore(&intf->counter_lock, flags);
3122
3123 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003124 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 /* We couldn't allocate memory for the
3126 message, so requeue it for handling
3127 later. */
3128 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003129 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 } else {
3131 /* Extract the source address from the data. */
3132 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
3133 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
3134 lan_addr->session_handle = msg->rsp[4];
3135 lan_addr->remote_SWID = msg->rsp[8];
3136 lan_addr->local_SWID = msg->rsp[5];
3137 lan_addr->lun = msg->rsp[9] & 3;
3138 lan_addr->channel = msg->rsp[3] & 0xf;
3139 lan_addr->privilege = msg->rsp[3] >> 4;
3140
3141 /* Extract the rest of the message information
3142 from the IPMB header.*/
3143 recv_msg->user = user;
3144 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
3145 recv_msg->msgid = msg->rsp[9] >> 2;
3146 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3147 recv_msg->msg.cmd = msg->rsp[10];
3148 recv_msg->msg.data = recv_msg->msg_data;
3149
3150 /* We chop off 12, not 11 bytes because the checksum
3151 at the end also needs to be removed. */
3152 recv_msg->msg.data_len = msg->rsp_size - 12;
3153 memcpy(recv_msg->msg_data,
3154 &(msg->rsp[11]),
3155 msg->rsp_size - 12);
3156 deliver_response(recv_msg);
3157 }
3158 }
3159
3160 return rv;
3161}
3162
3163static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
3164 struct ipmi_smi_msg *msg)
3165{
3166 struct ipmi_system_interface_addr *smi_addr;
3167
3168 recv_msg->msgid = 0;
3169 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
3170 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3171 smi_addr->channel = IPMI_BMC_CHANNEL;
3172 smi_addr->lun = msg->rsp[0] & 3;
3173 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
3174 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3175 recv_msg->msg.cmd = msg->rsp[1];
3176 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
3177 recv_msg->msg.data = recv_msg->msg_data;
3178 recv_msg->msg.data_len = msg->rsp_size - 3;
3179}
3180
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181static int handle_read_event_rsp(ipmi_smi_t intf,
3182 struct ipmi_smi_msg *msg)
3183{
3184 struct ipmi_recv_msg *recv_msg, *recv_msg2;
3185 struct list_head msgs;
3186 ipmi_user_t user;
3187 int rv = 0;
3188 int deliver_count = 0;
3189 unsigned long flags;
3190
3191 if (msg->rsp_size < 19) {
3192 /* Message is too small to be an IPMB event. */
3193 spin_lock_irqsave(&intf->counter_lock, flags);
3194 intf->invalid_events++;
3195 spin_unlock_irqrestore(&intf->counter_lock, flags);
3196 return 0;
3197 }
3198
3199 if (msg->rsp[2] != 0) {
3200 /* An error getting the event, just ignore it. */
3201 return 0;
3202 }
3203
3204 INIT_LIST_HEAD(&msgs);
3205
Corey Minyard393d2cc2005-11-07 00:59:54 -08003206 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
3208 spin_lock(&intf->counter_lock);
3209 intf->events++;
3210 spin_unlock(&intf->counter_lock);
3211
3212 /* Allocate and fill in one message for every user that is getting
3213 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003214 rcu_read_lock();
3215 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003216 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 continue;
3218
3219 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003220 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003221 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003222 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
3223 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 list_del(&recv_msg->link);
3225 ipmi_free_recv_msg(recv_msg);
3226 }
3227 /* We couldn't allocate memory for the
3228 message, so requeue it for handling
3229 later. */
3230 rv = 1;
3231 goto out;
3232 }
3233
3234 deliver_count++;
3235
3236 copy_event_into_recv_msg(recv_msg, msg);
3237 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003238 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 list_add_tail(&(recv_msg->link), &msgs);
3240 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003241 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242
3243 if (deliver_count) {
3244 /* Now deliver all the messages. */
3245 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
3246 list_del(&recv_msg->link);
3247 deliver_response(recv_msg);
3248 }
3249 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
3250 /* No one to receive the message, put it in queue if there's
3251 not already too many things in the queue. */
3252 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003253 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 /* We couldn't allocate memory for the
3255 message, so requeue it for handling
3256 later. */
3257 rv = 1;
3258 goto out;
3259 }
3260
3261 copy_event_into_recv_msg(recv_msg, msg);
3262 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
Corey Minyard4791c032006-04-10 22:54:31 -07003263 intf->waiting_events_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 } else {
3265 /* There's too many things in the queue, discard this
3266 message. */
3267 printk(KERN_WARNING PFX "Event queue full, discarding an"
3268 " incoming event\n");
3269 }
3270
3271 out:
3272 spin_unlock_irqrestore(&(intf->events_lock), flags);
3273
3274 return rv;
3275}
3276
3277static int handle_bmc_rsp(ipmi_smi_t intf,
3278 struct ipmi_smi_msg *msg)
3279{
3280 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003282 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283
3284 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07003285 if (recv_msg == NULL)
3286 {
3287 printk(KERN_WARNING"IPMI message received with no owner. This\n"
3288 "could be because of a malformed message, or\n"
3289 "because of a hardware error. Contact your\n"
3290 "hardware vender for assistance\n");
3291 return 0;
3292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293
Corey Minyard393d2cc2005-11-07 00:59:54 -08003294 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003296 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07003297 /* The user for the message went away, so give up. */
3298 spin_lock_irqsave(&intf->counter_lock, flags);
3299 intf->unhandled_local_responses++;
3300 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 ipmi_free_recv_msg(recv_msg);
3302 } else {
3303 struct ipmi_system_interface_addr *smi_addr;
3304
3305 spin_lock_irqsave(&intf->counter_lock, flags);
3306 intf->handled_local_responses++;
3307 spin_unlock_irqrestore(&intf->counter_lock, flags);
3308 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3309 recv_msg->msgid = msg->msgid;
3310 smi_addr = ((struct ipmi_system_interface_addr *)
3311 &(recv_msg->addr));
3312 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3313 smi_addr->channel = IPMI_BMC_CHANNEL;
3314 smi_addr->lun = msg->rsp[0] & 3;
3315 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3316 recv_msg->msg.cmd = msg->rsp[1];
3317 memcpy(recv_msg->msg_data,
3318 &(msg->rsp[2]),
3319 msg->rsp_size - 2);
3320 recv_msg->msg.data = recv_msg->msg_data;
3321 recv_msg->msg.data_len = msg->rsp_size - 2;
3322 deliver_response(recv_msg);
3323 }
3324
3325 return 0;
3326}
3327
3328/* Handle a new message. Return 1 if the message should be requeued,
3329 0 if the message should be freed, or -1 if the message should not
3330 be freed or requeued. */
3331static int handle_new_recv_msg(ipmi_smi_t intf,
3332 struct ipmi_smi_msg *msg)
3333{
3334 int requeue;
3335 int chan;
3336
3337#ifdef DEBUG_MSGING
3338 int m;
3339 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07003340 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 printk(" %2.2x", msg->rsp[m]);
3342 printk("\n");
3343#endif
3344 if (msg->rsp_size < 2) {
3345 /* Message is too small to be correct. */
3346 printk(KERN_WARNING PFX "BMC returned to small a message"
3347 " for netfn %x cmd %x, got %d bytes\n",
3348 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3349
3350 /* Generate an error response for the message. */
3351 msg->rsp[0] = msg->data[0] | (1 << 2);
3352 msg->rsp[1] = msg->data[1];
3353 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3354 msg->rsp_size = 3;
3355 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3356 || (msg->rsp[1] != msg->data[1])) /* Command */
3357 {
3358 /* The response is not even marginally correct. */
3359 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3360 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3361 (msg->data[0] >> 2) | 1, msg->data[1],
3362 msg->rsp[0] >> 2, msg->rsp[1]);
3363
3364 /* Generate an error response for the message. */
3365 msg->rsp[0] = msg->data[0] | (1 << 2);
3366 msg->rsp[1] = msg->data[1];
3367 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3368 msg->rsp_size = 3;
3369 }
3370
3371 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3372 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3373 && (msg->user_data != NULL))
3374 {
3375 /* It's a response to a response we sent. For this we
3376 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003377 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378
3379 requeue = 0;
3380 if (msg->rsp_size < 2)
3381 /* Message is too small to be correct. */
3382 goto out;
3383
3384 chan = msg->data[2] & 0x0f;
3385 if (chan >= IPMI_MAX_CHANNELS)
3386 /* Invalid channel number */
3387 goto out;
3388
Corey Minyard393d2cc2005-11-07 00:59:54 -08003389 if (!recv_msg)
3390 goto out;
3391
3392 /* Make sure the user still exists. */
3393 if (!recv_msg->user || !recv_msg->user->valid)
3394 goto out;
3395
3396 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3397 recv_msg->msg.data = recv_msg->msg_data;
3398 recv_msg->msg.data_len = 1;
3399 recv_msg->msg_data[0] = msg->rsp[2];
3400 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3402 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3403 {
3404 /* It's from the receive queue. */
3405 chan = msg->rsp[3] & 0xf;
3406 if (chan >= IPMI_MAX_CHANNELS) {
3407 /* Invalid channel number */
3408 requeue = 0;
3409 goto out;
3410 }
3411
3412 switch (intf->channels[chan].medium) {
3413 case IPMI_CHANNEL_MEDIUM_IPMB:
3414 if (msg->rsp[4] & 0x04) {
3415 /* It's a response, so find the
3416 requesting message and send it up. */
3417 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3418 } else {
3419 /* It's a command to the SMS from some other
3420 entity. Handle that. */
3421 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3422 }
3423 break;
3424
3425 case IPMI_CHANNEL_MEDIUM_8023LAN:
3426 case IPMI_CHANNEL_MEDIUM_ASYNC:
3427 if (msg->rsp[6] & 0x04) {
3428 /* It's a response, so find the
3429 requesting message and send it up. */
3430 requeue = handle_lan_get_msg_rsp(intf, msg);
3431 } else {
3432 /* It's a command to the SMS from some other
3433 entity. Handle that. */
3434 requeue = handle_lan_get_msg_cmd(intf, msg);
3435 }
3436 break;
3437
3438 default:
3439 /* We don't handle the channel type, so just
3440 * free the message. */
3441 requeue = 0;
3442 }
3443
3444 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3445 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3446 {
3447 /* It's an asyncronous event. */
3448 requeue = handle_read_event_rsp(intf, msg);
3449 } else {
3450 /* It's a response from the local BMC. */
3451 requeue = handle_bmc_rsp(intf, msg);
3452 }
3453
3454 out:
3455 return requeue;
3456}
3457
3458/* Handle a new message from the lower layer. */
3459void ipmi_smi_msg_received(ipmi_smi_t intf,
3460 struct ipmi_smi_msg *msg)
3461{
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003462 unsigned long flags = 0; /* keep us warning-free. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 int rv;
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003464 int run_to_completion;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465
3466
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 if ((msg->data_size >= 2)
3468 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3469 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003470 && (msg->user_data == NULL))
3471 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 /* This is the local response to a command send, start
3473 the timer for these. The user_data will not be
3474 NULL if this is a response send, and we will let
3475 response sends just go through. */
3476
3477 /* Check for errors, if we get certain errors (ones
3478 that mean basically we can try again later), we
3479 ignore them and start the timer. Otherwise we
3480 report the error immediately. */
3481 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3482 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
Corey Minyard46d52b02006-11-08 17:44:55 -08003483 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
3484 && (msg->rsp[2] != IPMI_BUS_ERR)
3485 && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 {
3487 int chan = msg->rsp[3] & 0xf;
3488
3489 /* Got an error sending the message, handle it. */
3490 spin_lock_irqsave(&intf->counter_lock, flags);
3491 if (chan >= IPMI_MAX_CHANNELS)
3492 ; /* This shouldn't happen */
3493 else if ((intf->channels[chan].medium
3494 == IPMI_CHANNEL_MEDIUM_8023LAN)
3495 || (intf->channels[chan].medium
3496 == IPMI_CHANNEL_MEDIUM_ASYNC))
3497 intf->sent_lan_command_errs++;
3498 else
3499 intf->sent_ipmb_command_errs++;
3500 spin_unlock_irqrestore(&intf->counter_lock, flags);
3501 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3502 } else {
3503 /* The message was sent, start the timer. */
3504 intf_start_seq_timer(intf, msg->msgid);
3505 }
3506
3507 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003508 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 }
3510
3511 /* To preserve message order, if the list is not empty, we
3512 tack this message onto the end of the list. */
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003513 run_to_completion = intf->run_to_completion;
3514 if (!run_to_completion)
3515 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003516 if (!list_empty(&intf->waiting_msgs)) {
3517 list_add_tail(&msg->link, &intf->waiting_msgs);
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003518 if (!run_to_completion)
3519 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003520 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 }
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003522 if (!run_to_completion)
3523 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524
3525 rv = handle_new_recv_msg(intf, msg);
3526 if (rv > 0) {
3527 /* Could not handle the message now, just add it to a
3528 list to handle later. */
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003529 run_to_completion = intf->run_to_completion;
3530 if (!run_to_completion)
3531 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003532 list_add_tail(&msg->link, &intf->waiting_msgs);
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003533 if (!run_to_completion)
3534 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 } else if (rv == 0) {
3536 ipmi_free_smi_msg(msg);
3537 }
3538
Corey Minyard393d2cc2005-11-07 00:59:54 -08003539 out:
3540 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541}
3542
3543void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3544{
3545 ipmi_user_t user;
3546
Corey Minyard393d2cc2005-11-07 00:59:54 -08003547 rcu_read_lock();
3548 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003549 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 continue;
3551
3552 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3553 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003554 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555}
3556
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557
Corey Minyard882fe012005-05-01 08:59:12 -07003558static struct ipmi_smi_msg *
3559smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3560 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561{
Corey Minyard882fe012005-05-01 08:59:12 -07003562 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 if (!smi_msg)
3564 /* If we can't allocate the message, then just return, we
3565 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003566 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567
3568 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3569 smi_msg->data_size = recv_msg->msg.data_len;
3570 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3571
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572#ifdef DEBUG_MSGING
3573 {
3574 int m;
3575 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003576 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 printk(" %2.2x", smi_msg->data[m]);
3578 printk("\n");
3579 }
3580#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003581 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582}
3583
Corey Minyard393d2cc2005-11-07 00:59:54 -08003584static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3585 struct list_head *timeouts, long timeout_period,
3586 int slot, unsigned long *flags)
3587{
Corey Minyardb2c03942006-12-06 20:41:00 -08003588 struct ipmi_recv_msg *msg;
3589 struct ipmi_smi_handlers *handlers;
3590
3591 if (intf->intf_num == -1)
3592 return;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003593
3594 if (!ent->inuse)
3595 return;
3596
3597 ent->timeout -= timeout_period;
3598 if (ent->timeout > 0)
3599 return;
3600
3601 if (ent->retries_left == 0) {
3602 /* The message has used all its retries. */
3603 ent->inuse = 0;
3604 msg = ent->recv_msg;
3605 list_add_tail(&msg->link, timeouts);
3606 spin_lock(&intf->counter_lock);
3607 if (ent->broadcast)
3608 intf->timed_out_ipmb_broadcasts++;
3609 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3610 intf->timed_out_lan_commands++;
3611 else
3612 intf->timed_out_ipmb_commands++;
3613 spin_unlock(&intf->counter_lock);
3614 } else {
3615 struct ipmi_smi_msg *smi_msg;
3616 /* More retries, send again. */
3617
3618 /* Start with the max timer, set to normal
3619 timer after the message is sent. */
3620 ent->timeout = MAX_MSG_TIMEOUT;
3621 ent->retries_left--;
3622 spin_lock(&intf->counter_lock);
3623 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3624 intf->retransmitted_lan_commands++;
3625 else
3626 intf->retransmitted_ipmb_commands++;
3627 spin_unlock(&intf->counter_lock);
3628
3629 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3630 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003631 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003632 return;
3633
3634 spin_unlock_irqrestore(&intf->seq_lock, *flags);
Corey Minyardb2c03942006-12-06 20:41:00 -08003635
Corey Minyard393d2cc2005-11-07 00:59:54 -08003636 /* Send the new message. We send with a zero
3637 * priority. It timed out, I doubt time is
3638 * that critical now, and high priority
3639 * messages are really only for messages to the
3640 * local MC, which don't get resent. */
Corey Minyardb2c03942006-12-06 20:41:00 -08003641 handlers = intf->handlers;
3642 if (handlers)
3643 intf->handlers->sender(intf->send_info,
3644 smi_msg, 0);
3645 else
3646 ipmi_free_smi_msg(smi_msg);
3647
Corey Minyard393d2cc2005-11-07 00:59:54 -08003648 spin_lock_irqsave(&intf->seq_lock, *flags);
3649 }
3650}
3651
3652static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653{
3654 ipmi_smi_t intf;
3655 struct list_head timeouts;
3656 struct ipmi_recv_msg *msg, *msg2;
3657 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3658 unsigned long flags;
Corey Minyardbca03242006-12-06 20:40:57 -08003659 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660
Corey Minyardbca03242006-12-06 20:40:57 -08003661 rcu_read_lock();
3662 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003664 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003665 list_for_each_entry_safe(smi_msg, smi_msg2,
3666 &intf->waiting_msgs, link) {
3667 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 list_del(&smi_msg->link);
3669 ipmi_free_smi_msg(smi_msg);
3670 } else {
3671 /* To preserve message order, quit if we
3672 can't handle a message. */
3673 break;
3674 }
3675 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003676 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677
3678 /* Go through the seq table and find any messages that
3679 have timed out, putting them in the timeouts
3680 list. */
David Barksdale41c57a82007-01-30 14:36:25 -08003681 INIT_LIST_HEAD(&timeouts);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003682 spin_lock_irqsave(&intf->seq_lock, flags);
Corey Minyardbca03242006-12-06 20:40:57 -08003683 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
3684 check_msg_timeout(intf, &(intf->seq_table[i]),
3685 &timeouts, timeout_period, i,
Corey Minyard393d2cc2005-11-07 00:59:54 -08003686 &flags);
3687 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688
Corey Minyard393d2cc2005-11-07 00:59:54 -08003689 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08003690 deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE);
Corey Minyardb9675132006-12-06 20:41:02 -08003691
3692 /*
3693 * Maintenance mode handling. Check the timeout
3694 * optimistically before we claim the lock. It may
3695 * mean a timeout gets missed occasionally, but that
3696 * only means the timeout gets extended by one period
3697 * in that case. No big deal, and it avoids the lock
3698 * most of the time.
3699 */
3700 if (intf->auto_maintenance_timeout > 0) {
3701 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
3702 if (intf->auto_maintenance_timeout > 0) {
3703 intf->auto_maintenance_timeout
3704 -= timeout_period;
3705 if (!intf->maintenance_mode
3706 && (intf->auto_maintenance_timeout <= 0))
3707 {
3708 intf->maintenance_mode_enable = 0;
3709 maintenance_mode_update(intf);
3710 }
3711 }
3712 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
3713 flags);
3714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 }
Corey Minyardbca03242006-12-06 20:40:57 -08003716 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717}
3718
3719static void ipmi_request_event(void)
3720{
Corey Minyardb2c03942006-12-06 20:41:00 -08003721 ipmi_smi_t intf;
3722 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723
Corey Minyardbca03242006-12-06 20:40:57 -08003724 rcu_read_lock();
Corey Minyardb2c03942006-12-06 20:41:00 -08003725 /* Called from the timer, no need to check if handlers is
3726 * valid. */
3727 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb9675132006-12-06 20:41:02 -08003728 /* No event requests when in maintenance mode. */
3729 if (intf->maintenance_mode_enable)
3730 continue;
3731
Corey Minyardb2c03942006-12-06 20:41:00 -08003732 handlers = intf->handlers;
3733 if (handlers)
3734 handlers->request_events(intf->send_info);
3735 }
Corey Minyardbca03242006-12-06 20:40:57 -08003736 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737}
3738
3739static struct timer_list ipmi_timer;
3740
3741/* Call every ~100 ms. */
3742#define IPMI_TIMEOUT_TIME 100
3743
3744/* How many jiffies does it take to get to the timeout time. */
3745#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3746
3747/* Request events from the queue every second (this is the number of
3748 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3749 future, IPMI will add a way to know immediately if an event is in
3750 the queue and this silliness can go away. */
3751#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3752
Corey Minyard8f43f842005-06-23 22:01:40 -07003753static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3755
3756static void ipmi_timeout(unsigned long data)
3757{
Corey Minyard8f43f842005-06-23 22:01:40 -07003758 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760
3761 ticks_to_req_ev--;
3762 if (ticks_to_req_ev == 0) {
3763 ipmi_request_event();
3764 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3765 }
3766
3767 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3768
Corey Minyard8f43f842005-06-23 22:01:40 -07003769 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770}
3771
3772
3773static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3774static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3775
3776/* FIXME - convert these to slabs. */
3777static void free_smi_msg(struct ipmi_smi_msg *msg)
3778{
3779 atomic_dec(&smi_msg_inuse_count);
3780 kfree(msg);
3781}
3782
3783struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3784{
3785 struct ipmi_smi_msg *rv;
3786 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3787 if (rv) {
3788 rv->done = free_smi_msg;
3789 rv->user_data = NULL;
3790 atomic_inc(&smi_msg_inuse_count);
3791 }
3792 return rv;
3793}
3794
3795static void free_recv_msg(struct ipmi_recv_msg *msg)
3796{
3797 atomic_dec(&recv_msg_inuse_count);
3798 kfree(msg);
3799}
3800
3801struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3802{
3803 struct ipmi_recv_msg *rv;
3804
3805 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3806 if (rv) {
Corey Minyarda9eec552006-08-31 21:27:45 -07003807 rv->user = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 rv->done = free_recv_msg;
3809 atomic_inc(&recv_msg_inuse_count);
3810 }
3811 return rv;
3812}
3813
Corey Minyard393d2cc2005-11-07 00:59:54 -08003814void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3815{
3816 if (msg->user)
3817 kref_put(&msg->user->refcount, free_user);
3818 msg->done(msg);
3819}
3820
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821#ifdef CONFIG_IPMI_PANIC_EVENT
3822
3823static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3824{
3825}
3826
3827static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3828{
3829}
3830
3831#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003832static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003834 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3835 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3836 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3837 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 {
3839 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003840 intf->event_receiver = msg->msg.data[1];
3841 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 }
3843}
3844
Corey Minyard56a55ec2005-09-06 15:18:42 -07003845static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003847 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3848 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3849 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3850 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 {
3852 /* A get device id command, save if we are an event
3853 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003854 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3855 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 }
3857}
3858#endif
3859
3860static void send_panic_events(char *str)
3861{
3862 struct kernel_ipmi_msg msg;
3863 ipmi_smi_t intf;
3864 unsigned char data[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 struct ipmi_system_interface_addr *si;
3866 struct ipmi_addr addr;
3867 struct ipmi_smi_msg smi_msg;
3868 struct ipmi_recv_msg recv_msg;
3869
3870 si = (struct ipmi_system_interface_addr *) &addr;
3871 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3872 si->channel = IPMI_BMC_CHANNEL;
3873 si->lun = 0;
3874
3875 /* Fill in an event telling that we have failed. */
3876 msg.netfn = 0x04; /* Sensor or Event. */
3877 msg.cmd = 2; /* Platform event command. */
3878 msg.data = data;
3879 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003880 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 data[1] = 0x03; /* This is for IPMI 1.0. */
3882 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3883 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3884 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3885
3886 /* Put a few breadcrumbs in. Hopefully later we can add more things
3887 to make the panic events more useful. */
3888 if (str) {
3889 data[3] = str[0];
3890 data[6] = str[1];
3891 data[7] = str[2];
3892 }
3893
3894 smi_msg.done = dummy_smi_done_handler;
3895 recv_msg.done = dummy_recv_done_handler;
3896
3897 /* For every registered interface, send the event. */
Corey Minyardbca03242006-12-06 20:40:57 -08003898 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08003899 if (!intf->handlers)
3900 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 continue;
3902
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003903 intf->run_to_completion = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 /* Send the event announcing the panic. */
3905 intf->handlers->set_run_to_completion(intf->send_info, 1);
3906 i_ipmi_request(NULL,
3907 intf,
3908 &addr,
3909 0,
3910 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003911 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 &smi_msg,
3913 &recv_msg,
3914 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003915 intf->channels[0].address,
3916 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 0, 1); /* Don't retry, and don't wait. */
3918 }
3919
3920#ifdef CONFIG_IPMI_PANIC_STRING
3921 /* On every interface, dump a bunch of OEM event holding the
3922 string. */
3923 if (!str)
3924 return;
3925
Corey Minyardbca03242006-12-06 20:40:57 -08003926 /* For every registered interface, send the event. */
3927 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 char *p = str;
3929 struct ipmi_ipmb_addr *ipmb;
3930 int j;
3931
Corey Minyardbca03242006-12-06 20:40:57 -08003932 if (intf->intf_num == -1)
3933 /* Interface was not ready yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 continue;
3935
Corey Minyard78ba2fa2007-02-10 01:45:45 -08003936 /*
3937 * intf_num is used as an marker to tell if the
3938 * interface is valid. Thus we need a read barrier to
3939 * make sure data fetched before checking intf_num
3940 * won't be used.
3941 */
3942 smp_rmb();
3943
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 /* First job here is to figure out where to send the
3945 OEM events. There's no way in IPMI to send OEM
3946 events using an event send command, so we have to
3947 find the SEL to put them in and stick them in
3948 there. */
3949
3950 /* Get capabilities from the get device id. */
3951 intf->local_sel_device = 0;
3952 intf->local_event_generator = 0;
3953 intf->event_receiver = 0;
3954
3955 /* Request the device info from the local MC. */
3956 msg.netfn = IPMI_NETFN_APP_REQUEST;
3957 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3958 msg.data = NULL;
3959 msg.data_len = 0;
3960 intf->null_user_handler = device_id_fetcher;
3961 i_ipmi_request(NULL,
3962 intf,
3963 &addr,
3964 0,
3965 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003966 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 &smi_msg,
3968 &recv_msg,
3969 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003970 intf->channels[0].address,
3971 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 0, 1); /* Don't retry, and don't wait. */
3973
3974 if (intf->local_event_generator) {
3975 /* Request the event receiver from the local MC. */
3976 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3977 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3978 msg.data = NULL;
3979 msg.data_len = 0;
3980 intf->null_user_handler = event_receiver_fetcher;
3981 i_ipmi_request(NULL,
3982 intf,
3983 &addr,
3984 0,
3985 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003986 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 &smi_msg,
3988 &recv_msg,
3989 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003990 intf->channels[0].address,
3991 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 0, 1); /* no retry, and no wait. */
3993 }
3994 intf->null_user_handler = NULL;
3995
3996 /* Validate the event receiver. The low bit must not
3997 be 1 (it must be a valid IPMB address), it cannot
3998 be zero, and it must not be my address. */
3999 if (((intf->event_receiver & 1) == 0)
4000 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07004001 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 {
4003 /* The event receiver is valid, send an IPMB
4004 message. */
4005 ipmb = (struct ipmi_ipmb_addr *) &addr;
4006 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
4007 ipmb->channel = 0; /* FIXME - is this right? */
4008 ipmb->lun = intf->event_receiver_lun;
4009 ipmb->slave_addr = intf->event_receiver;
4010 } else if (intf->local_sel_device) {
4011 /* The event receiver was not valid (or was
4012 me), but I am an SEL device, just dump it
4013 in my SEL. */
4014 si = (struct ipmi_system_interface_addr *) &addr;
4015 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
4016 si->channel = IPMI_BMC_CHANNEL;
4017 si->lun = 0;
4018 } else
4019 continue; /* No where to send the event. */
4020
4021
4022 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
4023 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
4024 msg.data = data;
4025 msg.data_len = 16;
4026
4027 j = 0;
4028 while (*p) {
4029 int size = strlen(p);
4030
4031 if (size > 11)
4032 size = 11;
4033 data[0] = 0;
4034 data[1] = 0;
4035 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07004036 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 data[4] = j++; /* sequence # */
4038 /* Always give 11 bytes, so strncpy will fill
4039 it with zeroes for me. */
4040 strncpy(data+5, p, 11);
4041 p += size;
4042
4043 i_ipmi_request(NULL,
4044 intf,
4045 &addr,
4046 0,
4047 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07004048 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 &smi_msg,
4050 &recv_msg,
4051 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07004052 intf->channels[0].address,
4053 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 0, 1); /* no retry, and no wait. */
4055 }
4056 }
4057#endif /* CONFIG_IPMI_PANIC_STRING */
4058}
4059#endif /* CONFIG_IPMI_PANIC_EVENT */
4060
Randy Dunlap0c8204b2006-12-10 02:19:06 -08004061static int has_panicked;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062
4063static int panic_event(struct notifier_block *this,
4064 unsigned long event,
4065 void *ptr)
4066{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 ipmi_smi_t intf;
4068
Lee Revellf18190b2006-06-26 18:30:00 +02004069 if (has_panicked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 return NOTIFY_DONE;
Lee Revellf18190b2006-06-26 18:30:00 +02004071 has_panicked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072
4073 /* For every registered interface, set it to run to completion. */
Corey Minyardbca03242006-12-06 20:40:57 -08004074 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08004075 if (!intf->handlers)
4076 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 continue;
4078
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07004079 intf->run_to_completion = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 intf->handlers->set_run_to_completion(intf->send_info, 1);
4081 }
4082
4083#ifdef CONFIG_IPMI_PANIC_EVENT
4084 send_panic_events(ptr);
4085#endif
4086
4087 return NOTIFY_DONE;
4088}
4089
4090static struct notifier_block panic_block = {
4091 .notifier_call = panic_event,
4092 .next = NULL,
4093 .priority = 200 /* priority: INT_MAX >= x >= 0 */
4094};
4095
4096static int ipmi_init_msghandler(void)
4097{
Corey Minyard50c812b2006-03-26 01:37:21 -08004098 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099
4100 if (initialized)
4101 return 0;
4102
Corey Minyard50c812b2006-03-26 01:37:21 -08004103 rv = driver_register(&ipmidriver);
4104 if (rv) {
4105 printk(KERN_ERR PFX "Could not register IPMI driver\n");
4106 return rv;
4107 }
4108
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004110 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111
Corey Minyard3b625942005-06-23 22:01:42 -07004112#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 proc_ipmi_root = proc_mkdir("ipmi", NULL);
4114 if (!proc_ipmi_root) {
4115 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
4116 return -ENOMEM;
4117 }
4118
4119 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07004120#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121
Corey Minyard409035e2006-06-28 04:26:53 -07004122 setup_timer(&ipmi_timer, ipmi_timeout, 0);
4123 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124
Alan Sterne041c682006-03-27 01:16:30 -08004125 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126
4127 initialized = 1;
4128
4129 return 0;
4130}
4131
4132static __init int ipmi_init_msghandler_mod(void)
4133{
4134 ipmi_init_msghandler();
4135 return 0;
4136}
4137
4138static __exit void cleanup_ipmi(void)
4139{
4140 int count;
4141
4142 if (!initialized)
4143 return;
4144
Alan Sterne041c682006-03-27 01:16:30 -08004145 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146
4147 /* This can't be called if any interfaces exist, so no worry about
4148 shutting down the interfaces. */
4149
4150 /* Tell the timer to stop, then wait for it to stop. This avoids
4151 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07004152 atomic_inc(&stop_operation);
4153 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154
Corey Minyard3b625942005-06-23 22:01:42 -07004155#ifdef CONFIG_PROC_FS
Alexey Dobriyan3542ae42007-10-16 23:26:50 -07004156 remove_proc_entry(proc_ipmi_root->name, NULL);
Corey Minyard3b625942005-06-23 22:01:42 -07004157#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158
Corey Minyard50c812b2006-03-26 01:37:21 -08004159 driver_unregister(&ipmidriver);
4160
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 initialized = 0;
4162
4163 /* Check for buffer leaks. */
4164 count = atomic_read(&smi_msg_inuse_count);
4165 if (count != 0)
4166 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
4167 count);
4168 count = atomic_read(&recv_msg_inuse_count);
4169 if (count != 0)
4170 printk(KERN_WARNING PFX "recv message count %d at exit\n",
4171 count);
4172}
4173module_exit(cleanup_ipmi);
4174
4175module_init(ipmi_init_msghandler_mod);
4176MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004177MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
4178MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
4179MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
4181EXPORT_SYMBOL(ipmi_create_user);
4182EXPORT_SYMBOL(ipmi_destroy_user);
4183EXPORT_SYMBOL(ipmi_get_version);
4184EXPORT_SYMBOL(ipmi_request_settime);
4185EXPORT_SYMBOL(ipmi_request_supply_msgs);
Corey Minyardfcfa4722007-10-18 03:07:09 -07004186EXPORT_SYMBOL(ipmi_poll_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187EXPORT_SYMBOL(ipmi_register_smi);
4188EXPORT_SYMBOL(ipmi_unregister_smi);
4189EXPORT_SYMBOL(ipmi_register_for_cmd);
4190EXPORT_SYMBOL(ipmi_unregister_for_cmd);
4191EXPORT_SYMBOL(ipmi_smi_msg_received);
4192EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
4193EXPORT_SYMBOL(ipmi_alloc_smi_msg);
4194EXPORT_SYMBOL(ipmi_addr_length);
4195EXPORT_SYMBOL(ipmi_validate_addr);
4196EXPORT_SYMBOL(ipmi_set_gets_events);
4197EXPORT_SYMBOL(ipmi_smi_watcher_register);
4198EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
4199EXPORT_SYMBOL(ipmi_set_my_address);
4200EXPORT_SYMBOL(ipmi_get_my_address);
4201EXPORT_SYMBOL(ipmi_set_my_LUN);
4202EXPORT_SYMBOL(ipmi_get_my_LUN);
4203EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Corey Minyard393d2cc2005-11-07 00:59:54 -08004204EXPORT_SYMBOL(ipmi_free_recv_msg);