aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorey Minyard <minyard@acm.org>2005-09-06 18:18:38 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:57:47 -0400
commitc14979b993021377228958498937bcdd9539cbce (patch)
treee30638df99aa69f707e7549e4e990e9e92d477ae
parentb224cd3a0ca376dd52f382905c1aaf5a83a54692 (diff)
[PATCH] ipmi: add per-channel IPMB addresses
IPMI allows multiple IPMB channels on a single interface, and each channel might have a different IPMB address. However, the driver has only one IPMB address that it uses for everything. This patch adds new IOCTLS and a new internal interface for setting per-channel IPMB addresses and LUNs. New systems are coming out with support for multiple IPMB channels, and they are broken without this patch. Signed-off-by: Corey Minyard <minyard@acm.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c94
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c137
-rw-r--r--include/linux/ipmi.h30
3 files changed, 201 insertions, 60 deletions
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index e0a53570fea1..5571e92c520f 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -411,6 +411,7 @@ static int ipmi_ioctl(struct inode *inode,
411 break; 411 break;
412 } 412 }
413 413
414 /* The next four are legacy, not per-channel. */
414 case IPMICTL_SET_MY_ADDRESS_CMD: 415 case IPMICTL_SET_MY_ADDRESS_CMD:
415 { 416 {
416 unsigned int val; 417 unsigned int val;
@@ -420,22 +421,25 @@ static int ipmi_ioctl(struct inode *inode,
420 break; 421 break;
421 } 422 }
422 423
423 ipmi_set_my_address(priv->user, val); 424 rv = ipmi_set_my_address(priv->user, 0, val);
424 rv = 0;
425 break; 425 break;
426 } 426 }
427 427
428 case IPMICTL_GET_MY_ADDRESS_CMD: 428 case IPMICTL_GET_MY_ADDRESS_CMD:
429 { 429 {
430 unsigned int val; 430 unsigned int val;
431 unsigned char rval;
432
433 rv = ipmi_get_my_address(priv->user, 0, &rval);
434 if (rv)
435 break;
431 436
432 val = ipmi_get_my_address(priv->user); 437 val = rval;
433 438
434 if (copy_to_user(arg, &val, sizeof(val))) { 439 if (copy_to_user(arg, &val, sizeof(val))) {
435 rv = -EFAULT; 440 rv = -EFAULT;
436 break; 441 break;
437 } 442 }
438 rv = 0;
439 break; 443 break;
440 } 444 }
441 445
@@ -448,24 +452,94 @@ static int ipmi_ioctl(struct inode *inode,
448 break; 452 break;
449 } 453 }
450 454
451 ipmi_set_my_LUN(priv->user, val); 455 rv = ipmi_set_my_LUN(priv->user, 0, val);
452 rv = 0;
453 break; 456 break;
454 } 457 }
455 458
456 case IPMICTL_GET_MY_LUN_CMD: 459 case IPMICTL_GET_MY_LUN_CMD:
457 { 460 {
458 unsigned int val; 461 unsigned int val;
462 unsigned char rval;
463
464 rv = ipmi_get_my_LUN(priv->user, 0, &rval);
465 if (rv)
466 break;
459 467
460 val = ipmi_get_my_LUN(priv->user); 468 val = rval;
461 469
462 if (copy_to_user(arg, &val, sizeof(val))) { 470 if (copy_to_user(arg, &val, sizeof(val))) {
463 rv = -EFAULT; 471 rv = -EFAULT;
464 break; 472 break;
465 } 473 }
466 rv = 0;
467 break; 474 break;
468 } 475 }
476
477 case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
478 {
479 struct ipmi_channel_lun_address_set val;
480
481 if (copy_from_user(&val, arg, sizeof(val))) {
482 rv = -EFAULT;
483 break;
484 }
485
486 return ipmi_set_my_address(priv->user, val.channel, val.value);
487 break;
488 }
489
490 case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
491 {
492 struct ipmi_channel_lun_address_set val;
493
494 if (copy_from_user(&val, arg, sizeof(val))) {
495 rv = -EFAULT;
496 break;
497 }
498
499 rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
500 if (rv)
501 break;
502
503 if (copy_to_user(arg, &val, sizeof(val))) {
504 rv = -EFAULT;
505 break;
506 }
507 break;
508 }
509
510 case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
511 {
512 struct ipmi_channel_lun_address_set val;
513
514 if (copy_from_user(&val, arg, sizeof(val))) {
515 rv = -EFAULT;
516 break;
517 }
518
519 rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
520 break;
521 }
522
523 case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
524 {
525 struct ipmi_channel_lun_address_set val;
526
527 if (copy_from_user(&val, arg, sizeof(val))) {
528 rv = -EFAULT;
529 break;
530 }
531
532 rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
533 if (rv)
534 break;
535
536 if (copy_to_user(arg, &val, sizeof(val))) {
537 rv = -EFAULT;
538 break;
539 }
540 break;
541 }
542
469 case IPMICTL_SET_TIMING_PARMS_CMD: 543 case IPMICTL_SET_TIMING_PARMS_CMD:
470 { 544 {
471 struct ipmi_timing_parms parms; 545 struct ipmi_timing_parms parms;
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index e16c13fe698d..84d477c6f925 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -124,6 +124,14 @@ struct ipmi_channel
124{ 124{
125 unsigned char medium; 125 unsigned char medium;
126 unsigned char protocol; 126 unsigned char protocol;
127
128 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
129 but may be changed by the user. */
130 unsigned char address;
131
132 /* My LUN. This should generally stay the SMS LUN, but just in
133 case... */
134 unsigned char lun;
127}; 135};
128 136
129#ifdef CONFIG_PROC_FS 137#ifdef CONFIG_PROC_FS
@@ -135,7 +143,7 @@ struct ipmi_proc_entry
135#endif 143#endif
136 144
137#define IPMI_IPMB_NUM_SEQ 64 145#define IPMI_IPMB_NUM_SEQ 64
138#define IPMI_MAX_CHANNELS 8 146#define IPMI_MAX_CHANNELS 16
139struct ipmi_smi 147struct ipmi_smi
140{ 148{
141 /* What interface number are we? */ 149 /* What interface number are we? */
@@ -199,14 +207,6 @@ struct ipmi_smi
199 this is registered. */ 207 this is registered. */
200 ipmi_user_t all_cmd_rcvr; 208 ipmi_user_t all_cmd_rcvr;
201 209
202 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
203 but may be changed by the user. */
204 unsigned char my_address;
205
206 /* My LUN. This should generally stay the SMS LUN, but just in
207 case... */
208 unsigned char my_lun;
209
210 /* The event receiver for my BMC, only really used at panic 210 /* The event receiver for my BMC, only really used at panic
211 shutdown as a place to store this. */ 211 shutdown as a place to store this. */
212 unsigned char event_receiver; 212 unsigned char event_receiver;
@@ -766,26 +766,44 @@ void ipmi_get_version(ipmi_user_t user,
766 *minor = user->intf->version_minor; 766 *minor = user->intf->version_minor;
767} 767}
768 768
769void ipmi_set_my_address(ipmi_user_t user, 769int ipmi_set_my_address(ipmi_user_t user,
770 unsigned char address) 770 unsigned int channel,
771 unsigned char address)
771{ 772{
772 user->intf->my_address = address; 773 if (channel >= IPMI_MAX_CHANNELS)
774 return -EINVAL;
775 user->intf->channels[channel].address = address;
776 return 0;
773} 777}
774 778
775unsigned char ipmi_get_my_address(ipmi_user_t user) 779int ipmi_get_my_address(ipmi_user_t user,
780 unsigned int channel,
781 unsigned char *address)
776{ 782{
777 return user->intf->my_address; 783 if (channel >= IPMI_MAX_CHANNELS)
784 return -EINVAL;
785 *address = user->intf->channels[channel].address;
786 return 0;
778} 787}
779 788
780void ipmi_set_my_LUN(ipmi_user_t user, 789int ipmi_set_my_LUN(ipmi_user_t user,
781 unsigned char LUN) 790 unsigned int channel,
791 unsigned char LUN)
782{ 792{
783 user->intf->my_lun = LUN & 0x3; 793 if (channel >= IPMI_MAX_CHANNELS)
794 return -EINVAL;
795 user->intf->channels[channel].lun = LUN & 0x3;
796 return 0;
784} 797}
785 798
786unsigned char ipmi_get_my_LUN(ipmi_user_t user) 799int ipmi_get_my_LUN(ipmi_user_t user,
800 unsigned int channel,
801 unsigned char *address)
787{ 802{
788 return user->intf->my_lun; 803 if (channel >= IPMI_MAX_CHANNELS)
804 return -EINVAL;
805 *address = user->intf->channels[channel].lun;
806 return 0;
789} 807}
790 808
791int ipmi_set_gets_events(ipmi_user_t user, int val) 809int ipmi_set_gets_events(ipmi_user_t user, int val)
@@ -1213,7 +1231,7 @@ static inline int i_ipmi_request(ipmi_user_t user,
1213 unsigned char ipmb_seq; 1231 unsigned char ipmb_seq;
1214 long seqid; 1232 long seqid;
1215 1233
1216 if (addr->channel > IPMI_NUM_CHANNELS) { 1234 if (addr->channel >= IPMI_NUM_CHANNELS) {
1217 spin_lock_irqsave(&intf->counter_lock, flags); 1235 spin_lock_irqsave(&intf->counter_lock, flags);
1218 intf->sent_invalid_commands++; 1236 intf->sent_invalid_commands++;
1219 spin_unlock_irqrestore(&intf->counter_lock, flags); 1237 spin_unlock_irqrestore(&intf->counter_lock, flags);
@@ -1346,6 +1364,18 @@ static inline int i_ipmi_request(ipmi_user_t user,
1346 return rv; 1364 return rv;
1347} 1365}
1348 1366
1367static int check_addr(ipmi_smi_t intf,
1368 struct ipmi_addr *addr,
1369 unsigned char *saddr,
1370 unsigned char *lun)
1371{
1372 if (addr->channel >= IPMI_MAX_CHANNELS)
1373 return -EINVAL;
1374 *lun = intf->channels[addr->channel].lun;
1375 *saddr = intf->channels[addr->channel].address;
1376 return 0;
1377}
1378
1349int ipmi_request_settime(ipmi_user_t user, 1379int ipmi_request_settime(ipmi_user_t user,
1350 struct ipmi_addr *addr, 1380 struct ipmi_addr *addr,
1351 long msgid, 1381 long msgid,
@@ -1355,6 +1385,12 @@ int ipmi_request_settime(ipmi_user_t user,
1355 int retries, 1385 int retries,
1356 unsigned int retry_time_ms) 1386 unsigned int retry_time_ms)
1357{ 1387{
1388 unsigned char saddr, lun;
1389 int rv;
1390
1391 rv = check_addr(user->intf, addr, &saddr, &lun);
1392 if (rv)
1393 return rv;
1358 return i_ipmi_request(user, 1394 return i_ipmi_request(user,
1359 user->intf, 1395 user->intf,
1360 addr, 1396 addr,
@@ -1363,8 +1399,8 @@ int ipmi_request_settime(ipmi_user_t user,
1363 user_msg_data, 1399 user_msg_data,
1364 NULL, NULL, 1400 NULL, NULL,
1365 priority, 1401 priority,
1366 user->intf->my_address, 1402 saddr,
1367 user->intf->my_lun, 1403 lun,
1368 retries, 1404 retries,
1369 retry_time_ms); 1405 retry_time_ms);
1370} 1406}
@@ -1378,6 +1414,12 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
1378 struct ipmi_recv_msg *supplied_recv, 1414 struct ipmi_recv_msg *supplied_recv,
1379 int priority) 1415 int priority)
1380{ 1416{
1417 unsigned char saddr, lun;
1418 int rv;
1419
1420 rv = check_addr(user->intf, addr, &saddr, &lun);
1421 if (rv)
1422 return rv;
1381 return i_ipmi_request(user, 1423 return i_ipmi_request(user,
1382 user->intf, 1424 user->intf,
1383 addr, 1425 addr,
@@ -1387,8 +1429,8 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
1387 supplied_smi, 1429 supplied_smi,
1388 supplied_recv, 1430 supplied_recv,
1389 priority, 1431 priority,
1390 user->intf->my_address, 1432 saddr,
1391 user->intf->my_lun, 1433 lun,
1392 -1, 0); 1434 -1, 0);
1393} 1435}
1394 1436
@@ -1397,8 +1439,15 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off,
1397{ 1439{
1398 char *out = (char *) page; 1440 char *out = (char *) page;
1399 ipmi_smi_t intf = data; 1441 ipmi_smi_t intf = data;
1442 int i;
1443 int rv= 0;
1400 1444
1401 return sprintf(out, "%x\n", intf->my_address); 1445 for (i=0; i<IPMI_MAX_CHANNELS; i++)
1446 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1447 out[rv-1] = '\n'; /* Replace the final space with a newline */
1448 out[rv] = '\0';
1449 rv++;
1450 return rv;
1402} 1451}
1403 1452
1404static int version_file_read_proc(char *page, char **start, off_t off, 1453static int version_file_read_proc(char *page, char **start, off_t off,
@@ -1592,8 +1641,8 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan)
1592 NULL, 1641 NULL,
1593 NULL, 1642 NULL,
1594 0, 1643 0,
1595 intf->my_address, 1644 intf->channels[0].address,
1596 intf->my_lun, 1645 intf->channels[0].lun,
1597 -1, 0); 1646 -1, 0);
1598} 1647}
1599 1648
@@ -1696,11 +1745,13 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
1696 new_intf->intf_num = i; 1745 new_intf->intf_num = i;
1697 new_intf->version_major = version_major; 1746 new_intf->version_major = version_major;
1698 new_intf->version_minor = version_minor; 1747 new_intf->version_minor = version_minor;
1699 if (slave_addr == 0) 1748 for (j=0; j<IPMI_MAX_CHANNELS; j++) {
1700 new_intf->my_address = IPMI_BMC_SLAVE_ADDR; 1749 new_intf->channels[j].address
1701 else 1750 = IPMI_BMC_SLAVE_ADDR;
1702 new_intf->my_address = slave_addr; 1751 new_intf->channels[j].lun = 2;
1703 new_intf->my_lun = 2; /* the SMS LUN. */ 1752 }
1753 if (slave_addr != 0)
1754 new_intf->channels[0].address = slave_addr;
1704 rwlock_init(&(new_intf->users_lock)); 1755 rwlock_init(&(new_intf->users_lock));
1705 INIT_LIST_HEAD(&(new_intf->users)); 1756 INIT_LIST_HEAD(&(new_intf->users));
1706 new_intf->handlers = handlers; 1757 new_intf->handlers = handlers;
@@ -1985,7 +2036,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
1985 msg->data[3] = msg->rsp[6]; 2036 msg->data[3] = msg->rsp[6];
1986 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); 2037 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
1987 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2); 2038 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
1988 msg->data[6] = intf->my_address; 2039 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
1989 /* rqseq/lun */ 2040 /* rqseq/lun */
1990 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); 2041 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
1991 msg->data[8] = msg->rsp[8]; /* cmd */ 2042 msg->data[8] = msg->rsp[8]; /* cmd */
@@ -2919,8 +2970,8 @@ static void send_panic_events(char *str)
2919 &smi_msg, 2970 &smi_msg,
2920 &recv_msg, 2971 &recv_msg,
2921 0, 2972 0,
2922 intf->my_address, 2973 intf->channels[0].address,
2923 intf->my_lun, 2974 intf->channels[0].lun,
2924 0, 1); /* Don't retry, and don't wait. */ 2975 0, 1); /* Don't retry, and don't wait. */
2925 } 2976 }
2926 2977
@@ -2965,8 +3016,8 @@ static void send_panic_events(char *str)
2965 &smi_msg, 3016 &smi_msg,
2966 &recv_msg, 3017 &recv_msg,
2967 0, 3018 0,
2968 intf->my_address, 3019 intf->channels[0].address,
2969 intf->my_lun, 3020 intf->channels[0].lun,
2970 0, 1); /* Don't retry, and don't wait. */ 3021 0, 1); /* Don't retry, and don't wait. */
2971 3022
2972 if (intf->local_event_generator) { 3023 if (intf->local_event_generator) {
@@ -2985,8 +3036,8 @@ static void send_panic_events(char *str)
2985 &smi_msg, 3036 &smi_msg,
2986 &recv_msg, 3037 &recv_msg,
2987 0, 3038 0,
2988 intf->my_address, 3039 intf->channels[0].address,
2989 intf->my_lun, 3040 intf->channels[0].lun,
2990 0, 1); /* no retry, and no wait. */ 3041 0, 1); /* no retry, and no wait. */
2991 } 3042 }
2992 intf->null_user_handler = NULL; 3043 intf->null_user_handler = NULL;
@@ -2996,7 +3047,7 @@ static void send_panic_events(char *str)
2996 be zero, and it must not be my address. */ 3047 be zero, and it must not be my address. */
2997 if (((intf->event_receiver & 1) == 0) 3048 if (((intf->event_receiver & 1) == 0)
2998 && (intf->event_receiver != 0) 3049 && (intf->event_receiver != 0)
2999 && (intf->event_receiver != intf->my_address)) 3050 && (intf->event_receiver != intf->channels[0].address))
3000 { 3051 {
3001 /* The event receiver is valid, send an IPMB 3052 /* The event receiver is valid, send an IPMB
3002 message. */ 3053 message. */
@@ -3031,7 +3082,7 @@ static void send_panic_events(char *str)
3031 data[0] = 0; 3082 data[0] = 0;
3032 data[1] = 0; 3083 data[1] = 0;
3033 data[2] = 0xf0; /* OEM event without timestamp. */ 3084 data[2] = 0xf0; /* OEM event without timestamp. */
3034 data[3] = intf->my_address; 3085 data[3] = intf->channels[0].address;
3035 data[4] = j++; /* sequence # */ 3086 data[4] = j++; /* sequence # */
3036 /* Always give 11 bytes, so strncpy will fill 3087 /* Always give 11 bytes, so strncpy will fill
3037 it with zeroes for me. */ 3088 it with zeroes for me. */
@@ -3047,8 +3098,8 @@ static void send_panic_events(char *str)
3047 &smi_msg, 3098 &smi_msg,
3048 &recv_msg, 3099 &recv_msg,
3049 0, 3100 0,
3050 intf->my_address, 3101 intf->channels[0].address,
3051 intf->my_lun, 3102 intf->channels[0].lun,
3052 0, 1); /* no retry, and no wait. */ 3103 0, 1); /* no retry, and no wait. */
3053 } 3104 }
3054 } 3105 }
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index 596ca6130159..846b69899776 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -298,13 +298,19 @@ void ipmi_get_version(ipmi_user_t user,
298 this user, so it will affect all users of this interface. This is 298 this user, so it will affect all users of this interface. This is
299 so some initialization code can come in and do the OEM-specific 299 so some initialization code can come in and do the OEM-specific
300 things it takes to determine your address (if not the BMC) and set 300 things it takes to determine your address (if not the BMC) and set
301 it for everyone else. */ 301 it for everyone else. Note that each channel can have its own address. */
302void ipmi_set_my_address(ipmi_user_t user, 302int ipmi_set_my_address(ipmi_user_t user,
303 unsigned char address); 303 unsigned int channel,
304unsigned char ipmi_get_my_address(ipmi_user_t user); 304 unsigned char address);
305void ipmi_set_my_LUN(ipmi_user_t user, 305int ipmi_get_my_address(ipmi_user_t user,
306 unsigned char LUN); 306 unsigned int channel,
307unsigned char ipmi_get_my_LUN(ipmi_user_t user); 307 unsigned char *address);
308int ipmi_set_my_LUN(ipmi_user_t user,
309 unsigned int channel,
310 unsigned char LUN);
311int ipmi_get_my_LUN(ipmi_user_t user,
312 unsigned int channel,
313 unsigned char *LUN);
308 314
309/* 315/*
310 * Like ipmi_request, but lets you specify the number of retries and 316 * Like ipmi_request, but lets you specify the number of retries and
@@ -585,6 +591,16 @@ struct ipmi_cmdspec
585 * things it takes to determine your address (if not the BMC) and set 591 * things it takes to determine your address (if not the BMC) and set
586 * it for everyone else. You should probably leave the LUN alone. 592 * it for everyone else. You should probably leave the LUN alone.
587 */ 593 */
594struct ipmi_channel_lun_address_set
595{
596 unsigned short channel;
597 unsigned char value;
598};
599#define IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 24, struct ipmi_channel_lun_address_set)
600#define IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 25, struct ipmi_channel_lun_address_set)
601#define IPMICTL_SET_MY_CHANNEL_LUN_CMD _IOR(IPMI_IOC_MAGIC, 26, struct ipmi_channel_lun_address_set)
602#define IPMICTL_GET_MY_CHANNEL_LUN_CMD _IOR(IPMI_IOC_MAGIC, 27, struct ipmi_channel_lun_address_set)
603/* Legacy interfaces, these only set IPMB 0. */
588#define IPMICTL_SET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 17, unsigned int) 604#define IPMICTL_SET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 17, unsigned int)
589#define IPMICTL_GET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 18, unsigned int) 605#define IPMICTL_GET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 18, unsigned int)
590#define IPMICTL_SET_MY_LUN_CMD _IOR(IPMI_IOC_MAGIC, 19, unsigned int) 606#define IPMICTL_SET_MY_LUN_CMD _IOR(IPMI_IOC_MAGIC, 19, unsigned int)