1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause 2a6dbe372Spaul luse * Copyright (C) 2017 Intel Corporation. 307fe6a43SSeth Howell * All rights reserved. 407fe6a43SSeth Howell */ 507fe6a43SSeth Howell 607fe6a43SSeth Howell #include "spdk/stdinc.h" 707fe6a43SSeth Howell 807fe6a43SSeth Howell #include "spdk/bdev.h" 907fe6a43SSeth Howell #include "spdk/endian.h" 1007fe6a43SSeth Howell #include "spdk/env.h" 1107fe6a43SSeth Howell #include "spdk/thread.h" 1207fe6a43SSeth Howell #include "spdk/scsi_spec.h" 1307fe6a43SSeth Howell #include "spdk/string.h" 1407fe6a43SSeth Howell #include "spdk/util.h" 1507fe6a43SSeth Howell #include "spdk/json.h" 1607fe6a43SSeth Howell 1707fe6a43SSeth Howell #include "spdk/bdev_module.h" 184e8e97c8STomasz Zawadzki #include "spdk/log.h" 1907fe6a43SSeth Howell #include "spdk_internal/virtio.h" 20e7379fc2SChangpeng Liu #include "spdk_internal/vhost_user.h" 2107fe6a43SSeth Howell 2207fe6a43SSeth Howell #include <linux/virtio_scsi.h> 234c890c31SJin Yu #include <linux/virtio_ids.h> 2407fe6a43SSeth Howell 2507fe6a43SSeth Howell #include "bdev_virtio.h" 2607fe6a43SSeth Howell 2707fe6a43SSeth Howell #define BDEV_VIRTIO_MAX_TARGET 64 2807fe6a43SSeth Howell #define BDEV_VIRTIO_SCAN_PAYLOAD_SIZE 256 2907fe6a43SSeth Howell #define MGMT_POLL_PERIOD_US (1000 * 5) 3007fe6a43SSeth Howell #define CTRLQ_RING_SIZE 16 3107fe6a43SSeth Howell #define SCAN_REQUEST_RETRIES 5 3207fe6a43SSeth Howell 3307fe6a43SSeth Howell /* Number of non-request queues - eventq and controlq */ 3407fe6a43SSeth Howell #define SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED 2 3507fe6a43SSeth Howell 3607fe6a43SSeth Howell #define VIRTIO_SCSI_EVENTQ_BUFFER_COUNT 16 3707fe6a43SSeth Howell 3807fe6a43SSeth Howell #define VIRTIO_SCSI_CONTROLQ 0 3907fe6a43SSeth Howell #define VIRTIO_SCSI_EVENTQ 1 4007fe6a43SSeth Howell #define VIRTIO_SCSI_REQUESTQ 2 4107fe6a43SSeth Howell 4207fe6a43SSeth Howell static int bdev_virtio_initialize(void); 4307fe6a43SSeth Howell static void bdev_virtio_finish(void); 4407fe6a43SSeth Howell 4507fe6a43SSeth Howell struct virtio_scsi_dev { 4607fe6a43SSeth Howell /* Generic virtio device data. */ 4707fe6a43SSeth Howell struct virtio_dev vdev; 4807fe6a43SSeth Howell 4907fe6a43SSeth Howell /** Detected SCSI LUNs */ 5007fe6a43SSeth Howell TAILQ_HEAD(, virtio_scsi_disk) luns; 5107fe6a43SSeth Howell 5207fe6a43SSeth Howell /** Context for the SCSI target scan. */ 5307fe6a43SSeth Howell struct virtio_scsi_scan_base *scan_ctx; 5407fe6a43SSeth Howell 5507fe6a43SSeth Howell /** Controlq poller. */ 5607fe6a43SSeth Howell struct spdk_poller *mgmt_poller; 5707fe6a43SSeth Howell 5807fe6a43SSeth Howell /** Controlq messages to be sent. */ 5907fe6a43SSeth Howell struct spdk_ring *ctrlq_ring; 6007fe6a43SSeth Howell 6107fe6a43SSeth Howell /** Buffers for the eventq. */ 6207fe6a43SSeth Howell struct virtio_scsi_eventq_io *eventq_ios; 6307fe6a43SSeth Howell 6407fe6a43SSeth Howell /** Device marked for removal. */ 6507fe6a43SSeth Howell bool removed; 6607fe6a43SSeth Howell 6707fe6a43SSeth Howell /** Callback to be called after vdev removal. */ 6807fe6a43SSeth Howell bdev_virtio_remove_cb remove_cb; 6907fe6a43SSeth Howell 7007fe6a43SSeth Howell /** Context for the `remove_cb`. */ 7107fe6a43SSeth Howell void *remove_ctx; 7207fe6a43SSeth Howell 7307fe6a43SSeth Howell TAILQ_ENTRY(virtio_scsi_dev) tailq; 7407fe6a43SSeth Howell }; 7507fe6a43SSeth Howell 7607fe6a43SSeth Howell struct virtio_scsi_io_ctx { 7707fe6a43SSeth Howell struct iovec iov_req; 7807fe6a43SSeth Howell struct iovec iov_resp; 7907fe6a43SSeth Howell union { 8007fe6a43SSeth Howell struct virtio_scsi_cmd_req req; 8107fe6a43SSeth Howell struct virtio_scsi_ctrl_tmf_req tmf_req; 8207fe6a43SSeth Howell }; 8307fe6a43SSeth Howell union { 8407fe6a43SSeth Howell struct virtio_scsi_cmd_resp resp; 8507fe6a43SSeth Howell struct virtio_scsi_ctrl_tmf_resp tmf_resp; 8607fe6a43SSeth Howell }; 8707fe6a43SSeth Howell }; 8807fe6a43SSeth Howell 8907fe6a43SSeth Howell struct virtio_scsi_eventq_io { 9007fe6a43SSeth Howell struct iovec iov; 9107fe6a43SSeth Howell struct virtio_scsi_event ev; 9207fe6a43SSeth Howell }; 9307fe6a43SSeth Howell 9407fe6a43SSeth Howell struct virtio_scsi_scan_info { 9507fe6a43SSeth Howell uint64_t num_blocks; 9607fe6a43SSeth Howell uint32_t block_size; 9707fe6a43SSeth Howell uint8_t target; 9807fe6a43SSeth Howell bool unmap_supported; 9907fe6a43SSeth Howell TAILQ_ENTRY(virtio_scsi_scan_info) tailq; 10007fe6a43SSeth Howell }; 10107fe6a43SSeth Howell 10207fe6a43SSeth Howell struct virtio_scsi_scan_base { 10307fe6a43SSeth Howell struct virtio_scsi_dev *svdev; 10407fe6a43SSeth Howell 10507fe6a43SSeth Howell /** I/O channel used for the scan I/O. */ 10607fe6a43SSeth Howell struct bdev_virtio_io_channel *channel; 10707fe6a43SSeth Howell 10807fe6a43SSeth Howell bdev_virtio_create_cb cb_fn; 10907fe6a43SSeth Howell void *cb_arg; 11007fe6a43SSeth Howell 11107fe6a43SSeth Howell /** Scan all targets on the device. */ 11207fe6a43SSeth Howell bool full_scan; 11307fe6a43SSeth Howell 11407fe6a43SSeth Howell /** Start a full rescan after receiving next scan I/O response. */ 11507fe6a43SSeth Howell bool restart; 11607fe6a43SSeth Howell 11707fe6a43SSeth Howell /** Additional targets to be (re)scanned. */ 11807fe6a43SSeth Howell TAILQ_HEAD(, virtio_scsi_scan_info) scan_queue; 11907fe6a43SSeth Howell 12007fe6a43SSeth Howell /** Remaining attempts for sending the current request. */ 12107fe6a43SSeth Howell unsigned retries; 12207fe6a43SSeth Howell 12307fe6a43SSeth Howell /** If set, the last scan I/O needs to be resent */ 12407fe6a43SSeth Howell bool needs_resend; 12507fe6a43SSeth Howell 12607fe6a43SSeth Howell struct virtio_scsi_io_ctx io_ctx; 12707fe6a43SSeth Howell struct iovec iov; 12807fe6a43SSeth Howell uint8_t payload[BDEV_VIRTIO_SCAN_PAYLOAD_SIZE]; 12907fe6a43SSeth Howell 13007fe6a43SSeth Howell /** Scan results for the current target. */ 13107fe6a43SSeth Howell struct virtio_scsi_scan_info info; 13207fe6a43SSeth Howell }; 13307fe6a43SSeth Howell 13407fe6a43SSeth Howell struct virtio_scsi_disk { 13507fe6a43SSeth Howell struct spdk_bdev bdev; 13607fe6a43SSeth Howell struct virtio_scsi_dev *svdev; 13707fe6a43SSeth Howell struct virtio_scsi_scan_info info; 13807fe6a43SSeth Howell 13907fe6a43SSeth Howell /** Descriptor opened just to be notified of external bdev hotremove. */ 14007fe6a43SSeth Howell struct spdk_bdev_desc *notify_desc; 14107fe6a43SSeth Howell 14207fe6a43SSeth Howell /** Disk marked for removal. */ 14307fe6a43SSeth Howell bool removed; 14407fe6a43SSeth Howell TAILQ_ENTRY(virtio_scsi_disk) link; 14507fe6a43SSeth Howell }; 14607fe6a43SSeth Howell 14707fe6a43SSeth Howell struct bdev_virtio_io_channel { 14807fe6a43SSeth Howell struct virtio_scsi_dev *svdev; 14907fe6a43SSeth Howell 15007fe6a43SSeth Howell /** Virtqueue exclusively assigned to this channel. */ 15107fe6a43SSeth Howell struct virtqueue *vq; 15207fe6a43SSeth Howell 15307fe6a43SSeth Howell /** Virtio response poller. */ 15407fe6a43SSeth Howell struct spdk_poller *poller; 15507fe6a43SSeth Howell }; 15607fe6a43SSeth Howell 15707fe6a43SSeth Howell static TAILQ_HEAD(, virtio_scsi_dev) g_virtio_scsi_devs = 15807fe6a43SSeth Howell TAILQ_HEAD_INITIALIZER(g_virtio_scsi_devs); 15907fe6a43SSeth Howell 16007fe6a43SSeth Howell static pthread_mutex_t g_virtio_scsi_mutex = PTHREAD_MUTEX_INITIALIZER; 16107fe6a43SSeth Howell 16207fe6a43SSeth Howell /** Module finish in progress */ 16307fe6a43SSeth Howell static bool g_bdev_virtio_finish = false; 16407fe6a43SSeth Howell 16507fe6a43SSeth Howell /* Features desired/implemented by this driver. */ 16607fe6a43SSeth Howell #define VIRTIO_SCSI_DEV_SUPPORTED_FEATURES \ 16707fe6a43SSeth Howell (1ULL << VIRTIO_SCSI_F_INOUT | \ 16807fe6a43SSeth Howell 1ULL << VIRTIO_SCSI_F_HOTPLUG | \ 169515d028eSChangpeng Liu 1ULL << VIRTIO_RING_F_EVENT_IDX) 17007fe6a43SSeth Howell 17107fe6a43SSeth Howell static void virtio_scsi_dev_unregister_cb(void *io_device); 17207fe6a43SSeth Howell static void virtio_scsi_dev_remove(struct virtio_scsi_dev *svdev, 17307fe6a43SSeth Howell bdev_virtio_remove_cb cb_fn, void *cb_arg); 17407fe6a43SSeth Howell static int bdev_virtio_scsi_ch_create_cb(void *io_device, void *ctx_buf); 17507fe6a43SSeth Howell static void bdev_virtio_scsi_ch_destroy_cb(void *io_device, void *ctx_buf); 17607fe6a43SSeth Howell static void process_scan_resp(struct virtio_scsi_scan_base *base); 17707fe6a43SSeth Howell static int bdev_virtio_mgmt_poll(void *arg); 17807fe6a43SSeth Howell 17907fe6a43SSeth Howell static int 18007fe6a43SSeth Howell virtio_scsi_dev_send_eventq_io(struct virtqueue *vq, struct virtio_scsi_eventq_io *io) 18107fe6a43SSeth Howell { 18207fe6a43SSeth Howell int rc; 18307fe6a43SSeth Howell 18407fe6a43SSeth Howell rc = virtqueue_req_start(vq, io, 1); 18507fe6a43SSeth Howell if (rc != 0) { 18607fe6a43SSeth Howell return -1; 18707fe6a43SSeth Howell } 18807fe6a43SSeth Howell 18907fe6a43SSeth Howell virtqueue_req_add_iovs(vq, &io->iov, 1, SPDK_VIRTIO_DESC_WR); 19007fe6a43SSeth Howell virtqueue_req_flush(vq); 19107fe6a43SSeth Howell 19207fe6a43SSeth Howell return 0; 19307fe6a43SSeth Howell } 19407fe6a43SSeth Howell 19507fe6a43SSeth Howell static int 196515d028eSChangpeng Liu virtio_scsi_dev_init(struct virtio_scsi_dev *svdev, uint16_t max_queues, uint64_t feature_bits) 19707fe6a43SSeth Howell { 19807fe6a43SSeth Howell struct virtio_dev *vdev = &svdev->vdev; 19907fe6a43SSeth Howell struct spdk_ring *ctrlq_ring; 20007fe6a43SSeth Howell struct virtio_scsi_eventq_io *eventq_io; 20107fe6a43SSeth Howell struct virtqueue *eventq; 20207fe6a43SSeth Howell uint16_t i, num_events; 20307fe6a43SSeth Howell int rc; 20407fe6a43SSeth Howell 205515d028eSChangpeng Liu rc = virtio_dev_reset(vdev, feature_bits); 20607fe6a43SSeth Howell if (rc != 0) { 20707fe6a43SSeth Howell return rc; 20807fe6a43SSeth Howell } 20907fe6a43SSeth Howell 21007fe6a43SSeth Howell rc = virtio_dev_start(vdev, max_queues, SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED); 21107fe6a43SSeth Howell if (rc != 0) { 21207fe6a43SSeth Howell return rc; 21307fe6a43SSeth Howell } 21407fe6a43SSeth Howell 21507fe6a43SSeth Howell ctrlq_ring = spdk_ring_create(SPDK_RING_TYPE_MP_SC, CTRLQ_RING_SIZE, 216*186b109dSJim Harris SPDK_ENV_NUMA_ID_ANY); 21707fe6a43SSeth Howell if (ctrlq_ring == NULL) { 21807fe6a43SSeth Howell SPDK_ERRLOG("Failed to allocate send ring for the controlq.\n"); 21907fe6a43SSeth Howell return -1; 22007fe6a43SSeth Howell } 22107fe6a43SSeth Howell 22207fe6a43SSeth Howell rc = virtio_dev_acquire_queue(vdev, VIRTIO_SCSI_CONTROLQ); 22307fe6a43SSeth Howell if (rc != 0) { 22407fe6a43SSeth Howell SPDK_ERRLOG("Failed to acquire the controlq.\n"); 22507fe6a43SSeth Howell spdk_ring_free(ctrlq_ring); 22607fe6a43SSeth Howell return -1; 22707fe6a43SSeth Howell } 22807fe6a43SSeth Howell 22907fe6a43SSeth Howell rc = virtio_dev_acquire_queue(vdev, VIRTIO_SCSI_EVENTQ); 23007fe6a43SSeth Howell if (rc != 0) { 23107fe6a43SSeth Howell SPDK_ERRLOG("Failed to acquire the eventq.\n"); 23207fe6a43SSeth Howell virtio_dev_release_queue(vdev, VIRTIO_SCSI_CONTROLQ); 23307fe6a43SSeth Howell spdk_ring_free(ctrlq_ring); 23407fe6a43SSeth Howell return -1; 23507fe6a43SSeth Howell } 23607fe6a43SSeth Howell 23707fe6a43SSeth Howell eventq = vdev->vqs[VIRTIO_SCSI_EVENTQ]; 23807fe6a43SSeth Howell num_events = spdk_min(eventq->vq_nentries, VIRTIO_SCSI_EVENTQ_BUFFER_COUNT); 23907fe6a43SSeth Howell svdev->eventq_ios = spdk_zmalloc(sizeof(*svdev->eventq_ios) * num_events, 24007fe6a43SSeth Howell 0, NULL, SPDK_ENV_LCORE_ID_ANY, 24107fe6a43SSeth Howell SPDK_MALLOC_DMA); 24207fe6a43SSeth Howell if (svdev->eventq_ios == NULL) { 24307fe6a43SSeth Howell SPDK_ERRLOG("cannot allocate memory for %"PRIu16" eventq buffers\n", 24407fe6a43SSeth Howell num_events); 24507fe6a43SSeth Howell virtio_dev_release_queue(vdev, VIRTIO_SCSI_EVENTQ); 24607fe6a43SSeth Howell virtio_dev_release_queue(vdev, VIRTIO_SCSI_CONTROLQ); 24707fe6a43SSeth Howell spdk_ring_free(ctrlq_ring); 24807fe6a43SSeth Howell return -1; 24907fe6a43SSeth Howell } 25007fe6a43SSeth Howell 25107fe6a43SSeth Howell for (i = 0; i < num_events; i++) { 25207fe6a43SSeth Howell eventq_io = &svdev->eventq_ios[i]; 25307fe6a43SSeth Howell eventq_io->iov.iov_base = &eventq_io->ev; 25407fe6a43SSeth Howell eventq_io->iov.iov_len = sizeof(eventq_io->ev); 25507fe6a43SSeth Howell virtio_scsi_dev_send_eventq_io(eventq, eventq_io); 25607fe6a43SSeth Howell } 25707fe6a43SSeth Howell 25807fe6a43SSeth Howell svdev->ctrlq_ring = ctrlq_ring; 25907fe6a43SSeth Howell 260ab0bc5c2SShuhei Matsumoto svdev->mgmt_poller = SPDK_POLLER_REGISTER(bdev_virtio_mgmt_poll, svdev, 26107fe6a43SSeth Howell MGMT_POLL_PERIOD_US); 26207fe6a43SSeth Howell 26307fe6a43SSeth Howell TAILQ_INIT(&svdev->luns); 26407fe6a43SSeth Howell svdev->scan_ctx = NULL; 26507fe6a43SSeth Howell svdev->removed = false; 26607fe6a43SSeth Howell svdev->remove_cb = NULL; 26707fe6a43SSeth Howell svdev->remove_ctx = NULL; 26807fe6a43SSeth Howell 26907fe6a43SSeth Howell spdk_io_device_register(svdev, bdev_virtio_scsi_ch_create_cb, 27007fe6a43SSeth Howell bdev_virtio_scsi_ch_destroy_cb, 27107fe6a43SSeth Howell sizeof(struct bdev_virtio_io_channel), 27207fe6a43SSeth Howell svdev->vdev.name); 27307fe6a43SSeth Howell 27407fe6a43SSeth Howell pthread_mutex_lock(&g_virtio_scsi_mutex); 27507fe6a43SSeth Howell TAILQ_INSERT_TAIL(&g_virtio_scsi_devs, svdev, tailq); 27607fe6a43SSeth Howell pthread_mutex_unlock(&g_virtio_scsi_mutex); 27707fe6a43SSeth Howell return 0; 27807fe6a43SSeth Howell } 27907fe6a43SSeth Howell 28007fe6a43SSeth Howell static struct virtio_scsi_dev * 28107fe6a43SSeth Howell virtio_pci_scsi_dev_create(const char *name, struct virtio_pci_ctx *pci_ctx) 28207fe6a43SSeth Howell { 28307fe6a43SSeth Howell static int pci_dev_counter = 0; 28407fe6a43SSeth Howell struct virtio_scsi_dev *svdev; 28507fe6a43SSeth Howell struct virtio_dev *vdev; 28607fe6a43SSeth Howell char *default_name = NULL; 28707fe6a43SSeth Howell uint32_t num_queues; 28807fe6a43SSeth Howell int rc; 28907fe6a43SSeth Howell 29007fe6a43SSeth Howell svdev = calloc(1, sizeof(*svdev)); 29107fe6a43SSeth Howell if (svdev == NULL) { 29207fe6a43SSeth Howell SPDK_ERRLOG("virtio device calloc failed\n"); 29307fe6a43SSeth Howell return NULL; 29407fe6a43SSeth Howell } 29507fe6a43SSeth Howell 29607fe6a43SSeth Howell vdev = &svdev->vdev; 29707fe6a43SSeth Howell if (name == NULL) { 29807fe6a43SSeth Howell default_name = spdk_sprintf_alloc("VirtioScsi%"PRIu32, pci_dev_counter++); 29907fe6a43SSeth Howell if (default_name == NULL) { 30007fe6a43SSeth Howell free(vdev); 30107fe6a43SSeth Howell return NULL; 30207fe6a43SSeth Howell } 30307fe6a43SSeth Howell name = default_name; 30407fe6a43SSeth Howell } 30507fe6a43SSeth Howell 30607fe6a43SSeth Howell rc = virtio_pci_dev_init(vdev, name, pci_ctx); 30707fe6a43SSeth Howell free(default_name); 30807fe6a43SSeth Howell 30907fe6a43SSeth Howell if (rc != 0) { 31007fe6a43SSeth Howell free(svdev); 31107fe6a43SSeth Howell return NULL; 31207fe6a43SSeth Howell } 31307fe6a43SSeth Howell 31407fe6a43SSeth Howell rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_scsi_config, num_queues), 31507fe6a43SSeth Howell &num_queues, sizeof(num_queues)); 31607fe6a43SSeth Howell if (rc) { 31707fe6a43SSeth Howell SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc)); 3187ef6d8ddSJin Yu goto fail; 31907fe6a43SSeth Howell } 32007fe6a43SSeth Howell 321515d028eSChangpeng Liu rc = virtio_scsi_dev_init(svdev, num_queues, VIRTIO_SCSI_DEV_SUPPORTED_FEATURES); 32207fe6a43SSeth Howell if (rc != 0) { 3237ef6d8ddSJin Yu goto fail; 32407fe6a43SSeth Howell } 32507fe6a43SSeth Howell 32607fe6a43SSeth Howell return svdev; 3277ef6d8ddSJin Yu 3287ef6d8ddSJin Yu fail: 3297ef6d8ddSJin Yu vdev->ctx = NULL; 3307ef6d8ddSJin Yu virtio_dev_destruct(vdev); 3317ef6d8ddSJin Yu free(svdev); 3327ef6d8ddSJin Yu return NULL; 33307fe6a43SSeth Howell } 33407fe6a43SSeth Howell 33507fe6a43SSeth Howell static struct virtio_scsi_dev * 33607fe6a43SSeth Howell virtio_user_scsi_dev_create(const char *name, const char *path, 33707fe6a43SSeth Howell uint16_t num_queues, uint32_t queue_size) 33807fe6a43SSeth Howell { 33907fe6a43SSeth Howell struct virtio_scsi_dev *svdev; 34007fe6a43SSeth Howell struct virtio_dev *vdev; 341515d028eSChangpeng Liu uint64_t feature_bits; 34207fe6a43SSeth Howell int rc; 34307fe6a43SSeth Howell 34407fe6a43SSeth Howell svdev = calloc(1, sizeof(*svdev)); 34507fe6a43SSeth Howell if (svdev == NULL) { 34607fe6a43SSeth Howell SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", name, path); 34707fe6a43SSeth Howell return NULL; 34807fe6a43SSeth Howell } 34907fe6a43SSeth Howell 35007fe6a43SSeth Howell vdev = &svdev->vdev; 35107fe6a43SSeth Howell rc = virtio_user_dev_init(vdev, name, path, queue_size); 35207fe6a43SSeth Howell if (rc != 0) { 35307fe6a43SSeth Howell SPDK_ERRLOG("Failed to create virito device %s: %s\n", name, path); 35407fe6a43SSeth Howell free(svdev); 35507fe6a43SSeth Howell return NULL; 35607fe6a43SSeth Howell } 35707fe6a43SSeth Howell 358515d028eSChangpeng Liu feature_bits = VIRTIO_SCSI_DEV_SUPPORTED_FEATURES; 359515d028eSChangpeng Liu feature_bits |= (1ULL << VHOST_USER_F_PROTOCOL_FEATURES); 360a02483e6SChangpeng Liu rc = virtio_scsi_dev_init(svdev, num_queues + SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED, feature_bits); 36107fe6a43SSeth Howell if (rc != 0) { 36207fe6a43SSeth Howell virtio_dev_destruct(vdev); 36307fe6a43SSeth Howell free(svdev); 36407fe6a43SSeth Howell return NULL; 36507fe6a43SSeth Howell } 36607fe6a43SSeth Howell 36707fe6a43SSeth Howell return svdev; 36807fe6a43SSeth Howell } 36907fe6a43SSeth Howell 37007fe6a43SSeth Howell static struct virtio_scsi_disk * 37107fe6a43SSeth Howell virtio_scsi_dev_get_disk_by_id(struct virtio_scsi_dev *svdev, uint8_t target_id) 37207fe6a43SSeth Howell { 37307fe6a43SSeth Howell struct virtio_scsi_disk *disk; 37407fe6a43SSeth Howell 37507fe6a43SSeth Howell TAILQ_FOREACH(disk, &svdev->luns, link) { 37607fe6a43SSeth Howell if (disk->info.target == target_id) { 37707fe6a43SSeth Howell return disk; 37807fe6a43SSeth Howell } 37907fe6a43SSeth Howell } 38007fe6a43SSeth Howell 38107fe6a43SSeth Howell return NULL; 38207fe6a43SSeth Howell } 38307fe6a43SSeth Howell 38407fe6a43SSeth Howell static int virtio_scsi_dev_scan(struct virtio_scsi_dev *svdev, 38507fe6a43SSeth Howell bdev_virtio_create_cb cb_fn, void *cb_arg); 38607fe6a43SSeth Howell static int send_scan_io(struct virtio_scsi_scan_base *base); 38707fe6a43SSeth Howell static void _virtio_scsi_dev_scan_tgt(struct virtio_scsi_scan_base *base, uint8_t target); 38807fe6a43SSeth Howell static int _virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base, int rc); 38907fe6a43SSeth Howell static void _virtio_scsi_dev_scan_finish(struct virtio_scsi_scan_base *base, int errnum); 39007fe6a43SSeth Howell static int virtio_scsi_dev_scan_tgt(struct virtio_scsi_dev *svdev, uint8_t target); 39107fe6a43SSeth Howell 39207fe6a43SSeth Howell static int 39307fe6a43SSeth Howell bdev_virtio_get_ctx_size(void) 39407fe6a43SSeth Howell { 39507fe6a43SSeth Howell return sizeof(struct virtio_scsi_io_ctx); 39607fe6a43SSeth Howell } 39707fe6a43SSeth Howell 39807fe6a43SSeth Howell static int 39907fe6a43SSeth Howell bdev_virtio_scsi_config_json(struct spdk_json_write_ctx *w) 40007fe6a43SSeth Howell { 40107fe6a43SSeth Howell struct virtio_scsi_dev *svdev; 40207fe6a43SSeth Howell 40307fe6a43SSeth Howell pthread_mutex_lock(&g_virtio_scsi_mutex); 40407fe6a43SSeth Howell TAILQ_FOREACH(svdev, &g_virtio_scsi_devs, tailq) { 40507fe6a43SSeth Howell spdk_json_write_object_begin(w); 40607fe6a43SSeth Howell 4072aed03f0SMaciej Wawryk spdk_json_write_named_string(w, "method", "bdev_virtio_attach_controller"); 40807fe6a43SSeth Howell 40907fe6a43SSeth Howell spdk_json_write_named_object_begin(w, "params"); 41007fe6a43SSeth Howell spdk_json_write_named_string(w, "name", svdev->vdev.name); 41107fe6a43SSeth Howell spdk_json_write_named_string(w, "dev_type", "scsi"); 41207fe6a43SSeth Howell 41307fe6a43SSeth Howell /* Write transport specific parameters. */ 41407fe6a43SSeth Howell svdev->vdev.backend_ops->write_json_config(&svdev->vdev, w); 41507fe6a43SSeth Howell 41607fe6a43SSeth Howell spdk_json_write_object_end(w); 41707fe6a43SSeth Howell 41807fe6a43SSeth Howell spdk_json_write_object_end(w); 41907fe6a43SSeth Howell 42007fe6a43SSeth Howell } 42107fe6a43SSeth Howell pthread_mutex_unlock(&g_virtio_scsi_mutex); 42207fe6a43SSeth Howell 42307fe6a43SSeth Howell return 0; 42407fe6a43SSeth Howell } 42507fe6a43SSeth Howell 42607fe6a43SSeth Howell 42707fe6a43SSeth Howell static struct spdk_bdev_module virtio_scsi_if = { 42807fe6a43SSeth Howell .name = "virtio_scsi", 42907fe6a43SSeth Howell .module_init = bdev_virtio_initialize, 43007fe6a43SSeth Howell .module_fini = bdev_virtio_finish, 43107fe6a43SSeth Howell .get_ctx_size = bdev_virtio_get_ctx_size, 43207fe6a43SSeth Howell .config_json = bdev_virtio_scsi_config_json, 43307fe6a43SSeth Howell .async_fini = true, 43407fe6a43SSeth Howell }; 43507fe6a43SSeth Howell 43607fe6a43SSeth Howell SPDK_BDEV_MODULE_REGISTER(virtio_scsi, &virtio_scsi_if) 43707fe6a43SSeth Howell 43807fe6a43SSeth Howell static struct virtio_scsi_io_ctx * 43907fe6a43SSeth Howell bdev_virtio_init_io_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 44007fe6a43SSeth Howell { 44107fe6a43SSeth Howell struct virtio_scsi_cmd_req *req; 44207fe6a43SSeth Howell struct virtio_scsi_cmd_resp *resp; 44307fe6a43SSeth Howell struct virtio_scsi_disk *disk = (struct virtio_scsi_disk *)bdev_io->bdev; 44407fe6a43SSeth Howell struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx; 44507fe6a43SSeth Howell 44607fe6a43SSeth Howell req = &io_ctx->req; 44707fe6a43SSeth Howell resp = &io_ctx->resp; 44807fe6a43SSeth Howell 44907fe6a43SSeth Howell io_ctx->iov_req.iov_base = req; 45007fe6a43SSeth Howell io_ctx->iov_req.iov_len = sizeof(*req); 45107fe6a43SSeth Howell 45207fe6a43SSeth Howell io_ctx->iov_resp.iov_base = resp; 45307fe6a43SSeth Howell io_ctx->iov_resp.iov_len = sizeof(*resp); 45407fe6a43SSeth Howell 45507fe6a43SSeth Howell memset(req, 0, sizeof(*req)); 45607fe6a43SSeth Howell req->lun[0] = 1; 45707fe6a43SSeth Howell req->lun[1] = disk->info.target; 45807fe6a43SSeth Howell 45907fe6a43SSeth Howell return io_ctx; 46007fe6a43SSeth Howell } 46107fe6a43SSeth Howell 46207fe6a43SSeth Howell static struct virtio_scsi_io_ctx * 46307fe6a43SSeth Howell bdev_virtio_init_tmf_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 46407fe6a43SSeth Howell { 46507fe6a43SSeth Howell struct virtio_scsi_ctrl_tmf_req *tmf_req; 46607fe6a43SSeth Howell struct virtio_scsi_ctrl_tmf_resp *tmf_resp; 46707fe6a43SSeth Howell struct virtio_scsi_disk *disk = SPDK_CONTAINEROF(bdev_io->bdev, struct virtio_scsi_disk, bdev); 46807fe6a43SSeth Howell struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx; 46907fe6a43SSeth Howell 47007fe6a43SSeth Howell tmf_req = &io_ctx->tmf_req; 47107fe6a43SSeth Howell tmf_resp = &io_ctx->tmf_resp; 47207fe6a43SSeth Howell 47307fe6a43SSeth Howell io_ctx->iov_req.iov_base = tmf_req; 47407fe6a43SSeth Howell io_ctx->iov_req.iov_len = sizeof(*tmf_req); 47507fe6a43SSeth Howell io_ctx->iov_resp.iov_base = tmf_resp; 47607fe6a43SSeth Howell io_ctx->iov_resp.iov_len = sizeof(*tmf_resp); 47707fe6a43SSeth Howell 47807fe6a43SSeth Howell memset(tmf_req, 0, sizeof(*tmf_req)); 47907fe6a43SSeth Howell tmf_req->lun[0] = 1; 48007fe6a43SSeth Howell tmf_req->lun[1] = disk->info.target; 48107fe6a43SSeth Howell 48207fe6a43SSeth Howell return io_ctx; 48307fe6a43SSeth Howell } 48407fe6a43SSeth Howell 48507fe6a43SSeth Howell static void 48607fe6a43SSeth Howell bdev_virtio_send_io(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 48707fe6a43SSeth Howell { 48807fe6a43SSeth Howell struct bdev_virtio_io_channel *virtio_channel = spdk_io_channel_get_ctx(ch); 48907fe6a43SSeth Howell struct virtqueue *vq = virtio_channel->vq; 49007fe6a43SSeth Howell struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx; 49107fe6a43SSeth Howell int rc; 49207fe6a43SSeth Howell 49307fe6a43SSeth Howell rc = virtqueue_req_start(vq, bdev_io, bdev_io->u.bdev.iovcnt + 2); 49407fe6a43SSeth Howell if (rc == -ENOMEM) { 49507fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM); 49607fe6a43SSeth Howell return; 49707fe6a43SSeth Howell } else if (rc != 0) { 49807fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 49907fe6a43SSeth Howell return; 50007fe6a43SSeth Howell } 50107fe6a43SSeth Howell 50207fe6a43SSeth Howell virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO); 50307fe6a43SSeth Howell if (bdev_io->type == SPDK_BDEV_IO_TYPE_READ) { 50407fe6a43SSeth Howell virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR); 50507fe6a43SSeth Howell virtqueue_req_add_iovs(vq, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, 50607fe6a43SSeth Howell SPDK_VIRTIO_DESC_WR); 50707fe6a43SSeth Howell } else { 50807fe6a43SSeth Howell virtqueue_req_add_iovs(vq, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, 50907fe6a43SSeth Howell SPDK_VIRTIO_DESC_RO); 51007fe6a43SSeth Howell virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR); 51107fe6a43SSeth Howell } 51207fe6a43SSeth Howell 51307fe6a43SSeth Howell virtqueue_req_flush(vq); 51407fe6a43SSeth Howell } 51507fe6a43SSeth Howell 51607fe6a43SSeth Howell static void 51707fe6a43SSeth Howell bdev_virtio_rw(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 51807fe6a43SSeth Howell { 51907fe6a43SSeth Howell struct virtio_scsi_disk *disk = SPDK_CONTAINEROF(bdev_io->bdev, struct virtio_scsi_disk, bdev); 52007fe6a43SSeth Howell struct virtio_scsi_io_ctx *io_ctx = bdev_virtio_init_io_vreq(ch, bdev_io); 52107fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &io_ctx->req; 52207fe6a43SSeth Howell bool is_write = bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE; 52307fe6a43SSeth Howell 52407fe6a43SSeth Howell if (disk->info.num_blocks > (1ULL << 32)) { 52507fe6a43SSeth Howell req->cdb[0] = is_write ? SPDK_SBC_WRITE_16 : SPDK_SBC_READ_16; 52607fe6a43SSeth Howell to_be64(&req->cdb[2], bdev_io->u.bdev.offset_blocks); 52707fe6a43SSeth Howell to_be32(&req->cdb[10], bdev_io->u.bdev.num_blocks); 52807fe6a43SSeth Howell } else { 52907fe6a43SSeth Howell req->cdb[0] = is_write ? SPDK_SBC_WRITE_10 : SPDK_SBC_READ_10; 53007fe6a43SSeth Howell to_be32(&req->cdb[2], bdev_io->u.bdev.offset_blocks); 53107fe6a43SSeth Howell to_be16(&req->cdb[7], bdev_io->u.bdev.num_blocks); 53207fe6a43SSeth Howell } 53307fe6a43SSeth Howell 53407fe6a43SSeth Howell bdev_virtio_send_io(ch, bdev_io); 53507fe6a43SSeth Howell } 53607fe6a43SSeth Howell 53707fe6a43SSeth Howell static void 53807fe6a43SSeth Howell bdev_virtio_reset(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 53907fe6a43SSeth Howell { 54007fe6a43SSeth Howell struct bdev_virtio_io_channel *virtio_ch = spdk_io_channel_get_ctx(ch); 54107fe6a43SSeth Howell struct virtio_scsi_io_ctx *io_ctx = bdev_virtio_init_tmf_vreq(ch, bdev_io); 54207fe6a43SSeth Howell struct virtio_scsi_ctrl_tmf_req *tmf_req = &io_ctx->tmf_req; 54307fe6a43SSeth Howell struct virtio_scsi_dev *svdev = virtio_ch->svdev; 54407fe6a43SSeth Howell size_t enqueued_count; 54507fe6a43SSeth Howell 54607fe6a43SSeth Howell tmf_req->type = VIRTIO_SCSI_T_TMF; 54707fe6a43SSeth Howell tmf_req->subtype = VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET; 54807fe6a43SSeth Howell 54907fe6a43SSeth Howell enqueued_count = spdk_ring_enqueue(svdev->ctrlq_ring, (void **)&bdev_io, 1, NULL); 55007fe6a43SSeth Howell if (spdk_likely(enqueued_count == 1)) { 55107fe6a43SSeth Howell return; 55207fe6a43SSeth Howell } else { 55307fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM); 55407fe6a43SSeth Howell } 55507fe6a43SSeth Howell } 55607fe6a43SSeth Howell 55707fe6a43SSeth Howell static void 55807fe6a43SSeth Howell bdev_virtio_unmap(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, bool success) 55907fe6a43SSeth Howell { 56007fe6a43SSeth Howell struct virtio_scsi_io_ctx *io_ctx = bdev_virtio_init_io_vreq(ch, bdev_io); 56107fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &io_ctx->req; 56207fe6a43SSeth Howell struct spdk_scsi_unmap_bdesc *desc, *first_desc; 56307fe6a43SSeth Howell uint8_t *buf; 56407fe6a43SSeth Howell uint64_t offset_blocks, num_blocks; 56507fe6a43SSeth Howell uint16_t cmd_len; 56607fe6a43SSeth Howell 56707fe6a43SSeth Howell if (!success) { 56807fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 56907fe6a43SSeth Howell return; 57007fe6a43SSeth Howell } 57107fe6a43SSeth Howell 57207fe6a43SSeth Howell buf = bdev_io->u.bdev.iovs[0].iov_base; 57307fe6a43SSeth Howell 57407fe6a43SSeth Howell offset_blocks = bdev_io->u.bdev.offset_blocks; 57507fe6a43SSeth Howell num_blocks = bdev_io->u.bdev.num_blocks; 57607fe6a43SSeth Howell 57707fe6a43SSeth Howell /* (n-1) * 16-byte descriptors */ 57807fe6a43SSeth Howell first_desc = desc = (struct spdk_scsi_unmap_bdesc *)&buf[8]; 57907fe6a43SSeth Howell while (num_blocks > UINT32_MAX) { 58007fe6a43SSeth Howell to_be64(&desc->lba, offset_blocks); 58107fe6a43SSeth Howell to_be32(&desc->block_count, UINT32_MAX); 58207fe6a43SSeth Howell memset(&desc->reserved, 0, sizeof(desc->reserved)); 58307fe6a43SSeth Howell offset_blocks += UINT32_MAX; 58407fe6a43SSeth Howell num_blocks -= UINT32_MAX; 58507fe6a43SSeth Howell desc++; 58607fe6a43SSeth Howell } 58707fe6a43SSeth Howell 58807fe6a43SSeth Howell /* The last descriptor with block_count <= UINT32_MAX */ 58907fe6a43SSeth Howell to_be64(&desc->lba, offset_blocks); 59007fe6a43SSeth Howell to_be32(&desc->block_count, num_blocks); 59107fe6a43SSeth Howell memset(&desc->reserved, 0, sizeof(desc->reserved)); 59207fe6a43SSeth Howell 59307fe6a43SSeth Howell /* 8-byte header + n * 16-byte block descriptor */ 59407fe6a43SSeth Howell cmd_len = 8 + (desc - first_desc + 1) * sizeof(struct spdk_scsi_unmap_bdesc); 59507fe6a43SSeth Howell 59607fe6a43SSeth Howell req->cdb[0] = SPDK_SBC_UNMAP; 59707fe6a43SSeth Howell to_be16(&req->cdb[7], cmd_len); 59807fe6a43SSeth Howell 59907fe6a43SSeth Howell /* 8-byte header */ 60007fe6a43SSeth Howell to_be16(&buf[0], cmd_len - 2); /* total length (excluding the length field) */ 60107fe6a43SSeth Howell to_be16(&buf[2], cmd_len - 8); /* length of block descriptors */ 60207fe6a43SSeth Howell memset(&buf[4], 0, 4); /* reserved */ 60307fe6a43SSeth Howell 60407fe6a43SSeth Howell bdev_virtio_send_io(ch, bdev_io); 60507fe6a43SSeth Howell } 60607fe6a43SSeth Howell 60707fe6a43SSeth Howell static void 60807fe6a43SSeth Howell bdev_virtio_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, 60907fe6a43SSeth Howell bool success) 61007fe6a43SSeth Howell { 61107fe6a43SSeth Howell if (!success) { 61207fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 61307fe6a43SSeth Howell return; 61407fe6a43SSeth Howell } 61507fe6a43SSeth Howell 61607fe6a43SSeth Howell bdev_virtio_rw(ch, bdev_io); 61707fe6a43SSeth Howell } 61807fe6a43SSeth Howell 6198dd1cd21SBen Walker static int 6208dd1cd21SBen Walker _bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 62107fe6a43SSeth Howell { 62207fe6a43SSeth Howell struct virtio_scsi_disk *disk = SPDK_CONTAINEROF(bdev_io->bdev, struct virtio_scsi_disk, bdev); 62307fe6a43SSeth Howell 62407fe6a43SSeth Howell switch (bdev_io->type) { 62507fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_READ: 62607fe6a43SSeth Howell spdk_bdev_io_get_buf(bdev_io, bdev_virtio_get_buf_cb, 62707fe6a43SSeth Howell bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen); 62807fe6a43SSeth Howell return 0; 62907fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE: 63007fe6a43SSeth Howell bdev_virtio_rw(ch, bdev_io); 63107fe6a43SSeth Howell return 0; 63207fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_RESET: 63307fe6a43SSeth Howell bdev_virtio_reset(ch, bdev_io); 63407fe6a43SSeth Howell return 0; 63507fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_UNMAP: { 63607fe6a43SSeth Howell uint64_t buf_len = 8 /* header size */ + 63707fe6a43SSeth Howell (bdev_io->u.bdev.num_blocks + UINT32_MAX - 1) / 63807fe6a43SSeth Howell UINT32_MAX * sizeof(struct spdk_scsi_unmap_bdesc); 63907fe6a43SSeth Howell 64007fe6a43SSeth Howell if (!disk->info.unmap_supported) { 64107fe6a43SSeth Howell return -1; 64207fe6a43SSeth Howell } 64307fe6a43SSeth Howell 64407fe6a43SSeth Howell if (buf_len > SPDK_BDEV_LARGE_BUF_MAX_SIZE) { 64507fe6a43SSeth Howell SPDK_ERRLOG("Trying to UNMAP too many blocks: %"PRIu64"\n", 64607fe6a43SSeth Howell bdev_io->u.bdev.num_blocks); 64707fe6a43SSeth Howell return -1; 64807fe6a43SSeth Howell } 64907fe6a43SSeth Howell spdk_bdev_io_get_buf(bdev_io, bdev_virtio_unmap, buf_len); 65007fe6a43SSeth Howell return 0; 65107fe6a43SSeth Howell } 65207fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_FLUSH: 65307fe6a43SSeth Howell default: 65407fe6a43SSeth Howell return -1; 65507fe6a43SSeth Howell } 65607fe6a43SSeth Howell return 0; 65707fe6a43SSeth Howell } 65807fe6a43SSeth Howell 6598dd1cd21SBen Walker static void 6608dd1cd21SBen Walker bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 66107fe6a43SSeth Howell { 66207fe6a43SSeth Howell if (_bdev_virtio_submit_request(ch, bdev_io) < 0) { 66307fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 66407fe6a43SSeth Howell } 66507fe6a43SSeth Howell } 66607fe6a43SSeth Howell 66707fe6a43SSeth Howell static bool 66807fe6a43SSeth Howell bdev_virtio_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) 66907fe6a43SSeth Howell { 67007fe6a43SSeth Howell struct virtio_scsi_disk *disk = ctx; 67107fe6a43SSeth Howell 67207fe6a43SSeth Howell switch (io_type) { 67307fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_READ: 67407fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE: 67507fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_FLUSH: 67607fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_RESET: 67707fe6a43SSeth Howell return true; 67807fe6a43SSeth Howell 67907fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_UNMAP: 68007fe6a43SSeth Howell return disk->info.unmap_supported; 68107fe6a43SSeth Howell 68207fe6a43SSeth Howell default: 68307fe6a43SSeth Howell return false; 68407fe6a43SSeth Howell } 68507fe6a43SSeth Howell } 68607fe6a43SSeth Howell 68707fe6a43SSeth Howell static struct spdk_io_channel * 68807fe6a43SSeth Howell bdev_virtio_get_io_channel(void *ctx) 68907fe6a43SSeth Howell { 69007fe6a43SSeth Howell struct virtio_scsi_disk *disk = ctx; 69107fe6a43SSeth Howell 69207fe6a43SSeth Howell return spdk_get_io_channel(disk->svdev); 69307fe6a43SSeth Howell } 69407fe6a43SSeth Howell 69507fe6a43SSeth Howell static int 69607fe6a43SSeth Howell bdev_virtio_disk_destruct(void *ctx) 69707fe6a43SSeth Howell { 69807fe6a43SSeth Howell struct virtio_scsi_disk *disk = ctx; 69907fe6a43SSeth Howell struct virtio_scsi_dev *svdev = disk->svdev; 70007fe6a43SSeth Howell 70107fe6a43SSeth Howell TAILQ_REMOVE(&svdev->luns, disk, link); 70207fe6a43SSeth Howell free(disk->bdev.name); 70307fe6a43SSeth Howell free(disk); 70407fe6a43SSeth Howell 70507fe6a43SSeth Howell if (svdev->removed && TAILQ_EMPTY(&svdev->luns)) { 70607fe6a43SSeth Howell spdk_io_device_unregister(svdev, virtio_scsi_dev_unregister_cb); 70707fe6a43SSeth Howell } 70807fe6a43SSeth Howell 70907fe6a43SSeth Howell return 0; 71007fe6a43SSeth Howell } 71107fe6a43SSeth Howell 71207fe6a43SSeth Howell static int 71307fe6a43SSeth Howell bdev_virtio_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 71407fe6a43SSeth Howell { 71507fe6a43SSeth Howell struct virtio_scsi_disk *disk = ctx; 71607fe6a43SSeth Howell 71707fe6a43SSeth Howell virtio_dev_dump_json_info(&disk->svdev->vdev, w); 71807fe6a43SSeth Howell return 0; 71907fe6a43SSeth Howell } 72007fe6a43SSeth Howell 72107fe6a43SSeth Howell static void 72207fe6a43SSeth Howell bdev_virtio_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 72307fe6a43SSeth Howell { 72407fe6a43SSeth Howell /* SCSI targets and LUNS are discovered during scan process so nothing 72507fe6a43SSeth Howell * to save here. 72607fe6a43SSeth Howell */ 72707fe6a43SSeth Howell } 72807fe6a43SSeth Howell 72907fe6a43SSeth Howell static const struct spdk_bdev_fn_table virtio_fn_table = { 73007fe6a43SSeth Howell .destruct = bdev_virtio_disk_destruct, 73107fe6a43SSeth Howell .submit_request = bdev_virtio_submit_request, 73207fe6a43SSeth Howell .io_type_supported = bdev_virtio_io_type_supported, 73307fe6a43SSeth Howell .get_io_channel = bdev_virtio_get_io_channel, 73407fe6a43SSeth Howell .dump_info_json = bdev_virtio_dump_info_json, 73507fe6a43SSeth Howell .write_config_json = bdev_virtio_write_config_json, 73607fe6a43SSeth Howell }; 73707fe6a43SSeth Howell 73807fe6a43SSeth Howell static void 73907fe6a43SSeth Howell get_scsi_status(struct virtio_scsi_cmd_resp *resp, int *sk, int *asc, int *ascq) 74007fe6a43SSeth Howell { 74107fe6a43SSeth Howell /* see spdk_scsi_task_build_sense_data() for sense data details */ 74207fe6a43SSeth Howell *sk = 0; 74307fe6a43SSeth Howell *asc = 0; 74407fe6a43SSeth Howell *ascq = 0; 74507fe6a43SSeth Howell 74607fe6a43SSeth Howell if (resp->sense_len < 3) { 74707fe6a43SSeth Howell return; 74807fe6a43SSeth Howell } 74907fe6a43SSeth Howell 75007fe6a43SSeth Howell *sk = resp->sense[2] & 0xf; 75107fe6a43SSeth Howell 75207fe6a43SSeth Howell if (resp->sense_len < 13) { 75307fe6a43SSeth Howell return; 75407fe6a43SSeth Howell } 75507fe6a43SSeth Howell 75607fe6a43SSeth Howell *asc = resp->sense[12]; 75707fe6a43SSeth Howell 75807fe6a43SSeth Howell if (resp->sense_len < 14) { 75907fe6a43SSeth Howell return; 76007fe6a43SSeth Howell } 76107fe6a43SSeth Howell 76207fe6a43SSeth Howell *ascq = resp->sense[13]; 76307fe6a43SSeth Howell } 76407fe6a43SSeth Howell 76507fe6a43SSeth Howell static void 76607fe6a43SSeth Howell bdev_virtio_io_cpl(struct spdk_bdev_io *bdev_io) 76707fe6a43SSeth Howell { 76807fe6a43SSeth Howell struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx; 76907fe6a43SSeth Howell int sk, asc, ascq; 77007fe6a43SSeth Howell 77107fe6a43SSeth Howell get_scsi_status(&io_ctx->resp, &sk, &asc, &ascq); 77207fe6a43SSeth Howell spdk_bdev_io_complete_scsi_status(bdev_io, io_ctx->resp.status, sk, asc, ascq); 77307fe6a43SSeth Howell } 77407fe6a43SSeth Howell 77507fe6a43SSeth Howell static int 77607fe6a43SSeth Howell bdev_virtio_poll(void *arg) 77707fe6a43SSeth Howell { 77807fe6a43SSeth Howell struct bdev_virtio_io_channel *ch = arg; 77907fe6a43SSeth Howell struct virtio_scsi_dev *svdev = ch->svdev; 78007fe6a43SSeth Howell struct virtio_scsi_scan_base *scan_ctx = svdev->scan_ctx; 78107fe6a43SSeth Howell void *io[32]; 78207fe6a43SSeth Howell uint32_t io_len[32]; 78307fe6a43SSeth Howell uint16_t i, cnt; 78407fe6a43SSeth Howell int rc; 78507fe6a43SSeth Howell 78607fe6a43SSeth Howell cnt = virtio_recv_pkts(ch->vq, (void **)io, io_len, SPDK_COUNTOF(io)); 78707fe6a43SSeth Howell for (i = 0; i < cnt; ++i) { 78807fe6a43SSeth Howell if (spdk_unlikely(scan_ctx && io[i] == &scan_ctx->io_ctx)) { 78907fe6a43SSeth Howell if (svdev->removed) { 79007fe6a43SSeth Howell _virtio_scsi_dev_scan_finish(scan_ctx, -EINTR); 791eb05cbd6SMaciej Szwed return SPDK_POLLER_BUSY; 79207fe6a43SSeth Howell } 79307fe6a43SSeth Howell 79407fe6a43SSeth Howell if (scan_ctx->restart) { 79507fe6a43SSeth Howell scan_ctx->restart = false; 79607fe6a43SSeth Howell scan_ctx->full_scan = true; 79707fe6a43SSeth Howell _virtio_scsi_dev_scan_tgt(scan_ctx, 0); 79807fe6a43SSeth Howell continue; 79907fe6a43SSeth Howell } 80007fe6a43SSeth Howell 80107fe6a43SSeth Howell process_scan_resp(scan_ctx); 80207fe6a43SSeth Howell continue; 80307fe6a43SSeth Howell } 80407fe6a43SSeth Howell 80507fe6a43SSeth Howell bdev_virtio_io_cpl(io[i]); 80607fe6a43SSeth Howell } 80707fe6a43SSeth Howell 80808422b58SJim Harris /* scan_ctx could have been freed while processing completions above, so 80908422b58SJim Harris * we need to re-read the value again here into the local variable before 81008422b58SJim Harris * using it. 81108422b58SJim Harris */ 81208422b58SJim Harris scan_ctx = svdev->scan_ctx; 81307fe6a43SSeth Howell if (spdk_unlikely(scan_ctx && scan_ctx->needs_resend)) { 81407fe6a43SSeth Howell if (svdev->removed) { 81507fe6a43SSeth Howell _virtio_scsi_dev_scan_finish(scan_ctx, -EINTR); 816eb05cbd6SMaciej Szwed return SPDK_POLLER_BUSY; 81707fe6a43SSeth Howell } else if (cnt == 0) { 818eb05cbd6SMaciej Szwed return SPDK_POLLER_IDLE; 81907fe6a43SSeth Howell } 82007fe6a43SSeth Howell 82107fe6a43SSeth Howell rc = send_scan_io(scan_ctx); 82207fe6a43SSeth Howell if (rc != 0) { 82307fe6a43SSeth Howell assert(scan_ctx->retries > 0); 82407fe6a43SSeth Howell scan_ctx->retries--; 82507fe6a43SSeth Howell if (scan_ctx->retries == 0) { 82607fe6a43SSeth Howell SPDK_ERRLOG("Target scan failed unrecoverably with rc = %d.\n", rc); 82707fe6a43SSeth Howell _virtio_scsi_dev_scan_finish(scan_ctx, rc); 82807fe6a43SSeth Howell } 82907fe6a43SSeth Howell } 83007fe6a43SSeth Howell } 83107fe6a43SSeth Howell 83207fe6a43SSeth Howell return cnt; 83307fe6a43SSeth Howell } 83407fe6a43SSeth Howell 83507fe6a43SSeth Howell static void 83607fe6a43SSeth Howell bdev_virtio_tmf_cpl_cb(void *ctx) 83707fe6a43SSeth Howell { 83807fe6a43SSeth Howell struct spdk_bdev_io *bdev_io = ctx; 83907fe6a43SSeth Howell struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx; 84007fe6a43SSeth Howell 84107fe6a43SSeth Howell if (io_ctx->tmf_resp.response == VIRTIO_SCSI_S_OK) { 84207fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); 84307fe6a43SSeth Howell } else { 84407fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 84507fe6a43SSeth Howell } 84607fe6a43SSeth Howell } 84707fe6a43SSeth Howell 84807fe6a43SSeth Howell static void 84907fe6a43SSeth Howell bdev_virtio_tmf_cpl(struct spdk_bdev_io *bdev_io) 85007fe6a43SSeth Howell { 85107fe6a43SSeth Howell spdk_thread_send_msg(spdk_bdev_io_get_thread(bdev_io), bdev_virtio_tmf_cpl_cb, bdev_io); 85207fe6a43SSeth Howell } 85307fe6a43SSeth Howell 85407fe6a43SSeth Howell static void 85507fe6a43SSeth Howell bdev_virtio_eventq_io_cpl(struct virtio_scsi_dev *svdev, struct virtio_scsi_eventq_io *io) 85607fe6a43SSeth Howell { 85707fe6a43SSeth Howell struct virtio_scsi_event *ev = &io->ev; 85807fe6a43SSeth Howell struct virtio_scsi_disk *disk; 85907fe6a43SSeth Howell 86007fe6a43SSeth Howell if (ev->lun[0] != 1) { 86107fe6a43SSeth Howell SPDK_WARNLOG("Received an event with invalid data layout.\n"); 86207fe6a43SSeth Howell goto out; 86307fe6a43SSeth Howell } 86407fe6a43SSeth Howell 86507fe6a43SSeth Howell if (ev->event & VIRTIO_SCSI_T_EVENTS_MISSED) { 86607fe6a43SSeth Howell ev->event &= ~VIRTIO_SCSI_T_EVENTS_MISSED; 86707fe6a43SSeth Howell virtio_scsi_dev_scan(svdev, NULL, NULL); 86807fe6a43SSeth Howell } 86907fe6a43SSeth Howell 87007fe6a43SSeth Howell switch (ev->event) { 87107fe6a43SSeth Howell case VIRTIO_SCSI_T_NO_EVENT: 87207fe6a43SSeth Howell break; 87307fe6a43SSeth Howell case VIRTIO_SCSI_T_TRANSPORT_RESET: 87407fe6a43SSeth Howell switch (ev->reason) { 87507fe6a43SSeth Howell case VIRTIO_SCSI_EVT_RESET_RESCAN: 87607fe6a43SSeth Howell virtio_scsi_dev_scan_tgt(svdev, ev->lun[1]); 87707fe6a43SSeth Howell break; 87807fe6a43SSeth Howell case VIRTIO_SCSI_EVT_RESET_REMOVED: 87907fe6a43SSeth Howell disk = virtio_scsi_dev_get_disk_by_id(svdev, ev->lun[1]); 88007fe6a43SSeth Howell if (disk != NULL) { 88107fe6a43SSeth Howell spdk_bdev_unregister(&disk->bdev, NULL, NULL); 88207fe6a43SSeth Howell } 88307fe6a43SSeth Howell break; 88407fe6a43SSeth Howell default: 88507fe6a43SSeth Howell break; 88607fe6a43SSeth Howell } 88707fe6a43SSeth Howell break; 88807fe6a43SSeth Howell default: 88907fe6a43SSeth Howell break; 89007fe6a43SSeth Howell } 89107fe6a43SSeth Howell 89207fe6a43SSeth Howell out: 89307fe6a43SSeth Howell virtio_scsi_dev_send_eventq_io(svdev->vdev.vqs[VIRTIO_SCSI_EVENTQ], io); 89407fe6a43SSeth Howell } 89507fe6a43SSeth Howell 89607fe6a43SSeth Howell static void 89707fe6a43SSeth Howell bdev_virtio_tmf_abort_nomem_cb(void *ctx) 89807fe6a43SSeth Howell { 89907fe6a43SSeth Howell struct spdk_bdev_io *bdev_io = ctx; 90007fe6a43SSeth Howell 90107fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM); 90207fe6a43SSeth Howell } 90307fe6a43SSeth Howell 90407fe6a43SSeth Howell static void 90507fe6a43SSeth Howell bdev_virtio_tmf_abort_ioerr_cb(void *ctx) 90607fe6a43SSeth Howell { 90707fe6a43SSeth Howell struct spdk_bdev_io *bdev_io = ctx; 90807fe6a43SSeth Howell 90907fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 91007fe6a43SSeth Howell } 91107fe6a43SSeth Howell 91207fe6a43SSeth Howell static void 91307fe6a43SSeth Howell bdev_virtio_tmf_abort(struct spdk_bdev_io *bdev_io, int status) 91407fe6a43SSeth Howell { 91507fe6a43SSeth Howell spdk_msg_fn fn; 91607fe6a43SSeth Howell 91707fe6a43SSeth Howell if (status == -ENOMEM) { 91807fe6a43SSeth Howell fn = bdev_virtio_tmf_abort_nomem_cb; 91907fe6a43SSeth Howell } else { 92007fe6a43SSeth Howell fn = bdev_virtio_tmf_abort_ioerr_cb; 92107fe6a43SSeth Howell } 92207fe6a43SSeth Howell 92307fe6a43SSeth Howell spdk_thread_send_msg(spdk_bdev_io_get_thread(bdev_io), fn, bdev_io); 92407fe6a43SSeth Howell } 92507fe6a43SSeth Howell 92607fe6a43SSeth Howell static int 92707fe6a43SSeth Howell bdev_virtio_send_tmf_io(struct virtqueue *ctrlq, struct spdk_bdev_io *bdev_io) 92807fe6a43SSeth Howell { 92907fe6a43SSeth Howell struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx; 93007fe6a43SSeth Howell int rc; 93107fe6a43SSeth Howell 93207fe6a43SSeth Howell rc = virtqueue_req_start(ctrlq, bdev_io, 2); 93307fe6a43SSeth Howell if (rc != 0) { 93407fe6a43SSeth Howell return rc; 93507fe6a43SSeth Howell } 93607fe6a43SSeth Howell 93707fe6a43SSeth Howell virtqueue_req_add_iovs(ctrlq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO); 93807fe6a43SSeth Howell virtqueue_req_add_iovs(ctrlq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR); 93907fe6a43SSeth Howell 94007fe6a43SSeth Howell virtqueue_req_flush(ctrlq); 94107fe6a43SSeth Howell return 0; 94207fe6a43SSeth Howell } 94307fe6a43SSeth Howell 94407fe6a43SSeth Howell static int 94507fe6a43SSeth Howell bdev_virtio_mgmt_poll(void *arg) 94607fe6a43SSeth Howell { 94707fe6a43SSeth Howell struct virtio_scsi_dev *svdev = arg; 94807fe6a43SSeth Howell struct virtio_dev *vdev = &svdev->vdev; 94907fe6a43SSeth Howell struct virtqueue *eventq = vdev->vqs[VIRTIO_SCSI_EVENTQ]; 95007fe6a43SSeth Howell struct virtqueue *ctrlq = vdev->vqs[VIRTIO_SCSI_CONTROLQ]; 95107fe6a43SSeth Howell struct spdk_ring *send_ring = svdev->ctrlq_ring; 95207fe6a43SSeth Howell void *io[16]; 95307fe6a43SSeth Howell uint32_t io_len[16]; 95407fe6a43SSeth Howell uint16_t i, cnt; 95507fe6a43SSeth Howell int rc; 95607fe6a43SSeth Howell int total = 0; 95707fe6a43SSeth Howell 95807fe6a43SSeth Howell cnt = spdk_ring_dequeue(send_ring, io, SPDK_COUNTOF(io)); 95907fe6a43SSeth Howell total += cnt; 96007fe6a43SSeth Howell for (i = 0; i < cnt; ++i) { 96107fe6a43SSeth Howell rc = bdev_virtio_send_tmf_io(ctrlq, io[i]); 96207fe6a43SSeth Howell if (rc != 0) { 96307fe6a43SSeth Howell bdev_virtio_tmf_abort(io[i], rc); 96407fe6a43SSeth Howell } 96507fe6a43SSeth Howell } 96607fe6a43SSeth Howell 96707fe6a43SSeth Howell cnt = virtio_recv_pkts(ctrlq, io, io_len, SPDK_COUNTOF(io)); 96807fe6a43SSeth Howell total += cnt; 96907fe6a43SSeth Howell for (i = 0; i < cnt; ++i) { 97007fe6a43SSeth Howell bdev_virtio_tmf_cpl(io[i]); 97107fe6a43SSeth Howell } 97207fe6a43SSeth Howell 97307fe6a43SSeth Howell cnt = virtio_recv_pkts(eventq, io, io_len, SPDK_COUNTOF(io)); 97407fe6a43SSeth Howell total += cnt; 97507fe6a43SSeth Howell for (i = 0; i < cnt; ++i) { 97607fe6a43SSeth Howell bdev_virtio_eventq_io_cpl(svdev, io[i]); 97707fe6a43SSeth Howell } 97807fe6a43SSeth Howell 97907fe6a43SSeth Howell return total; 98007fe6a43SSeth Howell } 98107fe6a43SSeth Howell 98207fe6a43SSeth Howell static int 98307fe6a43SSeth Howell bdev_virtio_scsi_ch_create_cb(void *io_device, void *ctx_buf) 98407fe6a43SSeth Howell { 98507fe6a43SSeth Howell struct virtio_scsi_dev *svdev = io_device; 98607fe6a43SSeth Howell struct virtio_dev *vdev = &svdev->vdev; 98707fe6a43SSeth Howell struct bdev_virtio_io_channel *ch = ctx_buf; 98807fe6a43SSeth Howell struct virtqueue *vq; 98907fe6a43SSeth Howell int32_t queue_idx; 99007fe6a43SSeth Howell 99107fe6a43SSeth Howell queue_idx = virtio_dev_find_and_acquire_queue(vdev, VIRTIO_SCSI_REQUESTQ); 99207fe6a43SSeth Howell if (queue_idx < 0) { 99307fe6a43SSeth Howell SPDK_ERRLOG("Couldn't get an unused queue for the io_channel.\n"); 99407fe6a43SSeth Howell return -1; 99507fe6a43SSeth Howell } 99607fe6a43SSeth Howell 99707fe6a43SSeth Howell vq = vdev->vqs[queue_idx]; 99807fe6a43SSeth Howell 99907fe6a43SSeth Howell ch->svdev = svdev; 100007fe6a43SSeth Howell ch->vq = vq; 100107fe6a43SSeth Howell 1002ab0bc5c2SShuhei Matsumoto ch->poller = SPDK_POLLER_REGISTER(bdev_virtio_poll, ch, 0); 100307fe6a43SSeth Howell 100407fe6a43SSeth Howell return 0; 100507fe6a43SSeth Howell } 100607fe6a43SSeth Howell 100707fe6a43SSeth Howell static void 100807fe6a43SSeth Howell bdev_virtio_scsi_ch_destroy_cb(void *io_device, void *ctx_buf) 100907fe6a43SSeth Howell { 101007fe6a43SSeth Howell struct bdev_virtio_io_channel *ch = ctx_buf; 101107fe6a43SSeth Howell struct virtio_scsi_dev *svdev = ch->svdev; 101207fe6a43SSeth Howell struct virtio_dev *vdev = &svdev->vdev; 101307fe6a43SSeth Howell struct virtqueue *vq = ch->vq; 101407fe6a43SSeth Howell 101507fe6a43SSeth Howell spdk_poller_unregister(&ch->poller); 101607fe6a43SSeth Howell virtio_dev_release_queue(vdev, vq->vq_queue_index); 101707fe6a43SSeth Howell } 101807fe6a43SSeth Howell 101907fe6a43SSeth Howell static void 102007fe6a43SSeth Howell _virtio_scsi_dev_scan_finish(struct virtio_scsi_scan_base *base, int errnum) 102107fe6a43SSeth Howell { 102207fe6a43SSeth Howell struct virtio_scsi_dev *svdev = base->svdev; 102307fe6a43SSeth Howell size_t bdevs_cnt; 102407fe6a43SSeth Howell struct spdk_bdev *bdevs[BDEV_VIRTIO_MAX_TARGET]; 102507fe6a43SSeth Howell struct virtio_scsi_disk *disk; 102607fe6a43SSeth Howell struct virtio_scsi_scan_info *tgt, *next_tgt; 102707fe6a43SSeth Howell 102807fe6a43SSeth Howell spdk_put_io_channel(spdk_io_channel_from_ctx(base->channel)); 102907fe6a43SSeth Howell base->svdev->scan_ctx = NULL; 103007fe6a43SSeth Howell 103107fe6a43SSeth Howell TAILQ_FOREACH_SAFE(tgt, &base->scan_queue, tailq, next_tgt) { 103207fe6a43SSeth Howell TAILQ_REMOVE(&base->scan_queue, tgt, tailq); 103307fe6a43SSeth Howell free(tgt); 103407fe6a43SSeth Howell } 103507fe6a43SSeth Howell 103607fe6a43SSeth Howell if (base->cb_fn == NULL) { 103707fe6a43SSeth Howell spdk_free(base); 103807fe6a43SSeth Howell return; 103907fe6a43SSeth Howell } 104007fe6a43SSeth Howell 104107fe6a43SSeth Howell bdevs_cnt = 0; 104207fe6a43SSeth Howell if (errnum == 0) { 104307fe6a43SSeth Howell TAILQ_FOREACH(disk, &svdev->luns, link) { 104407fe6a43SSeth Howell bdevs[bdevs_cnt] = &disk->bdev; 104507fe6a43SSeth Howell bdevs_cnt++; 104607fe6a43SSeth Howell } 104707fe6a43SSeth Howell } 104807fe6a43SSeth Howell 104907fe6a43SSeth Howell base->cb_fn(base->cb_arg, errnum, bdevs, bdevs_cnt); 105007fe6a43SSeth Howell spdk_free(base); 105107fe6a43SSeth Howell } 105207fe6a43SSeth Howell 105307fe6a43SSeth Howell static int 105407fe6a43SSeth Howell send_scan_io(struct virtio_scsi_scan_base *base) 105507fe6a43SSeth Howell { 105607fe6a43SSeth Howell struct virtio_scsi_io_ctx *io_ctx = &base->io_ctx; 105707fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &base->io_ctx.req; 105807fe6a43SSeth Howell struct virtqueue *vq = base->channel->vq; 105907fe6a43SSeth Howell int payload_iov_cnt = base->iov.iov_len > 0 ? 1 : 0; 106007fe6a43SSeth Howell int rc; 106107fe6a43SSeth Howell 106207fe6a43SSeth Howell req->lun[0] = 1; 106307fe6a43SSeth Howell req->lun[1] = base->info.target; 106407fe6a43SSeth Howell 106507fe6a43SSeth Howell rc = virtqueue_req_start(vq, io_ctx, 2 + payload_iov_cnt); 106607fe6a43SSeth Howell if (rc != 0) { 106707fe6a43SSeth Howell base->needs_resend = true; 106807fe6a43SSeth Howell return -1; 106907fe6a43SSeth Howell } 107007fe6a43SSeth Howell 107107fe6a43SSeth Howell virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO); 107207fe6a43SSeth Howell virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR); 107307fe6a43SSeth Howell virtqueue_req_add_iovs(vq, &base->iov, payload_iov_cnt, SPDK_VIRTIO_DESC_WR); 107407fe6a43SSeth Howell 107507fe6a43SSeth Howell virtqueue_req_flush(vq); 107607fe6a43SSeth Howell return 0; 107707fe6a43SSeth Howell } 107807fe6a43SSeth Howell 107907fe6a43SSeth Howell static int 108007fe6a43SSeth Howell send_inquiry(struct virtio_scsi_scan_base *base) 108107fe6a43SSeth Howell { 108207fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &base->io_ctx.req; 108307fe6a43SSeth Howell struct spdk_scsi_cdb_inquiry *cdb; 108407fe6a43SSeth Howell 108507fe6a43SSeth Howell memset(req, 0, sizeof(*req)); 108607fe6a43SSeth Howell 108707fe6a43SSeth Howell base->iov.iov_len = BDEV_VIRTIO_SCAN_PAYLOAD_SIZE; 108807fe6a43SSeth Howell cdb = (struct spdk_scsi_cdb_inquiry *)req->cdb; 108907fe6a43SSeth Howell cdb->opcode = SPDK_SPC_INQUIRY; 109007fe6a43SSeth Howell to_be16(cdb->alloc_len, BDEV_VIRTIO_SCAN_PAYLOAD_SIZE); 109107fe6a43SSeth Howell 109207fe6a43SSeth Howell return send_scan_io(base); 109307fe6a43SSeth Howell } 109407fe6a43SSeth Howell 109507fe6a43SSeth Howell static int 109607fe6a43SSeth Howell send_inquiry_vpd(struct virtio_scsi_scan_base *base, uint8_t page_code) 109707fe6a43SSeth Howell { 109807fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &base->io_ctx.req; 109907fe6a43SSeth Howell struct spdk_scsi_cdb_inquiry *inquiry_cdb = (struct spdk_scsi_cdb_inquiry *)req->cdb; 110007fe6a43SSeth Howell 110107fe6a43SSeth Howell memset(req, 0, sizeof(*req)); 110207fe6a43SSeth Howell 110307fe6a43SSeth Howell base->iov.iov_len = BDEV_VIRTIO_SCAN_PAYLOAD_SIZE; 110407fe6a43SSeth Howell inquiry_cdb->opcode = SPDK_SPC_INQUIRY; 110507fe6a43SSeth Howell inquiry_cdb->evpd = 1; 110607fe6a43SSeth Howell inquiry_cdb->page_code = page_code; 110707fe6a43SSeth Howell to_be16(inquiry_cdb->alloc_len, base->iov.iov_len); 110807fe6a43SSeth Howell 110907fe6a43SSeth Howell return send_scan_io(base); 111007fe6a43SSeth Howell } 111107fe6a43SSeth Howell 111207fe6a43SSeth Howell static int 111307fe6a43SSeth Howell send_read_cap_10(struct virtio_scsi_scan_base *base) 111407fe6a43SSeth Howell { 111507fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &base->io_ctx.req; 111607fe6a43SSeth Howell 111707fe6a43SSeth Howell memset(req, 0, sizeof(*req)); 111807fe6a43SSeth Howell 111907fe6a43SSeth Howell base->iov.iov_len = 8; 112007fe6a43SSeth Howell req->cdb[0] = SPDK_SBC_READ_CAPACITY_10; 112107fe6a43SSeth Howell 112207fe6a43SSeth Howell return send_scan_io(base); 112307fe6a43SSeth Howell } 112407fe6a43SSeth Howell 112507fe6a43SSeth Howell static int 112607fe6a43SSeth Howell send_read_cap_16(struct virtio_scsi_scan_base *base) 112707fe6a43SSeth Howell { 112807fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &base->io_ctx.req; 112907fe6a43SSeth Howell 113007fe6a43SSeth Howell memset(req, 0, sizeof(*req)); 113107fe6a43SSeth Howell 113207fe6a43SSeth Howell base->iov.iov_len = 32; 113307fe6a43SSeth Howell req->cdb[0] = SPDK_SPC_SERVICE_ACTION_IN_16; 113407fe6a43SSeth Howell req->cdb[1] = SPDK_SBC_SAI_READ_CAPACITY_16; 113507fe6a43SSeth Howell to_be32(&req->cdb[10], base->iov.iov_len); 113607fe6a43SSeth Howell 113707fe6a43SSeth Howell return send_scan_io(base); 113807fe6a43SSeth Howell } 113907fe6a43SSeth Howell 114007fe6a43SSeth Howell static int 114107fe6a43SSeth Howell send_test_unit_ready(struct virtio_scsi_scan_base *base) 114207fe6a43SSeth Howell { 114307fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &base->io_ctx.req; 114407fe6a43SSeth Howell 114507fe6a43SSeth Howell memset(req, 0, sizeof(*req)); 114607fe6a43SSeth Howell req->cdb[0] = SPDK_SPC_TEST_UNIT_READY; 114707fe6a43SSeth Howell base->iov.iov_len = 0; 114807fe6a43SSeth Howell 114907fe6a43SSeth Howell return send_scan_io(base); 115007fe6a43SSeth Howell } 115107fe6a43SSeth Howell 115207fe6a43SSeth Howell static int 115307fe6a43SSeth Howell send_start_stop_unit(struct virtio_scsi_scan_base *base) 115407fe6a43SSeth Howell { 115507fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &base->io_ctx.req; 115607fe6a43SSeth Howell 115707fe6a43SSeth Howell memset(req, 0, sizeof(*req)); 115807fe6a43SSeth Howell req->cdb[0] = SPDK_SBC_START_STOP_UNIT; 115907fe6a43SSeth Howell req->cdb[4] = SPDK_SBC_START_STOP_UNIT_START_BIT; 116007fe6a43SSeth Howell base->iov.iov_len = 0; 116107fe6a43SSeth Howell 116207fe6a43SSeth Howell return send_scan_io(base); 116307fe6a43SSeth Howell } 116407fe6a43SSeth Howell 116507fe6a43SSeth Howell static int 116607fe6a43SSeth Howell process_scan_start_stop_unit(struct virtio_scsi_scan_base *base) 116707fe6a43SSeth Howell { 116807fe6a43SSeth Howell struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp; 116907fe6a43SSeth Howell 117007fe6a43SSeth Howell if (resp->status == SPDK_SCSI_STATUS_GOOD) { 117107fe6a43SSeth Howell return send_inquiry_vpd(base, SPDK_SPC_VPD_SUPPORTED_VPD_PAGES); 117207fe6a43SSeth Howell } 117307fe6a43SSeth Howell 117407fe6a43SSeth Howell return -1; 117507fe6a43SSeth Howell } 117607fe6a43SSeth Howell 117707fe6a43SSeth Howell static int 117807fe6a43SSeth Howell process_scan_test_unit_ready(struct virtio_scsi_scan_base *base) 117907fe6a43SSeth Howell { 118007fe6a43SSeth Howell struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp; 118107fe6a43SSeth Howell int sk, asc, ascq; 118207fe6a43SSeth Howell 118307fe6a43SSeth Howell get_scsi_status(resp, &sk, &asc, &ascq); 118407fe6a43SSeth Howell 118507fe6a43SSeth Howell /* check response, get VPD if spun up otherwise send SSU */ 118607fe6a43SSeth Howell if (resp->status == SPDK_SCSI_STATUS_GOOD) { 118707fe6a43SSeth Howell return send_inquiry_vpd(base, SPDK_SPC_VPD_SUPPORTED_VPD_PAGES); 118807fe6a43SSeth Howell } else if (resp->response == VIRTIO_SCSI_S_OK && 118907fe6a43SSeth Howell resp->status == SPDK_SCSI_STATUS_CHECK_CONDITION && 119007fe6a43SSeth Howell sk == SPDK_SCSI_SENSE_UNIT_ATTENTION && 119107fe6a43SSeth Howell asc == SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_READY) { 119207fe6a43SSeth Howell return send_start_stop_unit(base); 119307fe6a43SSeth Howell } else { 119407fe6a43SSeth Howell return -1; 119507fe6a43SSeth Howell } 119607fe6a43SSeth Howell } 119707fe6a43SSeth Howell 119807fe6a43SSeth Howell static int 119907fe6a43SSeth Howell process_scan_inquiry_standard(struct virtio_scsi_scan_base *base) 120007fe6a43SSeth Howell { 120107fe6a43SSeth Howell struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp; 120207fe6a43SSeth Howell struct spdk_scsi_cdb_inquiry_data *inquiry_data = 120307fe6a43SSeth Howell (struct spdk_scsi_cdb_inquiry_data *)base->payload; 120407fe6a43SSeth Howell 120507fe6a43SSeth Howell if (resp->status != SPDK_SCSI_STATUS_GOOD) { 120607fe6a43SSeth Howell return -1; 120707fe6a43SSeth Howell } 120807fe6a43SSeth Howell 120907fe6a43SSeth Howell /* check to make sure its a supported device */ 121007fe6a43SSeth Howell if (inquiry_data->peripheral_device_type != SPDK_SPC_PERIPHERAL_DEVICE_TYPE_DISK || 121107fe6a43SSeth Howell inquiry_data->peripheral_qualifier != SPDK_SPC_PERIPHERAL_QUALIFIER_CONNECTED) { 121207fe6a43SSeth Howell SPDK_WARNLOG("Unsupported peripheral device type 0x%02x (qualifier 0x%02x)\n", 121307fe6a43SSeth Howell inquiry_data->peripheral_device_type, 121407fe6a43SSeth Howell inquiry_data->peripheral_qualifier); 121507fe6a43SSeth Howell return -1; 121607fe6a43SSeth Howell } 121707fe6a43SSeth Howell 121807fe6a43SSeth Howell return send_test_unit_ready(base); 121907fe6a43SSeth Howell } 122007fe6a43SSeth Howell 122107fe6a43SSeth Howell static int 122207fe6a43SSeth Howell process_scan_inquiry_vpd_supported_vpd_pages(struct virtio_scsi_scan_base *base) 122307fe6a43SSeth Howell { 122407fe6a43SSeth Howell struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp; 122507fe6a43SSeth Howell bool block_provisioning_page_supported = false; 122607fe6a43SSeth Howell 122707fe6a43SSeth Howell if (resp->status == SPDK_SCSI_STATUS_GOOD) { 122807fe6a43SSeth Howell const uint8_t *vpd_data = base->payload; 122907fe6a43SSeth Howell const uint8_t *supported_vpd_pages = vpd_data + 4; 123007fe6a43SSeth Howell uint16_t page_length; 123107fe6a43SSeth Howell uint16_t num_supported_pages; 123207fe6a43SSeth Howell uint16_t i; 123307fe6a43SSeth Howell 123407fe6a43SSeth Howell page_length = from_be16(vpd_data + 2); 123507fe6a43SSeth Howell num_supported_pages = spdk_min(page_length, base->iov.iov_len - 4); 123607fe6a43SSeth Howell 123707fe6a43SSeth Howell for (i = 0; i < num_supported_pages; i++) { 123807fe6a43SSeth Howell if (supported_vpd_pages[i] == SPDK_SPC_VPD_BLOCK_THIN_PROVISION) { 123907fe6a43SSeth Howell block_provisioning_page_supported = true; 124007fe6a43SSeth Howell break; 124107fe6a43SSeth Howell } 124207fe6a43SSeth Howell } 124307fe6a43SSeth Howell } 124407fe6a43SSeth Howell 124507fe6a43SSeth Howell if (block_provisioning_page_supported) { 124607fe6a43SSeth Howell return send_inquiry_vpd(base, SPDK_SPC_VPD_BLOCK_THIN_PROVISION); 124707fe6a43SSeth Howell } else { 124807fe6a43SSeth Howell return send_read_cap_10(base); 124907fe6a43SSeth Howell } 125007fe6a43SSeth Howell } 125107fe6a43SSeth Howell 125207fe6a43SSeth Howell static int 125307fe6a43SSeth Howell process_scan_inquiry_vpd_block_thin_provision(struct virtio_scsi_scan_base *base) 125407fe6a43SSeth Howell { 125507fe6a43SSeth Howell struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp; 125607fe6a43SSeth Howell 125707fe6a43SSeth Howell base->info.unmap_supported = false; 125807fe6a43SSeth Howell 125907fe6a43SSeth Howell if (resp->status == SPDK_SCSI_STATUS_GOOD) { 126007fe6a43SSeth Howell uint8_t *vpd_data = base->payload; 126107fe6a43SSeth Howell 126207fe6a43SSeth Howell base->info.unmap_supported = !!(vpd_data[5] & SPDK_SCSI_UNMAP_LBPU); 126307fe6a43SSeth Howell } 126407fe6a43SSeth Howell 12652172c432STomasz Zawadzki SPDK_INFOLOG(virtio, "Target %u: unmap supported = %d\n", 126607fe6a43SSeth Howell base->info.target, (int)base->info.unmap_supported); 126707fe6a43SSeth Howell 126807fe6a43SSeth Howell return send_read_cap_10(base); 126907fe6a43SSeth Howell } 127007fe6a43SSeth Howell 127107fe6a43SSeth Howell static int 127207fe6a43SSeth Howell process_scan_inquiry(struct virtio_scsi_scan_base *base) 127307fe6a43SSeth Howell { 127407fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &base->io_ctx.req; 127507fe6a43SSeth Howell struct spdk_scsi_cdb_inquiry *inquiry_cdb = (struct spdk_scsi_cdb_inquiry *)req->cdb; 127607fe6a43SSeth Howell 127707fe6a43SSeth Howell if ((inquiry_cdb->evpd & 1) == 0) { 127807fe6a43SSeth Howell return process_scan_inquiry_standard(base); 127907fe6a43SSeth Howell } 128007fe6a43SSeth Howell 128107fe6a43SSeth Howell switch (inquiry_cdb->page_code) { 128207fe6a43SSeth Howell case SPDK_SPC_VPD_SUPPORTED_VPD_PAGES: 128307fe6a43SSeth Howell return process_scan_inquiry_vpd_supported_vpd_pages(base); 128407fe6a43SSeth Howell case SPDK_SPC_VPD_BLOCK_THIN_PROVISION: 128507fe6a43SSeth Howell return process_scan_inquiry_vpd_block_thin_provision(base); 128607fe6a43SSeth Howell default: 12872172c432STomasz Zawadzki SPDK_DEBUGLOG(virtio, "Unexpected VPD page 0x%02x\n", inquiry_cdb->page_code); 128807fe6a43SSeth Howell return -1; 128907fe6a43SSeth Howell } 129007fe6a43SSeth Howell } 129107fe6a43SSeth Howell 129207fe6a43SSeth Howell static void 1293aed3d21eSShuhei Matsumoto bdev_virtio_disk_notify_remove(struct virtio_scsi_disk *disk) 129407fe6a43SSeth Howell { 129507fe6a43SSeth Howell disk->removed = true; 129607fe6a43SSeth Howell spdk_bdev_close(disk->notify_desc); 129707fe6a43SSeth Howell } 129807fe6a43SSeth Howell 1299aed3d21eSShuhei Matsumoto static void 1300aed3d21eSShuhei Matsumoto bdev_virtio_disk_notify_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, 1301aed3d21eSShuhei Matsumoto void *event_ctx) 1302aed3d21eSShuhei Matsumoto { 1303aed3d21eSShuhei Matsumoto switch (type) { 1304aed3d21eSShuhei Matsumoto case SPDK_BDEV_EVENT_REMOVE: 1305aed3d21eSShuhei Matsumoto bdev_virtio_disk_notify_remove(event_ctx); 1306aed3d21eSShuhei Matsumoto break; 1307aed3d21eSShuhei Matsumoto default: 1308aed3d21eSShuhei Matsumoto SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type); 1309aed3d21eSShuhei Matsumoto break; 1310aed3d21eSShuhei Matsumoto } 1311aed3d21eSShuhei Matsumoto } 1312aed3d21eSShuhei Matsumoto 131307fe6a43SSeth Howell /* To be called only from the thread performing target scan */ 131407fe6a43SSeth Howell static int 131507fe6a43SSeth Howell virtio_scsi_dev_add_tgt(struct virtio_scsi_dev *svdev, struct virtio_scsi_scan_info *info) 131607fe6a43SSeth Howell { 131707fe6a43SSeth Howell struct virtio_scsi_disk *disk; 131807fe6a43SSeth Howell struct spdk_bdev *bdev; 131907fe6a43SSeth Howell int rc; 132007fe6a43SSeth Howell 132107fe6a43SSeth Howell TAILQ_FOREACH(disk, &svdev->luns, link) { 132207fe6a43SSeth Howell if (disk->info.target == info->target) { 132307fe6a43SSeth Howell /* Target is already attached and param change is not supported */ 132407fe6a43SSeth Howell return 0; 132507fe6a43SSeth Howell } 132607fe6a43SSeth Howell } 132707fe6a43SSeth Howell 132807fe6a43SSeth Howell if (info->block_size == 0 || info->num_blocks == 0) { 132907fe6a43SSeth Howell SPDK_ERRLOG("%s: invalid target %u: bs=%"PRIu32" blocks=%"PRIu64"\n", 133007fe6a43SSeth Howell svdev->vdev.name, info->target, info->block_size, info->num_blocks); 133107fe6a43SSeth Howell return -EINVAL; 133207fe6a43SSeth Howell } 133307fe6a43SSeth Howell 133407fe6a43SSeth Howell disk = calloc(1, sizeof(*disk)); 133507fe6a43SSeth Howell if (disk == NULL) { 133607fe6a43SSeth Howell SPDK_ERRLOG("could not allocate disk\n"); 133707fe6a43SSeth Howell return -ENOMEM; 133807fe6a43SSeth Howell } 133907fe6a43SSeth Howell 134007fe6a43SSeth Howell disk->svdev = svdev; 134107fe6a43SSeth Howell memcpy(&disk->info, info, sizeof(*info)); 134207fe6a43SSeth Howell 134307fe6a43SSeth Howell bdev = &disk->bdev; 134407fe6a43SSeth Howell bdev->name = spdk_sprintf_alloc("%st%"PRIu8, svdev->vdev.name, info->target); 134507fe6a43SSeth Howell if (bdev->name == NULL) { 134607fe6a43SSeth Howell SPDK_ERRLOG("Couldn't alloc memory for the bdev name.\n"); 134707fe6a43SSeth Howell free(disk); 134807fe6a43SSeth Howell return -ENOMEM; 134907fe6a43SSeth Howell } 135007fe6a43SSeth Howell 135107fe6a43SSeth Howell bdev->product_name = "Virtio SCSI Disk"; 135207fe6a43SSeth Howell bdev->write_cache = 0; 135307fe6a43SSeth Howell bdev->blocklen = disk->info.block_size; 135407fe6a43SSeth Howell bdev->blockcnt = disk->info.num_blocks; 135507fe6a43SSeth Howell 135607fe6a43SSeth Howell bdev->ctxt = disk; 135707fe6a43SSeth Howell bdev->fn_table = &virtio_fn_table; 135807fe6a43SSeth Howell bdev->module = &virtio_scsi_if; 135907fe6a43SSeth Howell 136007fe6a43SSeth Howell rc = spdk_bdev_register(&disk->bdev); 136107fe6a43SSeth Howell if (rc) { 136207fe6a43SSeth Howell SPDK_ERRLOG("Failed to register bdev name=%s\n", disk->bdev.name); 136307fe6a43SSeth Howell free(bdev->name); 136407fe6a43SSeth Howell free(disk); 136507fe6a43SSeth Howell return rc; 136607fe6a43SSeth Howell } 136707fe6a43SSeth Howell 1368aed3d21eSShuhei Matsumoto rc = spdk_bdev_open_ext(bdev->name, false, bdev_virtio_disk_notify_event_cb, 1369aed3d21eSShuhei Matsumoto disk, &disk->notify_desc); 137007fe6a43SSeth Howell if (rc) { 137107fe6a43SSeth Howell assert(false); 137207fe6a43SSeth Howell } 137307fe6a43SSeth Howell 137407fe6a43SSeth Howell TAILQ_INSERT_TAIL(&svdev->luns, disk, link); 137507fe6a43SSeth Howell return 0; 137607fe6a43SSeth Howell } 137707fe6a43SSeth Howell 137807fe6a43SSeth Howell static int 137907fe6a43SSeth Howell process_read_cap_10(struct virtio_scsi_scan_base *base) 138007fe6a43SSeth Howell { 138107fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &base->io_ctx.req; 138207fe6a43SSeth Howell struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp; 138307fe6a43SSeth Howell uint64_t max_block; 138407fe6a43SSeth Howell uint32_t block_size; 138507fe6a43SSeth Howell uint8_t target_id = req->lun[1]; 138607fe6a43SSeth Howell int rc; 138707fe6a43SSeth Howell 138807fe6a43SSeth Howell if (resp->response != VIRTIO_SCSI_S_OK || resp->status != SPDK_SCSI_STATUS_GOOD) { 138907fe6a43SSeth Howell SPDK_ERRLOG("READ CAPACITY (10) failed for target %"PRIu8".\n", target_id); 139007fe6a43SSeth Howell return -1; 139107fe6a43SSeth Howell } 139207fe6a43SSeth Howell 139307fe6a43SSeth Howell block_size = from_be32(base->payload + 4); 139407fe6a43SSeth Howell max_block = from_be32(base->payload); 139507fe6a43SSeth Howell 139607fe6a43SSeth Howell if (max_block == 0xffffffff) { 139707fe6a43SSeth Howell return send_read_cap_16(base); 139807fe6a43SSeth Howell } 139907fe6a43SSeth Howell 140007fe6a43SSeth Howell base->info.num_blocks = (uint64_t)max_block + 1; 140107fe6a43SSeth Howell base->info.block_size = block_size; 140207fe6a43SSeth Howell 140307fe6a43SSeth Howell rc = virtio_scsi_dev_add_tgt(base->svdev, &base->info); 140407fe6a43SSeth Howell if (rc != 0) { 140507fe6a43SSeth Howell return rc; 140607fe6a43SSeth Howell } 140707fe6a43SSeth Howell 140807fe6a43SSeth Howell return _virtio_scsi_dev_scan_next(base, 0); 140907fe6a43SSeth Howell } 141007fe6a43SSeth Howell 141107fe6a43SSeth Howell static int 141207fe6a43SSeth Howell process_read_cap_16(struct virtio_scsi_scan_base *base) 141307fe6a43SSeth Howell { 141407fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &base->io_ctx.req; 141507fe6a43SSeth Howell struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp; 141607fe6a43SSeth Howell uint8_t target_id = req->lun[1]; 141707fe6a43SSeth Howell int rc; 141807fe6a43SSeth Howell 141907fe6a43SSeth Howell if (resp->response != VIRTIO_SCSI_S_OK || resp->status != SPDK_SCSI_STATUS_GOOD) { 142007fe6a43SSeth Howell SPDK_ERRLOG("READ CAPACITY (16) failed for target %"PRIu8".\n", target_id); 142107fe6a43SSeth Howell return -1; 142207fe6a43SSeth Howell } 142307fe6a43SSeth Howell 142407fe6a43SSeth Howell base->info.num_blocks = from_be64(base->payload) + 1; 142507fe6a43SSeth Howell base->info.block_size = from_be32(base->payload + 8); 142607fe6a43SSeth Howell rc = virtio_scsi_dev_add_tgt(base->svdev, &base->info); 142707fe6a43SSeth Howell if (rc != 0) { 142807fe6a43SSeth Howell return rc; 142907fe6a43SSeth Howell } 143007fe6a43SSeth Howell 143107fe6a43SSeth Howell return _virtio_scsi_dev_scan_next(base, 0); 143207fe6a43SSeth Howell } 143307fe6a43SSeth Howell 143407fe6a43SSeth Howell static void 143507fe6a43SSeth Howell process_scan_resp(struct virtio_scsi_scan_base *base) 143607fe6a43SSeth Howell { 143707fe6a43SSeth Howell struct virtio_scsi_cmd_req *req = &base->io_ctx.req; 143807fe6a43SSeth Howell struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp; 143907fe6a43SSeth Howell int rc, sk, asc, ascq; 144007fe6a43SSeth Howell uint8_t target_id; 144107fe6a43SSeth Howell 144207fe6a43SSeth Howell if (base->io_ctx.iov_req.iov_len < sizeof(struct virtio_scsi_cmd_req) || 144307fe6a43SSeth Howell base->io_ctx.iov_resp.iov_len < sizeof(struct virtio_scsi_cmd_resp)) { 144407fe6a43SSeth Howell SPDK_ERRLOG("Received target scan message with invalid length.\n"); 144507fe6a43SSeth Howell _virtio_scsi_dev_scan_next(base, -EIO); 144607fe6a43SSeth Howell return; 144707fe6a43SSeth Howell } 144807fe6a43SSeth Howell 144907fe6a43SSeth Howell get_scsi_status(resp, &sk, &asc, &ascq); 145007fe6a43SSeth Howell target_id = req->lun[1]; 145107fe6a43SSeth Howell 145207fe6a43SSeth Howell if (resp->response == VIRTIO_SCSI_S_BAD_TARGET || 145307fe6a43SSeth Howell resp->response == VIRTIO_SCSI_S_INCORRECT_LUN) { 145407fe6a43SSeth Howell _virtio_scsi_dev_scan_next(base, -ENODEV); 145507fe6a43SSeth Howell return; 145607fe6a43SSeth Howell } 145707fe6a43SSeth Howell 145807fe6a43SSeth Howell if (resp->response != VIRTIO_SCSI_S_OK || 145907fe6a43SSeth Howell (resp->status == SPDK_SCSI_STATUS_CHECK_CONDITION && 146007fe6a43SSeth Howell sk != SPDK_SCSI_SENSE_ILLEGAL_REQUEST)) { 146107fe6a43SSeth Howell assert(base->retries > 0); 146207fe6a43SSeth Howell base->retries--; 146307fe6a43SSeth Howell if (base->retries == 0) { 146407fe6a43SSeth Howell SPDK_NOTICELOG("Target %"PRIu8" is present, but unavailable.\n", target_id); 14652172c432STomasz Zawadzki SPDK_LOGDUMP(virtio, "CDB", req->cdb, sizeof(req->cdb)); 14662172c432STomasz Zawadzki SPDK_LOGDUMP(virtio, "SENSE DATA", resp->sense, sizeof(resp->sense)); 146707fe6a43SSeth Howell _virtio_scsi_dev_scan_next(base, -EBUSY); 146807fe6a43SSeth Howell return; 146907fe6a43SSeth Howell } 147007fe6a43SSeth Howell 147107fe6a43SSeth Howell /* resend the same request */ 147207fe6a43SSeth Howell rc = send_scan_io(base); 147307fe6a43SSeth Howell if (rc != 0) { 147407fe6a43SSeth Howell /* Let response poller do the resend */ 147507fe6a43SSeth Howell } 147607fe6a43SSeth Howell return; 147707fe6a43SSeth Howell } 147807fe6a43SSeth Howell 147907fe6a43SSeth Howell base->retries = SCAN_REQUEST_RETRIES; 148007fe6a43SSeth Howell 148107fe6a43SSeth Howell switch (req->cdb[0]) { 148207fe6a43SSeth Howell case SPDK_SPC_INQUIRY: 148307fe6a43SSeth Howell rc = process_scan_inquiry(base); 148407fe6a43SSeth Howell break; 148507fe6a43SSeth Howell case SPDK_SPC_TEST_UNIT_READY: 148607fe6a43SSeth Howell rc = process_scan_test_unit_ready(base); 148707fe6a43SSeth Howell break; 148807fe6a43SSeth Howell case SPDK_SBC_START_STOP_UNIT: 148907fe6a43SSeth Howell rc = process_scan_start_stop_unit(base); 149007fe6a43SSeth Howell break; 149107fe6a43SSeth Howell case SPDK_SBC_READ_CAPACITY_10: 149207fe6a43SSeth Howell rc = process_read_cap_10(base); 149307fe6a43SSeth Howell break; 149407fe6a43SSeth Howell case SPDK_SPC_SERVICE_ACTION_IN_16: 149507fe6a43SSeth Howell rc = process_read_cap_16(base); 149607fe6a43SSeth Howell break; 149707fe6a43SSeth Howell default: 149807fe6a43SSeth Howell SPDK_ERRLOG("Received invalid target scan message: cdb[0] = %"PRIu8".\n", req->cdb[0]); 149907fe6a43SSeth Howell rc = -1; 150007fe6a43SSeth Howell break; 150107fe6a43SSeth Howell } 150207fe6a43SSeth Howell 150307fe6a43SSeth Howell if (rc != 0) { 150407fe6a43SSeth Howell if (base->needs_resend) { 150507fe6a43SSeth Howell return; /* Let response poller do the resend */ 150607fe6a43SSeth Howell } 150707fe6a43SSeth Howell 150807fe6a43SSeth Howell _virtio_scsi_dev_scan_next(base, rc); 150907fe6a43SSeth Howell } 151007fe6a43SSeth Howell } 151107fe6a43SSeth Howell 151207fe6a43SSeth Howell static int 151307fe6a43SSeth Howell _virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base, int rc) 151407fe6a43SSeth Howell { 151507fe6a43SSeth Howell struct virtio_scsi_scan_info *next; 151607fe6a43SSeth Howell struct virtio_scsi_disk *disk; 151707fe6a43SSeth Howell uint8_t target_id; 151807fe6a43SSeth Howell 151907fe6a43SSeth Howell if (base->full_scan) { 152007fe6a43SSeth Howell if (rc != 0) { 152107fe6a43SSeth Howell disk = virtio_scsi_dev_get_disk_by_id(base->svdev, 152207fe6a43SSeth Howell base->info.target); 152307fe6a43SSeth Howell if (disk != NULL) { 152407fe6a43SSeth Howell spdk_bdev_unregister(&disk->bdev, NULL, NULL); 152507fe6a43SSeth Howell } 152607fe6a43SSeth Howell } 152707fe6a43SSeth Howell 152807fe6a43SSeth Howell target_id = base->info.target + 1; 152907fe6a43SSeth Howell if (target_id < BDEV_VIRTIO_MAX_TARGET) { 153007fe6a43SSeth Howell _virtio_scsi_dev_scan_tgt(base, target_id); 153107fe6a43SSeth Howell return 0; 153207fe6a43SSeth Howell } 153307fe6a43SSeth Howell 153407fe6a43SSeth Howell base->full_scan = false; 153507fe6a43SSeth Howell } 153607fe6a43SSeth Howell 153707fe6a43SSeth Howell next = TAILQ_FIRST(&base->scan_queue); 153807fe6a43SSeth Howell if (next == NULL) { 153907fe6a43SSeth Howell _virtio_scsi_dev_scan_finish(base, 0); 154007fe6a43SSeth Howell return 0; 154107fe6a43SSeth Howell } 154207fe6a43SSeth Howell 154307fe6a43SSeth Howell TAILQ_REMOVE(&base->scan_queue, next, tailq); 154407fe6a43SSeth Howell target_id = next->target; 154507fe6a43SSeth Howell free(next); 154607fe6a43SSeth Howell 154707fe6a43SSeth Howell _virtio_scsi_dev_scan_tgt(base, target_id); 154807fe6a43SSeth Howell return 0; 154907fe6a43SSeth Howell } 155007fe6a43SSeth Howell 155107fe6a43SSeth Howell static int 155207fe6a43SSeth Howell _virtio_scsi_dev_scan_init(struct virtio_scsi_dev *svdev) 155307fe6a43SSeth Howell { 155407fe6a43SSeth Howell struct virtio_scsi_scan_base *base; 155507fe6a43SSeth Howell struct spdk_io_channel *io_ch; 155607fe6a43SSeth Howell struct virtio_scsi_io_ctx *io_ctx; 155707fe6a43SSeth Howell struct virtio_scsi_cmd_req *req; 155807fe6a43SSeth Howell struct virtio_scsi_cmd_resp *resp; 155907fe6a43SSeth Howell 156007fe6a43SSeth Howell io_ch = spdk_get_io_channel(svdev); 156107fe6a43SSeth Howell if (io_ch == NULL) { 156207fe6a43SSeth Howell return -EBUSY; 156307fe6a43SSeth Howell } 156407fe6a43SSeth Howell 156507fe6a43SSeth Howell base = spdk_zmalloc(sizeof(*base), 64, NULL, 156607fe6a43SSeth Howell SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 156707fe6a43SSeth Howell if (base == NULL) { 156807fe6a43SSeth Howell SPDK_ERRLOG("couldn't allocate memory for scsi target scan.\n"); 156907fe6a43SSeth Howell return -ENOMEM; 157007fe6a43SSeth Howell } 157107fe6a43SSeth Howell 157207fe6a43SSeth Howell base->svdev = svdev; 157307fe6a43SSeth Howell 157407fe6a43SSeth Howell base->channel = spdk_io_channel_get_ctx(io_ch); 157507fe6a43SSeth Howell TAILQ_INIT(&base->scan_queue); 157607fe6a43SSeth Howell svdev->scan_ctx = base; 157707fe6a43SSeth Howell 157807fe6a43SSeth Howell base->iov.iov_base = base->payload; 157907fe6a43SSeth Howell io_ctx = &base->io_ctx; 158007fe6a43SSeth Howell req = &io_ctx->req; 158107fe6a43SSeth Howell resp = &io_ctx->resp; 158207fe6a43SSeth Howell io_ctx->iov_req.iov_base = req; 158307fe6a43SSeth Howell io_ctx->iov_req.iov_len = sizeof(*req); 158407fe6a43SSeth Howell io_ctx->iov_resp.iov_base = resp; 158507fe6a43SSeth Howell io_ctx->iov_resp.iov_len = sizeof(*resp); 158607fe6a43SSeth Howell 158707fe6a43SSeth Howell base->retries = SCAN_REQUEST_RETRIES; 158807fe6a43SSeth Howell return 0; 158907fe6a43SSeth Howell } 159007fe6a43SSeth Howell 159107fe6a43SSeth Howell static void 159207fe6a43SSeth Howell _virtio_scsi_dev_scan_tgt(struct virtio_scsi_scan_base *base, uint8_t target) 159307fe6a43SSeth Howell { 159407fe6a43SSeth Howell int rc; 159507fe6a43SSeth Howell 159607fe6a43SSeth Howell memset(&base->info, 0, sizeof(base->info)); 159707fe6a43SSeth Howell base->info.target = target; 159807fe6a43SSeth Howell 159907fe6a43SSeth Howell rc = send_inquiry(base); 160007fe6a43SSeth Howell if (rc) { 160107fe6a43SSeth Howell /* Let response poller do the resend */ 160207fe6a43SSeth Howell } 160307fe6a43SSeth Howell } 160407fe6a43SSeth Howell 160507fe6a43SSeth Howell static int 160607fe6a43SSeth Howell virtio_scsi_dev_scan(struct virtio_scsi_dev *svdev, bdev_virtio_create_cb cb_fn, 160707fe6a43SSeth Howell void *cb_arg) 160807fe6a43SSeth Howell { 160907fe6a43SSeth Howell struct virtio_scsi_scan_base *base; 161007fe6a43SSeth Howell struct virtio_scsi_scan_info *tgt, *next_tgt; 161107fe6a43SSeth Howell int rc; 161207fe6a43SSeth Howell 161307fe6a43SSeth Howell if (svdev->scan_ctx) { 161407fe6a43SSeth Howell if (svdev->scan_ctx->full_scan) { 161507fe6a43SSeth Howell return -EEXIST; 161607fe6a43SSeth Howell } 161707fe6a43SSeth Howell 161807fe6a43SSeth Howell /* We're about to start a full rescan, so there's no need 161907fe6a43SSeth Howell * to scan particular targets afterwards. 162007fe6a43SSeth Howell */ 162107fe6a43SSeth Howell TAILQ_FOREACH_SAFE(tgt, &svdev->scan_ctx->scan_queue, tailq, next_tgt) { 162207fe6a43SSeth Howell TAILQ_REMOVE(&svdev->scan_ctx->scan_queue, tgt, tailq); 162307fe6a43SSeth Howell free(tgt); 162407fe6a43SSeth Howell } 162507fe6a43SSeth Howell 162607fe6a43SSeth Howell svdev->scan_ctx->cb_fn = cb_fn; 162707fe6a43SSeth Howell svdev->scan_ctx->cb_arg = cb_arg; 162807fe6a43SSeth Howell svdev->scan_ctx->restart = true; 162907fe6a43SSeth Howell return 0; 163007fe6a43SSeth Howell } 163107fe6a43SSeth Howell 163207fe6a43SSeth Howell rc = _virtio_scsi_dev_scan_init(svdev); 163307fe6a43SSeth Howell if (rc != 0) { 163407fe6a43SSeth Howell return rc; 163507fe6a43SSeth Howell } 163607fe6a43SSeth Howell 163707fe6a43SSeth Howell base = svdev->scan_ctx; 163807fe6a43SSeth Howell base->cb_fn = cb_fn; 163907fe6a43SSeth Howell base->cb_arg = cb_arg; 164007fe6a43SSeth Howell base->full_scan = true; 164107fe6a43SSeth Howell 164207fe6a43SSeth Howell _virtio_scsi_dev_scan_tgt(base, 0); 164307fe6a43SSeth Howell return 0; 164407fe6a43SSeth Howell } 164507fe6a43SSeth Howell 164607fe6a43SSeth Howell static int 164707fe6a43SSeth Howell virtio_scsi_dev_scan_tgt(struct virtio_scsi_dev *svdev, uint8_t target) 164807fe6a43SSeth Howell { 164907fe6a43SSeth Howell struct virtio_scsi_scan_base *base; 165007fe6a43SSeth Howell struct virtio_scsi_scan_info *info; 165107fe6a43SSeth Howell int rc; 165207fe6a43SSeth Howell 165307fe6a43SSeth Howell base = svdev->scan_ctx; 165407fe6a43SSeth Howell if (base) { 165507fe6a43SSeth Howell info = calloc(1, sizeof(*info)); 165607fe6a43SSeth Howell if (info == NULL) { 165707fe6a43SSeth Howell SPDK_ERRLOG("calloc failed\n"); 165807fe6a43SSeth Howell return -ENOMEM; 165907fe6a43SSeth Howell } 166007fe6a43SSeth Howell 166107fe6a43SSeth Howell info->target = target; 166207fe6a43SSeth Howell TAILQ_INSERT_TAIL(&base->scan_queue, info, tailq); 166307fe6a43SSeth Howell return 0; 166407fe6a43SSeth Howell } 166507fe6a43SSeth Howell 166607fe6a43SSeth Howell rc = _virtio_scsi_dev_scan_init(svdev); 166707fe6a43SSeth Howell if (rc != 0) { 166807fe6a43SSeth Howell return rc; 166907fe6a43SSeth Howell } 167007fe6a43SSeth Howell 167107fe6a43SSeth Howell base = svdev->scan_ctx; 167207fe6a43SSeth Howell base->full_scan = true; 167307fe6a43SSeth Howell _virtio_scsi_dev_scan_tgt(base, target); 167407fe6a43SSeth Howell return 0; 167507fe6a43SSeth Howell } 167607fe6a43SSeth Howell 167707fe6a43SSeth Howell static int 167807fe6a43SSeth Howell bdev_virtio_initialize(void) 167907fe6a43SSeth Howell { 168007fe6a43SSeth Howell return 0; 168107fe6a43SSeth Howell } 168207fe6a43SSeth Howell 168307fe6a43SSeth Howell static void 168407fe6a43SSeth Howell _virtio_scsi_dev_unregister_cb(void *io_device) 168507fe6a43SSeth Howell { 168607fe6a43SSeth Howell struct virtio_scsi_dev *svdev = io_device; 168707fe6a43SSeth Howell struct virtio_dev *vdev = &svdev->vdev; 168807fe6a43SSeth Howell bool finish_module; 168907fe6a43SSeth Howell bdev_virtio_remove_cb remove_cb; 169007fe6a43SSeth Howell void *remove_ctx; 169107fe6a43SSeth Howell 169207fe6a43SSeth Howell assert(spdk_ring_count(svdev->ctrlq_ring) == 0); 169307fe6a43SSeth Howell spdk_ring_free(svdev->ctrlq_ring); 169407fe6a43SSeth Howell spdk_poller_unregister(&svdev->mgmt_poller); 169507fe6a43SSeth Howell 169607fe6a43SSeth Howell virtio_dev_release_queue(vdev, VIRTIO_SCSI_EVENTQ); 169707fe6a43SSeth Howell virtio_dev_release_queue(vdev, VIRTIO_SCSI_CONTROLQ); 169807fe6a43SSeth Howell 169907fe6a43SSeth Howell virtio_dev_stop(vdev); 170007fe6a43SSeth Howell virtio_dev_destruct(vdev); 170107fe6a43SSeth Howell 170207fe6a43SSeth Howell pthread_mutex_lock(&g_virtio_scsi_mutex); 170307fe6a43SSeth Howell TAILQ_REMOVE(&g_virtio_scsi_devs, svdev, tailq); 170407fe6a43SSeth Howell pthread_mutex_unlock(&g_virtio_scsi_mutex); 170507fe6a43SSeth Howell 170607fe6a43SSeth Howell remove_cb = svdev->remove_cb; 170707fe6a43SSeth Howell remove_ctx = svdev->remove_ctx; 170807fe6a43SSeth Howell spdk_free(svdev->eventq_ios); 170907fe6a43SSeth Howell free(svdev); 171007fe6a43SSeth Howell 171107fe6a43SSeth Howell if (remove_cb) { 171207fe6a43SSeth Howell remove_cb(remove_ctx, 0); 171307fe6a43SSeth Howell } 171407fe6a43SSeth Howell 171507fe6a43SSeth Howell finish_module = TAILQ_EMPTY(&g_virtio_scsi_devs); 171607fe6a43SSeth Howell 171707fe6a43SSeth Howell if (g_bdev_virtio_finish && finish_module) { 1718511fe155STomasz Zawadzki spdk_bdev_module_fini_done(); 171907fe6a43SSeth Howell } 172007fe6a43SSeth Howell } 172107fe6a43SSeth Howell 172207fe6a43SSeth Howell static void 172307fe6a43SSeth Howell virtio_scsi_dev_unregister_cb(void *io_device) 172407fe6a43SSeth Howell { 172507fe6a43SSeth Howell struct virtio_scsi_dev *svdev = io_device; 172607fe6a43SSeth Howell struct spdk_thread *thread; 172707fe6a43SSeth Howell 172807fe6a43SSeth Howell thread = virtio_dev_queue_get_thread(&svdev->vdev, VIRTIO_SCSI_CONTROLQ); 172907fe6a43SSeth Howell spdk_thread_send_msg(thread, _virtio_scsi_dev_unregister_cb, io_device); 173007fe6a43SSeth Howell } 173107fe6a43SSeth Howell 173207fe6a43SSeth Howell static void 173307fe6a43SSeth Howell virtio_scsi_dev_remove(struct virtio_scsi_dev *svdev, 173407fe6a43SSeth Howell bdev_virtio_remove_cb cb_fn, void *cb_arg) 173507fe6a43SSeth Howell { 173607fe6a43SSeth Howell struct virtio_scsi_disk *disk, *disk_tmp; 173707fe6a43SSeth Howell bool do_remove = true; 173807fe6a43SSeth Howell 173907fe6a43SSeth Howell if (svdev->removed) { 174007fe6a43SSeth Howell if (cb_fn) { 174107fe6a43SSeth Howell cb_fn(cb_arg, -EBUSY); 174207fe6a43SSeth Howell } 174307fe6a43SSeth Howell return; 174407fe6a43SSeth Howell } 174507fe6a43SSeth Howell 174607fe6a43SSeth Howell svdev->remove_cb = cb_fn; 174707fe6a43SSeth Howell svdev->remove_ctx = cb_arg; 174807fe6a43SSeth Howell svdev->removed = true; 174907fe6a43SSeth Howell 175007fe6a43SSeth Howell if (svdev->scan_ctx) { 175107fe6a43SSeth Howell /* The removal will continue after we receive a pending scan I/O. */ 175207fe6a43SSeth Howell return; 175307fe6a43SSeth Howell } 175407fe6a43SSeth Howell 175507fe6a43SSeth Howell TAILQ_FOREACH_SAFE(disk, &svdev->luns, link, disk_tmp) { 175607fe6a43SSeth Howell if (!disk->removed) { 175707fe6a43SSeth Howell spdk_bdev_unregister(&disk->bdev, NULL, NULL); 175807fe6a43SSeth Howell } 175907fe6a43SSeth Howell do_remove = false; 176007fe6a43SSeth Howell } 176107fe6a43SSeth Howell 176207fe6a43SSeth Howell if (do_remove) { 176307fe6a43SSeth Howell spdk_io_device_unregister(svdev, virtio_scsi_dev_unregister_cb); 176407fe6a43SSeth Howell } 176507fe6a43SSeth Howell } 176607fe6a43SSeth Howell 176707fe6a43SSeth Howell static void 176807fe6a43SSeth Howell bdev_virtio_finish(void) 176907fe6a43SSeth Howell { 177007fe6a43SSeth Howell struct virtio_scsi_dev *svdev, *next; 177107fe6a43SSeth Howell 177207fe6a43SSeth Howell g_bdev_virtio_finish = true; 177307fe6a43SSeth Howell 177407fe6a43SSeth Howell pthread_mutex_lock(&g_virtio_scsi_mutex); 177507fe6a43SSeth Howell if (TAILQ_EMPTY(&g_virtio_scsi_devs)) { 177607fe6a43SSeth Howell pthread_mutex_unlock(&g_virtio_scsi_mutex); 1777511fe155STomasz Zawadzki spdk_bdev_module_fini_done(); 177807fe6a43SSeth Howell return; 177907fe6a43SSeth Howell } 178007fe6a43SSeth Howell 178107fe6a43SSeth Howell /* Defer module finish until all controllers are removed. */ 178207fe6a43SSeth Howell TAILQ_FOREACH_SAFE(svdev, &g_virtio_scsi_devs, tailq, next) { 178307fe6a43SSeth Howell virtio_scsi_dev_remove(svdev, NULL, NULL); 178407fe6a43SSeth Howell } 178507fe6a43SSeth Howell pthread_mutex_unlock(&g_virtio_scsi_mutex); 178607fe6a43SSeth Howell } 178707fe6a43SSeth Howell 178807fe6a43SSeth Howell int 178907fe6a43SSeth Howell bdev_virtio_user_scsi_dev_create(const char *base_name, const char *path, 179007fe6a43SSeth Howell unsigned num_queues, unsigned queue_size, 179107fe6a43SSeth Howell bdev_virtio_create_cb cb_fn, void *cb_arg) 179207fe6a43SSeth Howell { 179307fe6a43SSeth Howell struct virtio_scsi_dev *svdev; 179407fe6a43SSeth Howell int rc; 179507fe6a43SSeth Howell 179607fe6a43SSeth Howell svdev = virtio_user_scsi_dev_create(base_name, path, num_queues, queue_size); 179707fe6a43SSeth Howell if (svdev == NULL) { 179807fe6a43SSeth Howell return -1; 179907fe6a43SSeth Howell } 180007fe6a43SSeth Howell 180107fe6a43SSeth Howell rc = virtio_scsi_dev_scan(svdev, cb_fn, cb_arg); 180207fe6a43SSeth Howell if (rc) { 180307fe6a43SSeth Howell virtio_scsi_dev_remove(svdev, NULL, NULL); 180407fe6a43SSeth Howell } 180507fe6a43SSeth Howell 180607fe6a43SSeth Howell return rc; 180707fe6a43SSeth Howell } 180807fe6a43SSeth Howell 18098b260d5cSChangpeng Liu int 18108b260d5cSChangpeng Liu bdev_vfio_user_scsi_dev_create(const char *base_name, const char *path, 18118b260d5cSChangpeng Liu bdev_virtio_create_cb cb_fn, void *cb_arg) 18128b260d5cSChangpeng Liu { 18138b260d5cSChangpeng Liu struct virtio_scsi_dev *svdev; 18148b260d5cSChangpeng Liu uint32_t num_queues = 0; 18158b260d5cSChangpeng Liu int rc; 18168b260d5cSChangpeng Liu 18178b260d5cSChangpeng Liu svdev = calloc(1, sizeof(*svdev)); 18188b260d5cSChangpeng Liu if (svdev == NULL) { 18198b260d5cSChangpeng Liu SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", base_name, path); 18208b260d5cSChangpeng Liu return -ENOMEM; 18218b260d5cSChangpeng Liu } 18228b260d5cSChangpeng Liu 18238b260d5cSChangpeng Liu rc = virtio_vfio_user_dev_init(&svdev->vdev, base_name, path); 18248b260d5cSChangpeng Liu if (rc != 0) { 18258b260d5cSChangpeng Liu SPDK_ERRLOG("Failed to create %s as virtio device\n", path); 18268b260d5cSChangpeng Liu free(svdev); 18278b260d5cSChangpeng Liu return -EFAULT; 18288b260d5cSChangpeng Liu } 18298b260d5cSChangpeng Liu 18308b260d5cSChangpeng Liu rc = virtio_dev_read_dev_config(&svdev->vdev, offsetof(struct virtio_scsi_config, num_queues), 18318b260d5cSChangpeng Liu &num_queues, sizeof(num_queues)); 18328b260d5cSChangpeng Liu if (rc) { 18338b260d5cSChangpeng Liu SPDK_ERRLOG("%s: config read failed: %s\n", base_name, spdk_strerror(-rc)); 18348b260d5cSChangpeng Liu virtio_dev_destruct(&svdev->vdev); 18358b260d5cSChangpeng Liu free(svdev); 18368b260d5cSChangpeng Liu return rc; 18378b260d5cSChangpeng Liu } 18388b260d5cSChangpeng Liu 18398b260d5cSChangpeng Liu if (num_queues < SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED) { 18408b260d5cSChangpeng Liu SPDK_ERRLOG("%s: invalid num_queues %u\n", base_name, num_queues); 18418b260d5cSChangpeng Liu virtio_dev_destruct(&svdev->vdev); 18428b260d5cSChangpeng Liu free(svdev); 18438b260d5cSChangpeng Liu return -EINVAL; 18448b260d5cSChangpeng Liu } 18458b260d5cSChangpeng Liu 18468b260d5cSChangpeng Liu rc = virtio_scsi_dev_init(svdev, num_queues, VIRTIO_SCSI_DEV_SUPPORTED_FEATURES); 18478b260d5cSChangpeng Liu if (rc != 0) { 18488b260d5cSChangpeng Liu virtio_dev_destruct(&svdev->vdev); 18498b260d5cSChangpeng Liu free(svdev); 18508b260d5cSChangpeng Liu return -EFAULT; 18518b260d5cSChangpeng Liu } 18528b260d5cSChangpeng Liu 18538b260d5cSChangpeng Liu rc = virtio_scsi_dev_scan(svdev, cb_fn, cb_arg); 18548b260d5cSChangpeng Liu if (rc) { 18558b260d5cSChangpeng Liu virtio_scsi_dev_remove(svdev, NULL, NULL); 18568b260d5cSChangpeng Liu } 18578b260d5cSChangpeng Liu 18588b260d5cSChangpeng Liu return rc; 18598b260d5cSChangpeng Liu } 18608b260d5cSChangpeng Liu 186107fe6a43SSeth Howell struct bdev_virtio_pci_dev_create_ctx { 186207fe6a43SSeth Howell const char *name; 186307fe6a43SSeth Howell bdev_virtio_create_cb cb_fn; 186407fe6a43SSeth Howell void *cb_arg; 186507fe6a43SSeth Howell }; 186607fe6a43SSeth Howell 186707fe6a43SSeth Howell static int 186807fe6a43SSeth Howell bdev_virtio_pci_scsi_dev_create_cb(struct virtio_pci_ctx *pci_ctx, void *ctx) 186907fe6a43SSeth Howell { 187007fe6a43SSeth Howell struct virtio_scsi_dev *svdev; 187107fe6a43SSeth Howell struct bdev_virtio_pci_dev_create_ctx *create_ctx = ctx; 187207fe6a43SSeth Howell int rc; 187307fe6a43SSeth Howell 187407fe6a43SSeth Howell svdev = virtio_pci_scsi_dev_create(create_ctx->name, pci_ctx); 187507fe6a43SSeth Howell if (svdev == NULL) { 187607fe6a43SSeth Howell return -1; 187707fe6a43SSeth Howell } 187807fe6a43SSeth Howell 187907fe6a43SSeth Howell rc = virtio_scsi_dev_scan(svdev, create_ctx->cb_fn, create_ctx->cb_arg); 188007fe6a43SSeth Howell if (rc) { 18817ef6d8ddSJin Yu svdev->vdev.ctx = NULL; 188207fe6a43SSeth Howell virtio_scsi_dev_remove(svdev, NULL, NULL); 188307fe6a43SSeth Howell } 188407fe6a43SSeth Howell 188507fe6a43SSeth Howell return rc; 188607fe6a43SSeth Howell } 188707fe6a43SSeth Howell 188807fe6a43SSeth Howell int 188907fe6a43SSeth Howell bdev_virtio_pci_scsi_dev_create(const char *name, struct spdk_pci_addr *pci_addr, 189007fe6a43SSeth Howell bdev_virtio_create_cb cb_fn, void *cb_arg) 189107fe6a43SSeth Howell { 189207fe6a43SSeth Howell struct bdev_virtio_pci_dev_create_ctx create_ctx; 189307fe6a43SSeth Howell 189407fe6a43SSeth Howell create_ctx.name = name; 189507fe6a43SSeth Howell create_ctx.cb_fn = cb_fn; 189607fe6a43SSeth Howell create_ctx.cb_arg = cb_arg; 189707fe6a43SSeth Howell 189807fe6a43SSeth Howell return virtio_pci_dev_attach(bdev_virtio_pci_scsi_dev_create_cb, &create_ctx, 18994c890c31SJin Yu VIRTIO_ID_SCSI, pci_addr); 190007fe6a43SSeth Howell } 190107fe6a43SSeth Howell 190207fe6a43SSeth Howell int 190307fe6a43SSeth Howell bdev_virtio_scsi_dev_remove(const char *name, bdev_virtio_remove_cb cb_fn, void *cb_arg) 190407fe6a43SSeth Howell { 190507fe6a43SSeth Howell struct virtio_scsi_dev *svdev; 190607fe6a43SSeth Howell 190707fe6a43SSeth Howell pthread_mutex_lock(&g_virtio_scsi_mutex); 190807fe6a43SSeth Howell TAILQ_FOREACH(svdev, &g_virtio_scsi_devs, tailq) { 190907fe6a43SSeth Howell if (strcmp(svdev->vdev.name, name) == 0) { 191007fe6a43SSeth Howell break; 191107fe6a43SSeth Howell } 191207fe6a43SSeth Howell } 191307fe6a43SSeth Howell 191407fe6a43SSeth Howell if (svdev == NULL) { 191507fe6a43SSeth Howell pthread_mutex_unlock(&g_virtio_scsi_mutex); 191607fe6a43SSeth Howell SPDK_ERRLOG("Cannot find Virtio-SCSI device named '%s'\n", name); 191707fe6a43SSeth Howell return -ENODEV; 191807fe6a43SSeth Howell } 191907fe6a43SSeth Howell 192007fe6a43SSeth Howell virtio_scsi_dev_remove(svdev, cb_fn, cb_arg); 192107fe6a43SSeth Howell pthread_mutex_unlock(&g_virtio_scsi_mutex); 192207fe6a43SSeth Howell 192307fe6a43SSeth Howell return 0; 192407fe6a43SSeth Howell } 192507fe6a43SSeth Howell 192607fe6a43SSeth Howell void 192707fe6a43SSeth Howell bdev_virtio_scsi_dev_list(struct spdk_json_write_ctx *w) 192807fe6a43SSeth Howell { 192907fe6a43SSeth Howell struct virtio_scsi_dev *svdev; 193007fe6a43SSeth Howell 193107fe6a43SSeth Howell spdk_json_write_array_begin(w); 193207fe6a43SSeth Howell 193307fe6a43SSeth Howell pthread_mutex_lock(&g_virtio_scsi_mutex); 193407fe6a43SSeth Howell TAILQ_FOREACH(svdev, &g_virtio_scsi_devs, tailq) { 193507fe6a43SSeth Howell spdk_json_write_object_begin(w); 193607fe6a43SSeth Howell 193707fe6a43SSeth Howell spdk_json_write_named_string(w, "name", svdev->vdev.name); 193807fe6a43SSeth Howell 193907fe6a43SSeth Howell virtio_dev_dump_json_info(&svdev->vdev, w); 194007fe6a43SSeth Howell 194107fe6a43SSeth Howell spdk_json_write_object_end(w); 194207fe6a43SSeth Howell } 194307fe6a43SSeth Howell pthread_mutex_unlock(&g_virtio_scsi_mutex); 194407fe6a43SSeth Howell 194507fe6a43SSeth Howell spdk_json_write_array_end(w); 194607fe6a43SSeth Howell } 194707fe6a43SSeth Howell 19482172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(virtio) 1949