The branch main has been updated by philip:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=18db96dbfd4a09063a0abcefd51fa8d2aeb115d6

commit 18db96dbfd4a09063a0abcefd51fa8d2aeb115d6
Author:     Yuri <[email protected]>
AuthorDate: 2022-07-04 04:55:18 +0000
Commit:     Philip Paeps <[email protected]>
CommitDate: 2022-07-04 05:00:42 +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
    MFC after:      1 week
    Differential Revision: https://reviews.freebsd.org/D35605
---
 sys/dev/ipmi/ipmi.c     | 185 ++++++++++++++++++++----------------------------
 sys/dev/ipmi/ipmivars.h |  13 ++--
 sys/sys/ipmi.h          |   4 +-
 3 files changed, 85 insertions(+), 117 deletions(-)

diff --git a/sys/dev/ipmi/ipmi.c b/sys/dev/ipmi/ipmi.c
index c4fb804987c0..775734d3e1aa 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,26 +384,38 @@ 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) {
                        TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq,
                            ir_link);
                        dev->ipmi_requests--;
                        IPMI_UNLOCK(sc);
                        ipmi_free_request(kreq);
-                       return (error);
+                       return (kreq->ir_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 +490,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 a7ab23336ff5..b0548ee3d7c3 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 int ipmi_attached;
 
 #endif /* !__IPMIVARS_H__ */
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

Reply via email to