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: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/392374
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Dariusz Stojaczyk 2017-12-19 09:48:51 +01:00 committed by Ben Walker
parent 31177e645c
commit 91a1d8ae93

View File

@ -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) {