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 @@ -208,6 +208,15 @@ IPMI_LOCK(sc); if (dev->ipmi_requests) { /* Throw away any pending requests for this device. */ + TAILQ_FOREACH_SAFE(req, &sc->ipmi_pending_requests_highpri, ir_link, + nreq) { + if (req->ir_owner == dev) { + TAILQ_REMOVE(&sc->ipmi_pending_requests_highpri, req, + ir_link); + dev->ipmi_requests--; + ipmi_free_request(req); + } + } TAILQ_FOREACH_SAFE(req, &sc->ipmi_pending_requests, ir_link, nreq) { if (req->ir_owner == dev) { @@ -579,13 +588,19 @@ IPMI_LOCK_ASSERT(sc); - while (!sc->ipmi_detaching && TAILQ_EMPTY(&sc->ipmi_pending_requests)) + while (!sc->ipmi_detaching && TAILQ_EMPTY(&sc->ipmi_pending_requests) && + TAILQ_EMPTY(&sc->ipmi_pending_requests_highpri)) cv_wait(&sc->ipmi_request_added, &sc->ipmi_requests_lock); if (sc->ipmi_detaching) return (NULL); - req = TAILQ_FIRST(&sc->ipmi_pending_requests); - TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link); + req = TAILQ_FIRST(&sc->ipmi_pending_requests_highpri); + if (req != NULL) + TAILQ_REMOVE(&sc->ipmi_pending_requests_highpri, req, ir_link); + else { + req = TAILQ_FIRST(&sc->ipmi_pending_requests); + TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link); + } return (req); } @@ -601,6 +616,17 @@ return (0); } +int +ipmi_polled_enqueue_request_highpri(struct ipmi_softc *sc, struct ipmi_request *req) +{ + + IPMI_LOCK_ASSERT(sc); + + TAILQ_INSERT_TAIL(&sc->ipmi_pending_requests_highpri, req, ir_link); + cv_signal(&sc->ipmi_request_added); + return (0); +} + /* * Watchdog event handler. */ @@ -817,6 +843,7 @@ mtx_init(&sc->ipmi_requests_lock, "ipmi requests", NULL, MTX_DEF); mtx_init(&sc->ipmi_io_lock, "ipmi io", NULL, MTX_DEF); cv_init(&sc->ipmi_request_added, "ipmireq"); + TAILQ_INIT(&sc->ipmi_pending_requests_highpri); TAILQ_INIT(&sc->ipmi_pending_requests); /* Initialize interface-dependent state. */ diff --git a/sys/dev/ipmi/ipmi_kcs.c b/sys/dev/ipmi/ipmi_kcs.c --- a/sys/dev/ipmi/ipmi_kcs.c +++ b/sys/dev/ipmi/ipmi_kcs.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -490,7 +491,21 @@ } static int -kcs_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, int timo) +kcs_driver_request_queue(struct ipmi_softc *sc, struct ipmi_request *req, int timo) +{ + int error; + + IPMI_LOCK(sc); + ipmi_polled_enqueue_request_highpri(sc, req); + error = msleep(req, &sc->ipmi_requests_lock, 0, "ipmireq", timo); + if (error == 0) + error = req->ir_error; + IPMI_UNLOCK(sc); + return (error); +} + +static int +kcs_driver_request_poll(struct ipmi_softc *sc, struct ipmi_request *req) { int i, ok; @@ -504,6 +519,17 @@ return (req->ir_error); } +static int +kcs_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, int timo) +{ + + if (KERNEL_PANICKED() || dumping) + return (kcs_driver_request_poll(sc, req)); + else + return (kcs_driver_request_queue(sc, req, timo)); +} + + int ipmi_kcs_attach(struct ipmi_softc *sc) { 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 @@ -111,6 +111,7 @@ uint8_t ipmi_dev_support; /* IPMI_ADS_* */ struct cdev *ipmi_cdev; TAILQ_HEAD(,ipmi_request) ipmi_pending_requests; + TAILQ_HEAD(,ipmi_request) ipmi_pending_requests_highpri; int ipmi_driver_requests_polled; eventhandler_tag ipmi_power_cycle_tag; eventhandler_tag ipmi_watchdog_tag; @@ -237,6 +238,7 @@ struct ipmi_request *ipmi_dequeue_request(struct ipmi_softc *); void ipmi_free_request(struct ipmi_request *); int ipmi_polled_enqueue_request(struct ipmi_softc *, struct ipmi_request *); +int ipmi_polled_enqueue_request_highpri(struct ipmi_softc *, struct ipmi_request *); int ipmi_submit_driver_request(struct ipmi_softc *, struct ipmi_request *, int);