return addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE;
 }
 
+static int is_ipmb_direct_addr(struct ipmi_addr *addr)
+{
+       return addr->addr_type == IPMI_IPMB_DIRECT_ADDR_TYPE;
+}
+
 static void free_recv_msg_list(struct list_head *q)
 {
        struct ipmi_recv_msg *msg, *msg2;
                        && (ipmb_addr1->lun == ipmb_addr2->lun));
        }
 
+       if (is_ipmb_direct_addr(addr1)) {
+               struct ipmi_ipmb_direct_addr *daddr1
+                       = (struct ipmi_ipmb_direct_addr *) addr1;
+               struct ipmi_ipmb_direct_addr *daddr2
+                       = (struct ipmi_ipmb_direct_addr *) addr2;
+
+               return daddr1->slave_addr == daddr2->slave_addr &&
+                       daddr1->rq_lun == daddr2->rq_lun &&
+                       daddr1->rs_lun == daddr2->rs_lun;
+       }
+
        if (is_lan_addr(addr1)) {
                struct ipmi_lan_addr *lan_addr1
                        = (struct ipmi_lan_addr *) addr1;
                return 0;
        }
 
+       if (is_ipmb_direct_addr(addr)) {
+               struct ipmi_ipmb_direct_addr *daddr = (void *) addr;
+
+               if (addr->channel != 0)
+                       return -EINVAL;
+               if (len < sizeof(struct ipmi_ipmb_direct_addr))
+                       return -EINVAL;
+
+               if (daddr->slave_addr & 0x01)
+                       return -EINVAL;
+               if (daddr->rq_lun >= 4)
+                       return -EINVAL;
+               if (daddr->rs_lun >= 4)
+                       return -EINVAL;
+               return 0;
+       }
+
        if (is_lan_addr(addr)) {
                if (len < sizeof(struct ipmi_lan_addr))
                        return -EINVAL;
                        || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
                return sizeof(struct ipmi_ipmb_addr);
 
+       if (addr_type == IPMI_IPMB_DIRECT_ADDR_TYPE)
+               return sizeof(struct ipmi_ipmb_direct_addr);
+
        if (addr_type == IPMI_LAN_ADDR_TYPE)
                return sizeof(struct ipmi_lan_addr);
 
        return rv;
 }
 
+static int i_ipmi_req_ipmb_direct(struct ipmi_smi        *intf,
+                                 struct ipmi_addr       *addr,
+                                 long                   msgid,
+                                 struct kernel_ipmi_msg *msg,
+                                 struct ipmi_smi_msg    *smi_msg,
+                                 struct ipmi_recv_msg   *recv_msg,
+                                 unsigned char          source_lun)
+{
+       struct ipmi_ipmb_direct_addr *daddr;
+       bool is_cmd = !(recv_msg->msg.netfn & 0x1);
+
+       if (!(intf->handlers->flags & IPMI_SMI_CAN_HANDLE_IPMB_DIRECT))
+               return -EAFNOSUPPORT;
+
+       /* Responses must have a completion code. */
+       if (!is_cmd && msg->data_len < 1) {
+               ipmi_inc_stat(intf, sent_invalid_commands);
+               return -EINVAL;
+       }
+
+       if ((msg->data_len + 4) > IPMI_MAX_MSG_LENGTH) {
+               ipmi_inc_stat(intf, sent_invalid_commands);
+               return -EMSGSIZE;
+       }
+
+       daddr = (struct ipmi_ipmb_direct_addr *) addr;
+       if (daddr->rq_lun > 3 || daddr->rs_lun > 3) {
+               ipmi_inc_stat(intf, sent_invalid_commands);
+               return -EINVAL;
+       }
+
+       smi_msg->type = IPMI_SMI_MSG_TYPE_IPMB_DIRECT;
+       smi_msg->msgid = msgid;
+
+       if (is_cmd) {
+               smi_msg->data[0] = msg->netfn << 2 | daddr->rs_lun;
+               smi_msg->data[2] = recv_msg->msgid << 2 | daddr->rq_lun;
+       } else {
+               smi_msg->data[0] = msg->netfn << 2 | daddr->rq_lun;
+               smi_msg->data[2] = recv_msg->msgid << 2 | daddr->rs_lun;
+       }
+       smi_msg->data[1] = daddr->slave_addr;
+       smi_msg->data[3] = msg->cmd;
+
+       memcpy(smi_msg->data + 4, msg->data, msg->data_len);
+       smi_msg->data_size = msg->data_len + 4;
+
+       smi_msg->user_data = recv_msg;
+
+       return 0;
+}
+
 static int i_ipmi_req_lan(struct ipmi_smi        *intf,
                          struct ipmi_addr       *addr,
                          long                   msgid,
                rv = i_ipmi_req_ipmb(intf, addr, msgid, msg, smi_msg, recv_msg,
                                     source_address, source_lun,
                                     retries, retry_time_ms);
+       } else if (is_ipmb_direct_addr(addr)) {
+               rv = i_ipmi_req_ipmb_direct(intf, addr, msgid, msg, smi_msg,
+                                           recv_msg, source_lun);
        } else if (is_lan_addr(addr)) {
                rv = i_ipmi_req_lan(intf, addr, msgid, msg, smi_msg, recv_msg,
                                    source_lun, retries, retry_time_ms);
        return rv;
 }
 
