Example #1
0
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);
}
Example #2
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);
}
Example #3
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);
}
Example #4
0
/*
 * 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);
}
Example #5
0
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;
}
Example #6
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);
}
Example #7
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);
}