static void ssif_loop(void *arg) { struct ipmi_softc *sc = arg; struct ipmi_request *req; int i, ok; IPMI_LOCK(sc); while ((req = ipmi_dequeue_request(sc)) != NULL) { IPMI_UNLOCK(sc); ok = 0; for (i = 0; i < 5; i++) { ok = ssif_polled_request(sc, req); if (ok) break; /* Wait 60 ms between retries. */ pause("retry", 60 * hz / 1000); #ifdef SSIF_RETRY_DEBUG device_printf(sc->ipmi_dev, "SSIF: Retrying request (%d)\n", i + 1); #endif } if (ok) req->ir_error = 0; else req->ir_error = EIO; IPMI_LOCK(sc); ipmi_complete_request(sc, req); IPMI_UNLOCK(sc); /* Enforce 10ms between requests. */ pause("delay", hz / 100); IPMI_LOCK(sc); } IPMI_UNLOCK(sc); kproc_exit(0); }
static void smic_loop(void *arg) { struct ipmi_softc *sc = arg; struct ipmi_request *req; int i, ok; IPMI_LOCK(sc); while ((req = ipmi_dequeue_request(sc)) != NULL) { IPMI_UNLOCK(sc); ok = 0; for (i = 0; i < 3 && !ok; i++) ok = smic_polled_request(sc, req); if (ok) req->ir_error = 0; else req->ir_error = EIO; IPMI_LOCK(sc); ipmi_complete_request(sc, req); } IPMI_UNLOCK(sc); kproc_exit(0); }
static int ssif_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, int timo) { int error; IPMI_LOCK(sc); error = ipmi_polled_enqueue_request(sc, req); if (error == 0) error = msleep(req, &sc->ipmi_requests_lock, 0, "ipmireq", timo); if (error == 0) error = req->ir_error; IPMI_UNLOCK(sc); return (error); }
/* * Enqueue an internal driver request and wait until it is completed. */ static int ipmi_submit_driver_request(struct ipmi_softc *sc, struct ipmi_request **preq, int timo) { int error; struct ipmi_request *req = *preq; ASSERT(req->ir_owner == NULL); IPMI_LOCK(sc); error = sc->ipmi_enqueue_request(sc, req); if (error != 0) { IPMI_UNLOCK(sc); return (error); } while (req->ir_status != IRS_COMPLETED && error >= 0) if (timo == 0) cv_wait(&req->ir_cv, &sc->ipmi_lock); else error = cv_timedwait(&req->ir_cv, &sc->ipmi_lock, ddi_get_lbolt() + timo); switch (req->ir_status) { case IRS_QUEUED: TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link); req->ir_status = IRS_CANCELED; error = EWOULDBLOCK; break; case IRS_PROCESSED: req->ir_status = IRS_CANCELED; error = EWOULDBLOCK; *preq = NULL; break; case IRS_COMPLETED: error = req->ir_error; break; default: panic("IPMI: Invalid request status"); break; } IPMI_UNLOCK(sc); return (error); }
static void ipmi_cleanup(dev_info_t *dip) { /* poke the taskq so that it can terminate */ IPMI_LOCK(sc); sc->ipmi_detaching = 1; cv_signal(&sc->ipmi_request_added); IPMI_UNLOCK(sc); ipmi_shutdown(sc); ddi_remove_minor_node(dip, NULL); ipmi_dip = NULL; list_destroy(&dev_list); id_space_destroy(minor_ids); sc->ipmi_detaching = 0; }
/*ARGSUSED*/ static int ipmi_close(dev_t dev, int flag, int otyp, cred_t *cred) { ipmi_device_t *dp; struct ipmi_request *req, *next; if ((dp = lookup_ipmidev_by_dev(dev)) == NULL) return (ENODEV); IPMI_LOCK(sc); /* remove any pending requests */ req = TAILQ_FIRST(&sc->ipmi_pending_requests); while (req != NULL) { next = TAILQ_NEXT(req, ir_link); if (req->ir_owner == dp) { TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link); ipmi_free_request(req); } req = next; } dp->ipmi_status |= IPMI_CLOSING; while (dp->ipmi_status & IPMI_BUSY) cv_wait(&dp->ipmi_cv, &sc->ipmi_lock); IPMI_UNLOCK(sc); /* remove any requests in queue of stuff completed */ while ((req = TAILQ_FIRST(&dp->ipmi_completed_requests)) != NULL) { TAILQ_REMOVE(&dp->ipmi_completed_requests, req, ir_link); ipmi_free_request(req); } list_remove(&dev_list, dp); id_free(minor_ids, getminor(dev)); cv_destroy(&dp->ipmi_cv); kmem_free(dp->ipmi_pollhead, sizeof (pollhead_t)); kmem_free(dp, sizeof (ipmi_device_t)); return (0); }
/*ARGSUSED*/ static int ipmi_ioctl(dev_t dv, int cmd, intptr_t data, int flags, cred_t *cr, int *rvalp) { struct ipmi_device *dev; struct ipmi_request *kreq; struct ipmi_req req; struct ipmi_recv recv; struct ipmi_recv32 recv32; struct ipmi_addr addr; int error, len; model_t model; int orig_cmd = 0; uchar_t t_lun; if (secpolicy_sys_config(cr, B_FALSE) != 0) return (EPERM); if ((dev = lookup_ipmidev_by_dev(dv)) == NULL) return (ENODEV); model = get_udatamodel(); if (model == DATAMODEL_NATIVE) { switch (cmd) { case IPMICTL_SEND_COMMAND: if (copyin((void *)data, &req, sizeof (req))) return (EFAULT); break; case IPMICTL_RECEIVE_MSG_TRUNC: case IPMICTL_RECEIVE_MSG: if (copyin((void *)data, &recv, sizeof (recv))) return (EFAULT); break; } } else { /* Convert 32-bit structures to native. */ struct ipmi_req32 req32; switch (cmd) { case IPMICTL_SEND_COMMAND_32: if (copyin((void *)data, &req32, sizeof (req32))) return (EFAULT); req.addr = PTRIN(req32.addr); req.addr_len = req32.addr_len; req.msgid = req32.msgid; req.msg.netfn = req32.msg.netfn; req.msg.cmd = req32.msg.cmd; req.msg.data_len = req32.msg.data_len; req.msg.data = PTRIN(req32.msg.data); cmd = IPMICTL_SEND_COMMAND; break; case IPMICTL_RECEIVE_MSG_TRUNC_32: case IPMICTL_RECEIVE_MSG_32: if (copyin((void *)data, &recv32, sizeof (recv32))) return (EFAULT); recv.addr = PTRIN(recv32.addr); recv.addr_len = recv32.addr_len; recv.msg.data_len = recv32.msg.data_len; recv.msg.data = PTRIN(recv32.msg.data); orig_cmd = cmd; cmd = (cmd == IPMICTL_RECEIVE_MSG_TRUNC_32) ? IPMICTL_RECEIVE_MSG_TRUNC : IPMICTL_RECEIVE_MSG; break; } } switch (cmd) { case IPMICTL_SEND_COMMAND: IPMI_LOCK(sc); /* clear out old stuff in queue of stuff done */ while ((kreq = TAILQ_FIRST(&dev->ipmi_completed_requests)) != NULL) { TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, ir_link); dev->ipmi_requests--; ipmi_free_request(kreq); } IPMI_UNLOCK(sc); /* Check that we didn't get a ridiculous length */ if (req.msg.data_len > IPMI_MAX_RX) return (EINVAL); kreq = ipmi_alloc_request(dev, req.msgid, IPMI_ADDR(req.msg.netfn, 0), req.msg.cmd, req.msg.data_len, IPMI_MAX_RX); /* This struct is the same for 32/64 */ if (req.msg.data_len > 0 && copyin(req.msg.data, kreq->ir_request, req.msg.data_len)) { ipmi_free_request(kreq); return (EFAULT); } IPMI_LOCK(sc); dev->ipmi_requests++; error = sc->ipmi_enqueue_request(sc, kreq); IPMI_UNLOCK(sc); if (error) return (error); break; case IPMICTL_RECEIVE_MSG_TRUNC: case IPMICTL_RECEIVE_MSG: /* This struct is the same for 32/64 */ if (copyin(recv.addr, &addr, sizeof (addr))) return (EFAULT); IPMI_LOCK(sc); kreq = TAILQ_FIRST(&dev->ipmi_completed_requests); if (kreq == NULL) { IPMI_UNLOCK(sc); return (EAGAIN); } addr.channel = IPMI_BMC_CHANNEL; 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) { TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, ir_link); dev->ipmi_requests--; IPMI_UNLOCK(sc); ipmi_free_request(kreq); return (error); } len = kreq->ir_replylen + 1; if (recv.msg.data_len < len && cmd == IPMICTL_RECEIVE_MSG) { IPMI_UNLOCK(sc); ipmi_free_request(kreq); return (EMSGSIZE); } TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, ir_link); dev->ipmi_requests--; IPMI_UNLOCK(sc); len = min(recv.msg.data_len, len); recv.msg.data_len = (unsigned short)len; if (orig_cmd == IPMICTL_RECEIVE_MSG_TRUNC_32 || orig_cmd == IPMICTL_RECEIVE_MSG_32) { /* Update changed fields in 32-bit structure. */ recv32.recv_type = recv.recv_type; recv32.msgid = (int32_t)recv.msgid; recv32.msg.netfn = recv.msg.netfn; recv32.msg.cmd = recv.msg.cmd; recv32.msg.data_len = recv.msg.data_len; error = copyout(&recv32, (void *)data, sizeof (recv32)); } else { error = copyout(&recv, (void *)data, sizeof (recv)); } /* This struct is the same for 32/64 */ if (error == 0) error = copyout(&addr, recv.addr, sizeof (addr)); if (error == 0) error = copyout(&kreq->ir_compcode, recv.msg.data, 1); if (error == 0) error = copyout(kreq->ir_reply, recv.msg.data + 1, len - 1); ipmi_free_request(kreq); if (error) return (EFAULT); break; case IPMICTL_SET_MY_ADDRESS_CMD: IPMI_LOCK(sc); if (copyin((void *)data, &dev->ipmi_address, sizeof (dev->ipmi_address))) { IPMI_UNLOCK(sc); return (EFAULT); } IPMI_UNLOCK(sc); break; case IPMICTL_GET_MY_ADDRESS_CMD: IPMI_LOCK(sc); if (copyout(&dev->ipmi_address, (void *)data, sizeof (dev->ipmi_address))) { IPMI_UNLOCK(sc); return (EFAULT); } IPMI_UNLOCK(sc); break; case IPMICTL_SET_MY_LUN_CMD: IPMI_LOCK(sc); if (copyin((void *)data, &t_lun, sizeof (t_lun))) { IPMI_UNLOCK(sc); return (EFAULT); } dev->ipmi_lun = t_lun & 0x3; IPMI_UNLOCK(sc); break; case IPMICTL_GET_MY_LUN_CMD: IPMI_LOCK(sc); if (copyout(&dev->ipmi_lun, (void *)data, sizeof (dev->ipmi_lun))) { IPMI_UNLOCK(sc); return (EFAULT); } IPMI_UNLOCK(sc); break; case IPMICTL_SET_GETS_EVENTS_CMD: break; case IPMICTL_REGISTER_FOR_CMD: case IPMICTL_UNREGISTER_FOR_CMD: return (EINVAL); default: return (EINVAL); } return (0); }