Example #1
0
static void
vmbus_heartbeat_cb(struct vmbus_channel *chan, void *xsc)
{
	struct hv_util_sc *sc = xsc;
	struct vmbus_icmsg_hdr *hdr;
	int dlen, error;
	uint64_t xactid;
	void *data;

	/*
	 * Receive request.
	 */
	data = sc->receive_buffer;
	dlen = sc->ic_buflen;
	error = vmbus_chan_recv(chan, data, &dlen, &xactid);
	KASSERT(error != ENOBUFS, ("icbuf is not large enough"));
	if (error)
		return;

	if (dlen < sizeof(*hdr)) {
		device_printf(sc->ic_dev, "invalid data len %d\n", dlen);
		return;
	}
	hdr = data;

	/*
	 * Update request, which will be echoed back as response.
	 */
	switch (hdr->ic_type) {
	case VMBUS_ICMSG_TYPE_NEGOTIATE:
		error = vmbus_ic_negomsg(sc, data, &dlen);
		if (error)
			return;
		break;

	case VMBUS_ICMSG_TYPE_HEARTBEAT:
		/* Only ic_seq is a must */
		if (dlen < VMBUS_ICMSG_HEARTBEAT_SIZE_MIN) {
			device_printf(sc->ic_dev, "invalid heartbeat len %d\n",
			    dlen);
			return;
		}
		((struct vmbus_icmsg_heartbeat *)data)->ic_seq++;
		break;

	default:
		device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type);
		break;
	}

	/*
	 * Send response by echoing the updated request back.
	 */
	hdr->ic_flags = VMBUS_ICMSG_FLAG_XACT | VMBUS_ICMSG_FLAG_RESP;
	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND, 0,
	    data, dlen, xactid);
	if (error)
		device_printf(sc->ic_dev, "resp send failed: %d\n", error);
}
Example #2
0
/**
 * Time Sync Channel message handler
 */
static void
hv_timesync_cb(struct vmbus_channel *channel, void *context)
{
	hv_vmbus_icmsg_hdr*	icmsghdrp;
	uint32_t		recvlen;
	uint64_t		requestId;
	int			ret;
	uint8_t*		time_buf;
	struct hv_ictimesync_data* timedatap;
	hv_timesync_sc		*softc;

	softc = (hv_timesync_sc*)context;
	time_buf = softc->util_sc.receive_buffer;

	recvlen = PAGE_SIZE;
	ret = vmbus_chan_recv(channel, time_buf, &recvlen, &requestId);
	KASSERT(ret != ENOBUFS, ("hvtimesync recvbuf is not large enough"));
	/* XXX check recvlen to make sure that it contains enough data */

	if ((ret == 0) && recvlen > 0) {
	    icmsghdrp = (struct hv_vmbus_icmsg_hdr *) &time_buf[
		sizeof(struct hv_vmbus_pipe_hdr)];

	    if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
		hv_negotiate_version(icmsghdrp, NULL, time_buf);
	    } else {
		timedatap = (struct hv_ictimesync_data *) &time_buf[
		    sizeof(struct hv_vmbus_pipe_hdr) +
			sizeof(struct hv_vmbus_icmsg_hdr)];
		hv_adj_guesttime(softc, timedatap->parenttime, timedatap->flags);
	    }

	    icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION
		| HV_ICMSGHDRFLAG_RESPONSE;

	    vmbus_chan_send(channel, VMBUS_CHANPKT_TYPE_INBAND, 0,
	        time_buf, recvlen, requestId);
	}
}
Example #3
0
/**
 * Shutdown
 */
