diff options
author | dann frazier <dannf@hp.com> | 2009-04-21 15:24:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-21 16:41:48 -0400 |
commit | 4dec302ff71ebf48f5784a2d2fc5e3745e6d4d52 (patch) | |
tree | f2c7042168c8e25987c0b0cd55c546078f454089 | |
parent | 25176ed670121e1e0aae5c8161713c332b786538 (diff) |
ipmi: add oem message handling
Enable userspace to receive messages that a BMC transmits using an OEM
medium. This is used by the HP iLO2.
Based on code originally written by Patrick Schoeller.
Signed-off-by: dann frazier <dannf@hp.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 138 | ||||
-rw-r--r-- | include/linux/ipmi.h | 2 | ||||
-rw-r--r-- | include/linux/ipmi_msgdefs.h | 2 |
3 files changed, 137 insertions, 5 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 83c7477ba801..aa83a0865ec1 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -3284,6 +3284,114 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, | |||
3284 | return rv; | 3284 | return rv; |
3285 | } | 3285 | } |
3286 | 3286 | ||
3287 | /* | ||
3288 | * This routine will handle "Get Message" command responses with | ||
3289 | * channels that use an OEM Medium. The message format belongs to | ||
3290 | * the OEM. See IPMI 2.0 specification, Chapter 6 and | ||
3291 | * Chapter 22, sections 22.6 and 22.24 for more details. | ||
3292 | */ | ||
3293 | static int handle_oem_get_msg_cmd(ipmi_smi_t intf, | ||
3294 | struct ipmi_smi_msg *msg) | ||
3295 | { | ||
3296 | struct cmd_rcvr *rcvr; | ||
3297 | int rv = 0; | ||
3298 | unsigned char netfn; | ||
3299 | unsigned char cmd; | ||
3300 | unsigned char chan; | ||
3301 | ipmi_user_t user = NULL; | ||
3302 | struct ipmi_system_interface_addr *smi_addr; | ||
3303 | struct ipmi_recv_msg *recv_msg; | ||
3304 | |||
3305 | /* | ||
3306 | * We expect the OEM SW to perform error checking | ||
3307 | * so we just do some basic sanity checks | ||
3308 | */ | ||
3309 | if (msg->rsp_size < 4) { | ||
3310 | /* Message not big enough, just ignore it. */ | ||
3311 | ipmi_inc_stat(intf, invalid_commands); | ||
3312 | return 0; | ||
3313 | } | ||
3314 | |||
3315 | if (msg->rsp[2] != 0) { | ||
3316 | /* An error getting the response, just ignore it. */ | ||
3317 | return 0; | ||
3318 | } | ||
3319 | |||
3320 | /* | ||
3321 | * This is an OEM Message so the OEM needs to know how | ||
3322 | * handle the message. We do no interpretation. | ||
3323 | */ | ||
3324 | netfn = msg->rsp[0] >> 2; | ||
3325 | cmd = msg->rsp[1]; | ||
3326 | chan = msg->rsp[3] & 0xf; | ||
3327 | |||
3328 | rcu_read_lock(); | ||
3329 | rcvr = find_cmd_rcvr(intf, netfn, cmd, chan); | ||
3330 | if (rcvr) { | ||
3331 | user = rcvr->user; | ||
3332 | kref_get(&user->refcount); | ||
3333 | } else | ||
3334 | user = NULL; | ||
3335 | rcu_read_unlock(); | ||
3336 | |||
3337 | if (user == NULL) { | ||
3338 | /* We didn't find a user, just give up. */ | ||
3339 | ipmi_inc_stat(intf, unhandled_commands); | ||
3340 | |||
3341 | /* | ||
3342 | * Don't do anything with these messages, just allow | ||
3343 | * them to be freed. | ||
3344 | */ | ||
3345 | |||
3346 | rv = 0; | ||
3347 | } else { | ||
3348 | /* Deliver the message to the user. */ | ||
3349 | ipmi_inc_stat(intf, handled_commands); | ||
3350 | |||
3351 | recv_msg = ipmi_alloc_recv_msg(); | ||
3352 | if (!recv_msg) { | ||
3353 | /* | ||
3354 | * We couldn't allocate memory for the | ||
3355 | * message, so requeue it for handling | ||
3356 | * later. | ||
3357 | */ | ||
3358 | rv = 1; | ||
3359 | kref_put(&user->refcount, free_user); | ||
3360 | } else { | ||
3361 | /* | ||
3362 | * OEM Messages are expected to be delivered via | ||
3363 | * the system interface to SMS software. We might | ||
3364 | * need to visit this again depending on OEM | ||
3365 | * requirements | ||
3366 | */ | ||
3367 | smi_addr = ((struct ipmi_system_interface_addr *) | ||
3368 | &(recv_msg->addr)); | ||
3369 | smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; | ||
3370 | smi_addr->channel = IPMI_BMC_CHANNEL; | ||
3371 | smi_addr->lun = msg->rsp[0] & 3; | ||
3372 | |||
3373 | recv_msg->user = user; | ||
3374 | recv_msg->user_msg_data = NULL; | ||
3375 | recv_msg->recv_type = IPMI_OEM_RECV_TYPE; | ||
3376 | recv_msg->msg.netfn = msg->rsp[0] >> 2; | ||
3377 | recv_msg->msg.cmd = msg->rsp[1]; | ||
3378 | recv_msg->msg.data = recv_msg->msg_data; | ||
3379 | |||
3380 | /* | ||
3381 | * The message starts at byte 4 which follows the | ||
3382 | * the Channel Byte in the "GET MESSAGE" command | ||
3383 | */ | ||
3384 | recv_msg->msg.data_len = msg->rsp_size - 4; | ||
3385 | memcpy(recv_msg->msg_data, | ||
3386 | &(msg->rsp[4]), | ||
3387 | msg->rsp_size - 4); | ||
3388 | deliver_response(recv_msg); | ||
3389 | } | ||
3390 | } | ||
3391 | |||
3392 | return rv; | ||
3393 | } | ||
3394 | |||
3287 | static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg, | 3395 | static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg, |
3288 | struct ipmi_smi_msg *msg) | 3396 | struct ipmi_smi_msg *msg) |
3289 | { | 3397 | { |
@@ -3539,6 +3647,17 @@ static int handle_new_recv_msg(ipmi_smi_t intf, | |||
3539 | goto out; | 3647 | goto out; |
3540 | } | 3648 | } |
3541 | 3649 | ||
3650 | /* | ||
3651 | ** We need to make sure the channels have been initialized. | ||
3652 | ** The channel_handler routine will set the "curr_channel" | ||
3653 | ** equal to or greater than IPMI_MAX_CHANNELS when all the | ||
3654 | ** channels for this interface have been initialized. | ||
3655 | */ | ||
3656 | if (intf->curr_channel < IPMI_MAX_CHANNELS) { | ||
3657 | requeue = 1; /* Just put the message back for now */ | ||
3658 | goto out; | ||
3659 | } | ||
3660 | |||
3542 | switch (intf->channels[chan].medium) { | 3661 | switch (intf->channels[chan].medium) { |
3543 | case IPMI_CHANNEL_MEDIUM_IPMB: | 3662 | case IPMI_CHANNEL_MEDIUM_IPMB: |
3544 | if (msg->rsp[4] & 0x04) { | 3663 | if (msg->rsp[4] & 0x04) { |
@@ -3574,11 +3693,20 @@ static int handle_new_recv_msg(ipmi_smi_t intf, | |||
3574 | break; | 3693 | break; |
3575 | 3694 | ||
3576 | default: | 3695 | default: |
3577 | /* | 3696 | /* Check for OEM Channels. Clients had better |
3578 | * We don't handle the channel type, so just | 3697 | register for these commands. */ |
3579 | * free the message. | 3698 | if ((intf->channels[chan].medium |
3580 | */ | 3699 | >= IPMI_CHANNEL_MEDIUM_OEM_MIN) |
3581 | requeue = 0; | 3700 | && (intf->channels[chan].medium |
3701 | <= IPMI_CHANNEL_MEDIUM_OEM_MAX)) { | ||
3702 | requeue = handle_oem_get_msg_cmd(intf, msg); | ||
3703 | } else { | ||
3704 | /* | ||
3705 | * We don't handle the channel type, so just | ||
3706 | * free the message. | ||
3707 | */ | ||
3708 | requeue = 0; | ||
3709 | } | ||
3582 | } | 3710 | } |
3583 | 3711 | ||
3584 | } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) | 3712 | } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) |
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h index 7ebdb4fb4e54..65aae34759de 100644 --- a/include/linux/ipmi.h +++ b/include/linux/ipmi.h | |||
@@ -198,6 +198,8 @@ struct kernel_ipmi_msg { | |||
198 | response. When you send a | 198 | response. When you send a |
199 | response message, this will | 199 | response message, this will |
200 | be returned. */ | 200 | be returned. */ |
201 | #define IPMI_OEM_RECV_TYPE 5 /* The response for OEM Channels */ | ||
202 | |||
201 | /* Note that async events and received commands do not have a completion | 203 | /* Note that async events and received commands do not have a completion |
202 | code as the first byte of the incoming data, unlike a response. */ | 204 | code as the first byte of the incoming data, unlike a response. */ |
203 | 205 | ||
diff --git a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h index a079f586e907..df97e6e31e87 100644 --- a/include/linux/ipmi_msgdefs.h +++ b/include/linux/ipmi_msgdefs.h | |||
@@ -115,5 +115,7 @@ | |||
115 | #define IPMI_CHANNEL_MEDIUM_USB1 10 | 115 | #define IPMI_CHANNEL_MEDIUM_USB1 10 |
116 | #define IPMI_CHANNEL_MEDIUM_USB2 11 | 116 | #define IPMI_CHANNEL_MEDIUM_USB2 11 |
117 | #define IPMI_CHANNEL_MEDIUM_SYSINTF 12 | 117 | #define IPMI_CHANNEL_MEDIUM_SYSINTF 12 |
118 | #define IPMI_CHANNEL_MEDIUM_OEM_MIN 0x60 | ||
119 | #define IPMI_CHANNEL_MEDIUM_OEM_MAX 0x7f | ||
118 | 120 | ||
119 | #endif /* __LINUX_IPMI_MSGDEFS_H */ | 121 | #endif /* __LINUX_IPMI_MSGDEFS_H */ |