Date: Mon, 11 Jul 2022 03:15:19 GMT From: Philip Paeps <philip@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: 1549a6172f9d - stable/13 - ipmi: correctly handle ipmb requests Message-ID: <202207110315.26B3FJEF046225@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by philip: URL: https://cgit.FreeBSD.org/src/commit/?id=1549a6172f9d2957e023398d01a675912683afb9 commit 1549a6172f9d2957e023398d01a675912683afb9 Author: Yuri <yuri@aetern.org> AuthorDate: 2022-07-04 04:55:18 +0000 Commit: Philip Paeps <philip@FreeBSD.org> CommitDate: 2022-07-11 03:10:05 +0000 ipmi: correctly handle ipmb requests Handle IPMB requests using SEND_MSG (sent as driver request as we do not need to return anything back to userland for this) and GET_MSG (sent as usual request so we can return the data for RECEIVE_MSG ioctl) pair. This fixes fetching complete sensor data from boards (e.g. HP ProLiant DL380 Gen10). Reviewed by: philip Differential Revision: https://reviews.freebsd.org/D35605 (cherry picked from commit 18db96dbfd4a09063a0abcefd51fa8d2aeb115d6) (cherry picked from commit c4995b69db93fdab5fe375eae129aeff1cbca1bb) --- sys/dev/ipmi/ipmi.c | 184 ++++++++++++++++++++---------------------------- sys/dev/ipmi/ipmivars.h | 13 ++-- sys/sys/ipmi.h | 4 +- 3 files changed, 85 insertions(+), 116 deletions(-) diff --git a/sys/dev/ipmi/ipmi.c b/sys/dev/ipmi/ipmi.c index 3a9fb80fc208..3666b8dd2033 100644 --- a/sys/dev/ipmi/ipmi.c +++ b/sys/dev/ipmi/ipmi.c @@ -76,12 +76,6 @@ __FBSDID("$FreeBSD$"); IPMI_INIT_DRIVER_REQUEST((req), (addr), (cmd), (reqlen), \ (replylen)) -#ifdef IPMB -static int ipmi_ipmb_checksum(u_char, int); -static int ipmi_ipmb_send_message(device_t, u_char, u_char, u_char, - u_char, u_char, int) -#endif - static d_ioctl_t ipmi_ioctl; static d_poll_t ipmi_poll; static d_open_t ipmi_open; @@ -245,83 +239,16 @@ ipmi_dtor(void *arg) free(dev, M_IPMI); } -#ifdef IPMB -static int +static u_char ipmi_ipmb_checksum(u_char *data, int len) { u_char sum = 0; - for (; len; len--) { + for (; len; len--) sum += *data++; - } return (-sum); } -/* XXX: Needs work */ -static int -ipmi_ipmb_send_message(device_t dev, u_char channel, u_char netfn, - u_char command, u_char seq, u_char *data, int data_len) -{ - struct ipmi_softc *sc = device_get_softc(dev); - struct ipmi_request *req; - u_char slave_addr = 0x52; - int error; - - IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), - IPMI_SEND_MSG, data_len + 8, 0); - req->ir_request[0] = channel; - req->ir_request[1] = slave_addr; - req->ir_request[2] = IPMI_ADDR(netfn, 0); - req->ir_request[3] = ipmi_ipmb_checksum(&req->ir_request[1], 2); - req->ir_request[4] = sc->ipmi_address; - req->ir_request[5] = IPMI_ADDR(seq, sc->ipmi_lun); - req->ir_request[6] = command; - - bcopy(data, &req->ir_request[7], data_len); - temp[data_len + 7] = ipmi_ipmb_checksum(&req->ir_request[4], - data_len + 3); - - ipmi_submit_driver_request(sc, req); - error = req->ir_error; - - return (error); -} - -static int -ipmi_handle_attn(struct ipmi_softc *sc) -{ - struct ipmi_request *req; - int error; - - device_printf(sc->ipmi_dev, "BMC has a message\n"); - IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), - IPMI_GET_MSG_FLAGS, 0, 1); - - ipmi_submit_driver_request(sc, req); - - if (req->ir_error == 0 && req->ir_compcode == 0) { - if (req->ir_reply[0] & IPMI_MSG_BUFFER_FULL) { - device_printf(sc->ipmi_dev, "message buffer full"); - } - if (req->ir_reply[0] & IPMI_WDT_PRE_TIMEOUT) { - device_printf(sc->ipmi_dev, - "watchdog about to go off"); - } - if (req->ir_reply[0] & IPMI_MSG_AVAILABLE) { - IPMI_ALLOC_DRIVER_REQUEST(req, - IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_GET_MSG, 0, - 16); - - device_printf(sc->ipmi_dev, "throw out message "); - dump_buf(temp, 16); - } - } - error = req->ir_error; - - return (error); -} -#endif - static int ipmi_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int flags, struct thread *td) @@ -377,38 +304,68 @@ ipmi_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, case IPMICTL_SEND_COMMAND_32: #endif case IPMICTL_SEND_COMMAND: - /* - * XXX: Need to add proper handling of this. - */ error = copyin(req->addr, &addr, sizeof(addr)); if (error) return (error); - IPMI_LOCK(sc); - /* clear out old stuff in queue of stuff done */ - /* XXX: This seems odd. */ - while ((kreq = TAILQ_FIRST(&dev->ipmi_completed_requests))) { - TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, - ir_link); - dev->ipmi_requests--; - ipmi_free_request(kreq); + if (addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { + kreq = ipmi_alloc_request(dev, req->msgid, + IPMI_ADDR(req->msg.netfn, 0), req->msg.cmd, + req->msg.data_len, IPMI_MAX_RX); + error = copyin(req->msg.data, kreq->ir_request, + req->msg.data_len); + if (error) { + ipmi_free_request(kreq); + return (error); + } + IPMI_LOCK(sc); + dev->ipmi_requests++; + error = sc->ipmi_enqueue_request(sc, kreq); + IPMI_UNLOCK(sc); + if (error) + return (error); + break; } - IPMI_UNLOCK(sc); - kreq = ipmi_alloc_request(dev, req->msgid, - IPMI_ADDR(req->msg.netfn, 0), req->msg.cmd, - req->msg.data_len, IPMI_MAX_RX); - error = copyin(req->msg.data, kreq->ir_request, - req->msg.data_len); - if (error) { - ipmi_free_request(kreq); - return (error); + /* Special processing for IPMB commands */ + struct ipmi_ipmb_addr *iaddr = (struct ipmi_ipmb_addr *)&addr; + + IPMI_ALLOC_DRIVER_REQUEST(kreq, IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_SEND_MSG, req->msg.data_len + 8, IPMI_MAX_RX); + /* Construct the SEND MSG header */ + kreq->ir_request[0] = iaddr->channel; + kreq->ir_request[1] = iaddr->slave_addr; + kreq->ir_request[2] = IPMI_ADDR(req->msg.netfn, iaddr->lun); + kreq->ir_request[3] = + ipmi_ipmb_checksum(&kreq->ir_request[1], 2); + kreq->ir_request[4] = dev->ipmi_address; + kreq->ir_request[5] = IPMI_ADDR(0, dev->ipmi_lun); + kreq->ir_request[6] = req->msg.cmd; + /* Copy the message data */ + if (req->msg.data_len > 0) { + error = copyin(req->msg.data, &kreq->ir_request[7], + req->msg.data_len); + if (error != 0) + return (error); } + kreq->ir_request[req->msg.data_len + 7] = + ipmi_ipmb_checksum(&kreq->ir_request[4], + req->msg.data_len + 3); + error = ipmi_submit_driver_request(sc, kreq, MAX_TIMEOUT); + if (error != 0) + return (error); + + kreq = ipmi_alloc_request(dev, req->msgid, + IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_GET_MSG, + 0, IPMI_MAX_RX); + kreq->ir_ipmb = true; + kreq->ir_ipmb_addr = IPMI_ADDR(req->msg.netfn, 0); + kreq->ir_ipmb_command = req->msg.cmd; IPMI_LOCK(sc); dev->ipmi_requests++; error = sc->ipmi_enqueue_request(sc, kreq); IPMI_UNLOCK(sc); - if (error) + if (error != 0) return (error); break; #ifdef IPMICTL_SEND_COMMAND_32 @@ -427,14 +384,8 @@ ipmi_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, IPMI_UNLOCK(sc); return (EAGAIN); } - addr.channel = IPMI_BMC_CHANNEL; - /* XXX */ - recv->recv_type = IPMI_RESPONSE_RECV_TYPE; - recv->msgid = kreq->ir_msgid; - recv->msg.netfn = IPMI_REPLY_ADDR(kreq->ir_addr) >> 2; - recv->msg.cmd = kreq->ir_command; - error = kreq->ir_error; - if (error) { + if (kreq->ir_error != 0) { + error = kreq->ir_error; TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, ir_link); dev->ipmi_requests--; @@ -442,11 +393,30 @@ ipmi_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, ipmi_free_request(kreq); return (error); } - len = kreq->ir_replylen + 1; + + recv->recv_type = IPMI_RESPONSE_RECV_TYPE; + recv->msgid = kreq->ir_msgid; + if (kreq->ir_ipmb) { + addr.channel = IPMI_IPMB_CHANNEL; + recv->msg.netfn = + IPMI_REPLY_ADDR(kreq->ir_ipmb_addr) >> 2; + recv->msg.cmd = kreq->ir_ipmb_command; + /* Get the compcode of response */ + kreq->ir_compcode = kreq->ir_reply[6]; + /* Move the reply head past response header */ + kreq->ir_reply += 7; + len = kreq->ir_replylen - 7; + } else { + addr.channel = IPMI_BMC_CHANNEL; + recv->msg.netfn = IPMI_REPLY_ADDR(kreq->ir_addr) >> 2; + recv->msg.cmd = kreq->ir_command; + len = kreq->ir_replylen + 1; + } + if (recv->msg.data_len < len && (cmd == IPMICTL_RECEIVE_MSG #ifdef IPMICTL_RECEIVE_MSG_32 - || cmd == IPMICTL_RECEIVE_MSG_32 + || cmd == IPMICTL_RECEIVE_MSG_32 #endif )) { IPMI_UNLOCK(sc); @@ -521,7 +491,7 @@ ipmi_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, * Request management. */ -static __inline void +__inline void ipmi_init_request(struct ipmi_request *req, struct ipmi_device *dev, long msgid, uint8_t addr, uint8_t command, size_t requestlen, size_t replylen) { diff --git a/sys/dev/ipmi/ipmivars.h b/sys/dev/ipmi/ipmivars.h index 7a1346655983..8c6a716adb9c 100644 --- a/sys/dev/ipmi/ipmivars.h +++ b/sys/dev/ipmi/ipmivars.h @@ -54,6 +54,9 @@ struct ipmi_request { uint8_t ir_addr; uint8_t ir_command; uint8_t ir_compcode; + bool ir_ipmb; + uint8_t ir_ipmb_addr; + uint8_t ir_ipmb_command; }; #define MAX_RES 3 @@ -128,10 +131,6 @@ struct ipmi_softc { #define ipmi_ssif_smbus_address _iface.ssif.smbus_address #define ipmi_ssif_smbus _iface.ssif.smbus -struct ipmi_ipmb { - u_char foo; -}; - #define KCS_MODE 0x01 #define SMIC_MODE 0x02 #define BT_MODE 0x03 @@ -230,6 +229,8 @@ int ipmi_detach(device_t); void ipmi_release_resources(device_t); /* Manage requests. */ +void ipmi_init_request(struct ipmi_request *, struct ipmi_device *, long, + uint8_t, uint8_t, size_t, size_t); struct ipmi_request *ipmi_alloc_request(struct ipmi_device *, long, uint8_t, uint8_t, size_t, size_t); void ipmi_complete_request(struct ipmi_softc *, struct ipmi_request *); @@ -251,10 +252,6 @@ int ipmi_kcs_probe_align(struct ipmi_softc *); int ipmi_smic_attach(struct ipmi_softc *); int ipmi_ssif_attach(struct ipmi_softc *, device_t, int); -#ifdef IPMB -int ipmi_handle_attn(struct ipmi_softc *); -#endif - extern devclass_t ipmi_devclass; extern int ipmi_attached; diff --git a/sys/sys/ipmi.h b/sys/sys/ipmi.h index 3c805bac099d..9b46d1869101 100644 --- a/sys/sys/ipmi.h +++ b/sys/sys/ipmi.h @@ -33,9 +33,11 @@ #define IPMI_MAX_ADDR_SIZE 0x20 #define IPMI_MAX_RX 1024 -#define IPMI_BMC_SLAVE_ADDR 0x20 /* Linux Default slave address */ + #define IPMI_BMC_CHANNEL 0x0f /* Linux BMC channel */ +#define IPMI_IPMB_CHANNEL 0x00 +#define IPMI_BMC_SLAVE_ADDR 0x20 /* Linux Default slave address */ #define IPMI_BMC_SMS_LUN 0x02 #define IPMI_SYSTEM_INTERFACE_ADDR_TYPE 0x0c
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202207110315.26B3FJEF046225>