diff --git a/lib/bdev/virtio/bdev_virtio.c b/lib/bdev/virtio/bdev_virtio.c index 3f89e859d..e55ff227a 100644 --- a/lib/bdev/virtio/bdev_virtio.c +++ b/lib/bdev/virtio/bdev_virtio.c @@ -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) {