Commit 91a1d8ae authored by Dariusz Stojaczyk's avatar Dariusz Stojaczyk Committed by Ben Walker
Browse files

bdev/virtio: add target hot-attach support



Implemented eventq rescan message.
When the host hot-attaches a target
to the controller, it will now
automatically appear as a virtio bdev.

Change-Id: Ie81352b70808a0e078009f618cc1fcfed407d1ba
Signed-off-by: default avatarDariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/392374


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
parent 31177e64
Loading
Loading
Loading
Loading
+104 −15
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ struct virtio_scsi_scan_info {
	uint32_t			block_size;
	uint8_t				target;
	bool				unmap_supported;
	TAILQ_ENTRY(virtio_scsi_scan_info) tailq;
};

struct virtio_scsi_scan_base {
@@ -126,6 +127,12 @@ struct virtio_scsi_scan_base {
	bdev_virtio_create_cb		cb_fn;
	void				*cb_arg;

	/** Scan all targets on the device. */
	bool				full_scan;

	/** Additional targets to be (re)scanned. */
	TAILQ_HEAD(, virtio_scsi_scan_info) scan_queue;

	/** Remaining attempts for sending the current request. */
	unsigned                        retries;

@@ -356,6 +363,7 @@ virtio_scsi_dev_get_disk_by_id(struct virtio_scsi_dev *svdev, uint8_t target_id)
static int send_scan_io(struct virtio_scsi_scan_base *base);
static int _virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base);
static void _virtio_scsi_dev_scan_finish(struct virtio_scsi_scan_base *base, int errnum);
static int virtio_scsi_dev_scan_tgt(struct virtio_scsi_dev *svdev, uint8_t target);

static int
bdev_virtio_get_ctx_size(void)
@@ -758,12 +766,20 @@ bdev_virtio_eventq_io_cpl(struct virtio_scsi_dev *svdev, struct virtio_scsi_even
		goto out;
	}

	if (ev->event == VIRTIO_SCSI_T_TRANSPORT_RESET &&
	    ev->reason == VIRTIO_SCSI_EVT_RESET_REMOVED) {
	if (ev->event == VIRTIO_SCSI_T_TRANSPORT_RESET) {
		switch (ev->reason) {
		case VIRTIO_SCSI_EVT_RESET_RESCAN:
			virtio_scsi_dev_scan_tgt(svdev, ev->lun[1]);
			break;
		case VIRTIO_SCSI_EVT_RESET_REMOVED:
			disk = virtio_scsi_dev_get_disk_by_id(svdev, ev->lun[1]);
			if (disk != NULL) {
				spdk_bdev_unregister(&disk->bdev, NULL, NULL);
			}
			break;
		default:
			break;
		}
	}

out:
@@ -894,10 +910,16 @@ _virtio_scsi_dev_scan_finish(struct virtio_scsi_scan_base *base, int errnum)
	size_t bdevs_cnt;
	struct spdk_bdev *bdevs[BDEV_VIRTIO_MAX_TARGET];
	struct virtio_scsi_disk *disk;
	struct virtio_scsi_scan_info *tgt, *next_tgt;

	spdk_put_io_channel(spdk_io_channel_from_ctx(base->channel));
	base->svdev->scan_ctx = NULL;

	TAILQ_FOREACH_SAFE(tgt, &base->scan_queue, tailq, next_tgt) {
		TAILQ_REMOVE(&base->scan_queue, tgt, tailq);
		free(tgt);
	}

	if (base->cb_fn == NULL) {
		spdk_dma_free(base);
		return;
@@ -1337,16 +1359,31 @@ process_scan_resp(struct virtio_scsi_scan_base *base)
static int
_virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base)
{
	struct virtio_scsi_scan_info *next;
	uint8_t target_id;

	if (base->full_scan) {
		target_id = base->info.target + 1;
	if (target_id == BDEV_VIRTIO_MAX_TARGET) {
		if (target_id < BDEV_VIRTIO_MAX_TARGET) {
			memset(&base->info, 0, sizeof(base->info));
			base->info.target = target_id;

			return send_inquiry(base);
		}

		base->full_scan = false;
	}

	next = TAILQ_FIRST(&base->scan_queue);
	if (next == NULL) {
		_virtio_scsi_dev_scan_finish(base, 0);
		return 0;
	}

	TAILQ_REMOVE(&base->scan_queue, next, tailq);
	memset(&base->info, 0, sizeof(base->info));
	base->info.target = target_id;
	base->info.target = next->target;
	free(next);

	return send_inquiry(base);
}
@@ -1418,15 +1455,13 @@ out:
}

static int
virtio_scsi_dev_scan(struct virtio_scsi_dev *svdev, bdev_virtio_create_cb cb_fn,
		     void *cb_arg)
_virtio_scsi_dev_scan_init(struct virtio_scsi_dev *svdev)
{
	struct virtio_scsi_scan_base *base;
	struct spdk_io_channel *io_ch;
	struct virtio_scsi_io_ctx *io_ctx;
	struct virtio_scsi_cmd_req *req;
	struct virtio_scsi_cmd_resp *resp;
	int rc;

	io_ch = spdk_get_io_channel(svdev);
	if (io_ch == NULL) {
@@ -1439,16 +1474,13 @@ virtio_scsi_dev_scan(struct virtio_scsi_dev *svdev, bdev_virtio_create_cb cb_fn,
		return -ENOMEM;
	}

	base->cb_fn = cb_fn;
	base->cb_arg = cb_arg;

	base->svdev = svdev;

	base->channel = spdk_io_channel_get_ctx(io_ch);
	TAILQ_INIT(&base->scan_queue);
	svdev->scan_ctx = base;

	memset(&base->info, 0, sizeof(base->info));
	base->info.target = 0;

	base->iov.iov_base = base->payload;
	io_ctx = &base->io_ctx;
@@ -1460,6 +1492,63 @@ virtio_scsi_dev_scan(struct virtio_scsi_dev *svdev, bdev_virtio_create_cb cb_fn,
	io_ctx->iov_resp.iov_len = sizeof(*resp);

	base->retries = SCAN_REQUEST_RETRIES;
	return 0;
}

static int
virtio_scsi_dev_scan(struct virtio_scsi_dev *svdev, bdev_virtio_create_cb cb_fn,
		     void *cb_arg)
{
	struct virtio_scsi_scan_base *base;
	int rc;

	rc = _virtio_scsi_dev_scan_init(svdev);
	if (rc != 0) {
		return rc;
	}

	base = svdev->scan_ctx;
	base->cb_fn = cb_fn;
	base->cb_arg = cb_arg;
	base->full_scan = true;
	base->info.target = 0;

	rc = send_inquiry(base);
	if (rc) {
		/* Let response poller do the resend */
	}

	return 0;
}

static int
virtio_scsi_dev_scan_tgt(struct virtio_scsi_dev *svdev, uint8_t target)
{
	struct virtio_scsi_scan_base *base;
	struct virtio_scsi_scan_info *info;
	int rc;

	base = svdev->scan_ctx;
	if (base) {
		info = calloc(1, sizeof(*info));
		if (info == NULL) {
			SPDK_ERRLOG("calloc failed\n");
			return -ENOMEM;
		}

		info->target = target;
		TAILQ_INSERT_TAIL(&base->scan_queue, info, tailq);
		return 0;
	}

	rc = _virtio_scsi_dev_scan_init(svdev);
	if (rc != 0) {
		return rc;
	}

	base = svdev->scan_ctx;
	base->full_scan = true;
	base->info.target = target;

	rc = send_inquiry(base);
	if (rc) {