+static int handle_ipmb_direct_rcv_cmd(struct ipmi_smi *intf,
+                                     struct ipmi_smi_msg *msg)
+{
+       struct cmd_rcvr          *rcvr;
+       int                      rv = 0;
+       struct ipmi_user         *user = NULL;
+       struct ipmi_ipmb_direct_addr *daddr;
+       struct ipmi_recv_msg     *recv_msg;
+       unsigned char netfn = msg->rsp[0] >> 2;
+       unsigned char cmd = msg->rsp[3];
+
+       rcu_read_lock();
+       /* We always use channel 0 for direct messages. */
+       rcvr = find_cmd_rcvr(intf, netfn, cmd, 0);
+       if (rcvr) {
+               user = rcvr->user;
+               kref_get(&user->refcount);
+       } else
+               user = NULL;
+       rcu_read_unlock();
+
+       if (user == NULL) {
+               /* We didn't find a user, deliver an error response. */
+               ipmi_inc_stat(intf, unhandled_commands);
+
+               msg->data[0] = ((netfn + 1) << 2) | (msg->rsp[4] & 0x3);
+               msg->data[1] = msg->rsp[2];
+               msg->data[2] = msg->rsp[4] & ~0x3;
+               msg->data[3] = cmd;
+               msg->data[4] = IPMI_INVALID_CMD_COMPLETION_CODE;
+               msg->data_size = 5;
+
+               rcu_read_lock();
+               if (!intf->in_shutdown) {
+                       smi_send(intf, intf->handlers, msg, 0);
+                       /*
+                        * We used the message, so return the value
+                        * that causes it to not be freed or
+                        * queued.
+                        */
+                       rv = -1;
+               }
+               rcu_read_unlock();
+       } else {
+               recv_msg = ipmi_alloc_recv_msg();
+               if (!recv_msg) {
+                       /*
+                        * We couldn't allocate memory for the
+                        * message, so requeue it for handling
+                        * later.
+                        */
+                       rv = 1;
+                       kref_put(&user->refcount, free_user);
+               } else {
+                       /* Extract the source address from the data. */
+                       daddr = (struct ipmi_ipmb_direct_addr *)&recv_msg->addr;
+                       daddr->addr_type = IPMI_IPMB_DIRECT_ADDR_TYPE;
+                       daddr->channel = 0;
+                       daddr->slave_addr = msg->rsp[1];
+                       daddr->rs_lun = msg->rsp[0] & 3;
+                       daddr->rq_lun = msg->rsp[2] & 3;
+
+                       /*
+                        * Extract the rest of the message information
+                        * from the IPMB header.
+                        */
+                       recv_msg->user = user;
+                       recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
+                       recv_msg->msgid = (msg->rsp[2] >> 2);
+                       recv_msg->msg.netfn = msg->rsp[0] >> 2;
+                       recv_msg->msg.cmd = msg->rsp[3];
+                       recv_msg->msg.data = recv_msg->msg_data;
+
+                       recv_msg->msg.data_len = msg->rsp_size - 4;
+                       memcpy(recv_msg->msg_data, msg->rsp + 4,
+                              msg->rsp_size - 4);
+                       if (deliver_response(intf, recv_msg))
+                               ipmi_inc_stat(intf, unhandled_commands);
+                       else
+                               ipmi_inc_stat(intf, handled_commands);
+               }
+       }
+
+       return rv;
+}
+
+static int handle_ipmb_direct_rcv_rsp(struct ipmi_smi *intf,
+                                     struct ipmi_smi_msg *msg)
+{
+       struct ipmi_recv_msg *recv_msg;
+       struct ipmi_ipmb_direct_addr *daddr;
+
+       recv_msg = (struct ipmi_recv_msg *) msg->user_data;
+       if (recv_msg == NULL) {
+               dev_warn(intf->si_dev,
+                        "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");
+               return 0;
+       }
+
+       recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+       recv_msg->msgid = msg->msgid;
+       daddr = (struct ipmi_ipmb_direct_addr *) &recv_msg->addr;
+       daddr->addr_type = IPMI_IPMB_DIRECT_ADDR_TYPE;
+       daddr->channel = 0;
+       daddr->slave_addr = msg->rsp[1];
+       daddr->rq_lun = msg->rsp[0] & 3;
+       daddr->rs_lun = msg->rsp[2] & 3;
+       recv_msg->msg.netfn = msg->rsp[0] >> 2;
+       recv_msg->msg.cmd = msg->rsp[3];
+       memcpy(recv_msg->msg_data, &msg->rsp[4], msg->rsp_size - 4);
+       recv_msg->msg.data = recv_msg->msg_data;
+       recv_msg->msg.data_len = msg->rsp_size - 4;
+       deliver_local_response(intf, recv_msg);
+
+       return 0;
+}
+
 static int handle_lan_get_msg_rsp(struct ipmi_smi *intf,
                                  struct ipmi_smi_msg *msg)
 {
 static int handle_one_recv_msg(struct ipmi_smi *intf,
                               struct ipmi_smi_msg *msg)
 {
-       int requeue;
+       int requeue = 0;
        int chan;
+       unsigned char cc;
+       bool is_cmd = !((msg->rsp[0] >> 2) & 1);
 
        pr_debug("Recv: %*ph\n", msg->rsp_size, msg->rsp);
 
-       if ((msg->data_size >= 2)
+       if (msg->rsp_size < 2) {
+               /* Message is too small to be correct. */
+               dev_warn(intf->si_dev,
+                        "BMC returned too small a message for netfn %x cmd %x, got %d bytes\n",
+                        (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
+
+return_unspecified:
+               /* Generate an error response for the message. */
+               msg->rsp[0] = msg->data[0] | (1 << 2);
+               msg->rsp[1] = msg->data[1];
+               msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
+               msg->rsp_size = 3;
+       } else if (msg->type == IPMI_SMI_MSG_TYPE_IPMB_DIRECT) {
+               /* commands must have at least 3 bytes, responses 4. */
+               if (is_cmd && (msg->rsp_size < 3)) {
+                       ipmi_inc_stat(intf, invalid_commands);
+                       goto out;
+               }
+               if (!is_cmd && (msg->rsp_size < 4))
+                       goto return_unspecified;
+       } else if ((msg->data_size >= 2)
            && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
            && (msg->data[1] == IPMI_SEND_MSG_CMD)
            && (msg->user_data == NULL)) {
 
                if (intf->in_shutdown)
-                       goto free_msg;
+                       goto out;
 
                /*
                 * This is the local response to a command send, start
                } else
                        /* The message was sent, start the timer. */
                        intf_start_seq_timer(intf, msg->msgid);
-free_msg:
-               requeue = 0;
-               goto out;
-
-       } else if (msg->rsp_size < 2) {
-               /* Message is too small to be correct. */
-               dev_warn(intf->si_dev,
-                        "BMC returned too small a message for netfn %x cmd %x, got %d bytes\n",
-                        (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
-
-               /* Generate an error response for the message. */
-               msg->rsp[0] = msg->data[0] | (1 << 2);
-               msg->rsp[1] = msg->data[1];
-               msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
-               msg->rsp_size = 3;
        } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))
                   || (msg->rsp[1] != msg->data[1])) {
                /*
                         (msg->data[0] >> 2) | 1, msg->data[1],
                         msg->rsp[0] >> 2, msg->rsp[1]);
 
-               /* Generate an error response for the message. */
-               msg->rsp[0] = msg->data[0] | (1 << 2);
-               msg->rsp[1] = msg->data[1];
-               msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
-               msg->rsp_size = 3;
+               goto return_unspecified;
        }
 
-       if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
-           && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
-           && (msg->user_data != NULL)) {
+       if (msg->type == IPMI_SMI_MSG_TYPE_IPMB_DIRECT) {
+               if ((msg->data[0] >> 2) & 1) {
+                       /* It's a response to a sent response. */
+                       chan = 0;
+                       cc = msg->rsp[4];
+                       goto process_response_response;
+               }
+               if (is_cmd)
+                       requeue = handle_ipmb_direct_rcv_cmd(intf, msg);
+               else
+                       requeue = handle_ipmb_direct_rcv_rsp(intf, msg);
+       } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
+                  && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
+                  && (msg->user_data != NULL)) {
                /*
                 * It's a response to a response we sent.  For this we
                 * deliver a send message response to the user.
                 */
-               struct ipmi_recv_msg *recv_msg = msg->user_data;
-
-               requeue = 0;
-               if (msg->rsp_size < 2)
-                       /* Message is too small to be correct. */
-                       goto out;
+               struct ipmi_recv_msg *recv_msg;
 
                chan = msg->data[2] & 0x0f;
                if (chan >= IPMI_MAX_CHANNELS)
                        /* Invalid channel number */
                        goto out;
+               cc = msg->rsp[2];
 
+process_response_response:
+               recv_msg = msg->user_data;
+
+               requeue = 0;
                if (!recv_msg)
                        goto out;
 
                recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
                recv_msg->msg.data = recv_msg->msg_data;
+               recv_msg->msg_data[0] = cc;
                recv_msg->msg.data_len = 1;
-               recv_msg->msg_data[0] = msg->rsp[2];
                deliver_local_response(intf, recv_msg);
        } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
                   && (msg->rsp[1] == IPMI_GET_MSG_CMD)) {