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:
parent
31177e645c
commit
91a1d8ae93
@ -115,6 +115,7 @@ struct virtio_scsi_scan_info {
|
|||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
uint8_t target;
|
uint8_t target;
|
||||||
bool unmap_supported;
|
bool unmap_supported;
|
||||||
|
TAILQ_ENTRY(virtio_scsi_scan_info) tailq;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct virtio_scsi_scan_base {
|
struct virtio_scsi_scan_base {
|
||||||
@ -126,6 +127,12 @@ struct virtio_scsi_scan_base {
|
|||||||
bdev_virtio_create_cb cb_fn;
|
bdev_virtio_create_cb cb_fn;
|
||||||
void *cb_arg;
|
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. */
|
/** Remaining attempts for sending the current request. */
|
||||||
unsigned retries;
|
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 send_scan_io(struct virtio_scsi_scan_base *base);
|
||||||
static int _virtio_scsi_dev_scan_next(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 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
|
static int
|
||||||
bdev_virtio_get_ctx_size(void)
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ev->event == VIRTIO_SCSI_T_TRANSPORT_RESET &&
|
if (ev->event == VIRTIO_SCSI_T_TRANSPORT_RESET) {
|
||||||
ev->reason == VIRTIO_SCSI_EVT_RESET_REMOVED) {
|
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]);
|
disk = virtio_scsi_dev_get_disk_by_id(svdev, ev->lun[1]);
|
||||||
if (disk != NULL) {
|
if (disk != NULL) {
|
||||||
spdk_bdev_unregister(&disk->bdev, NULL, NULL);
|
spdk_bdev_unregister(&disk->bdev, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -894,10 +910,16 @@ _virtio_scsi_dev_scan_finish(struct virtio_scsi_scan_base *base, int errnum)
|
|||||||
size_t bdevs_cnt;
|
size_t bdevs_cnt;
|
||||||
struct spdk_bdev *bdevs[BDEV_VIRTIO_MAX_TARGET];
|
struct spdk_bdev *bdevs[BDEV_VIRTIO_MAX_TARGET];
|
||||||
struct virtio_scsi_disk *disk;
|
struct virtio_scsi_disk *disk;
|
||||||
|
struct virtio_scsi_scan_info *tgt, *next_tgt;
|
||||||
|
|
||||||
spdk_put_io_channel(spdk_io_channel_from_ctx(base->channel));
|
spdk_put_io_channel(spdk_io_channel_from_ctx(base->channel));
|
||||||
base->svdev->scan_ctx = NULL;
|
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) {
|
if (base->cb_fn == NULL) {
|
||||||
spdk_dma_free(base);
|
spdk_dma_free(base);
|
||||||
return;
|
return;
|
||||||
@ -1337,16 +1359,31 @@ process_scan_resp(struct virtio_scsi_scan_base *base)
|
|||||||
static int
|
static int
|
||||||
_virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base)
|
_virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base)
|
||||||
{
|
{
|
||||||
|
struct virtio_scsi_scan_info *next;
|
||||||
uint8_t target_id;
|
uint8_t target_id;
|
||||||
|
|
||||||
|
if (base->full_scan) {
|
||||||
target_id = base->info.target + 1;
|
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);
|
_virtio_scsi_dev_scan_finish(base, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&base->scan_queue, next, tailq);
|
||||||
memset(&base->info, 0, sizeof(base->info));
|
memset(&base->info, 0, sizeof(base->info));
|
||||||
base->info.target = target_id;
|
base->info.target = next->target;
|
||||||
|
free(next);
|
||||||
|
|
||||||
return send_inquiry(base);
|
return send_inquiry(base);
|
||||||
}
|
}
|
||||||
@ -1418,15 +1455,13 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virtio_scsi_dev_scan(struct virtio_scsi_dev *svdev, bdev_virtio_create_cb cb_fn,
|
_virtio_scsi_dev_scan_init(struct virtio_scsi_dev *svdev)
|
||||||
void *cb_arg)
|
|
||||||
{
|
{
|
||||||
struct virtio_scsi_scan_base *base;
|
struct virtio_scsi_scan_base *base;
|
||||||
struct spdk_io_channel *io_ch;
|
struct spdk_io_channel *io_ch;
|
||||||
struct virtio_scsi_io_ctx *io_ctx;
|
struct virtio_scsi_io_ctx *io_ctx;
|
||||||
struct virtio_scsi_cmd_req *req;
|
struct virtio_scsi_cmd_req *req;
|
||||||
struct virtio_scsi_cmd_resp *resp;
|
struct virtio_scsi_cmd_resp *resp;
|
||||||
int rc;
|
|
||||||
|
|
||||||
io_ch = spdk_get_io_channel(svdev);
|
io_ch = spdk_get_io_channel(svdev);
|
||||||
if (io_ch == NULL) {
|
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;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
base->cb_fn = cb_fn;
|
|
||||||
base->cb_arg = cb_arg;
|
|
||||||
|
|
||||||
base->svdev = svdev;
|
base->svdev = svdev;
|
||||||
|
|
||||||
base->channel = spdk_io_channel_get_ctx(io_ch);
|
base->channel = spdk_io_channel_get_ctx(io_ch);
|
||||||
|
TAILQ_INIT(&base->scan_queue);
|
||||||
svdev->scan_ctx = base;
|
svdev->scan_ctx = base;
|
||||||
|
|
||||||
memset(&base->info, 0, sizeof(base->info));
|
memset(&base->info, 0, sizeof(base->info));
|
||||||
base->info.target = 0;
|
|
||||||
|
|
||||||
base->iov.iov_base = base->payload;
|
base->iov.iov_base = base->payload;
|
||||||
io_ctx = &base->io_ctx;
|
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);
|
io_ctx->iov_resp.iov_len = sizeof(*resp);
|
||||||
|
|
||||||
base->retries = SCAN_REQUEST_RETRIES;
|
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);
|
rc = send_inquiry(base);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
Loading…
Reference in New Issue
Block a user