diff --git a/sys/dev/ipmi/ipmi.c b/sys/dev/ipmi/ipmi.c
--- a/sys/dev/ipmi/ipmi.c
+++ b/sys/dev/ipmi/ipmi.c
@@ -76,12 +76,6 @@
 	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,48 +239,7 @@
 	free(dev, M_IPMI);
 }
 
-#ifdef IPMB
-static int
-ipmi_ipmb_checksum(u_char *data, int len)
-{
-	u_char sum = 0;
-
-	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);
-}
-
+#if 0
 static int
 ipmi_handle_attn(struct ipmi_softc *sc)
 {
@@ -322,6 +275,16 @@
 }
 #endif
 
+static u_char
+ipmi_ipmb_checksum(u_char *data, int len)
+{
+	u_char sum = 0;
+
+	for (; len; len--)
+		sum += *data++;
+	return (-sum);
+}
+
 static int
 ipmi_ioctl(struct cdev *cdev, u_long cmd, caddr_t data,
     int flags, struct thread *td)
@@ -377,38 +340,68 @@
 	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 +420,38 @@
 			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 +526,7 @@
  * 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
--- a/sys/dev/ipmi/ipmivars.h
+++ b/sys/dev/ipmi/ipmivars.h
@@ -54,6 +54,9 @@
 	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
@@ -230,6 +233,8 @@
 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 *);
diff --git a/sys/sys/ipmi.h b/sys/sys/ipmi.h
--- 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