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,83 +239,16 @@ 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 @@ 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_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 @@ * 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 @@ -128,10 +131,6 @@ #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 @@ 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_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 --- 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