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

ipmi: Add support for IPMB direct messages

An application has come up that has a device sitting right on the IPMB
that would like to communicate with the BMC on the IPMB using normal
IPMI commands.

Sending these commands and handling the responses is easy enough, no
modifications are needed to the IPMI infrastructure. But if this is an
application that also needs to receive IPMB commands and respond, some
way is needed to handle these incoming commands and send the responses.

Currently, the IPMI message handler only sends commands to the interface
and only receives responses from interface. This change extends the
interface to receive commands/responses and send commands/responses.
These are formatted differently in support of receiving/sending IPMB
messages directly.

Signed-off-by: Corey Minyard <minyard@acm.org>
Tested-by: Andrew Manley <andrew.manley@sealingtech.com>
Reviewed-by: Andrew Manley <andrew.manley@sealingtech.com>

authored by

Corey Minyard and committed by
Corey Minyard
059747c2 1e4071f6

+328 -33
+255 -33
drivers/char/ipmi/ipmi_msghandler.c
··· 653 653 return addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE; 654 654 } 655 655 656 + static int is_ipmb_direct_addr(struct ipmi_addr *addr) 657 + { 658 + return addr->addr_type == IPMI_IPMB_DIRECT_ADDR_TYPE; 659 + } 660 + 656 661 static void free_recv_msg_list(struct list_head *q) 657 662 { 658 663 struct ipmi_recv_msg *msg, *msg2; ··· 810 805 && (ipmb_addr1->lun == ipmb_addr2->lun)); 811 806 } 812 807 808 + if (is_ipmb_direct_addr(addr1)) { 809 + struct ipmi_ipmb_direct_addr *daddr1 810 + = (struct ipmi_ipmb_direct_addr *) addr1; 811 + struct ipmi_ipmb_direct_addr *daddr2 812 + = (struct ipmi_ipmb_direct_addr *) addr2; 813 + 814 + return daddr1->slave_addr == daddr2->slave_addr && 815 + daddr1->rq_lun == daddr2->rq_lun && 816 + daddr1->rs_lun == daddr2->rs_lun; 817 + } 818 + 813 819 if (is_lan_addr(addr1)) { 814 820 struct ipmi_lan_addr *lan_addr1 815 821 = (struct ipmi_lan_addr *) addr1; ··· 859 843 return 0; 860 844 } 861 845 846 + if (is_ipmb_direct_addr(addr)) { 847 + struct ipmi_ipmb_direct_addr *daddr = (void *) addr; 848 + 849 + if (addr->channel != 0) 850 + return -EINVAL; 851 + if (len < sizeof(struct ipmi_ipmb_direct_addr)) 852 + return -EINVAL; 853 + 854 + if (daddr->slave_addr & 0x01) 855 + return -EINVAL; 856 + if (daddr->rq_lun >= 4) 857 + return -EINVAL; 858 + if (daddr->rs_lun >= 4) 859 + return -EINVAL; 860 + return 0; 861 + } 862 + 862 863 if (is_lan_addr(addr)) { 863 864 if (len < sizeof(struct ipmi_lan_addr)) 864 865 return -EINVAL; ··· 894 861 if ((addr_type == IPMI_IPMB_ADDR_TYPE) 895 862 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) 896 863 return sizeof(struct ipmi_ipmb_addr); 864 + 865 + if (addr_type == IPMI_IPMB_DIRECT_ADDR_TYPE) 866 + return sizeof(struct ipmi_ipmb_direct_addr); 897 867 898 868 if (addr_type == IPMI_LAN_ADDR_TYPE) 899 869 return sizeof(struct ipmi_lan_addr); ··· 2088 2052 return rv; 2089 2053 } 2090 2054 2055 + static int i_ipmi_req_ipmb_direct(struct ipmi_smi *intf, 2056 + struct ipmi_addr *addr, 2057 + long msgid, 2058 + struct kernel_ipmi_msg *msg, 2059 + struct ipmi_smi_msg *smi_msg, 2060 + struct ipmi_recv_msg *recv_msg, 2061 + unsigned char source_lun) 2062 + { 2063 + struct ipmi_ipmb_direct_addr *daddr; 2064 + bool is_cmd = !(recv_msg->msg.netfn & 0x1); 2065 + 2066 + if (!(intf->handlers->flags & IPMI_SMI_CAN_HANDLE_IPMB_DIRECT)) 2067 + return -EAFNOSUPPORT; 2068 + 2069 + /* Responses must have a completion code. */ 2070 + if (!is_cmd && msg->data_len < 1) { 2071 + ipmi_inc_stat(intf, sent_invalid_commands); 2072 + return -EINVAL; 2073 + } 2074 + 2075 + if ((msg->data_len + 4) > IPMI_MAX_MSG_LENGTH) { 2076 + ipmi_inc_stat(intf, sent_invalid_commands); 2077 + return -EMSGSIZE; 2078 + } 2079 + 2080 + daddr = (struct ipmi_ipmb_direct_addr *) addr; 2081 + if (daddr->rq_lun > 3 || daddr->rs_lun > 3) { 2082 + ipmi_inc_stat(intf, sent_invalid_commands); 2083 + return -EINVAL; 2084 + } 2085 + 2086 + smi_msg->type = IPMI_SMI_MSG_TYPE_IPMB_DIRECT; 2087 + smi_msg->msgid = msgid; 2088 + 2089 + if (is_cmd) { 2090 + smi_msg->data[0] = msg->netfn << 2 | daddr->rs_lun; 2091 + smi_msg->data[2] = recv_msg->msgid << 2 | daddr->rq_lun; 2092 + } else { 2093 + smi_msg->data[0] = msg->netfn << 2 | daddr->rq_lun; 2094 + smi_msg->data[2] = recv_msg->msgid << 2 | daddr->rs_lun; 2095 + } 2096 + smi_msg->data[1] = daddr->slave_addr; 2097 + smi_msg->data[3] = msg->cmd; 2098 + 2099 + memcpy(smi_msg->data + 4, msg->data, msg->data_len); 2100 + smi_msg->data_size = msg->data_len + 4; 2101 + 2102 + smi_msg->user_data = recv_msg; 2103 + 2104 + return 0; 2105 + } 2106 + 2091 2107 static int i_ipmi_req_lan(struct ipmi_smi *intf, 2092 2108 struct ipmi_addr *addr, 2093 2109 long msgid, ··· 2329 2241 rv = i_ipmi_req_ipmb(intf, addr, msgid, msg, smi_msg, recv_msg, 2330 2242 source_address, source_lun, 2331 2243 retries, retry_time_ms); 2244 + } else if (is_ipmb_direct_addr(addr)) { 2245 + rv = i_ipmi_req_ipmb_direct(intf, addr, msgid, msg, smi_msg, 2246 + recv_msg, source_lun); 2332 2247 } else if (is_lan_addr(addr)) { 2333 2248 rv = i_ipmi_req_lan(intf, addr, msgid, msg, smi_msg, recv_msg, 2334 2249 source_lun, retries, retry_time_ms); ··· 3893 3802 return rv; 3894 3803 } 3895 3804 3805 + static int handle_ipmb_direct_rcv_cmd(struct ipmi_smi *intf, 3806 + struct ipmi_smi_msg *msg) 3807 + { 3808 + struct cmd_rcvr *rcvr; 3809 + int rv = 0; 3810 + struct ipmi_user *user = NULL; 3811 + struct ipmi_ipmb_direct_addr *daddr; 3812 + struct ipmi_recv_msg *recv_msg; 3813 + unsigned char netfn = msg->rsp[0] >> 2; 3814 + unsigned char cmd = msg->rsp[3]; 3815 + 3816 + rcu_read_lock(); 3817 + /* We always use channel 0 for direct messages. */ 3818 + rcvr = find_cmd_rcvr(intf, netfn, cmd, 0); 3819 + if (rcvr) { 3820 + user = rcvr->user; 3821 + kref_get(&user->refcount); 3822 + } else 3823 + user = NULL; 3824 + rcu_read_unlock(); 3825 + 3826 + if (user == NULL) { 3827 + /* We didn't find a user, deliver an error response. */ 3828 + ipmi_inc_stat(intf, unhandled_commands); 3829 + 3830 + msg->data[0] = ((netfn + 1) << 2) | (msg->rsp[4] & 0x3); 3831 + msg->data[1] = msg->rsp[2]; 3832 + msg->data[2] = msg->rsp[4] & ~0x3; 3833 + msg->data[3] = cmd; 3834 + msg->data[4] = IPMI_INVALID_CMD_COMPLETION_CODE; 3835 + msg->data_size = 5; 3836 + 3837 + rcu_read_lock(); 3838 + if (!intf->in_shutdown) { 3839 + smi_send(intf, intf->handlers, msg, 0); 3840 + /* 3841 + * We used the message, so return the value 3842 + * that causes it to not be freed or 3843 + * queued. 3844 + */ 3845 + rv = -1; 3846 + } 3847 + rcu_read_unlock(); 3848 + } else { 3849 + recv_msg = ipmi_alloc_recv_msg(); 3850 + if (!recv_msg) { 3851 + /* 3852 + * We couldn't allocate memory for the 3853 + * message, so requeue it for handling 3854 + * later. 3855 + */ 3856 + rv = 1; 3857 + kref_put(&user->refcount, free_user); 3858 + } else { 3859 + /* Extract the source address from the data. */ 3860 + daddr = (struct ipmi_ipmb_direct_addr *)&recv_msg->addr; 3861 + daddr->addr_type = IPMI_IPMB_DIRECT_ADDR_TYPE; 3862 + daddr->channel = 0; 3863 + daddr->slave_addr = msg->rsp[1]; 3864 + daddr->rs_lun = msg->rsp[0] & 3; 3865 + daddr->rq_lun = msg->rsp[2] & 3; 3866 + 3867 + /* 3868 + * Extract the rest of the message information 3869 + * from the IPMB header. 3870 + */ 3871 + recv_msg->user = user; 3872 + recv_msg->recv_type = IPMI_CMD_RECV_TYPE; 3873 + recv_msg->msgid = (msg->rsp[2] >> 2); 3874 + recv_msg->msg.netfn = msg->rsp[0] >> 2; 3875 + recv_msg->msg.cmd = msg->rsp[3]; 3876 + recv_msg->msg.data = recv_msg->msg_data; 3877 + 3878 + recv_msg->msg.data_len = msg->rsp_size - 4; 3879 + memcpy(recv_msg->msg_data, msg->rsp + 4, 3880 + msg->rsp_size - 4); 3881 + if (deliver_response(intf, recv_msg)) 3882 + ipmi_inc_stat(intf, unhandled_commands); 3883 + else 3884 + ipmi_inc_stat(intf, handled_commands); 3885 + } 3886 + } 3887 + 3888 + return rv; 3889 + } 3890 + 3891 + static int handle_ipmb_direct_rcv_rsp(struct ipmi_smi *intf, 3892 + struct ipmi_smi_msg *msg) 3893 + { 3894 + struct ipmi_recv_msg *recv_msg; 3895 + struct ipmi_ipmb_direct_addr *daddr; 3896 + 3897 + recv_msg = (struct ipmi_recv_msg *) msg->user_data; 3898 + if (recv_msg == NULL) { 3899 + dev_warn(intf->si_dev, 3900 + "IPMI message received with no owner. This could be because of a malformed message, or because of a hardware error. Contact your hardware vendor for assistance.\n"); 3901 + return 0; 3902 + } 3903 + 3904 + recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; 3905 + recv_msg->msgid = msg->msgid; 3906 + daddr = (struct ipmi_ipmb_direct_addr *) &recv_msg->addr; 3907 + daddr->addr_type = IPMI_IPMB_DIRECT_ADDR_TYPE; 3908 + daddr->channel = 0; 3909 + daddr->slave_addr = msg->rsp[1]; 3910 + daddr->rq_lun = msg->rsp[0] & 3; 3911 + daddr->rs_lun = msg->rsp[2] & 3; 3912 + recv_msg->msg.netfn = msg->rsp[0] >> 2; 3913 + recv_msg->msg.cmd = msg->rsp[3]; 3914 + memcpy(recv_msg->msg_data, &msg->rsp[4], msg->rsp_size - 4); 3915 + recv_msg->msg.data = recv_msg->msg_data; 3916 + recv_msg->msg.data_len = msg->rsp_size - 4; 3917 + deliver_local_response(intf, recv_msg); 3918 + 3919 + return 0; 3920 + } 3921 + 3896 3922 static int handle_lan_get_msg_rsp(struct ipmi_smi *intf, 3897 3923 struct ipmi_smi_msg *msg) 3898 3924 { ··· 4435 4227 static int handle_one_recv_msg(struct ipmi_smi *intf, 4436 4228 struct ipmi_smi_msg *msg) 4437 4229 { 4438 - int requeue; 4230 + int requeue = 0; 4439 4231 int chan; 4232 + unsigned char cc; 4233 + bool is_cmd = !((msg->rsp[0] >> 2) & 1); 4440 4234 4441 4235 pr_debug("Recv: %*ph\n", msg->rsp_size, msg->rsp); 4442 4236 4443 - if ((msg->data_size >= 2) 4237 + if (msg->rsp_size < 2) { 4238 + /* Message is too small to be correct. */ 4239 + dev_warn(intf->si_dev, 4240 + "BMC returned too small a message for netfn %x cmd %x, got %d bytes\n", 4241 + (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size); 4242 + 4243 + return_unspecified: 4244 + /* Generate an error response for the message. */ 4245 + msg->rsp[0] = msg->data[0] | (1 << 2); 4246 + msg->rsp[1] = msg->data[1]; 4247 + msg->rsp[2] = IPMI_ERR_UNSPECIFIED; 4248 + msg->rsp_size = 3; 4249 + } else if (msg->type == IPMI_SMI_MSG_TYPE_IPMB_DIRECT) { 4250 + /* commands must have at least 3 bytes, responses 4. */ 4251 + if (is_cmd && (msg->rsp_size < 3)) { 4252 + ipmi_inc_stat(intf, invalid_commands); 4253 + goto out; 4254 + } 4255 + if (!is_cmd && (msg->rsp_size < 4)) 4256 + goto return_unspecified; 4257 + } else if ((msg->data_size >= 2) 4444 4258 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2)) 4445 4259 && (msg->data[1] == IPMI_SEND_MSG_CMD) 4446 4260 && (msg->user_data == NULL)) { 4447 4261 4448 4262 if (intf->in_shutdown) 4449 - goto free_msg; 4263 + goto out; 4450 4264 4451 4265 /* 4452 4266 * This is the local response to a command send, start ··· 4503 4273 } else 4504 4274 /* The message was sent, start the timer. */ 4505 4275 intf_start_seq_timer(intf, msg->msgid); 4506 - free_msg: 4507 - requeue = 0; 4508 - goto out; 4509 - 4510 - } else if (msg->rsp_size < 2) { 4511 - /* Message is too small to be correct. */ 4512 - dev_warn(intf->si_dev, 4513 - "BMC returned too small a message for netfn %x cmd %x, got %d bytes\n", 4514 - (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size); 4515 - 4516 - /* Generate an error response for the message. */ 4517 - msg->rsp[0] = msg->data[0] | (1 << 2); 4518 - msg->rsp[1] = msg->data[1]; 4519 - msg->rsp[2] = IPMI_ERR_UNSPECIFIED; 4520 - msg->rsp_size = 3; 4521 4276 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1)) 4522 4277 || (msg->rsp[1] != msg->data[1])) { 4523 4278 /* ··· 4514 4299 (msg->data[0] >> 2) | 1, msg->data[1], 4515 4300 msg->rsp[0] >> 2, msg->rsp[1]); 4516 4301 4517 - /* Generate an error response for the message. */ 4518 - msg->rsp[0] = msg->data[0] | (1 << 2); 4519 - msg->rsp[1] = msg->data[1]; 4520 - msg->rsp[2] = IPMI_ERR_UNSPECIFIED; 4521 - msg->rsp_size = 3; 4302 + goto return_unspecified; 4522 4303 } 4523 4304 4524 - if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) 4525 - && (msg->rsp[1] == IPMI_SEND_MSG_CMD) 4526 - && (msg->user_data != NULL)) { 4305 + if (msg->type == IPMI_SMI_MSG_TYPE_IPMB_DIRECT) { 4306 + if ((msg->data[0] >> 2) & 1) { 4307 + /* It's a response to a sent response. */ 4308 + chan = 0; 4309 + cc = msg->rsp[4]; 4310 + goto process_response_response; 4311 + } 4312 + if (is_cmd) 4313 + requeue = handle_ipmb_direct_rcv_cmd(intf, msg); 4314 + else 4315 + requeue = handle_ipmb_direct_rcv_rsp(intf, msg); 4316 + } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) 4317 + && (msg->rsp[1] == IPMI_SEND_MSG_CMD) 4318 + && (msg->user_data != NULL)) { 4527 4319 /* 4528 4320 * It's a response to a response we sent. For this we 4529 4321 * deliver a send message response to the user. 4530 4322 */ 4531 - struct ipmi_recv_msg *recv_msg = msg->user_data; 4532 - 4533 - requeue = 0; 4534 - if (msg->rsp_size < 2) 4535 - /* Message is too small to be correct. */ 4536 - goto out; 4323 + struct ipmi_recv_msg *recv_msg; 4537 4324 4538 4325 chan = msg->data[2] & 0x0f; 4539 4326 if (chan >= IPMI_MAX_CHANNELS) 4540 4327 /* Invalid channel number */ 4541 4328 goto out; 4329 + cc = msg->rsp[2]; 4542 4330 4331 + process_response_response: 4332 + recv_msg = msg->user_data; 4333 + 4334 + requeue = 0; 4543 4335 if (!recv_msg) 4544 4336 goto out; 4545 4337 4546 4338 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE; 4547 4339 recv_msg->msg.data = recv_msg->msg_data; 4340 + recv_msg->msg_data[0] = cc; 4548 4341 recv_msg->msg.data_len = 1; 4549 - recv_msg->msg_data[0] = msg->rsp[2]; 4550 4342 deliver_local_response(intf, recv_msg); 4551 4343 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) 4552 4344 && (msg->rsp[1] == IPMI_GET_MSG_CMD)) {
+59
include/linux/ipmi_smi.h
··· 39 39 #define IPMI_WATCH_MASK_CHECK_COMMANDS (1 << 2) 40 40 41 41 /* 42 + * SMI messages 43 + * 44 + * When communicating with an SMI, messages come in two formats: 45 + * 46 + * * Normal (to a BMC over a BMC interface) 47 + * 48 + * * IPMB (over a IPMB to another MC) 49 + * 50 + * When normal, commands are sent using the format defined by a 51 + * standard message over KCS (NetFn must be even): 52 + * 53 + * +-----------+-----+------+ 54 + * | NetFn/LUN | Cmd | Data | 55 + * +-----------+-----+------+ 56 + * 57 + * And responses, similarly, with an completion code added (NetFn must 58 + * be odd): 59 + * 60 + * +-----------+-----+------+------+ 61 + * | NetFn/LUN | Cmd | CC | Data | 62 + * +-----------+-----+------+------+ 63 + * 64 + * With normal messages, only commands are sent and only responses are 65 + * received. 66 + * 67 + * In IPMB mode, we are acting as an IPMB device. Commands will be in 68 + * the following format (NetFn must be even): 69 + * 70 + * +-------------+------+-------------+-----+------+ 71 + * | NetFn/rsLUN | Addr | rqSeq/rqLUN | Cmd | Data | 72 + * +-------------+------+-------------+-----+------+ 73 + * 74 + * Responses will using the following format: 75 + * 76 + * +-------------+------+-------------+-----+------+------+ 77 + * | NetFn/rqLUN | Addr | rqSeq/rsLUN | Cmd | CC | Data | 78 + * +-------------+------+-------------+-----+------+------+ 79 + * 80 + * This is similar to the format defined in the IPMB manual section 81 + * 2.11.1 with the checksums and the first address removed. Also, the 82 + * address is always the remote address. 83 + * 84 + * IPMB messages can be commands and responses in both directions. 85 + * Received commands are handled as received commands from the message 86 + * queue. 87 + */ 88 + 89 + enum ipmi_smi_msg_type { 90 + IPMI_SMI_MSG_TYPE_NORMAL = 0, 91 + IPMI_SMI_MSG_TYPE_IPMB_DIRECT 92 + }; 93 + 94 + /* 42 95 * Messages to/from the lower layer. The smi interface will take one 43 96 * of these to send. After the send has occurred and a response has 44 97 * been received, it will report this same data structure back up to ··· 106 53 */ 107 54 struct ipmi_smi_msg { 108 55 struct list_head link; 56 + 57 + enum ipmi_smi_msg_type type; 109 58 110 59 long msgid; 111 60 void *user_data; ··· 127 72 128 73 struct ipmi_smi_handlers { 129 74 struct module *owner; 75 + 76 + /* Capabilities of the SMI. */ 77 + #define IPMI_SMI_CAN_HANDLE_IPMB_DIRECT (1 << 0) 78 + unsigned int flags; 130 79 131 80 /* 132 81 * The low-level interface cannot start sending messages to
+14
include/uapi/linux/ipmi.h
··· 81 81 }; 82 82 83 83 /* 84 + * Used for messages received directly from an IPMB that have not gone 85 + * through a MC. This is for systems that sit right on an IPMB so 86 + * they can receive commands and respond to them. 87 + */ 88 + #define IPMI_IPMB_DIRECT_ADDR_TYPE 0x81 89 + struct ipmi_ipmb_direct_addr { 90 + int addr_type; 91 + short channel; 92 + unsigned char slave_addr; 93 + unsigned char rs_lun; 94 + unsigned char rq_lun; 95 + }; 96 + 97 + /* 84 98 * A LAN Address. This is an address to/from a LAN interface bridged 85 99 * by the BMC, not an address actually out on the LAN. 86 100 *