static void
hv_shutdown_cb(struct vmbus_channel *channel, void *context)
{
	uint8_t*			buf;
	uint8_t				execute_shutdown = 0;
	hv_vmbus_icmsg_hdr*		icmsghdrp;
	uint32_t			recv_len;
	uint64_t			request_id;
	int				ret;
	hv_vmbus_shutdown_msg_data*	shutdown_msg;
	hv_util_sc			*softc;

	softc = (hv_util_sc*)context;
	buf = softc->receive_buffer;

	recv_len = softc->ic_buflen;
	ret = vmbus_chan_recv(channel, buf, &recv_len, &request_id);
	KASSERT(ret != ENOBUFS, ("hvshutdown recvbuf is not large enough"));
	/* XXX check recv_len to make sure that it contains enough data */

	if ((ret == 0) && recv_len > 0) {

	    icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
		&buf[sizeof(struct hv_vmbus_pipe_hdr)];

	    if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
		hv_negotiate_version(icmsghdrp, buf);
	    } else {
		shutdown_msg =
		    (struct hv_vmbus_shutdown_msg_data *)
		    &buf[sizeof(struct hv_vmbus_pipe_hdr) +
			sizeof(struct hv_vmbus_icmsg_hdr)];

		switch (shutdown_msg->flags) {
		    case 0:
		    case 1:
			icmsghdrp->status = HV_S_OK;
			execute_shutdown = 1;
			if(bootverbose)
			    printf("Shutdown request received -"
				    " graceful shutdown initiated\n");
			break;
		    default:
			icmsghdrp->status = HV_E_FAIL;
			execute_shutdown = 0;
			printf("Shutdown request received -"
			    " Invalid request\n");
			break;
		    }
	    }

	icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION |
				 HV_ICMSGHDRFLAG_RESPONSE;

	    vmbus_chan_send(channel, VMBUS_CHANPKT_TYPE_INBAND, 0,
	        buf, recv_len, request_id);
	}

	if (execute_shutdown)
	    shutdown_nice(RB_POWEROFF);
}
Example #4
0
static void
vmbus_timesync_cb(struct vmbus_channel *chan, void *xsc)
{
	struct hv_util_sc *sc = xsc;
	struct vmbus_icmsg_hdr *hdr;
	const struct vmbus_icmsg_timesync *msg;
	int dlen, error;
	uint64_t xactid;
	void *data;

	/*
	 * Receive request.
	 */
	data = sc->receive_buffer;
	dlen = sc->ic_buflen;
	error = vmbus_chan_recv(chan, data, &dlen, &xactid);
	KASSERT(error != ENOBUFS, ("icbuf is not large enough"));
	if (error)
		return;

	if (dlen < sizeof(*hdr)) {
		device_printf(sc->ic_dev, "invalid data len %d\n", dlen);
		return;
	}
	hdr = data;

	/*
	 * Update request, which will be echoed back as response.
	 */
	switch (hdr->ic_type) {
	case VMBUS_ICMSG_TYPE_NEGOTIATE:
		error = vmbus_ic_negomsg(sc, data, &dlen,
		    VMBUS_TIMESYNC_FWVER, VMBUS_TIMESYNC_MSGVER);
		if (error)
			return;
		break;

	case VMBUS_ICMSG_TYPE_TIMESYNC:
		if (dlen < sizeof(*msg)) {
			device_printf(sc->ic_dev, "invalid timesync len %d\n",
			    dlen);
			return;
		}
		msg = data;
		vmbus_timesync(sc, msg->ic_hvtime, msg->ic_tsflags);
		break;

	default:
		device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type);
		break;
	}

	/*
	 * Send response by echoing the updated request back.
	 */
	hdr->ic_flags = VMBUS_ICMSG_FLAG_XACT | VMBUS_ICMSG_FLAG_RESP;
	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND, 0,
	    data, dlen, xactid);
	if (error)
		device_printf(sc->ic_dev, "resp send failed: %d\n", error);
}
Example #5
0
static void
vmbus_timesync_cb(struct vmbus_channel *chan, void *xsc)
{
	struct vmbus_ic_softc *sc = xsc;
	struct vmbus_icmsg_hdr *hdr;
	int dlen, error;
	uint64_t xactid;
	void *data;

	/*
	 * Receive request.
	 */
	data = sc->ic_buf;
	dlen = sc->ic_buflen;
	error = vmbus_chan_recv(chan, data, &dlen, &xactid);
	KASSERT(error != ENOBUFS, ("icbuf is not large enough"));
	if (error)
		return;

	if (dlen < sizeof(*hdr)) {
		device_printf(sc->ic_dev, "invalid data len %d\n", dlen);
		return;
	}
	hdr = data;

	/*
	 * Update request, which will be echoed back as response.
	 */
	switch (hdr->ic_type) {
	case VMBUS_ICMSG_TYPE_NEGOTIATE:
		error = vmbus_ic_negomsg(sc, data, &dlen,
		    VMBUS_TIMESYNC_FWVER, VMBUS_TIMESYNC_MSGVER);
		if (error)
			return;
		if (VMBUS_TIMESYNC_DORTT(sc))
			device_printf(sc->ic_dev, "RTT\n");
		break;

	case VMBUS_ICMSG_TYPE_TIMESYNC:
		if (VMBUS_TIMESYNC_MSGVER4(sc)) {
			const struct vmbus_icmsg_timesync4 *msg4;

			if (dlen < sizeof(*msg4)) {
				device_printf(sc->ic_dev, "invalid timesync4 "
				    "len %d\n", dlen);
				return;
			}
			msg4 = data;
			vmbus_timesync(sc, msg4->ic_hvtime, msg4->ic_sent_tc,
			    msg4->ic_tsflags);
		} else {
			const struct vmbus_icmsg_timesync *msg;

			if (dlen < sizeof(*msg)) {
				device_printf(sc->ic_dev, "invalid timesync "
				    "len %d\n", dlen);
				return;
			}
			msg = data;
			vmbus_timesync(sc, msg->ic_hvtime, 0, msg->ic_tsflags);
		}
		break;

	default:
		device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type);
		break;
	}

	/*
	 * Send response by echoing the request back.
	 */
	vmbus_ic_sendresp(sc, chan, data, dlen, xactid);
}
Example #6
0
/*
 * Function to read the kvp request buffer from host
 * and interact with daemon
 */
