aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi
diff options
context:
space:
mode:
authorCorey Minyard <minyard@acm.org>2006-12-06 23:41:07 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 11:39:47 -0500
commitb361e27bba261ba59c73df464fa640f7c0fe3553 (patch)
tree4c457c471eb42be1fbcc9e76989e275fa8e023df /drivers/char/ipmi
parent15c62e10bb49eebf3da2b010a9196f5095947b0b (diff)
[PATCH] IPMI: system interface hotplug
Add the ability to hot add and remove interfaces in the ipmi_si driver. Any users who have the device open will get errors if they try to send a message. Signed-off-by: Corey Minyard <minyard@acm.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/ipmi')
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c320
1 files changed, 297 insertions, 23 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index bedd76310045..8b36b5036391 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -61,6 +61,10 @@
61#include "ipmi_si_sm.h" 61#include "ipmi_si_sm.h"
62#include <linux/init.h> 62#include <linux/init.h>
63#include <linux/dmi.h> 63#include <linux/dmi.h>
64#include <linux/string.h>
65#include <linux/ctype.h>
66
67#define PFX "ipmi_si: "
64 68
65/* Measure times between events in the driver. */ 69/* Measure times between events in the driver. */
66#undef DEBUG_TIMING 70#undef DEBUG_TIMING
@@ -92,7 +96,7 @@ enum si_intf_state {
92enum si_type { 96enum si_type {
93 SI_KCS, SI_SMIC, SI_BT 97 SI_KCS, SI_SMIC, SI_BT
94}; 98};
95static char *si_to_str[] = { "KCS", "SMIC", "BT" }; 99static char *si_to_str[] = { "kcs", "smic", "bt" };
96 100
97#define DEVICE_NAME "ipmi_si" 101#define DEVICE_NAME "ipmi_si"
98 102
@@ -222,7 +226,10 @@ struct smi_info
222static int force_kipmid[SI_MAX_PARMS]; 226static int force_kipmid[SI_MAX_PARMS];
223static int num_force_kipmid; 227static int num_force_kipmid;
224 228
229static int unload_when_empty = 1;
230
225static int try_smi_init(struct smi_info *smi); 231static int try_smi_init(struct smi_info *smi);
232static void cleanup_one_si(struct smi_info *to_clean);
226 233
227static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); 234static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
228static int register_xaction_notifier(struct notifier_block * nb) 235static int register_xaction_notifier(struct notifier_block * nb)
@@ -247,7 +254,7 @@ static void return_hosed_msg(struct smi_info *smi_info)
247 /* Make it a reponse */ 254 /* Make it a reponse */
248 msg->rsp[0] = msg->data[0] | 4; 255 msg->rsp[0] = msg->data[0] | 4;
249 msg->rsp[1] = msg->data[1]; 256 msg->rsp[1] = msg->data[1];
250 msg->rsp[2] = 0xFF; /* Unknown error. */ 257 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
251 msg->rsp_size = 3; 258 msg->rsp_size = 3;
252 259
253 smi_info->curr_msg = NULL; 260 smi_info->curr_msg = NULL;
@@ -716,6 +723,15 @@ static void sender(void *send_info,
716 struct timeval t; 723 struct timeval t;
717#endif 724#endif
718 725
726 if (atomic_read(&smi_info->stop_operation)) {
727 msg->rsp[0] = msg->data[0] | 4;
728 msg->rsp[1] = msg->data[1];
729 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
730 msg->rsp_size = 3;
731 deliver_recv_msg(smi_info, msg);
732 return;
733 }
734
719 spin_lock_irqsave(&(smi_info->msg_lock), flags); 735 spin_lock_irqsave(&(smi_info->msg_lock), flags);
720#ifdef DEBUG_TIMING 736#ifdef DEBUG_TIMING
721 do_gettimeofday(&t); 737 do_gettimeofday(&t);
@@ -819,6 +835,9 @@ static void request_events(void *send_info)
819{ 835{
820 struct smi_info *smi_info = send_info; 836 struct smi_info *smi_info = send_info;
821 837
838 if (atomic_read(&smi_info->stop_operation))
839 return;
840
822 atomic_set(&smi_info->req_events, 1); 841 atomic_set(&smi_info->req_events, 1);
823} 842}
824 843
@@ -1003,6 +1022,16 @@ static int num_regshifts = 0;
1003static int slave_addrs[SI_MAX_PARMS]; 1022static int slave_addrs[SI_MAX_PARMS];
1004static int num_slave_addrs = 0; 1023static int num_slave_addrs = 0;
1005 1024
1025#define IPMI_IO_ADDR_SPACE 0
1026#define IPMI_MEM_ADDR_SPACE 1
1027static char *addr_space_to_str[] = { "I/O", "mem" };
1028
1029static int hotmod_handler(const char *val, struct kernel_param *kp);
1030
1031module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200);
1032MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See"
1033 " Documentation/IPMI.txt in the kernel sources for the"
1034 " gory details.");
1006 1035
1007module_param_named(trydefaults, si_trydefaults, bool, 0); 1036module_param_named(trydefaults, si_trydefaults, bool, 0);
1008MODULE_PARM_DESC(trydefaults, "Setting this to 'false' will disable the" 1037MODULE_PARM_DESC(trydefaults, "Setting this to 'false' will disable the"
@@ -1054,12 +1083,12 @@ module_param_array(force_kipmid, int, &num_force_kipmid, 0);
1054MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or" 1083MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or"
1055 " disabled(0). Normally the IPMI driver auto-detects" 1084 " disabled(0). Normally the IPMI driver auto-detects"
1056 " this, but the value may be overridden by this parm."); 1085 " this, but the value may be overridden by this parm.");
1086module_param(unload_when_empty, int, 0);
1087MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are"
1088 " specified or found, default is 1. Setting to 0"
1089 " is useful for hot add of devices using hotmod.");
1057 1090
1058 1091
1059#define IPMI_IO_ADDR_SPACE 0
1060#define IPMI_MEM_ADDR_SPACE 1
1061static char *addr_space_to_str[] = { "I/O", "memory" };
1062
1063static void std_irq_cleanup(struct smi_info *info) 1092static void std_irq_cleanup(struct smi_info *info)
1064{ 1093{
1065 if (info->si_type == SI_BT) 1094 if (info->si_type == SI_BT)
@@ -1333,6 +1362,234 @@ static int mem_setup(struct smi_info *info)
1333 return 0; 1362 return 0;
1334} 1363}
1335 1364
1365/*
1366 * Parms come in as <op1>[:op2[:op3...]]. ops are:
1367 * add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]]
1368 * Options are:
1369 * rsp=<regspacing>
1370 * rsi=<regsize>
1371 * rsh=<regshift>
1372 * irq=<irq>
1373 * ipmb=<ipmb addr>
1374 */
1375enum hotmod_op { HM_ADD, HM_REMOVE };
1376struct hotmod_vals {
1377 char *name;
1378 int val;
1379};
1380static struct hotmod_vals hotmod_ops[] = {
1381 { "add", HM_ADD },
1382 { "remove", HM_REMOVE },
1383 { NULL }
1384};
1385static struct hotmod_vals hotmod_si[] = {
1386 { "kcs", SI_KCS },
1387 { "smic", SI_SMIC },
1388 { "bt", SI_BT },
1389 { NULL }
1390};
1391static struct hotmod_vals hotmod_as[] = {
1392 { "mem", IPMI_MEM_ADDR_SPACE },
1393 { "i/o", IPMI_IO_ADDR_SPACE },
1394 { NULL }
1395};
1396static int ipmi_strcasecmp(const char *s1, const char *s2)
1397{
1398 while (*s1 || *s2) {
1399 if (!*s1)
1400 return -1;
1401 if (!*s2)
1402 return 1;
1403 if (*s1 != *s2)
1404 return *s1 - *s2;
1405 s1++;
1406 s2++;
1407 }
1408 return 0;
1409}
1410static int parse_str(struct hotmod_vals *v, int *val, char *name, char **curr)
1411{
1412 char *s;
1413 int i;
1414
1415 s = strchr(*curr, ',');
1416 if (!s) {
1417 printk(KERN_WARNING PFX "No hotmod %s given.\n", name);
1418 return -EINVAL;
1419 }
1420 *s = '\0';
1421 s++;
1422 for (i = 0; hotmod_ops[i].name; i++) {
1423 if (ipmi_strcasecmp(*curr, v[i].name) == 0) {
1424 *val = v[i].val;
1425 *curr = s;
1426 return 0;
1427 }
1428 }
1429
1430 printk(KERN_WARNING PFX "Invalid hotmod %s '%s'\n", name, *curr);
1431 return -EINVAL;
1432}
1433
1434static int hotmod_handler(const char *val, struct kernel_param *kp)
1435{
1436 char *str = kstrdup(val, GFP_KERNEL);
1437 int rv = -EINVAL;
1438 char *next, *curr, *s, *n, *o;
1439 enum hotmod_op op;
1440 enum si_type si_type;
1441 int addr_space;
1442 unsigned long addr;
1443 int regspacing;
1444 int regsize;
1445 int regshift;
1446 int irq;
1447 int ipmb;
1448 int ival;
1449 struct smi_info *info;
1450
1451 if (!str)
1452 return -ENOMEM;
1453
1454 /* Kill any trailing spaces, as we can get a "\n" from echo. */
1455 ival = strlen(str) - 1;
1456 while ((ival >= 0) && isspace(str[ival])) {
1457 str[ival] = '\0';
1458 ival--;
1459 }
1460
1461 for (curr = str; curr; curr = next) {
1462 regspacing = 1;
1463 regsize = 1;
1464 regshift = 0;
1465 irq = 0;
1466 ipmb = 0x20;
1467
1468 next = strchr(curr, ':');
1469 if (next) {
1470 *next = '\0';
1471 next++;
1472 }
1473
1474 rv = parse_str(hotmod_ops, &ival, "operation", &curr);
1475 if (rv)
1476 break;
1477 op = ival;
1478
1479 rv = parse_str(hotmod_si, &ival, "interface type", &curr);
1480 if (rv)
1481 break;
1482 si_type = ival;
1483
1484 rv = parse_str(hotmod_as, &addr_space, "address space", &curr);
1485 if (rv)
1486 break;
1487
1488 s = strchr(curr, ',');
1489 if (s) {
1490 *s = '\0';
1491 s++;
1492 }
1493 addr = simple_strtoul(curr, &n, 0);
1494 if ((*n != '\0') || (*curr == '\0')) {
1495 printk(KERN_WARNING PFX "Invalid hotmod address"
1496 " '%s'\n", curr);
1497 break;
1498 }
1499
1500 while (s) {
1501 curr = s;
1502 s = strchr(curr, ',');
1503 if (s) {
1504 *s = '\0';
1505 s++;
1506 }
1507 o = strchr(curr, '=');
1508 if (o) {
1509 *o = '\0';
1510 o++;
1511 }
1512#define HOTMOD_INT_OPT(name, val) \
1513 if (ipmi_strcasecmp(curr, name) == 0) { \
1514 if (!o) { \
1515 printk(KERN_WARNING PFX \
1516 "No option given for '%s'\n", \
1517 curr); \
1518 goto out; \
1519 } \
1520 val = simple_strtoul(o, &n, 0); \
1521 if ((*n != '\0') || (*o == '\0')) { \
1522 printk(KERN_WARNING PFX \
1523 "Bad option given for '%s'\n", \
1524 curr); \
1525 goto out; \
1526 } \
1527 }
1528
1529 HOTMOD_INT_OPT("rsp", regspacing)
1530 else HOTMOD_INT_OPT("rsi", regsize)
1531 else HOTMOD_INT_OPT("rsh", regshift)
1532 else HOTMOD_INT_OPT("irq", irq)
1533 else HOTMOD_INT_OPT("ipmb", ipmb)
1534 else {
1535 printk(KERN_WARNING PFX
1536 "Invalid hotmod option '%s'\n",
1537 curr);
1538 goto out;
1539 }
1540#undef HOTMOD_INT_OPT
1541 }
1542
1543 if (op == HM_ADD) {
1544 info = kzalloc(sizeof(*info), GFP_KERNEL);
1545 if (!info) {
1546 rv = -ENOMEM;
1547 goto out;
1548 }
1549
1550 info->addr_source = "hotmod";
1551 info->si_type = si_type;
1552 info->io.addr_data = addr;
1553 info->io.addr_type = addr_space;
1554 if (addr_space == IPMI_MEM_ADDR_SPACE)
1555 info->io_setup = mem_setup;
1556 else
1557 info->io_setup = port_setup;
1558
1559 info->io.addr = NULL;
1560 info->io.regspacing = regspacing;
1561 if (!info->io.regspacing)
1562 info->io.regspacing = DEFAULT_REGSPACING;
1563 info->io.regsize = regsize;
1564 if (!info->io.regsize)
1565 info->io.regsize = DEFAULT_REGSPACING;
1566 info->io.regshift = regshift;
1567 info->irq = irq;
1568 if (info->irq)
1569 info->irq_setup = std_irq_setup;
1570 info->slave_addr = ipmb;
1571
1572 try_smi_init(info);
1573 } else {
1574 /* remove */
1575 struct smi_info *e, *tmp_e;
1576
1577 mutex_lock(&smi_infos_lock);
1578 list_for_each_entry_safe(e, tmp_e, &smi_infos, link) {
1579 if (e->io.addr_type != addr_space)
1580 continue;
1581 if (e->si_type != si_type)
1582 continue;
1583 if (e->io.addr_data == addr)
1584 cleanup_one_si(e);
1585 }
1586 mutex_unlock(&smi_infos_lock);
1587 }
1588 }
1589 out:
1590 kfree(str);
1591 return rv;
1592}
1336 1593
1337static __devinit void hardcode_find_bmc(void) 1594static __devinit void hardcode_find_bmc(void)
1338{ 1595{
@@ -1349,11 +1606,11 @@ static __devinit void hardcode_find_bmc(void)
1349 1606
1350 info->addr_source = "hardcoded"; 1607 info->addr_source = "hardcoded";
1351 1608
1352 if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) { 1609 if (!si_type[i] || ipmi_strcasecmp(si_type[i], "kcs") == 0) {
1353 info->si_type = SI_KCS; 1610 info->si_type = SI_KCS;
1354 } else if (strcmp(si_type[i], "smic") == 0) { 1611 } else if (ipmi_strcasecmp(si_type[i], "smic") == 0) {
1355 info->si_type = SI_SMIC; 1612 info->si_type = SI_SMIC;
1356 } else if (strcmp(si_type[i], "bt") == 0) { 1613 } else if (ipmi_strcasecmp(si_type[i], "bt") == 0) {
1357 info->si_type = SI_BT; 1614 info->si_type = SI_BT;
1358 } else { 1615 } else {
1359 printk(KERN_WARNING 1616 printk(KERN_WARNING
@@ -1968,19 +2225,9 @@ static int try_get_dev_id(struct smi_info *smi_info)
1968static int type_file_read_proc(char *page, char **start, off_t off, 2225static int type_file_read_proc(char *page, char **start, off_t off,
1969 int count, int *eof, void *data) 2226 int count, int *eof, void *data)
1970{ 2227{
1971 char *out = (char *) page;
1972 struct smi_info *smi = data; 2228 struct smi_info *smi = data;
1973 2229
1974 switch (smi->si_type) { 2230 return sprintf(page, "%s\n", si_to_str[smi->si_type]);
1975 case SI_KCS:
1976 return sprintf(out, "kcs\n");
1977 case SI_SMIC:
1978 return sprintf(out, "smic\n");
1979 case SI_BT:
1980 return sprintf(out, "bt\n");
1981 default:
1982 return 0;
1983 }
1984} 2231}
1985 2232
1986static int stat_file_read_proc(char *page, char **start, off_t off, 2233static int stat_file_read_proc(char *page, char **start, off_t off,
@@ -2016,7 +2263,24 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
2016 out += sprintf(out, "incoming_messages: %ld\n", 2263 out += sprintf(out, "incoming_messages: %ld\n",
2017 smi->incoming_messages); 2264 smi->incoming_messages);
2018 2265
2019 return (out - ((char *) page)); 2266 return out - page;
2267}
2268
2269static int param_read_proc(char *page, char **start, off_t off,
2270 int count, int *eof, void *data)
2271{
2272 struct smi_info *smi = data;
2273
2274 return sprintf(page,
2275 "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n",
2276 si_to_str[smi->si_type],
2277 addr_space_to_str[smi->io.addr_type],
2278 smi->io.addr_data,
2279 smi->io.regspacing,
2280 smi->io.regsize,
2281 smi->io.regshift,
2282 smi->irq,
2283 smi->slave_addr);
2020} 2284}
2021 2285
2022/* 2286/*
@@ -2407,6 +2671,16 @@ static int try_smi_init(struct smi_info *new_smi)
2407 goto out_err_stop_timer; 2671 goto out_err_stop_timer;
2408 } 2672 }
2409 2673
2674 rv = ipmi_smi_add_proc_entry(new_smi->intf, "params",
2675 param_read_proc, NULL,
2676 new_smi, THIS_MODULE);
2677 if (rv) {
2678 printk(KERN_ERR
2679 "ipmi_si: Unable to create proc entry: %d\n",
2680 rv);
2681 goto out_err_stop_timer;
2682 }
2683
2410 list_add_tail(&new_smi->link, &smi_infos); 2684 list_add_tail(&new_smi->link, &smi_infos);
2411 2685
2412 mutex_unlock(&smi_infos_lock); 2686 mutex_unlock(&smi_infos_lock);
@@ -2515,7 +2789,7 @@ static __devinit int init_ipmi_si(void)
2515 } 2789 }
2516 2790
2517 mutex_lock(&smi_infos_lock); 2791 mutex_lock(&smi_infos_lock);
2518 if (list_empty(&smi_infos)) { 2792 if (unload_when_empty && list_empty(&smi_infos)) {
2519 mutex_unlock(&smi_infos_lock); 2793 mutex_unlock(&smi_infos_lock);
2520#ifdef CONFIG_PCI 2794#ifdef CONFIG_PCI
2521 pci_unregister_driver(&ipmi_pci_driver); 2795 pci_unregister_driver(&ipmi_pci_driver);
@@ -2530,7 +2804,7 @@ static __devinit int init_ipmi_si(void)
2530} 2804}
2531module_init(init_ipmi_si); 2805module_init(init_ipmi_si);
2532 2806
2533static void __devexit cleanup_one_si(struct smi_info *to_clean) 2807static void cleanup_one_si(struct smi_info *to_clean)
2534{ 2808{
2535 int rv; 2809 int rv;
2536 unsigned long flags; 2810 unsigned long flags;