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;
|
||||
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,11 +766,19 @@ 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) {
|
||||
disk = virtio_scsi_dev_get_disk_by_id(svdev, ev->lun[1]);
|
||||
if (disk != NULL) {
|
||||
spdk_bdev_unregister(&disk->bdev, NULL, NULL);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
target_id = base->info.target + 1;
|
||||
if (target_id == BDEV_VIRTIO_MAX_TARGET) {
|
||||
if (base->full_scan) {
|
||||
target_id = base->info.target + 1;
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user