Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

dann frazier and committed by
Linus Torvalds
4dec302f 25176ed6

+137 -5
+133 -5
drivers/char/ipmi/ipmi_msghandler.c
··· 3284 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 3395 static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg, 3288 3396 struct ipmi_smi_msg *msg) 3289 3397 { ··· 3647 3539 goto out; 3648 3540 } 3649 3541 3542 + /* 3543 + ** We need to make sure the channels have been initialized. 3544 + ** The channel_handler routine will set the "curr_channel" 3545 + ** equal to or greater than IPMI_MAX_CHANNELS when all the 3546 + ** channels for this interface have been initialized. 3547 + */ 3548 + if (intf->curr_channel < IPMI_MAX_CHANNELS) { 3549 + requeue = 1; /* Just put the message back for now */ 3550 + goto out; 3551 + } 3552 + 3650 3553 switch (intf->channels[chan].medium) { 3651 3554 case IPMI_CHANNEL_MEDIUM_IPMB: 3652 3555 if (msg->rsp[4] & 0x04) { ··· 3693 3574 break; 3694 3575 3695 3576 default: 3696 - /* 3697 - * We don't handle the channel type, so just 3698 - * free the message. 3699 - */ 3700 - requeue = 0; 3577 + /* Check for OEM Channels. Clients had better 3578 + register for these commands. */ 3579 + if ((intf->channels[chan].medium 3580 + >= IPMI_CHANNEL_MEDIUM_OEM_MIN) 3581 + && (intf->channels[chan].medium 3582 + <= IPMI_CHANNEL_MEDIUM_OEM_MAX)) { 3583 + requeue = handle_oem_get_msg_cmd(intf, msg); 3584 + } else { 3585 + /* 3586 + * We don't handle the channel type, so just 3587 + * free the message. 3588 + */ 3589 + requeue = 0; 3590 + } 3701 3591 } 3702 3592 3703 3593 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
+2
include/linux/ipmi.h
··· 198 198 response. When you send a 199 199 response message, this will 200 200 be returned. */ 201 + #define IPMI_OEM_RECV_TYPE 5 /* The response for OEM Channels */ 202 + 201 203 /* Note that async events and received commands do not have a completion 202 204 code as the first byte of the incoming data, unlike a response. */ 203 205
+2
include/linux/ipmi_msgdefs.h
··· 115 115 #define IPMI_CHANNEL_MEDIUM_USB1 10 116 116 #define IPMI_CHANNEL_MEDIUM_USB2 11 117 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 121 #endif /* __LINUX_IPMI_MSGDEFS_H */