static void
hv_kvp_process_request(void *context, int pending)
{
	uint8_t *kvp_buf;
	struct vmbus_channel *channel;
	uint32_t recvlen = 0;
	uint64_t requestid;
	struct hv_vmbus_icmsg_hdr *icmsghdrp;
	int ret = 0, error;
	hv_kvp_sc *sc;

	hv_kvp_log_info("%s: entering hv_kvp_process_request\n", __func__);

	sc = (hv_kvp_sc*)context;
	kvp_buf = sc->util_sc.ic_buf;
	channel = vmbus_get_channel(sc->dev);

	recvlen = sc->util_sc.ic_buflen;
	ret = vmbus_chan_recv(channel, kvp_buf, &recvlen, &requestid);
	KASSERT(ret != ENOBUFS, ("hvkvp recvbuf is not large enough"));
	/* XXX check recvlen to make sure that it contains enough data */

	while ((ret == 0) && (recvlen > 0)) {
		icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
		    &kvp_buf[sizeof(struct hv_vmbus_pipe_hdr)];

		hv_kvp_transaction_init(sc, recvlen, requestid, kvp_buf);
		if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
			error = vmbus_ic_negomsg(&sc->util_sc,
			    kvp_buf, &recvlen, KVP_FWVER, KVP_MSGVER);
			/* XXX handle vmbus_ic_negomsg failure. */
			if (!error)
				hv_kvp_respond_host(sc, HV_S_OK);
			else
				hv_kvp_respond_host(sc, HV_E_FAIL);
			/*
			 * It is ok to not acquire the mutex before setting
			 * req_in_progress here because negotiation is the
			 * first thing that happens and hence there is no
			 * chance of a race condition.
			 */

			sc->req_in_progress = false;
			hv_kvp_log_info("%s :version negotiated\n", __func__);

		} else {
			if (!sc->daemon_busy) {

				hv_kvp_log_info("%s: issuing qury to daemon\n", __func__);
				mtx_lock(&sc->pending_mutex);
				sc->req_timed_out = false;
				sc->daemon_busy = true;
				mtx_unlock(&sc->pending_mutex);

				hv_kvp_send_msg_to_daemon(sc);
				hv_kvp_log_info("%s: waiting for daemon\n", __func__);
			}

			/* Wait 5 seconds for daemon to respond back */
			tsleep(sc, 0, "kvpworkitem", 5 * hz);
			hv_kvp_log_info("%s: came out of wait\n", __func__);
		}

		mtx_lock(&sc->pending_mutex);

		/* Notice that once req_timed_out is set to true
		 * it will remain true until the next request is
		 * sent to the daemon. The response from daemon
		 * is forwarded to host only when this flag is
		 * false.
		 */
		sc->req_timed_out = true;

		/*
		 * Cancel request if so need be.
		 */
		if (hv_kvp_req_in_progress(sc)) {
			hv_kvp_log_info("%s: request was still active after wait so failing\n", __func__);
			hv_kvp_respond_host(sc, HV_E_FAIL);
			sc->req_in_progress = false;
		}

		mtx_unlock(&sc->pending_mutex);

		/*
		 * Try reading next buffer
		 */
		recvlen = sc->util_sc.ic_buflen;
		ret = vmbus_chan_recv(channel, kvp_buf, &recvlen, &requestid);
		KASSERT(ret != ENOBUFS, ("hvkvp recvbuf is not large enough"));
		/* XXX check recvlen to make sure that it contains enough data */

		hv_kvp_log_info("%s: read: context %p, ret =%d, recvlen=%d\n",
			__func__, context, ret, recvlen);
	}
}