2017-05-30 21:13:50 +00:00
|
|
|
/*-
|
|
|
|
* BSD LICENSE
|
|
|
|
*
|
|
|
|
* Copyright (c) Intel Corporation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
|
|
|
|
#include "spdk/bdev.h"
|
|
|
|
#include "spdk/conf.h"
|
2017-10-16 21:50:19 +00:00
|
|
|
#include "spdk/endian.h"
|
2017-05-30 21:13:50 +00:00
|
|
|
#include "spdk/env.h"
|
2018-06-11 20:32:15 +00:00
|
|
|
#include "spdk/thread.h"
|
2017-10-16 21:50:19 +00:00
|
|
|
#include "spdk/scsi_spec.h"
|
2017-05-30 21:13:50 +00:00
|
|
|
#include "spdk/string.h"
|
2017-08-21 18:50:56 +00:00
|
|
|
#include "spdk/util.h"
|
2017-10-09 18:45:13 +00:00
|
|
|
#include "spdk/json.h"
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2018-05-23 21:01:03 +00:00
|
|
|
#include "spdk/bdev_module.h"
|
2017-05-30 21:13:50 +00:00
|
|
|
#include "spdk_internal/log.h"
|
2017-11-20 12:17:52 +00:00
|
|
|
#include "spdk_internal/virtio.h"
|
2019-12-19 07:29:39 +00:00
|
|
|
#include "spdk_internal/vhost_user.h"
|
2017-05-30 21:13:50 +00:00
|
|
|
|
|
|
|
#include <linux/virtio_scsi.h>
|
|
|
|
|
2017-10-03 18:23:37 +00:00
|
|
|
#include "bdev_virtio.h"
|
|
|
|
|
2017-08-24 19:13:12 +00:00
|
|
|
#define BDEV_VIRTIO_MAX_TARGET 64
|
|
|
|
#define BDEV_VIRTIO_SCAN_PAYLOAD_SIZE 256
|
2017-12-02 09:34:55 +00:00
|
|
|
#define MGMT_POLL_PERIOD_US (1000 * 5)
|
2017-10-11 15:51:33 +00:00
|
|
|
#define CTRLQ_RING_SIZE 16
|
2017-10-25 08:08:37 +00:00
|
|
|
#define SCAN_REQUEST_RETRIES 5
|
2017-08-24 19:13:12 +00:00
|
|
|
|
2017-11-20 22:22:02 +00:00
|
|
|
/* Number of non-request queues - eventq and controlq */
|
|
|
|
#define SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED 2
|
|
|
|
|
2017-12-02 12:08:07 +00:00
|
|
|
#define VIRTIO_SCSI_EVENTQ_BUFFER_COUNT 16
|
|
|
|
|
2017-10-12 17:00:42 +00:00
|
|
|
#define VIRTIO_SCSI_CONTROLQ 0
|
|
|
|
#define VIRTIO_SCSI_EVENTQ 1
|
|
|
|
#define VIRTIO_SCSI_REQUESTQ 2
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
static int bdev_virtio_initialize(void);
|
|
|
|
static void bdev_virtio_finish(void);
|
|
|
|
|
2017-11-30 10:58:25 +00:00
|
|
|
struct virtio_scsi_dev {
|
|
|
|
/* Generic virtio device data. */
|
|
|
|
struct virtio_dev vdev;
|
2017-11-30 15:13:38 +00:00
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
/** Detected SCSI LUNs */
|
|
|
|
TAILQ_HEAD(, virtio_scsi_disk) luns;
|
|
|
|
|
2017-11-30 15:13:38 +00:00
|
|
|
/** Context for the SCSI target scan. */
|
|
|
|
struct virtio_scsi_scan_base *scan_ctx;
|
2017-12-01 00:46:59 +00:00
|
|
|
|
2017-12-02 09:34:55 +00:00
|
|
|
/** Controlq poller. */
|
|
|
|
struct spdk_poller *mgmt_poller;
|
|
|
|
|
|
|
|
/** Controlq messages to be sent. */
|
|
|
|
struct spdk_ring *ctrlq_ring;
|
|
|
|
|
2017-12-02 12:08:07 +00:00
|
|
|
/** Buffers for the eventq. */
|
|
|
|
struct virtio_scsi_eventq_io *eventq_ios;
|
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
/** Device marked for removal. */
|
2018-01-10 05:28:40 +00:00
|
|
|
bool removed;
|
|
|
|
|
|
|
|
/** Callback to be called after vdev removal. */
|
|
|
|
bdev_virtio_remove_cb remove_cb;
|
|
|
|
|
|
|
|
/** Context for the `remove_cb`. */
|
|
|
|
void *remove_ctx;
|
2018-03-23 12:49:35 +00:00
|
|
|
|
|
|
|
TAILQ_ENTRY(virtio_scsi_dev) tailq;
|
2017-11-30 10:58:25 +00:00
|
|
|
};
|
|
|
|
|
2017-08-24 19:13:12 +00:00
|
|
|
struct virtio_scsi_io_ctx {
|
2017-12-01 23:33:42 +00:00
|
|
|
struct iovec iov_req;
|
|
|
|
struct iovec iov_resp;
|
2017-10-11 15:51:33 +00:00
|
|
|
union {
|
|
|
|
struct virtio_scsi_cmd_req req;
|
|
|
|
struct virtio_scsi_ctrl_tmf_req tmf_req;
|
|
|
|
};
|
|
|
|
union {
|
|
|
|
struct virtio_scsi_cmd_resp resp;
|
|
|
|
struct virtio_scsi_ctrl_tmf_resp tmf_resp;
|
|
|
|
};
|
2017-08-24 19:13:12 +00:00
|
|
|
};
|
|
|
|
|
2017-12-02 12:08:07 +00:00
|
|
|
struct virtio_scsi_eventq_io {
|
|
|
|
struct iovec iov;
|
|
|
|
struct virtio_scsi_event ev;
|
|
|
|
};
|
|
|
|
|
2017-10-27 20:29:10 +00:00
|
|
|
struct virtio_scsi_scan_info {
|
|
|
|
uint64_t num_blocks;
|
|
|
|
uint32_t block_size;
|
|
|
|
uint8_t target;
|
2017-10-27 20:26:59 +00:00
|
|
|
bool unmap_supported;
|
2017-12-19 08:48:51 +00:00
|
|
|
TAILQ_ENTRY(virtio_scsi_scan_info) tailq;
|
2017-10-27 20:29:10 +00:00
|
|
|
};
|
|
|
|
|
2017-08-22 17:16:39 +00:00
|
|
|
struct virtio_scsi_scan_base {
|
2017-11-30 10:58:25 +00:00
|
|
|
struct virtio_scsi_dev *svdev;
|
2017-10-10 18:44:35 +00:00
|
|
|
|
2017-12-01 11:34:51 +00:00
|
|
|
/** I/O channel used for the scan I/O. */
|
|
|
|
struct bdev_virtio_io_channel *channel;
|
2017-09-12 18:53:17 +00:00
|
|
|
|
2017-11-30 10:09:23 +00:00
|
|
|
bdev_virtio_create_cb cb_fn;
|
2017-10-03 18:23:37 +00:00
|
|
|
void *cb_arg;
|
|
|
|
|
2017-12-19 08:48:51 +00:00
|
|
|
/** Scan all targets on the device. */
|
|
|
|
bool full_scan;
|
|
|
|
|
2017-12-19 09:28:05 +00:00
|
|
|
/** Start a full rescan after receiving next scan I/O response. */
|
|
|
|
bool restart;
|
|
|
|
|
2017-12-19 08:48:51 +00:00
|
|
|
/** Additional targets to be (re)scanned. */
|
|
|
|
TAILQ_HEAD(, virtio_scsi_scan_info) scan_queue;
|
|
|
|
|
2017-10-25 08:08:37 +00:00
|
|
|
/** Remaining attempts for sending the current request. */
|
|
|
|
unsigned retries;
|
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
/** If set, the last scan I/O needs to be resent */
|
|
|
|
bool needs_resend;
|
|
|
|
|
2017-09-12 18:53:17 +00:00
|
|
|
struct virtio_scsi_io_ctx io_ctx;
|
|
|
|
struct iovec iov;
|
|
|
|
uint8_t payload[BDEV_VIRTIO_SCAN_PAYLOAD_SIZE];
|
2017-10-27 20:29:10 +00:00
|
|
|
|
|
|
|
/** Scan results for the current target. */
|
|
|
|
struct virtio_scsi_scan_info info;
|
2017-08-22 17:16:39 +00:00
|
|
|
};
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
struct virtio_scsi_disk {
|
2017-10-27 20:29:10 +00:00
|
|
|
struct spdk_bdev bdev;
|
2017-11-30 10:58:25 +00:00
|
|
|
struct virtio_scsi_dev *svdev;
|
2017-10-27 20:29:10 +00:00
|
|
|
struct virtio_scsi_scan_info info;
|
2018-01-10 06:43:11 +00:00
|
|
|
|
|
|
|
/** Descriptor opened just to be notified of external bdev hotremove. */
|
|
|
|
struct spdk_bdev_desc *notify_desc;
|
|
|
|
|
|
|
|
/** Disk marked for removal. */
|
|
|
|
bool removed;
|
2017-10-27 20:29:10 +00:00
|
|
|
TAILQ_ENTRY(virtio_scsi_disk) link;
|
2017-05-30 21:13:50 +00:00
|
|
|
};
|
|
|
|
|
2017-08-21 18:50:56 +00:00
|
|
|
struct bdev_virtio_io_channel {
|
2017-11-30 10:58:25 +00:00
|
|
|
struct virtio_scsi_dev *svdev;
|
2017-10-10 18:44:35 +00:00
|
|
|
|
|
|
|
/** Virtqueue exclusively assigned to this channel. */
|
|
|
|
struct virtqueue *vq;
|
2017-12-02 09:34:55 +00:00
|
|
|
|
|
|
|
/** Virtio response poller. */
|
|
|
|
struct spdk_poller *poller;
|
2017-08-23 09:43:25 +00:00
|
|
|
};
|
|
|
|
|
2018-03-27 10:40:27 +00:00
|
|
|
static TAILQ_HEAD(, virtio_scsi_dev) g_virtio_scsi_devs =
|
2018-03-23 12:49:35 +00:00
|
|
|
TAILQ_HEAD_INITIALIZER(g_virtio_scsi_devs);
|
|
|
|
|
2018-03-27 10:40:27 +00:00
|
|
|
static pthread_mutex_t g_virtio_scsi_mutex = PTHREAD_MUTEX_INITIALIZER;
|
2018-03-25 12:03:28 +00:00
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
/** Module finish in progress */
|
|
|
|
static bool g_bdev_virtio_finish = false;
|
|
|
|
|
2017-12-21 15:01:06 +00:00
|
|
|
/* Features desired/implemented by this driver. */
|
|
|
|
#define VIRTIO_SCSI_DEV_SUPPORTED_FEATURES \
|
2017-12-02 12:08:07 +00:00
|
|
|
(1ULL << VIRTIO_SCSI_F_INOUT | \
|
2018-06-16 12:51:13 +00:00
|
|
|
1ULL << VIRTIO_SCSI_F_HOTPLUG | \
|
2018-07-02 10:43:05 +00:00
|
|
|
1ULL << VIRTIO_RING_F_EVENT_IDX | \
|
|
|
|
1ULL << VHOST_USER_F_PROTOCOL_FEATURES)
|
2017-12-21 15:01:06 +00:00
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
static void virtio_scsi_dev_unregister_cb(void *io_device);
|
2018-01-10 05:28:40 +00:00
|
|
|
static void virtio_scsi_dev_remove(struct virtio_scsi_dev *svdev,
|
|
|
|
bdev_virtio_remove_cb cb_fn, void *cb_arg);
|
2017-12-01 11:34:51 +00:00
|
|
|
static int bdev_virtio_scsi_ch_create_cb(void *io_device, void *ctx_buf);
|
|
|
|
static void bdev_virtio_scsi_ch_destroy_cb(void *io_device, void *ctx_buf);
|
2017-12-15 14:58:56 +00:00
|
|
|
static void process_scan_resp(struct virtio_scsi_scan_base *base);
|
2018-03-13 00:16:47 +00:00
|
|
|
static int bdev_virtio_mgmt_poll(void *arg);
|
2017-12-02 12:08:07 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
virtio_scsi_dev_send_eventq_io(struct virtqueue *vq, struct virtio_scsi_eventq_io *io)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = virtqueue_req_start(vq, io, 1);
|
|
|
|
if (rc != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtqueue_req_add_iovs(vq, &io->iov, 1, SPDK_VIRTIO_DESC_WR);
|
|
|
|
virtqueue_req_flush(vq);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2017-12-01 11:34:51 +00:00
|
|
|
|
2017-12-01 17:17:06 +00:00
|
|
|
static int
|
2017-12-27 14:51:17 +00:00
|
|
|
virtio_scsi_dev_init(struct virtio_scsi_dev *svdev, uint16_t max_queues)
|
2017-12-01 11:34:51 +00:00
|
|
|
{
|
2017-12-01 17:17:06 +00:00
|
|
|
struct virtio_dev *vdev = &svdev->vdev;
|
|
|
|
struct spdk_ring *ctrlq_ring;
|
2017-12-02 12:08:07 +00:00
|
|
|
struct virtio_scsi_eventq_io *eventq_io;
|
|
|
|
struct virtqueue *eventq;
|
|
|
|
uint16_t i, num_events;
|
2017-12-01 17:17:06 +00:00
|
|
|
int rc;
|
|
|
|
|
2017-12-27 14:51:17 +00:00
|
|
|
rc = virtio_dev_reset(vdev, VIRTIO_SCSI_DEV_SUPPORTED_FEATURES);
|
|
|
|
if (rc != 0) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = virtio_dev_start(vdev, max_queues, SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED);
|
2017-12-01 17:17:06 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrlq_ring = spdk_ring_create(SPDK_RING_TYPE_MP_SC, CTRLQ_RING_SIZE,
|
|
|
|
SPDK_ENV_SOCKET_ID_ANY);
|
|
|
|
if (ctrlq_ring == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to allocate send ring for the controlq.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = virtio_dev_acquire_queue(vdev, VIRTIO_SCSI_CONTROLQ);
|
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Failed to acquire the controlq.\n");
|
|
|
|
spdk_ring_free(ctrlq_ring);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-12-02 12:08:07 +00:00
|
|
|
rc = virtio_dev_acquire_queue(vdev, VIRTIO_SCSI_EVENTQ);
|
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Failed to acquire the eventq.\n");
|
|
|
|
virtio_dev_release_queue(vdev, VIRTIO_SCSI_CONTROLQ);
|
|
|
|
spdk_ring_free(ctrlq_ring);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
eventq = vdev->vqs[VIRTIO_SCSI_EVENTQ];
|
|
|
|
num_events = spdk_min(eventq->vq_nentries, VIRTIO_SCSI_EVENTQ_BUFFER_COUNT);
|
2019-03-15 14:35:49 +00:00
|
|
|
svdev->eventq_ios = spdk_zmalloc(sizeof(*svdev->eventq_ios) * num_events,
|
|
|
|
0, NULL, SPDK_ENV_LCORE_ID_ANY,
|
|
|
|
SPDK_MALLOC_DMA);
|
2017-12-02 12:08:07 +00:00
|
|
|
if (svdev->eventq_ios == NULL) {
|
2018-01-29 23:43:37 +00:00
|
|
|
SPDK_ERRLOG("cannot allocate memory for %"PRIu16" eventq buffers\n",
|
2017-12-02 12:08:07 +00:00
|
|
|
num_events);
|
|
|
|
virtio_dev_release_queue(vdev, VIRTIO_SCSI_EVENTQ);
|
|
|
|
virtio_dev_release_queue(vdev, VIRTIO_SCSI_CONTROLQ);
|
|
|
|
spdk_ring_free(ctrlq_ring);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < num_events; i++) {
|
|
|
|
eventq_io = &svdev->eventq_ios[i];
|
|
|
|
eventq_io->iov.iov_base = &eventq_io->ev;
|
|
|
|
eventq_io->iov.iov_len = sizeof(eventq_io->ev);
|
|
|
|
virtio_scsi_dev_send_eventq_io(eventq, eventq_io);
|
|
|
|
}
|
|
|
|
|
2017-12-02 09:34:55 +00:00
|
|
|
svdev->ctrlq_ring = ctrlq_ring;
|
2017-12-02 12:08:07 +00:00
|
|
|
|
2020-04-14 06:49:46 +00:00
|
|
|
svdev->mgmt_poller = SPDK_POLLER_REGISTER(bdev_virtio_mgmt_poll, svdev,
|
2017-12-02 09:34:55 +00:00
|
|
|
MGMT_POLL_PERIOD_US);
|
2017-12-01 17:17:06 +00:00
|
|
|
|
2017-12-01 11:34:51 +00:00
|
|
|
TAILQ_INIT(&svdev->luns);
|
|
|
|
svdev->scan_ctx = NULL;
|
|
|
|
svdev->removed = false;
|
2018-01-10 05:28:40 +00:00
|
|
|
svdev->remove_cb = NULL;
|
|
|
|
svdev->remove_ctx = NULL;
|
2017-12-01 11:34:51 +00:00
|
|
|
|
|
|
|
spdk_io_device_register(svdev, bdev_virtio_scsi_ch_create_cb,
|
|
|
|
bdev_virtio_scsi_ch_destroy_cb,
|
2018-08-30 20:26:50 +00:00
|
|
|
sizeof(struct bdev_virtio_io_channel),
|
|
|
|
svdev->vdev.name);
|
2017-12-01 11:34:51 +00:00
|
|
|
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_lock(&g_virtio_scsi_mutex);
|
2018-03-23 12:49:35 +00:00
|
|
|
TAILQ_INSERT_TAIL(&g_virtio_scsi_devs, svdev, tailq);
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
2017-12-01 17:17:06 +00:00
|
|
|
return 0;
|
2017-12-01 11:34:51 +00:00
|
|
|
}
|
2017-12-01 00:46:59 +00:00
|
|
|
|
2018-01-11 18:28:49 +00:00
|
|
|
static struct virtio_scsi_dev *
|
2018-01-11 18:42:04 +00:00
|
|
|
virtio_pci_scsi_dev_create(const char *name, struct virtio_pci_ctx *pci_ctx)
|
2017-11-20 22:22:02 +00:00
|
|
|
{
|
|
|
|
static int pci_dev_counter = 0;
|
2017-11-30 10:58:25 +00:00
|
|
|
struct virtio_scsi_dev *svdev;
|
2017-11-20 22:22:02 +00:00
|
|
|
struct virtio_dev *vdev;
|
2018-01-11 18:42:04 +00:00
|
|
|
char *default_name = NULL;
|
2017-11-20 22:22:02 +00:00
|
|
|
uint32_t num_queues;
|
|
|
|
int rc;
|
|
|
|
|
2017-11-30 10:58:25 +00:00
|
|
|
svdev = calloc(1, sizeof(*svdev));
|
|
|
|
if (svdev == NULL) {
|
2017-11-20 22:22:02 +00:00
|
|
|
SPDK_ERRLOG("virtio device calloc failed\n");
|
2018-01-11 18:28:49 +00:00
|
|
|
return NULL;
|
2017-11-20 22:22:02 +00:00
|
|
|
}
|
|
|
|
|
2017-11-30 10:58:25 +00:00
|
|
|
vdev = &svdev->vdev;
|
2017-11-20 22:22:02 +00:00
|
|
|
if (name == NULL) {
|
2018-01-11 18:42:04 +00:00
|
|
|
default_name = spdk_sprintf_alloc("VirtioScsi%"PRIu32, pci_dev_counter++);
|
|
|
|
if (default_name == NULL) {
|
|
|
|
free(vdev);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
name = default_name;
|
2017-11-20 22:22:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = virtio_pci_dev_init(vdev, name, pci_ctx);
|
2018-01-11 18:42:04 +00:00
|
|
|
free(default_name);
|
2017-11-20 22:22:02 +00:00
|
|
|
|
|
|
|
if (rc != 0) {
|
2017-11-30 10:58:25 +00:00
|
|
|
free(svdev);
|
2018-01-11 18:28:49 +00:00
|
|
|
return NULL;
|
2017-11-20 22:22:02 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 11:13:52 +00:00
|
|
|
rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_scsi_config, num_queues),
|
|
|
|
&num_queues, sizeof(num_queues));
|
|
|
|
if (rc) {
|
|
|
|
SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
|
2020-07-29 15:45:42 +00:00
|
|
|
goto fail;
|
2018-07-02 11:13:52 +00:00
|
|
|
}
|
2017-11-20 22:22:02 +00:00
|
|
|
|
2017-12-27 14:51:17 +00:00
|
|
|
rc = virtio_scsi_dev_init(svdev, num_queues);
|
2017-12-01 17:17:06 +00:00
|
|
|
if (rc != 0) {
|
2020-07-29 15:45:42 +00:00
|
|
|
goto fail;
|
2017-12-01 17:17:06 +00:00
|
|
|
}
|
|
|
|
|
2018-01-11 18:28:49 +00:00
|
|
|
return svdev;
|
2020-07-29 15:45:42 +00:00
|
|
|
|
|
|
|
fail:
|
|
|
|
vdev->ctx = NULL;
|
|
|
|
virtio_dev_destruct(vdev);
|
|
|
|
free(svdev);
|
|
|
|
return NULL;
|
2017-11-20 22:22:02 +00:00
|
|
|
}
|
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
static struct virtio_scsi_dev *
|
|
|
|
virtio_user_scsi_dev_create(const char *name, const char *path,
|
|
|
|
uint16_t num_queues, uint32_t queue_size)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_dev *svdev;
|
|
|
|
struct virtio_dev *vdev;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
svdev = calloc(1, sizeof(*svdev));
|
|
|
|
if (svdev == NULL) {
|
|
|
|
SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", name, path);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
vdev = &svdev->vdev;
|
2017-12-27 14:51:17 +00:00
|
|
|
rc = virtio_user_dev_init(vdev, name, path, queue_size);
|
2017-12-01 00:46:59 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Failed to create virito device %s: %s\n", name, path);
|
|
|
|
free(svdev);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-12-27 14:51:17 +00:00
|
|
|
rc = virtio_scsi_dev_init(svdev, num_queues);
|
2017-12-01 17:17:06 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
virtio_dev_destruct(vdev);
|
|
|
|
free(svdev);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
return svdev;
|
|
|
|
}
|
|
|
|
|
2017-12-02 12:08:07 +00:00
|
|
|
static struct virtio_scsi_disk *
|
|
|
|
virtio_scsi_dev_get_disk_by_id(struct virtio_scsi_dev *svdev, uint8_t target_id)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_disk *disk;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(disk, &svdev->luns, link) {
|
|
|
|
if (disk->info.target == target_id) {
|
|
|
|
return disk;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-12-22 11:58:30 +00:00
|
|
|
static int virtio_scsi_dev_scan(struct virtio_scsi_dev *svdev,
|
|
|
|
bdev_virtio_create_cb cb_fn, void *cb_arg);
|
2017-12-18 17:41:35 +00:00
|
|
|
static int send_scan_io(struct virtio_scsi_scan_base *base);
|
2017-12-22 10:57:52 +00:00
|
|
|
static void _virtio_scsi_dev_scan_tgt(struct virtio_scsi_scan_base *base, uint8_t target);
|
2018-03-01 16:16:44 +00:00
|
|
|
static int _virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base, int rc);
|
2017-12-18 17:41:35 +00:00
|
|
|
static void _virtio_scsi_dev_scan_finish(struct virtio_scsi_scan_base *base, int errnum);
|
2017-12-19 08:48:51 +00:00
|
|
|
static int virtio_scsi_dev_scan_tgt(struct virtio_scsi_dev *svdev, uint8_t target);
|
2017-09-12 18:53:17 +00:00
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
static int
|
|
|
|
bdev_virtio_get_ctx_size(void)
|
|
|
|
{
|
2017-08-23 09:43:25 +00:00
|
|
|
return sizeof(struct virtio_scsi_io_ctx);
|
2017-05-30 21:13:50 +00:00
|
|
|
}
|
|
|
|
|
2018-03-27 13:45:10 +00:00
|
|
|
static int
|
|
|
|
bdev_virtio_scsi_config_json(struct spdk_json_write_ctx *w)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_dev *svdev;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&g_virtio_scsi_mutex);
|
|
|
|
TAILQ_FOREACH(svdev, &g_virtio_scsi_devs, tailq) {
|
|
|
|
spdk_json_write_object_begin(w);
|
|
|
|
|
2019-09-11 12:50:38 +00:00
|
|
|
spdk_json_write_named_string(w, "method", "bdev_virtio_attach_controller");
|
2018-03-27 13:45:10 +00:00
|
|
|
|
|
|
|
spdk_json_write_named_object_begin(w, "params");
|
|
|
|
spdk_json_write_named_string(w, "name", svdev->vdev.name);
|
|
|
|
spdk_json_write_named_string(w, "dev_type", "scsi");
|
|
|
|
|
|
|
|
/* Write transport specific parameters. */
|
|
|
|
svdev->vdev.backend_ops->write_json_config(&svdev->vdev, w);
|
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-09 22:20:21 +00:00
|
|
|
static struct spdk_bdev_module virtio_scsi_if = {
|
2018-03-06 18:52:46 +00:00
|
|
|
.name = "virtio_scsi",
|
|
|
|
.module_init = bdev_virtio_initialize,
|
|
|
|
.module_fini = bdev_virtio_finish,
|
|
|
|
.get_ctx_size = bdev_virtio_get_ctx_size,
|
2018-03-27 13:45:10 +00:00
|
|
|
.config_json = bdev_virtio_scsi_config_json,
|
2018-03-06 18:52:46 +00:00
|
|
|
.async_init = true,
|
|
|
|
.async_fini = true,
|
|
|
|
};
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2019-02-05 10:46:48 +00:00
|
|
|
SPDK_BDEV_MODULE_REGISTER(virtio_scsi, &virtio_scsi_if)
|
2017-08-22 17:16:39 +00:00
|
|
|
|
2017-12-15 14:58:56 +00:00
|
|
|
static struct virtio_scsi_io_ctx *
|
2017-10-10 15:50:20 +00:00
|
|
|
bdev_virtio_init_io_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
2017-05-30 21:13:50 +00:00
|
|
|
{
|
|
|
|
struct virtio_scsi_cmd_req *req;
|
|
|
|
struct virtio_scsi_cmd_resp *resp;
|
|
|
|
struct virtio_scsi_disk *disk = (struct virtio_scsi_disk *)bdev_io->bdev;
|
2017-08-23 09:43:25 +00:00
|
|
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-08-23 09:43:25 +00:00
|
|
|
req = &io_ctx->req;
|
|
|
|
resp = &io_ctx->resp;
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-12-01 23:33:42 +00:00
|
|
|
io_ctx->iov_req.iov_base = req;
|
|
|
|
io_ctx->iov_req.iov_len = sizeof(*req);
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-12-01 23:33:42 +00:00
|
|
|
io_ctx->iov_resp.iov_base = resp;
|
|
|
|
io_ctx->iov_resp.iov_len = sizeof(*resp);
|
2017-05-30 21:13:50 +00:00
|
|
|
|
|
|
|
memset(req, 0, sizeof(*req));
|
|
|
|
req->lun[0] = 1;
|
2017-10-27 20:29:10 +00:00
|
|
|
req->lun[1] = disk->info.target;
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-12-15 14:58:56 +00:00
|
|
|
return io_ctx;
|
2017-09-06 18:51:28 +00:00
|
|
|
}
|
|
|
|
|
2017-12-15 14:58:56 +00:00
|
|
|
static struct virtio_scsi_io_ctx *
|
2017-10-11 15:51:33 +00:00
|
|
|
bdev_virtio_init_tmf_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_ctrl_tmf_req *tmf_req;
|
|
|
|
struct virtio_scsi_ctrl_tmf_resp *tmf_resp;
|
|
|
|
struct virtio_scsi_disk *disk = SPDK_CONTAINEROF(bdev_io->bdev, struct virtio_scsi_disk, bdev);
|
|
|
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
|
|
|
|
|
|
|
tmf_req = &io_ctx->tmf_req;
|
|
|
|
tmf_resp = &io_ctx->tmf_resp;
|
|
|
|
|
2017-12-01 23:33:42 +00:00
|
|
|
io_ctx->iov_req.iov_base = tmf_req;
|
|
|
|
io_ctx->iov_req.iov_len = sizeof(*tmf_req);
|
|
|
|
io_ctx->iov_resp.iov_base = tmf_resp;
|
|
|
|
io_ctx->iov_resp.iov_len = sizeof(*tmf_resp);
|
2017-10-11 15:51:33 +00:00
|
|
|
|
|
|
|
memset(tmf_req, 0, sizeof(*tmf_req));
|
|
|
|
tmf_req->lun[0] = 1;
|
2017-10-27 20:29:10 +00:00
|
|
|
tmf_req->lun[1] = disk->info.target;
|
2017-10-11 15:51:33 +00:00
|
|
|
|
2017-12-15 14:58:56 +00:00
|
|
|
return io_ctx;
|
2017-10-11 15:51:33 +00:00
|
|
|
}
|
|
|
|
|
2017-10-17 12:25:17 +00:00
|
|
|
static void
|
|
|
|
bdev_virtio_send_io(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
|
|
|
{
|
|
|
|
struct bdev_virtio_io_channel *virtio_channel = spdk_io_channel_get_ctx(ch);
|
2017-12-01 23:33:42 +00:00
|
|
|
struct virtqueue *vq = virtio_channel->vq;
|
2017-10-17 12:25:17 +00:00
|
|
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
|
|
|
int rc;
|
|
|
|
|
2017-12-01 23:33:42 +00:00
|
|
|
rc = virtqueue_req_start(vq, bdev_io, bdev_io->u.bdev.iovcnt + 2);
|
|
|
|
if (rc == -ENOMEM) {
|
2017-10-17 12:25:17 +00:00
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
|
2017-12-01 23:33:42 +00:00
|
|
|
return;
|
|
|
|
} else if (rc != 0) {
|
2017-10-17 12:25:17 +00:00
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
2017-12-01 23:33:42 +00:00
|
|
|
return;
|
2017-10-17 12:25:17 +00:00
|
|
|
}
|
2017-12-01 23:33:42 +00:00
|
|
|
|
|
|
|
virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
|
|
|
|
if (bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
|
|
|
|
virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
|
|
|
|
virtqueue_req_add_iovs(vq, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
|
|
|
|
SPDK_VIRTIO_DESC_WR);
|
|
|
|
} else {
|
|
|
|
virtqueue_req_add_iovs(vq, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
|
|
|
|
SPDK_VIRTIO_DESC_RO);
|
|
|
|
virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtqueue_req_flush(vq);
|
2017-10-17 12:25:17 +00:00
|
|
|
}
|
|
|
|
|
2017-09-06 18:51:28 +00:00
|
|
|
static void
|
|
|
|
bdev_virtio_rw(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
|
|
|
{
|
2017-10-10 15:50:20 +00:00
|
|
|
struct virtio_scsi_disk *disk = SPDK_CONTAINEROF(bdev_io->bdev, struct virtio_scsi_disk, bdev);
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_io_ctx *io_ctx = bdev_virtio_init_io_vreq(ch, bdev_io);
|
|
|
|
struct virtio_scsi_cmd_req *req = &io_ctx->req;
|
2017-12-01 23:33:42 +00:00
|
|
|
bool is_write = bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE;
|
2017-09-22 17:19:49 +00:00
|
|
|
|
2017-10-27 20:29:10 +00:00
|
|
|
if (disk->info.num_blocks > (1ULL << 32)) {
|
2017-12-01 23:33:42 +00:00
|
|
|
req->cdb[0] = is_write ? SPDK_SBC_WRITE_16 : SPDK_SBC_READ_16;
|
2017-09-22 17:19:49 +00:00
|
|
|
to_be64(&req->cdb[2], bdev_io->u.bdev.offset_blocks);
|
|
|
|
to_be32(&req->cdb[10], bdev_io->u.bdev.num_blocks);
|
2017-05-30 21:13:50 +00:00
|
|
|
} else {
|
2017-12-01 23:33:42 +00:00
|
|
|
req->cdb[0] = is_write ? SPDK_SBC_WRITE_10 : SPDK_SBC_READ_10;
|
2017-09-22 17:19:49 +00:00
|
|
|
to_be32(&req->cdb[2], bdev_io->u.bdev.offset_blocks);
|
|
|
|
to_be16(&req->cdb[7], bdev_io->u.bdev.num_blocks);
|
2017-05-30 21:13:50 +00:00
|
|
|
}
|
|
|
|
|
2017-10-17 12:25:17 +00:00
|
|
|
bdev_virtio_send_io(ch, bdev_io);
|
2017-05-30 21:13:50 +00:00
|
|
|
}
|
|
|
|
|
2017-10-11 15:51:33 +00:00
|
|
|
static void
|
|
|
|
bdev_virtio_reset(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
|
|
|
{
|
|
|
|
struct bdev_virtio_io_channel *virtio_ch = spdk_io_channel_get_ctx(ch);
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_io_ctx *io_ctx = bdev_virtio_init_tmf_vreq(ch, bdev_io);
|
|
|
|
struct virtio_scsi_ctrl_tmf_req *tmf_req = &io_ctx->tmf_req;
|
2017-12-02 09:34:55 +00:00
|
|
|
struct virtio_scsi_dev *svdev = virtio_ch->svdev;
|
2017-10-17 12:25:17 +00:00
|
|
|
size_t enqueued_count;
|
2017-10-11 15:51:33 +00:00
|
|
|
|
|
|
|
tmf_req->type = VIRTIO_SCSI_T_TMF;
|
|
|
|
tmf_req->subtype = VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET;
|
|
|
|
|
2019-06-04 04:22:00 +00:00
|
|
|
enqueued_count = spdk_ring_enqueue(svdev->ctrlq_ring, (void **)&bdev_io, 1, NULL);
|
2017-10-17 12:25:17 +00:00
|
|
|
if (spdk_likely(enqueued_count == 1)) {
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
|
|
|
|
}
|
2017-10-11 15:51:33 +00:00
|
|
|
}
|
|
|
|
|
2017-09-08 13:41:53 +00:00
|
|
|
static void
|
bdev: Not assert but pass completion status to spdk_bdev_io_get_buf_cb
When the specified buffer size to spdk_bdev_io_get_buf() is greater
than the permitted maximum, spdk_bdev_io_get_buf() asserts simply and
doesn't call the specified callback function.
SPDK SCSI library doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
Bdev perf tool also doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
When we support DIF insert and strip in iSCSI target, the read
buffer size iSCSI initiator requests and the read buffer size iSCSI target
requests will become different.
Even after that, iSCSI initiator and iSCSI target will negotiate correctly
not to cause buffer overflow in spdk_bdev_io_get_buf(), but if iSCSI
initiator ignores the result of negotiation, iSCSI initiator can request
read buffer size larger than the permitted maximum, and can cause
failure in iSCSI target. This is very flagile and should be avoided.
This patch do the following
- Add the completion status of spdk_bdev_io_get_buf() to
spdk_bdev_io_get_buf_cb(),
- spdk_bdev_io_get_buf() calls spdk_bdev_io_get_buf_cb() by setting
success to false, and return.
- spdk_bdev_io_get_buf_cb() in each bdev module calls assert if success
is false.
Subsequent patches will process the case that success is false
in spdk_bdev_io_get_buf_cb().
Change-Id: I76429a86e18a69aa085a353ac94743296d270b82
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/446045
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
2019-02-25 00:34:28 +00:00
|
|
|
bdev_virtio_unmap(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, bool success)
|
2017-09-08 13:41:53 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_io_ctx *io_ctx = bdev_virtio_init_io_vreq(ch, bdev_io);
|
|
|
|
struct virtio_scsi_cmd_req *req = &io_ctx->req;
|
2017-10-05 10:10:47 +00:00
|
|
|
struct spdk_scsi_unmap_bdesc *desc, *first_desc;
|
2017-09-08 13:41:53 +00:00
|
|
|
uint8_t *buf;
|
2017-10-05 10:10:47 +00:00
|
|
|
uint64_t offset_blocks, num_blocks;
|
|
|
|
uint16_t cmd_len;
|
2017-09-08 13:41:53 +00:00
|
|
|
|
2019-02-25 01:43:13 +00:00
|
|
|
if (!success) {
|
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
|
|
|
return;
|
|
|
|
}
|
bdev: Not assert but pass completion status to spdk_bdev_io_get_buf_cb
When the specified buffer size to spdk_bdev_io_get_buf() is greater
than the permitted maximum, spdk_bdev_io_get_buf() asserts simply and
doesn't call the specified callback function.
SPDK SCSI library doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
Bdev perf tool also doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
When we support DIF insert and strip in iSCSI target, the read
buffer size iSCSI initiator requests and the read buffer size iSCSI target
requests will become different.
Even after that, iSCSI initiator and iSCSI target will negotiate correctly
not to cause buffer overflow in spdk_bdev_io_get_buf(), but if iSCSI
initiator ignores the result of negotiation, iSCSI initiator can request
read buffer size larger than the permitted maximum, and can cause
failure in iSCSI target. This is very flagile and should be avoided.
This patch do the following
- Add the completion status of spdk_bdev_io_get_buf() to
spdk_bdev_io_get_buf_cb(),
- spdk_bdev_io_get_buf() calls spdk_bdev_io_get_buf_cb() by setting
success to false, and return.
- spdk_bdev_io_get_buf_cb() in each bdev module calls assert if success
is false.
Subsequent patches will process the case that success is false
in spdk_bdev_io_get_buf_cb().
Change-Id: I76429a86e18a69aa085a353ac94743296d270b82
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/446045
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
2019-02-25 00:34:28 +00:00
|
|
|
|
2018-06-25 18:03:11 +00:00
|
|
|
buf = bdev_io->u.bdev.iovs[0].iov_base;
|
2017-10-05 10:10:47 +00:00
|
|
|
|
|
|
|
offset_blocks = bdev_io->u.bdev.offset_blocks;
|
|
|
|
num_blocks = bdev_io->u.bdev.num_blocks;
|
|
|
|
|
|
|
|
/* (n-1) * 16-byte descriptors */
|
|
|
|
first_desc = desc = (struct spdk_scsi_unmap_bdesc *)&buf[8];
|
|
|
|
while (num_blocks > UINT32_MAX) {
|
|
|
|
to_be64(&desc->lba, offset_blocks);
|
|
|
|
to_be32(&desc->block_count, UINT32_MAX);
|
|
|
|
memset(&desc->reserved, 0, sizeof(desc->reserved));
|
|
|
|
offset_blocks += UINT32_MAX;
|
|
|
|
num_blocks -= UINT32_MAX;
|
|
|
|
desc++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The last descriptor with block_count <= UINT32_MAX */
|
|
|
|
to_be64(&desc->lba, offset_blocks);
|
|
|
|
to_be32(&desc->block_count, num_blocks);
|
|
|
|
memset(&desc->reserved, 0, sizeof(desc->reserved));
|
|
|
|
|
|
|
|
/* 8-byte header + n * 16-byte block descriptor */
|
|
|
|
cmd_len = 8 + (desc - first_desc + 1) * sizeof(struct spdk_scsi_unmap_bdesc);
|
2017-09-08 13:41:53 +00:00
|
|
|
|
|
|
|
req->cdb[0] = SPDK_SBC_UNMAP;
|
|
|
|
to_be16(&req->cdb[7], cmd_len);
|
|
|
|
|
2017-10-05 10:10:47 +00:00
|
|
|
/* 8-byte header */
|
2017-09-08 13:41:53 +00:00
|
|
|
to_be16(&buf[0], cmd_len - 2); /* total length (excluding the length field) */
|
|
|
|
to_be16(&buf[2], cmd_len - 8); /* length of block descriptors */
|
|
|
|
memset(&buf[4], 0, 4); /* reserved */
|
|
|
|
|
2017-10-17 12:25:17 +00:00
|
|
|
bdev_virtio_send_io(ch, bdev_io);
|
2017-09-08 13:41:53 +00:00
|
|
|
}
|
|
|
|
|
bdev: Not assert but pass completion status to spdk_bdev_io_get_buf_cb
When the specified buffer size to spdk_bdev_io_get_buf() is greater
than the permitted maximum, spdk_bdev_io_get_buf() asserts simply and
doesn't call the specified callback function.
SPDK SCSI library doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
Bdev perf tool also doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
When we support DIF insert and strip in iSCSI target, the read
buffer size iSCSI initiator requests and the read buffer size iSCSI target
requests will become different.
Even after that, iSCSI initiator and iSCSI target will negotiate correctly
not to cause buffer overflow in spdk_bdev_io_get_buf(), but if iSCSI
initiator ignores the result of negotiation, iSCSI initiator can request
read buffer size larger than the permitted maximum, and can cause
failure in iSCSI target. This is very flagile and should be avoided.
This patch do the following
- Add the completion status of spdk_bdev_io_get_buf() to
spdk_bdev_io_get_buf_cb(),
- spdk_bdev_io_get_buf() calls spdk_bdev_io_get_buf_cb() by setting
success to false, and return.
- spdk_bdev_io_get_buf_cb() in each bdev module calls assert if success
is false.
Subsequent patches will process the case that success is false
in spdk_bdev_io_get_buf_cb().
Change-Id: I76429a86e18a69aa085a353ac94743296d270b82
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/446045
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
2019-02-25 00:34:28 +00:00
|
|
|
static void
|
|
|
|
bdev_virtio_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
|
|
|
|
bool success)
|
|
|
|
{
|
2019-02-25 01:43:13 +00:00
|
|
|
if (!success) {
|
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
|
|
|
return;
|
|
|
|
}
|
bdev: Not assert but pass completion status to spdk_bdev_io_get_buf_cb
When the specified buffer size to spdk_bdev_io_get_buf() is greater
than the permitted maximum, spdk_bdev_io_get_buf() asserts simply and
doesn't call the specified callback function.
SPDK SCSI library doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
Bdev perf tool also doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
When we support DIF insert and strip in iSCSI target, the read
buffer size iSCSI initiator requests and the read buffer size iSCSI target
requests will become different.
Even after that, iSCSI initiator and iSCSI target will negotiate correctly
not to cause buffer overflow in spdk_bdev_io_get_buf(), but if iSCSI
initiator ignores the result of negotiation, iSCSI initiator can request
read buffer size larger than the permitted maximum, and can cause
failure in iSCSI target. This is very flagile and should be avoided.
This patch do the following
- Add the completion status of spdk_bdev_io_get_buf() to
spdk_bdev_io_get_buf_cb(),
- spdk_bdev_io_get_buf() calls spdk_bdev_io_get_buf_cb() by setting
success to false, and return.
- spdk_bdev_io_get_buf_cb() in each bdev module calls assert if success
is false.
Subsequent patches will process the case that success is false
in spdk_bdev_io_get_buf_cb().
Change-Id: I76429a86e18a69aa085a353ac94743296d270b82
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/446045
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
2019-02-25 00:34:28 +00:00
|
|
|
|
|
|
|
bdev_virtio_rw(ch, bdev_io);
|
|
|
|
}
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
static int _bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
|
|
|
{
|
2017-10-27 20:26:59 +00:00
|
|
|
struct virtio_scsi_disk *disk = SPDK_CONTAINEROF(bdev_io->bdev, struct virtio_scsi_disk, bdev);
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
switch (bdev_io->type) {
|
|
|
|
case SPDK_BDEV_IO_TYPE_READ:
|
bdev: Not assert but pass completion status to spdk_bdev_io_get_buf_cb
When the specified buffer size to spdk_bdev_io_get_buf() is greater
than the permitted maximum, spdk_bdev_io_get_buf() asserts simply and
doesn't call the specified callback function.
SPDK SCSI library doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
Bdev perf tool also doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
When we support DIF insert and strip in iSCSI target, the read
buffer size iSCSI initiator requests and the read buffer size iSCSI target
requests will become different.
Even after that, iSCSI initiator and iSCSI target will negotiate correctly
not to cause buffer overflow in spdk_bdev_io_get_buf(), but if iSCSI
initiator ignores the result of negotiation, iSCSI initiator can request
read buffer size larger than the permitted maximum, and can cause
failure in iSCSI target. This is very flagile and should be avoided.
This patch do the following
- Add the completion status of spdk_bdev_io_get_buf() to
spdk_bdev_io_get_buf_cb(),
- spdk_bdev_io_get_buf() calls spdk_bdev_io_get_buf_cb() by setting
success to false, and return.
- spdk_bdev_io_get_buf_cb() in each bdev module calls assert if success
is false.
Subsequent patches will process the case that success is false
in spdk_bdev_io_get_buf_cb().
Change-Id: I76429a86e18a69aa085a353ac94743296d270b82
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/446045
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
2019-02-25 00:34:28 +00:00
|
|
|
spdk_bdev_io_get_buf(bdev_io, bdev_virtio_get_buf_cb,
|
2017-09-22 20:59:55 +00:00
|
|
|
bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
|
2017-05-30 21:13:50 +00:00
|
|
|
return 0;
|
|
|
|
case SPDK_BDEV_IO_TYPE_WRITE:
|
|
|
|
bdev_virtio_rw(ch, bdev_io);
|
|
|
|
return 0;
|
|
|
|
case SPDK_BDEV_IO_TYPE_RESET:
|
2017-10-11 15:51:33 +00:00
|
|
|
bdev_virtio_reset(ch, bdev_io);
|
2017-05-30 21:13:50 +00:00
|
|
|
return 0;
|
2017-10-05 10:10:47 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_UNMAP: {
|
|
|
|
uint64_t buf_len = 8 /* header size */ +
|
|
|
|
(bdev_io->u.bdev.num_blocks + UINT32_MAX - 1) /
|
|
|
|
UINT32_MAX * sizeof(struct spdk_scsi_unmap_bdesc);
|
|
|
|
|
2017-10-27 20:26:59 +00:00
|
|
|
if (!disk->info.unmap_supported) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-10-05 10:10:47 +00:00
|
|
|
if (buf_len > SPDK_BDEV_LARGE_BUF_MAX_SIZE) {
|
|
|
|
SPDK_ERRLOG("Trying to UNMAP too many blocks: %"PRIu64"\n",
|
|
|
|
bdev_io->u.bdev.num_blocks);
|
2017-09-08 13:41:53 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2017-10-05 10:10:47 +00:00
|
|
|
spdk_bdev_io_get_buf(bdev_io, bdev_virtio_unmap, buf_len);
|
2017-09-08 13:41:53 +00:00
|
|
|
return 0;
|
2017-10-05 10:10:47 +00:00
|
|
|
}
|
2017-09-08 13:41:53 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_FLUSH:
|
2017-05-30 21:13:50 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
|
|
|
{
|
|
|
|
if (_bdev_virtio_submit_request(ch, bdev_io) < 0) {
|
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
bdev_virtio_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
|
|
|
|
{
|
2017-10-27 20:26:59 +00:00
|
|
|
struct virtio_scsi_disk *disk = ctx;
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
switch (io_type) {
|
|
|
|
case SPDK_BDEV_IO_TYPE_READ:
|
|
|
|
case SPDK_BDEV_IO_TYPE_WRITE:
|
|
|
|
case SPDK_BDEV_IO_TYPE_FLUSH:
|
|
|
|
case SPDK_BDEV_IO_TYPE_RESET:
|
|
|
|
return true;
|
|
|
|
|
2017-10-27 20:26:59 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_UNMAP:
|
|
|
|
return disk->info.unmap_supported;
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct spdk_io_channel *
|
|
|
|
bdev_virtio_get_io_channel(void *ctx)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_disk *disk = ctx;
|
|
|
|
|
2017-11-30 10:58:25 +00:00
|
|
|
return spdk_get_io_channel(disk->svdev);
|
2017-05-30 21:13:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-12-01 00:46:59 +00:00
|
|
|
bdev_virtio_disk_destruct(void *ctx)
|
2017-05-30 21:13:50 +00:00
|
|
|
{
|
2017-12-01 00:46:59 +00:00
|
|
|
struct virtio_scsi_disk *disk = ctx;
|
|
|
|
struct virtio_scsi_dev *svdev = disk->svdev;
|
|
|
|
|
|
|
|
TAILQ_REMOVE(&svdev->luns, disk, link);
|
2018-04-04 12:29:57 +00:00
|
|
|
free(disk->bdev.name);
|
2017-12-01 00:46:59 +00:00
|
|
|
free(disk);
|
|
|
|
|
|
|
|
if (svdev->removed && TAILQ_EMPTY(&svdev->luns)) {
|
|
|
|
spdk_io_device_unregister(svdev, virtio_scsi_dev_unregister_cb);
|
|
|
|
}
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-09 18:45:13 +00:00
|
|
|
static int
|
2018-03-27 13:45:10 +00:00
|
|
|
bdev_virtio_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
|
2017-10-09 18:45:13 +00:00
|
|
|
{
|
|
|
|
struct virtio_scsi_disk *disk = ctx;
|
|
|
|
|
2018-03-27 13:45:10 +00:00
|
|
|
virtio_dev_dump_json_info(&disk->svdev->vdev, w);
|
2017-10-09 18:45:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-27 13:45:10 +00:00
|
|
|
static void
|
|
|
|
bdev_virtio_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
|
|
|
|
{
|
|
|
|
/* SCSI targets and LUNS are discovered during scan process so nothing
|
|
|
|
* to save here.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
static const struct spdk_bdev_fn_table virtio_fn_table = {
|
2017-12-01 00:46:59 +00:00
|
|
|
.destruct = bdev_virtio_disk_destruct,
|
2017-05-30 21:13:50 +00:00
|
|
|
.submit_request = bdev_virtio_submit_request,
|
|
|
|
.io_type_supported = bdev_virtio_io_type_supported,
|
|
|
|
.get_io_channel = bdev_virtio_get_io_channel,
|
2018-03-27 13:45:10 +00:00
|
|
|
.dump_info_json = bdev_virtio_dump_info_json,
|
|
|
|
.write_config_json = bdev_virtio_write_config_json,
|
2017-05-30 21:13:50 +00:00
|
|
|
};
|
|
|
|
|
2017-08-24 16:44:41 +00:00
|
|
|
static void
|
|
|
|
get_scsi_status(struct virtio_scsi_cmd_resp *resp, int *sk, int *asc, int *ascq)
|
|
|
|
{
|
|
|
|
/* see spdk_scsi_task_build_sense_data() for sense data details */
|
|
|
|
*sk = 0;
|
|
|
|
*asc = 0;
|
|
|
|
*ascq = 0;
|
|
|
|
|
|
|
|
if (resp->sense_len < 3) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
*sk = resp->sense[2] & 0xf;
|
|
|
|
|
|
|
|
if (resp->sense_len < 13) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
*asc = resp->sense[12];
|
|
|
|
|
|
|
|
if (resp->sense_len < 14) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ascq = resp->sense[13];
|
|
|
|
}
|
|
|
|
|
2017-08-21 18:50:56 +00:00
|
|
|
static void
|
2017-12-01 23:33:42 +00:00
|
|
|
bdev_virtio_io_cpl(struct spdk_bdev_io *bdev_io)
|
2017-08-21 18:50:56 +00:00
|
|
|
{
|
2017-12-01 23:33:42 +00:00
|
|
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
2017-08-24 16:44:41 +00:00
|
|
|
int sk, asc, ascq;
|
2017-08-21 18:50:56 +00:00
|
|
|
|
2017-08-24 16:44:41 +00:00
|
|
|
get_scsi_status(&io_ctx->resp, &sk, &asc, &ascq);
|
|
|
|
spdk_bdev_io_complete_scsi_status(bdev_io, io_ctx->resp.status, sk, asc, ascq);
|
2017-08-21 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
2018-03-13 00:16:47 +00:00
|
|
|
static int
|
2017-08-21 18:50:56 +00:00
|
|
|
bdev_virtio_poll(void *arg)
|
|
|
|
{
|
|
|
|
struct bdev_virtio_io_channel *ch = arg;
|
2017-12-01 11:34:51 +00:00
|
|
|
struct virtio_scsi_dev *svdev = ch->svdev;
|
2017-12-19 09:28:05 +00:00
|
|
|
struct virtio_scsi_scan_base *scan_ctx = svdev->scan_ctx;
|
2017-12-01 23:33:42 +00:00
|
|
|
void *io[32];
|
|
|
|
uint32_t io_len[32];
|
2017-08-21 18:50:56 +00:00
|
|
|
uint16_t i, cnt;
|
2017-12-18 17:41:35 +00:00
|
|
|
int rc;
|
2017-08-21 18:50:56 +00:00
|
|
|
|
2017-12-01 23:33:42 +00:00
|
|
|
cnt = virtio_recv_pkts(ch->vq, (void **)io, io_len, SPDK_COUNTOF(io));
|
2017-08-21 18:50:56 +00:00
|
|
|
for (i = 0; i < cnt; ++i) {
|
2017-12-19 09:28:05 +00:00
|
|
|
if (spdk_unlikely(scan_ctx && io[i] == &scan_ctx->io_ctx)) {
|
2017-12-18 20:55:33 +00:00
|
|
|
if (svdev->removed) {
|
2017-12-19 09:28:05 +00:00
|
|
|
_virtio_scsi_dev_scan_finish(scan_ctx, -EINTR);
|
2020-05-04 09:51:27 +00:00
|
|
|
return SPDK_POLLER_BUSY;
|
2017-12-18 20:55:33 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 09:28:05 +00:00
|
|
|
if (scan_ctx->restart) {
|
|
|
|
scan_ctx->restart = false;
|
|
|
|
scan_ctx->full_scan = true;
|
|
|
|
_virtio_scsi_dev_scan_tgt(scan_ctx, 0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
process_scan_resp(scan_ctx);
|
2017-12-01 11:34:51 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-12-01 23:33:42 +00:00
|
|
|
bdev_virtio_io_cpl(io[i]);
|
2017-08-21 18:50:56 +00:00
|
|
|
}
|
2017-12-18 17:41:35 +00:00
|
|
|
|
2017-12-19 09:28:05 +00:00
|
|
|
if (spdk_unlikely(scan_ctx && scan_ctx->needs_resend)) {
|
2017-12-18 20:55:33 +00:00
|
|
|
if (svdev->removed) {
|
2017-12-19 09:28:05 +00:00
|
|
|
_virtio_scsi_dev_scan_finish(scan_ctx, -EINTR);
|
2020-05-04 09:51:27 +00:00
|
|
|
return SPDK_POLLER_BUSY;
|
2017-12-18 20:55:33 +00:00
|
|
|
} else if (cnt == 0) {
|
2020-05-04 09:51:27 +00:00
|
|
|
return SPDK_POLLER_IDLE;
|
2017-12-18 20:55:33 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 09:28:05 +00:00
|
|
|
rc = send_scan_io(scan_ctx);
|
2017-12-18 17:41:35 +00:00
|
|
|
if (rc != 0) {
|
2017-12-19 09:28:05 +00:00
|
|
|
assert(scan_ctx->retries > 0);
|
|
|
|
scan_ctx->retries--;
|
|
|
|
if (scan_ctx->retries == 0) {
|
2017-12-18 17:41:35 +00:00
|
|
|
SPDK_ERRLOG("Target scan failed unrecoverably with rc = %d.\n", rc);
|
2017-12-19 09:28:05 +00:00
|
|
|
_virtio_scsi_dev_scan_finish(scan_ctx, rc);
|
2017-12-18 17:41:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-13 00:16:47 +00:00
|
|
|
|
|
|
|
return cnt;
|
2017-08-21 18:50:56 +00:00
|
|
|
}
|
|
|
|
|
2017-10-11 15:51:33 +00:00
|
|
|
static void
|
|
|
|
bdev_virtio_tmf_cpl_cb(void *ctx)
|
|
|
|
{
|
2017-12-01 23:33:42 +00:00
|
|
|
struct spdk_bdev_io *bdev_io = ctx;
|
|
|
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
2017-10-11 15:51:33 +00:00
|
|
|
|
|
|
|
if (io_ctx->tmf_resp.response == VIRTIO_SCSI_S_OK) {
|
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
|
|
|
|
} else {
|
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-12-01 23:33:42 +00:00
|
|
|
bdev_virtio_tmf_cpl(struct spdk_bdev_io *bdev_io)
|
2017-10-11 15:51:33 +00:00
|
|
|
{
|
2017-12-01 23:33:42 +00:00
|
|
|
spdk_thread_send_msg(spdk_bdev_io_get_thread(bdev_io), bdev_virtio_tmf_cpl_cb, bdev_io);
|
2017-10-11 15:51:33 +00:00
|
|
|
}
|
|
|
|
|
2017-12-02 12:08:07 +00:00
|
|
|
static void
|
|
|
|
bdev_virtio_eventq_io_cpl(struct virtio_scsi_dev *svdev, struct virtio_scsi_eventq_io *io)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_event *ev = &io->ev;
|
|
|
|
struct virtio_scsi_disk *disk;
|
|
|
|
|
|
|
|
if (ev->lun[0] != 1) {
|
|
|
|
SPDK_WARNLOG("Received an event with invalid data layout.\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-12-22 11:58:30 +00:00
|
|
|
if (ev->event & VIRTIO_SCSI_T_EVENTS_MISSED) {
|
|
|
|
ev->event &= ~VIRTIO_SCSI_T_EVENTS_MISSED;
|
|
|
|
virtio_scsi_dev_scan(svdev, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (ev->event) {
|
|
|
|
case VIRTIO_SCSI_T_NO_EVENT:
|
|
|
|
break;
|
|
|
|
case VIRTIO_SCSI_T_TRANSPORT_RESET:
|
2017-12-19 08:48:51 +00:00
|
|
|
switch (ev->reason) {
|
|
|
|
case VIRTIO_SCSI_EVT_RESET_RESCAN:
|
|
|
|
virtio_scsi_dev_scan_tgt(svdev, ev->lun[1]);
|
|
|
|
break;
|
|
|
|
case VIRTIO_SCSI_EVT_RESET_REMOVED:
|
|
|
|
disk = virtio_scsi_dev_get_disk_by_id(svdev, ev->lun[1]);
|
|
|
|
if (disk != NULL) {
|
|
|
|
spdk_bdev_unregister(&disk->bdev, NULL, NULL);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2017-12-02 12:08:07 +00:00
|
|
|
}
|
2017-12-22 11:58:30 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2017-12-02 12:08:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
virtio_scsi_dev_send_eventq_io(svdev->vdev.vqs[VIRTIO_SCSI_EVENTQ], io);
|
|
|
|
}
|
|
|
|
|
2017-10-17 12:25:17 +00:00
|
|
|
static void
|
|
|
|
bdev_virtio_tmf_abort_nomem_cb(void *ctx)
|
|
|
|
{
|
|
|
|
struct spdk_bdev_io *bdev_io = ctx;
|
|
|
|
|
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_virtio_tmf_abort_ioerr_cb(void *ctx)
|
|
|
|
{
|
|
|
|
struct spdk_bdev_io *bdev_io = ctx;
|
|
|
|
|
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-12-15 14:58:56 +00:00
|
|
|
bdev_virtio_tmf_abort(struct spdk_bdev_io *bdev_io, int status)
|
2017-10-17 12:25:17 +00:00
|
|
|
{
|
2018-10-10 21:05:04 +00:00
|
|
|
spdk_msg_fn fn;
|
2017-10-17 12:25:17 +00:00
|
|
|
|
|
|
|
if (status == -ENOMEM) {
|
|
|
|
fn = bdev_virtio_tmf_abort_nomem_cb;
|
|
|
|
} else {
|
|
|
|
fn = bdev_virtio_tmf_abort_ioerr_cb;
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_thread_send_msg(spdk_bdev_io_get_thread(bdev_io), fn, bdev_io);
|
|
|
|
}
|
|
|
|
|
2017-12-15 14:58:56 +00:00
|
|
|
static int
|
|
|
|
bdev_virtio_send_tmf_io(struct virtqueue *ctrlq, struct spdk_bdev_io *bdev_io)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
2017-12-01 23:33:42 +00:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = virtqueue_req_start(ctrlq, bdev_io, 2);
|
|
|
|
if (rc != 0) {
|
|
|
|
return rc;
|
|
|
|
}
|
2017-12-15 14:58:56 +00:00
|
|
|
|
2017-12-01 23:33:42 +00:00
|
|
|
virtqueue_req_add_iovs(ctrlq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
|
|
|
|
virtqueue_req_add_iovs(ctrlq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
|
|
|
|
|
|
|
|
virtqueue_req_flush(ctrlq);
|
|
|
|
return 0;
|
2017-12-15 14:58:56 +00:00
|
|
|
}
|
|
|
|
|
2018-03-13 00:16:47 +00:00
|
|
|
static int
|
2017-12-02 12:08:07 +00:00
|
|
|
bdev_virtio_mgmt_poll(void *arg)
|
2017-10-11 15:51:33 +00:00
|
|
|
{
|
2017-12-02 09:34:55 +00:00
|
|
|
struct virtio_scsi_dev *svdev = arg;
|
|
|
|
struct virtio_dev *vdev = &svdev->vdev;
|
2017-12-02 12:08:07 +00:00
|
|
|
struct virtqueue *eventq = vdev->vqs[VIRTIO_SCSI_EVENTQ];
|
2017-10-11 15:51:33 +00:00
|
|
|
struct virtqueue *ctrlq = vdev->vqs[VIRTIO_SCSI_CONTROLQ];
|
2017-12-02 09:34:55 +00:00
|
|
|
struct spdk_ring *send_ring = svdev->ctrlq_ring;
|
2017-12-02 12:08:07 +00:00
|
|
|
void *io[16];
|
2017-12-01 23:33:42 +00:00
|
|
|
uint32_t io_len[16];
|
2017-10-11 15:51:33 +00:00
|
|
|
uint16_t i, cnt;
|
2017-10-17 12:25:17 +00:00
|
|
|
int rc;
|
2018-03-13 00:16:47 +00:00
|
|
|
int total = 0;
|
2017-10-11 15:51:33 +00:00
|
|
|
|
2017-12-02 12:08:07 +00:00
|
|
|
cnt = spdk_ring_dequeue(send_ring, io, SPDK_COUNTOF(io));
|
2018-03-13 00:16:47 +00:00
|
|
|
total += cnt;
|
2017-10-11 15:51:33 +00:00
|
|
|
for (i = 0; i < cnt; ++i) {
|
2017-12-02 12:08:07 +00:00
|
|
|
rc = bdev_virtio_send_tmf_io(ctrlq, io[i]);
|
2017-10-17 12:25:17 +00:00
|
|
|
if (rc != 0) {
|
2017-12-02 12:08:07 +00:00
|
|
|
bdev_virtio_tmf_abort(io[i], rc);
|
2017-10-17 12:25:17 +00:00
|
|
|
}
|
2017-10-11 15:51:33 +00:00
|
|
|
}
|
|
|
|
|
2017-12-02 12:08:07 +00:00
|
|
|
cnt = virtio_recv_pkts(ctrlq, io, io_len, SPDK_COUNTOF(io));
|
2018-03-13 00:16:47 +00:00
|
|
|
total += cnt;
|
2017-12-02 12:08:07 +00:00
|
|
|
for (i = 0; i < cnt; ++i) {
|
|
|
|
bdev_virtio_tmf_cpl(io[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
cnt = virtio_recv_pkts(eventq, io, io_len, SPDK_COUNTOF(io));
|
2018-03-13 00:16:47 +00:00
|
|
|
total += cnt;
|
2017-10-11 15:51:33 +00:00
|
|
|
for (i = 0; i < cnt; ++i) {
|
2017-12-02 12:08:07 +00:00
|
|
|
bdev_virtio_eventq_io_cpl(svdev, io[i]);
|
2017-10-11 15:51:33 +00:00
|
|
|
}
|
2018-03-13 00:16:47 +00:00
|
|
|
|
|
|
|
return total;
|
2017-10-11 15:51:33 +00:00
|
|
|
}
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
static int
|
2017-11-30 10:09:23 +00:00
|
|
|
bdev_virtio_scsi_ch_create_cb(void *io_device, void *ctx_buf)
|
2017-05-30 21:13:50 +00:00
|
|
|
{
|
2017-11-30 10:58:25 +00:00
|
|
|
struct virtio_scsi_dev *svdev = io_device;
|
|
|
|
struct virtio_dev *vdev = &svdev->vdev;
|
2017-08-21 18:50:56 +00:00
|
|
|
struct bdev_virtio_io_channel *ch = ctx_buf;
|
2017-10-10 18:44:35 +00:00
|
|
|
struct virtqueue *vq;
|
|
|
|
int32_t queue_idx;
|
|
|
|
|
2017-10-12 17:00:42 +00:00
|
|
|
queue_idx = virtio_dev_find_and_acquire_queue(vdev, VIRTIO_SCSI_REQUESTQ);
|
2017-10-10 18:44:35 +00:00
|
|
|
if (queue_idx < 0) {
|
|
|
|
SPDK_ERRLOG("Couldn't get an unused queue for the io_channel.\n");
|
2017-10-18 08:56:17 +00:00
|
|
|
return -1;
|
2017-10-10 18:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vq = vdev->vqs[queue_idx];
|
|
|
|
|
2017-11-30 10:58:25 +00:00
|
|
|
ch->svdev = svdev;
|
2017-10-10 18:44:35 +00:00
|
|
|
ch->vq = vq;
|
|
|
|
|
2020-04-14 06:49:46 +00:00
|
|
|
ch->poller = SPDK_POLLER_REGISTER(bdev_virtio_poll, ch, 0);
|
2017-08-21 18:50:56 +00:00
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-11-30 10:09:23 +00:00
|
|
|
bdev_virtio_scsi_ch_destroy_cb(void *io_device, void *ctx_buf)
|
2017-05-30 21:13:50 +00:00
|
|
|
{
|
2017-12-02 09:34:55 +00:00
|
|
|
struct bdev_virtio_io_channel *ch = ctx_buf;
|
|
|
|
struct virtio_scsi_dev *svdev = ch->svdev;
|
2017-11-30 10:58:25 +00:00
|
|
|
struct virtio_dev *vdev = &svdev->vdev;
|
2017-12-02 09:34:55 +00:00
|
|
|
struct virtqueue *vq = ch->vq;
|
2017-08-21 18:50:56 +00:00
|
|
|
|
2017-12-02 09:34:55 +00:00
|
|
|
spdk_poller_unregister(&ch->poller);
|
2017-10-10 18:44:35 +00:00
|
|
|
virtio_dev_release_queue(vdev, vq->vq_queue_index);
|
2017-05-30 21:13:50 +00:00
|
|
|
}
|
|
|
|
|
2017-10-11 15:51:33 +00:00
|
|
|
static void
|
2017-12-14 15:01:28 +00:00
|
|
|
_virtio_scsi_dev_scan_finish(struct virtio_scsi_scan_base *base, int errnum)
|
2017-08-22 17:16:39 +00:00
|
|
|
{
|
2017-12-01 00:46:59 +00:00
|
|
|
struct virtio_scsi_dev *svdev = base->svdev;
|
2017-12-14 15:01:28 +00:00
|
|
|
size_t bdevs_cnt;
|
2017-10-03 18:23:37 +00:00
|
|
|
struct spdk_bdev *bdevs[BDEV_VIRTIO_MAX_TARGET];
|
2017-09-12 12:04:50 +00:00
|
|
|
struct virtio_scsi_disk *disk;
|
2017-12-19 08:48:51 +00:00
|
|
|
struct virtio_scsi_scan_info *tgt, *next_tgt;
|
2017-09-12 12:04:50 +00:00
|
|
|
|
2017-12-01 11:34:51 +00:00
|
|
|
spdk_put_io_channel(spdk_io_channel_from_ctx(base->channel));
|
2017-12-14 15:01:28 +00:00
|
|
|
base->svdev->scan_ctx = NULL;
|
2017-09-12 12:04:50 +00:00
|
|
|
|
2017-12-19 08:48:51 +00:00
|
|
|
TAILQ_FOREACH_SAFE(tgt, &base->scan_queue, tailq, next_tgt) {
|
|
|
|
TAILQ_REMOVE(&base->scan_queue, tgt, tailq);
|
|
|
|
free(tgt);
|
|
|
|
}
|
|
|
|
|
2017-12-14 15:01:28 +00:00
|
|
|
if (base->cb_fn == NULL) {
|
2019-03-15 14:35:49 +00:00
|
|
|
spdk_free(base);
|
2017-12-14 15:01:28 +00:00
|
|
|
return;
|
2017-09-12 12:04:50 +00:00
|
|
|
}
|
|
|
|
|
2017-12-14 15:01:28 +00:00
|
|
|
bdevs_cnt = 0;
|
|
|
|
if (errnum == 0) {
|
|
|
|
TAILQ_FOREACH(disk, &svdev->luns, link) {
|
|
|
|
bdevs[bdevs_cnt] = &disk->bdev;
|
|
|
|
bdevs_cnt++;
|
|
|
|
}
|
2017-09-25 18:41:05 +00:00
|
|
|
}
|
2017-10-03 18:23:37 +00:00
|
|
|
|
2017-12-14 15:01:28 +00:00
|
|
|
base->cb_fn(base->cb_arg, errnum, bdevs, bdevs_cnt);
|
2019-03-15 14:35:49 +00:00
|
|
|
spdk_free(base);
|
2017-08-22 17:16:39 +00:00
|
|
|
}
|
|
|
|
|
2017-12-01 23:33:42 +00:00
|
|
|
static int
|
|
|
|
send_scan_io(struct virtio_scsi_scan_base *base)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_io_ctx *io_ctx = &base->io_ctx;
|
2017-12-14 15:31:45 +00:00
|
|
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
2017-12-01 23:33:42 +00:00
|
|
|
struct virtqueue *vq = base->channel->vq;
|
2017-12-14 16:43:03 +00:00
|
|
|
int payload_iov_cnt = base->iov.iov_len > 0 ? 1 : 0;
|
2017-12-01 23:33:42 +00:00
|
|
|
int rc;
|
|
|
|
|
2017-12-14 15:31:45 +00:00
|
|
|
req->lun[0] = 1;
|
|
|
|
req->lun[1] = base->info.target;
|
|
|
|
|
2017-12-14 16:43:03 +00:00
|
|
|
rc = virtqueue_req_start(vq, io_ctx, 2 + payload_iov_cnt);
|
2017-12-01 23:33:42 +00:00
|
|
|
if (rc != 0) {
|
2017-12-18 17:41:35 +00:00
|
|
|
base->needs_resend = true;
|
|
|
|
return -1;
|
2017-12-01 23:33:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
|
|
|
|
virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
|
2017-12-14 16:43:03 +00:00
|
|
|
virtqueue_req_add_iovs(vq, &base->iov, payload_iov_cnt, SPDK_VIRTIO_DESC_WR);
|
2017-12-01 23:33:42 +00:00
|
|
|
|
|
|
|
virtqueue_req_flush(vq);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-12-14 15:01:28 +00:00
|
|
|
static int
|
2017-12-14 15:31:45 +00:00
|
|
|
send_inquiry(struct virtio_scsi_scan_base *base)
|
2017-12-14 15:01:28 +00:00
|
|
|
{
|
|
|
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
|
|
|
struct spdk_scsi_cdb_inquiry *cdb;
|
|
|
|
|
|
|
|
memset(req, 0, sizeof(*req));
|
|
|
|
|
2017-12-14 16:43:03 +00:00
|
|
|
base->iov.iov_len = BDEV_VIRTIO_SCAN_PAYLOAD_SIZE;
|
2017-12-14 15:01:28 +00:00
|
|
|
cdb = (struct spdk_scsi_cdb_inquiry *)req->cdb;
|
|
|
|
cdb->opcode = SPDK_SPC_INQUIRY;
|
|
|
|
to_be16(cdb->alloc_len, BDEV_VIRTIO_SCAN_PAYLOAD_SIZE);
|
|
|
|
|
|
|
|
return send_scan_io(base);
|
|
|
|
}
|
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
static int
|
2017-12-14 15:31:45 +00:00
|
|
|
send_inquiry_vpd(struct virtio_scsi_scan_base *base, uint8_t page_code)
|
2017-10-27 20:26:59 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
2017-10-27 20:26:59 +00:00
|
|
|
struct spdk_scsi_cdb_inquiry *inquiry_cdb = (struct spdk_scsi_cdb_inquiry *)req->cdb;
|
|
|
|
|
|
|
|
memset(req, 0, sizeof(*req));
|
|
|
|
|
2017-12-14 16:43:03 +00:00
|
|
|
base->iov.iov_len = BDEV_VIRTIO_SCAN_PAYLOAD_SIZE;
|
2017-10-27 20:26:59 +00:00
|
|
|
inquiry_cdb->opcode = SPDK_SPC_INQUIRY;
|
|
|
|
inquiry_cdb->evpd = 1;
|
|
|
|
inquiry_cdb->page_code = page_code;
|
2017-12-14 16:43:03 +00:00
|
|
|
to_be16(inquiry_cdb->alloc_len, base->iov.iov_len);
|
2017-10-27 20:26:59 +00:00
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_scan_io(base);
|
2017-10-27 20:26:59 +00:00
|
|
|
}
|
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
static int
|
2017-12-14 15:31:45 +00:00
|
|
|
send_read_cap_10(struct virtio_scsi_scan_base *base)
|
2017-08-25 09:45:07 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
2017-08-25 09:45:07 +00:00
|
|
|
|
2017-09-04 17:23:46 +00:00
|
|
|
memset(req, 0, sizeof(*req));
|
|
|
|
|
2017-12-14 16:43:03 +00:00
|
|
|
base->iov.iov_len = 8;
|
2017-09-04 17:23:46 +00:00
|
|
|
req->cdb[0] = SPDK_SBC_READ_CAPACITY_10;
|
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_scan_io(base);
|
2017-09-04 17:23:46 +00:00
|
|
|
}
|
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
static int
|
2017-12-14 15:31:45 +00:00
|
|
|
send_read_cap_16(struct virtio_scsi_scan_base *base)
|
2017-09-04 17:23:46 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
2017-08-25 09:45:07 +00:00
|
|
|
|
|
|
|
memset(req, 0, sizeof(*req));
|
|
|
|
|
2017-12-14 16:43:03 +00:00
|
|
|
base->iov.iov_len = 32;
|
2017-08-25 09:45:07 +00:00
|
|
|
req->cdb[0] = SPDK_SPC_SERVICE_ACTION_IN_16;
|
|
|
|
req->cdb[1] = SPDK_SBC_SAI_READ_CAPACITY_16;
|
2017-12-14 16:43:03 +00:00
|
|
|
to_be32(&req->cdb[10], base->iov.iov_len);
|
2017-08-25 09:45:07 +00:00
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_scan_io(base);
|
2017-09-04 17:23:46 +00:00
|
|
|
}
|
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
static int
|
2017-12-14 15:31:45 +00:00
|
|
|
send_test_unit_ready(struct virtio_scsi_scan_base *base)
|
2017-11-14 14:33:08 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
2017-11-14 14:33:08 +00:00
|
|
|
|
|
|
|
memset(req, 0, sizeof(*req));
|
|
|
|
req->cdb[0] = SPDK_SPC_TEST_UNIT_READY;
|
2017-12-14 16:43:03 +00:00
|
|
|
base->iov.iov_len = 0;
|
2017-11-14 14:33:08 +00:00
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_scan_io(base);
|
2017-11-14 14:33:08 +00:00
|
|
|
}
|
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
static int
|
2017-12-14 15:31:45 +00:00
|
|
|
send_start_stop_unit(struct virtio_scsi_scan_base *base)
|
2017-11-14 14:33:08 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
2017-11-14 14:33:08 +00:00
|
|
|
|
|
|
|
memset(req, 0, sizeof(*req));
|
|
|
|
req->cdb[0] = SPDK_SBC_START_STOP_UNIT;
|
|
|
|
req->cdb[4] = SPDK_SBC_START_STOP_UNIT_START_BIT;
|
2017-12-14 16:43:03 +00:00
|
|
|
base->iov.iov_len = 0;
|
2017-11-14 14:33:08 +00:00
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_scan_io(base);
|
2017-11-14 14:33:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-12-15 14:58:56 +00:00
|
|
|
process_scan_start_stop_unit(struct virtio_scsi_scan_base *base)
|
2017-11-14 14:33:08 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
2017-11-14 14:33:08 +00:00
|
|
|
|
2018-03-01 15:49:40 +00:00
|
|
|
if (resp->status == SPDK_SCSI_STATUS_GOOD) {
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_inquiry_vpd(base, SPDK_SPC_VPD_SUPPORTED_VPD_PAGES);
|
2017-11-14 14:33:08 +00:00
|
|
|
}
|
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
return -1;
|
2017-11-14 14:33:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-12-15 14:58:56 +00:00
|
|
|
process_scan_test_unit_ready(struct virtio_scsi_scan_base *base)
|
2017-11-14 14:33:08 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
2017-11-14 14:33:08 +00:00
|
|
|
int sk, asc, ascq;
|
|
|
|
|
|
|
|
get_scsi_status(resp, &sk, &asc, &ascq);
|
|
|
|
|
|
|
|
/* check response, get VPD if spun up otherwise send SSU */
|
2018-03-01 15:49:40 +00:00
|
|
|
if (resp->status == SPDK_SCSI_STATUS_GOOD) {
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_inquiry_vpd(base, SPDK_SPC_VPD_SUPPORTED_VPD_PAGES);
|
2017-11-14 14:33:08 +00:00
|
|
|
} else if (resp->response == VIRTIO_SCSI_S_OK &&
|
|
|
|
resp->status == SPDK_SCSI_STATUS_CHECK_CONDITION &&
|
|
|
|
sk == SPDK_SCSI_SENSE_UNIT_ATTENTION &&
|
|
|
|
asc == SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_READY) {
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_start_stop_unit(base);
|
2017-11-14 14:33:08 +00:00
|
|
|
} else {
|
2017-12-18 17:41:35 +00:00
|
|
|
return -1;
|
2017-11-14 14:33:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-04 17:23:46 +00:00
|
|
|
static int
|
2017-12-15 14:58:56 +00:00
|
|
|
process_scan_inquiry_standard(struct virtio_scsi_scan_base *base)
|
2017-09-04 17:23:46 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
|
|
|
struct spdk_scsi_cdb_inquiry_data *inquiry_data =
|
|
|
|
(struct spdk_scsi_cdb_inquiry_data *)base->payload;
|
2017-09-04 17:23:46 +00:00
|
|
|
|
2018-03-01 15:49:40 +00:00
|
|
|
if (resp->status != SPDK_SCSI_STATUS_GOOD) {
|
2017-09-04 17:23:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-11-14 14:33:08 +00:00
|
|
|
/* check to make sure its a supported device */
|
2017-10-16 20:04:35 +00:00
|
|
|
if (inquiry_data->peripheral_device_type != SPDK_SPC_PERIPHERAL_DEVICE_TYPE_DISK ||
|
|
|
|
inquiry_data->peripheral_qualifier != SPDK_SPC_PERIPHERAL_QUALIFIER_CONNECTED) {
|
|
|
|
SPDK_WARNLOG("Unsupported peripheral device type 0x%02x (qualifier 0x%02x)\n",
|
|
|
|
inquiry_data->peripheral_device_type,
|
|
|
|
inquiry_data->peripheral_qualifier);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_test_unit_ready(base);
|
2017-10-27 20:26:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-12-15 14:58:56 +00:00
|
|
|
process_scan_inquiry_vpd_supported_vpd_pages(struct virtio_scsi_scan_base *base)
|
2017-10-27 20:26:59 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
2017-10-27 20:26:59 +00:00
|
|
|
bool block_provisioning_page_supported = false;
|
|
|
|
|
2018-03-01 15:49:40 +00:00
|
|
|
if (resp->status == SPDK_SCSI_STATUS_GOOD) {
|
2017-12-15 14:58:56 +00:00
|
|
|
const uint8_t *vpd_data = base->payload;
|
2017-10-27 20:26:59 +00:00
|
|
|
const uint8_t *supported_vpd_pages = vpd_data + 4;
|
|
|
|
uint16_t page_length;
|
|
|
|
uint16_t num_supported_pages;
|
|
|
|
uint16_t i;
|
|
|
|
|
|
|
|
page_length = from_be16(vpd_data + 2);
|
2017-12-01 23:33:42 +00:00
|
|
|
num_supported_pages = spdk_min(page_length, base->iov.iov_len - 4);
|
2017-10-27 20:26:59 +00:00
|
|
|
|
|
|
|
for (i = 0; i < num_supported_pages; i++) {
|
|
|
|
if (supported_vpd_pages[i] == SPDK_SPC_VPD_BLOCK_THIN_PROVISION) {
|
|
|
|
block_provisioning_page_supported = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (block_provisioning_page_supported) {
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_inquiry_vpd(base, SPDK_SPC_VPD_BLOCK_THIN_PROVISION);
|
2017-10-27 20:26:59 +00:00
|
|
|
} else {
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_read_cap_10(base);
|
2017-10-27 20:26:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-12-15 14:58:56 +00:00
|
|
|
process_scan_inquiry_vpd_block_thin_provision(struct virtio_scsi_scan_base *base)
|
2017-10-27 20:26:59 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
2017-10-27 20:26:59 +00:00
|
|
|
|
|
|
|
base->info.unmap_supported = false;
|
|
|
|
|
2018-03-01 15:49:40 +00:00
|
|
|
if (resp->status == SPDK_SCSI_STATUS_GOOD) {
|
2017-12-15 14:58:56 +00:00
|
|
|
uint8_t *vpd_data = base->payload;
|
2017-10-27 20:26:59 +00:00
|
|
|
|
|
|
|
base->info.unmap_supported = !!(vpd_data[5] & SPDK_SCSI_UNMAP_LBPU);
|
|
|
|
}
|
|
|
|
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_INFOLOG(virtio, "Target %u: unmap supported = %d\n",
|
2017-10-27 20:26:59 +00:00
|
|
|
base->info.target, (int)base->info.unmap_supported);
|
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_read_cap_10(base);
|
2017-08-25 09:45:07 +00:00
|
|
|
}
|
|
|
|
|
2017-10-27 20:26:59 +00:00
|
|
|
static int
|
2017-12-15 14:58:56 +00:00
|
|
|
process_scan_inquiry(struct virtio_scsi_scan_base *base)
|
2017-10-27 20:26:59 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
2017-10-27 20:26:59 +00:00
|
|
|
struct spdk_scsi_cdb_inquiry *inquiry_cdb = (struct spdk_scsi_cdb_inquiry *)req->cdb;
|
|
|
|
|
|
|
|
if ((inquiry_cdb->evpd & 1) == 0) {
|
2017-12-15 14:58:56 +00:00
|
|
|
return process_scan_inquiry_standard(base);
|
2017-10-27 20:26:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (inquiry_cdb->page_code) {
|
|
|
|
case SPDK_SPC_VPD_SUPPORTED_VPD_PAGES:
|
2017-12-15 14:58:56 +00:00
|
|
|
return process_scan_inquiry_vpd_supported_vpd_pages(base);
|
2017-10-27 20:26:59 +00:00
|
|
|
case SPDK_SPC_VPD_BLOCK_THIN_PROVISION:
|
2017-12-15 14:58:56 +00:00
|
|
|
return process_scan_inquiry_vpd_block_thin_provision(base);
|
2017-10-27 20:26:59 +00:00
|
|
|
default:
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_DEBUGLOG(virtio, "Unexpected VPD page 0x%02x\n", inquiry_cdb->page_code);
|
2017-10-27 20:26:59 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-10 06:43:11 +00:00
|
|
|
static void
|
|
|
|
bdev_virtio_disc_notify_remove(void *remove_ctx)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_disk *disk = remove_ctx;
|
|
|
|
|
|
|
|
disk->removed = true;
|
|
|
|
spdk_bdev_close(disk->notify_desc);
|
|
|
|
}
|
|
|
|
|
2017-12-14 13:54:03 +00:00
|
|
|
/* To be called only from the thread performing target scan */
|
2017-08-25 09:45:07 +00:00
|
|
|
static int
|
2017-12-14 13:54:03 +00:00
|
|
|
virtio_scsi_dev_add_tgt(struct virtio_scsi_dev *svdev, struct virtio_scsi_scan_info *info)
|
2017-08-25 09:45:07 +00:00
|
|
|
{
|
|
|
|
struct virtio_scsi_disk *disk;
|
|
|
|
struct spdk_bdev *bdev;
|
2017-12-14 13:54:03 +00:00
|
|
|
int rc;
|
2017-08-25 09:45:07 +00:00
|
|
|
|
2017-12-22 11:01:06 +00:00
|
|
|
TAILQ_FOREACH(disk, &svdev->luns, link) {
|
|
|
|
if (disk->info.target == info->target) {
|
|
|
|
/* Target is already attached and param change is not supported */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 13:44:37 +00:00
|
|
|
if (info->block_size == 0 || info->num_blocks == 0) {
|
|
|
|
SPDK_ERRLOG("%s: invalid target %u: bs=%"PRIu32" blocks=%"PRIu64"\n",
|
|
|
|
svdev->vdev.name, info->target, info->block_size, info->num_blocks);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2017-08-25 09:45:07 +00:00
|
|
|
disk = calloc(1, sizeof(*disk));
|
|
|
|
if (disk == NULL) {
|
|
|
|
SPDK_ERRLOG("could not allocate disk\n");
|
2017-12-14 13:54:03 +00:00
|
|
|
return -ENOMEM;
|
2017-08-25 09:45:07 +00:00
|
|
|
}
|
|
|
|
|
2017-12-14 13:54:03 +00:00
|
|
|
disk->svdev = svdev;
|
|
|
|
memcpy(&disk->info, info, sizeof(*info));
|
2017-08-25 09:45:07 +00:00
|
|
|
|
|
|
|
bdev = &disk->bdev;
|
2017-12-14 13:54:03 +00:00
|
|
|
bdev->name = spdk_sprintf_alloc("%st%"PRIu8, svdev->vdev.name, info->target);
|
2017-10-18 09:04:56 +00:00
|
|
|
if (bdev->name == NULL) {
|
|
|
|
SPDK_ERRLOG("Couldn't alloc memory for the bdev name.\n");
|
|
|
|
free(disk);
|
2017-12-14 13:54:03 +00:00
|
|
|
return -ENOMEM;
|
2017-10-18 09:04:56 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 09:45:07 +00:00
|
|
|
bdev->product_name = "Virtio SCSI Disk";
|
|
|
|
bdev->write_cache = 0;
|
2017-10-27 20:29:10 +00:00
|
|
|
bdev->blocklen = disk->info.block_size;
|
|
|
|
bdev->blockcnt = disk->info.num_blocks;
|
2017-08-25 09:45:07 +00:00
|
|
|
|
|
|
|
bdev->ctxt = disk;
|
|
|
|
bdev->fn_table = &virtio_fn_table;
|
2018-03-06 18:52:46 +00:00
|
|
|
bdev->module = &virtio_scsi_if;
|
2017-08-25 09:45:07 +00:00
|
|
|
|
2017-12-14 13:54:03 +00:00
|
|
|
rc = spdk_bdev_register(&disk->bdev);
|
|
|
|
if (rc) {
|
|
|
|
SPDK_ERRLOG("Failed to register bdev name=%s\n", disk->bdev.name);
|
2018-04-04 12:29:57 +00:00
|
|
|
free(bdev->name);
|
2017-12-14 13:54:03 +00:00
|
|
|
free(disk);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-01-10 06:43:11 +00:00
|
|
|
rc = spdk_bdev_open(bdev, false, bdev_virtio_disc_notify_remove, disk, &disk->notify_desc);
|
|
|
|
if (rc) {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
|
2017-12-14 13:54:03 +00:00
|
|
|
TAILQ_INSERT_TAIL(&svdev->luns, disk, link);
|
2017-08-25 09:45:07 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-21 09:36:06 +00:00
|
|
|
static int
|
2017-12-15 14:58:56 +00:00
|
|
|
process_read_cap_10(struct virtio_scsi_scan_base *base)
|
2017-09-04 17:23:46 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
|
|
|
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
2017-09-04 17:23:46 +00:00
|
|
|
uint64_t max_block;
|
|
|
|
uint32_t block_size;
|
2017-09-25 16:15:27 +00:00
|
|
|
uint8_t target_id = req->lun[1];
|
2017-12-14 13:54:03 +00:00
|
|
|
int rc;
|
2017-09-04 17:23:46 +00:00
|
|
|
|
|
|
|
if (resp->response != VIRTIO_SCSI_S_OK || resp->status != SPDK_SCSI_STATUS_GOOD) {
|
2017-09-25 16:15:27 +00:00
|
|
|
SPDK_ERRLOG("READ CAPACITY (10) failed for target %"PRIu8".\n", target_id);
|
2017-09-04 17:23:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-12-15 14:58:56 +00:00
|
|
|
block_size = from_be32(base->payload + 4);
|
|
|
|
max_block = from_be32(base->payload);
|
2017-09-04 17:23:46 +00:00
|
|
|
|
|
|
|
if (max_block == 0xffffffff) {
|
2017-12-18 17:41:35 +00:00
|
|
|
return send_read_cap_16(base);
|
2017-09-04 17:23:46 +00:00
|
|
|
}
|
|
|
|
|
2017-10-27 20:29:10 +00:00
|
|
|
base->info.num_blocks = (uint64_t)max_block + 1;
|
|
|
|
base->info.block_size = block_size;
|
|
|
|
|
2017-12-14 13:54:03 +00:00
|
|
|
rc = virtio_scsi_dev_add_tgt(base->svdev, &base->info);
|
|
|
|
if (rc != 0) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-03-01 16:16:44 +00:00
|
|
|
return _virtio_scsi_dev_scan_next(base, 0);
|
2017-09-04 17:23:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-12-15 14:58:56 +00:00
|
|
|
process_read_cap_16(struct virtio_scsi_scan_base *base)
|
2017-09-21 09:36:06 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
|
|
|
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
2017-09-25 16:15:27 +00:00
|
|
|
uint8_t target_id = req->lun[1];
|
2017-12-14 13:54:03 +00:00
|
|
|
int rc;
|
2017-09-21 09:36:06 +00:00
|
|
|
|
|
|
|
if (resp->response != VIRTIO_SCSI_S_OK || resp->status != SPDK_SCSI_STATUS_GOOD) {
|
2017-09-25 16:15:27 +00:00
|
|
|
SPDK_ERRLOG("READ CAPACITY (16) failed for target %"PRIu8".\n", target_id);
|
2017-09-21 09:36:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-12-15 14:58:56 +00:00
|
|
|
base->info.num_blocks = from_be64(base->payload) + 1;
|
|
|
|
base->info.block_size = from_be32(base->payload + 8);
|
2017-12-14 13:54:03 +00:00
|
|
|
rc = virtio_scsi_dev_add_tgt(base->svdev, &base->info);
|
|
|
|
if (rc != 0) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-03-01 16:16:44 +00:00
|
|
|
return _virtio_scsi_dev_scan_next(base, 0);
|
2017-09-21 09:36:06 +00:00
|
|
|
}
|
|
|
|
|
2017-08-22 17:16:39 +00:00
|
|
|
static void
|
2017-12-15 14:58:56 +00:00
|
|
|
process_scan_resp(struct virtio_scsi_scan_base *base)
|
2017-08-22 17:16:39 +00:00
|
|
|
{
|
2017-12-15 14:58:56 +00:00
|
|
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
|
|
|
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
2017-10-25 08:08:37 +00:00
|
|
|
int rc, sk, asc, ascq;
|
|
|
|
uint8_t target_id;
|
2017-08-22 17:16:39 +00:00
|
|
|
|
2017-12-01 23:33:42 +00:00
|
|
|
if (base->io_ctx.iov_req.iov_len < sizeof(struct virtio_scsi_cmd_req) ||
|
|
|
|
base->io_ctx.iov_resp.iov_len < sizeof(struct virtio_scsi_cmd_resp)) {
|
2017-08-22 17:16:39 +00:00
|
|
|
SPDK_ERRLOG("Received target scan message with invalid length.\n");
|
2018-03-01 16:16:44 +00:00
|
|
|
_virtio_scsi_dev_scan_next(base, -EIO);
|
2017-08-22 17:16:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-25 08:08:37 +00:00
|
|
|
get_scsi_status(resp, &sk, &asc, &ascq);
|
|
|
|
target_id = req->lun[1];
|
|
|
|
|
2018-03-01 15:49:40 +00:00
|
|
|
if (resp->response == VIRTIO_SCSI_S_BAD_TARGET ||
|
|
|
|
resp->response == VIRTIO_SCSI_S_INCORRECT_LUN) {
|
2018-03-01 16:16:44 +00:00
|
|
|
_virtio_scsi_dev_scan_next(base, -ENODEV);
|
2018-03-01 15:49:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resp->response != VIRTIO_SCSI_S_OK ||
|
|
|
|
(resp->status == SPDK_SCSI_STATUS_CHECK_CONDITION &&
|
|
|
|
sk != SPDK_SCSI_SENSE_ILLEGAL_REQUEST)) {
|
2017-10-25 08:08:37 +00:00
|
|
|
assert(base->retries > 0);
|
|
|
|
base->retries--;
|
|
|
|
if (base->retries == 0) {
|
|
|
|
SPDK_NOTICELOG("Target %"PRIu8" is present, but unavailable.\n", target_id);
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_LOGDUMP(virtio, "CDB", req->cdb, sizeof(req->cdb));
|
|
|
|
SPDK_LOGDUMP(virtio, "SENSE DATA", resp->sense, sizeof(resp->sense));
|
2018-03-01 16:16:44 +00:00
|
|
|
_virtio_scsi_dev_scan_next(base, -EBUSY);
|
2017-10-25 08:08:37 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* resend the same request */
|
2017-12-01 23:33:42 +00:00
|
|
|
rc = send_scan_io(base);
|
2017-10-25 08:08:37 +00:00
|
|
|
if (rc != 0) {
|
2017-12-18 17:41:35 +00:00
|
|
|
/* Let response poller do the resend */
|
2017-10-25 08:08:37 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
base->retries = SCAN_REQUEST_RETRIES;
|
|
|
|
|
2017-08-22 17:16:39 +00:00
|
|
|
switch (req->cdb[0]) {
|
|
|
|
case SPDK_SPC_INQUIRY:
|
2017-12-15 14:58:56 +00:00
|
|
|
rc = process_scan_inquiry(base);
|
2017-08-22 17:16:39 +00:00
|
|
|
break;
|
2017-11-14 14:33:08 +00:00
|
|
|
case SPDK_SPC_TEST_UNIT_READY:
|
2017-12-15 14:58:56 +00:00
|
|
|
rc = process_scan_test_unit_ready(base);
|
2017-11-14 14:33:08 +00:00
|
|
|
break;
|
|
|
|
case SPDK_SBC_START_STOP_UNIT:
|
2017-12-15 14:58:56 +00:00
|
|
|
rc = process_scan_start_stop_unit(base);
|
2017-11-14 14:33:08 +00:00
|
|
|
break;
|
2017-09-04 17:23:46 +00:00
|
|
|
case SPDK_SBC_READ_CAPACITY_10:
|
2017-12-15 14:58:56 +00:00
|
|
|
rc = process_read_cap_10(base);
|
2017-09-04 17:23:46 +00:00
|
|
|
break;
|
2017-08-22 17:16:39 +00:00
|
|
|
case SPDK_SPC_SERVICE_ACTION_IN_16:
|
2017-12-15 14:58:56 +00:00
|
|
|
rc = process_read_cap_16(base);
|
2017-08-22 17:16:39 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SPDK_ERRLOG("Received invalid target scan message: cdb[0] = %"PRIu8".\n", req->cdb[0]);
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-12-18 17:41:35 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
if (base->needs_resend) {
|
|
|
|
return; /* Let response poller do the resend */
|
|
|
|
}
|
|
|
|
|
2018-03-01 16:16:44 +00:00
|
|
|
_virtio_scsi_dev_scan_next(base, rc);
|
2017-08-22 17:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-17 12:36:39 +00:00
|
|
|
static int
|
2018-03-01 16:16:44 +00:00
|
|
|
_virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base, int rc)
|
2017-05-30 21:13:50 +00:00
|
|
|
{
|
2017-12-19 08:48:51 +00:00
|
|
|
struct virtio_scsi_scan_info *next;
|
2018-03-01 16:16:44 +00:00
|
|
|
struct virtio_scsi_disk *disk;
|
2017-12-14 15:01:28 +00:00
|
|
|
uint8_t target_id;
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-12-19 08:48:51 +00:00
|
|
|
if (base->full_scan) {
|
2018-03-01 16:16:44 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
disk = virtio_scsi_dev_get_disk_by_id(base->svdev,
|
|
|
|
base->info.target);
|
|
|
|
if (disk != NULL) {
|
|
|
|
spdk_bdev_unregister(&disk->bdev, NULL, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-19 08:48:51 +00:00
|
|
|
target_id = base->info.target + 1;
|
|
|
|
if (target_id < BDEV_VIRTIO_MAX_TARGET) {
|
2017-12-22 10:57:52 +00:00
|
|
|
_virtio_scsi_dev_scan_tgt(base, target_id);
|
|
|
|
return 0;
|
2017-12-19 08:48:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
base->full_scan = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
next = TAILQ_FIRST(&base->scan_queue);
|
|
|
|
if (next == NULL) {
|
2017-12-14 15:01:28 +00:00
|
|
|
_virtio_scsi_dev_scan_finish(base, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-12-19 08:48:51 +00:00
|
|
|
TAILQ_REMOVE(&base->scan_queue, next, tailq);
|
2017-12-22 10:57:52 +00:00
|
|
|
target_id = next->target;
|
2017-12-19 08:48:51 +00:00
|
|
|
free(next);
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-12-22 10:57:52 +00:00
|
|
|
_virtio_scsi_dev_scan_tgt(base, target_id);
|
|
|
|
return 0;
|
2017-05-30 21:13:50 +00:00
|
|
|
}
|
|
|
|
|
2018-01-11 18:28:49 +00:00
|
|
|
static int
|
|
|
|
virtio_pci_scsi_dev_enumerate_cb(struct virtio_pci_ctx *pci_ctx, void *ctx)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_dev *svdev;
|
|
|
|
|
2018-01-11 18:42:04 +00:00
|
|
|
svdev = virtio_pci_scsi_dev_create(NULL, pci_ctx);
|
2018-01-11 18:28:49 +00:00
|
|
|
return svdev == NULL ? -1 : 0;
|
|
|
|
}
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
static int
|
2017-10-12 18:48:18 +00:00
|
|
|
bdev_virtio_process_config(void)
|
2017-05-30 21:13:50 +00:00
|
|
|
{
|
2017-10-12 18:48:18 +00:00
|
|
|
struct spdk_conf_section *sp;
|
2017-11-30 10:58:25 +00:00
|
|
|
struct virtio_scsi_dev *svdev;
|
2017-10-03 18:23:37 +00:00
|
|
|
char *default_name = NULL;
|
2017-12-27 15:22:48 +00:00
|
|
|
char *path, *type, *name;
|
2017-10-12 18:48:18 +00:00
|
|
|
unsigned vdev_num;
|
2017-10-10 18:44:35 +00:00
|
|
|
int num_queues;
|
2017-10-12 18:48:18 +00:00
|
|
|
bool enable_pci;
|
2017-08-22 17:16:39 +00:00
|
|
|
int rc = 0;
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-10-12 18:48:18 +00:00
|
|
|
for (sp = spdk_conf_first_section(NULL); sp != NULL; sp = spdk_conf_next_section(sp)) {
|
|
|
|
if (!spdk_conf_section_match_prefix(sp, "VirtioUser")) {
|
2017-05-30 21:13:50 +00:00
|
|
|
continue;
|
|
|
|
}
|
2017-10-12 18:48:18 +00:00
|
|
|
|
|
|
|
if (sscanf(spdk_conf_section_get_name(sp), "VirtioUser%u", &vdev_num) != 1) {
|
|
|
|
SPDK_ERRLOG("Section '%s' has non-numeric suffix.\n",
|
|
|
|
spdk_conf_section_get_name(sp));
|
|
|
|
rc = -1;
|
|
|
|
goto out;
|
2017-05-30 21:13:50 +00:00
|
|
|
}
|
2017-10-12 18:48:18 +00:00
|
|
|
|
|
|
|
path = spdk_conf_section_get_val(sp, "Path");
|
|
|
|
if (path == NULL) {
|
|
|
|
SPDK_ERRLOG("VirtioUser%u: missing Path\n", vdev_num);
|
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-12-27 15:22:48 +00:00
|
|
|
type = spdk_conf_section_get_val(sp, "Type");
|
|
|
|
if (type != NULL && strcmp(type, "SCSI") != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-10-10 18:44:35 +00:00
|
|
|
num_queues = spdk_conf_section_get_intval(sp, "Queues");
|
|
|
|
if (num_queues < 1) {
|
|
|
|
num_queues = 1;
|
2018-04-20 21:53:24 +00:00
|
|
|
} else if (num_queues > SPDK_VIRTIO_MAX_VIRTQUEUES) {
|
|
|
|
num_queues = SPDK_VIRTIO_MAX_VIRTQUEUES;
|
2017-10-10 18:44:35 +00:00
|
|
|
}
|
|
|
|
|
2017-10-03 18:23:37 +00:00
|
|
|
name = spdk_conf_section_get_val(sp, "Name");
|
|
|
|
if (name == NULL) {
|
|
|
|
default_name = spdk_sprintf_alloc("VirtioScsi%u", vdev_num);
|
|
|
|
name = default_name;
|
|
|
|
}
|
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
svdev = virtio_user_scsi_dev_create(name, path, num_queues, 512);
|
2017-10-03 18:23:37 +00:00
|
|
|
free(default_name);
|
|
|
|
default_name = NULL;
|
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
if (svdev == NULL) {
|
|
|
|
rc = -1;
|
2017-10-12 18:48:18 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sp = spdk_conf_find_section(NULL, "VirtioPci");
|
|
|
|
if (sp == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
enable_pci = spdk_conf_section_get_boolval(sp, "Enable", false);
|
|
|
|
if (enable_pci) {
|
2018-01-11 18:28:49 +00:00
|
|
|
rc = virtio_pci_dev_enumerate(virtio_pci_scsi_dev_enumerate_cb, NULL,
|
2017-12-27 23:27:47 +00:00
|
|
|
PCI_DEVICE_ID_VIRTIO_SCSI_MODERN);
|
2017-10-12 18:48:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-10-03 18:23:37 +00:00
|
|
|
static int
|
2017-12-19 08:48:51 +00:00
|
|
|
_virtio_scsi_dev_scan_init(struct virtio_scsi_dev *svdev)
|
2017-10-03 18:23:37 +00:00
|
|
|
{
|
2017-12-01 17:17:06 +00:00
|
|
|
struct virtio_scsi_scan_base *base;
|
2017-12-01 11:34:51 +00:00
|
|
|
struct spdk_io_channel *io_ch;
|
2017-12-14 15:01:28 +00:00
|
|
|
struct virtio_scsi_io_ctx *io_ctx;
|
|
|
|
struct virtio_scsi_cmd_req *req;
|
|
|
|
struct virtio_scsi_cmd_resp *resp;
|
2017-10-03 18:23:37 +00:00
|
|
|
|
2017-12-01 17:17:06 +00:00
|
|
|
io_ch = spdk_get_io_channel(svdev);
|
|
|
|
if (io_ch == NULL) {
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2019-03-15 14:35:49 +00:00
|
|
|
base = spdk_zmalloc(sizeof(*base), 64, NULL,
|
|
|
|
SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
|
2017-10-03 18:23:37 +00:00
|
|
|
if (base == NULL) {
|
|
|
|
SPDK_ERRLOG("couldn't allocate memory for scsi target scan.\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2017-11-30 10:58:25 +00:00
|
|
|
base->svdev = svdev;
|
2017-10-03 18:23:37 +00:00
|
|
|
|
2017-12-01 11:34:51 +00:00
|
|
|
base->channel = spdk_io_channel_get_ctx(io_ch);
|
2017-12-19 08:48:51 +00:00
|
|
|
TAILQ_INIT(&base->scan_queue);
|
2017-11-30 15:13:38 +00:00
|
|
|
svdev->scan_ctx = base;
|
2017-12-14 15:01:28 +00:00
|
|
|
|
|
|
|
base->iov.iov_base = base->payload;
|
|
|
|
io_ctx = &base->io_ctx;
|
|
|
|
req = &io_ctx->req;
|
|
|
|
resp = &io_ctx->resp;
|
|
|
|
io_ctx->iov_req.iov_base = req;
|
|
|
|
io_ctx->iov_req.iov_len = sizeof(*req);
|
|
|
|
io_ctx->iov_resp.iov_base = resp;
|
|
|
|
io_ctx->iov_resp.iov_len = sizeof(*resp);
|
|
|
|
|
|
|
|
base->retries = SCAN_REQUEST_RETRIES;
|
2017-12-19 08:48:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-12-22 10:57:52 +00:00
|
|
|
static void
|
|
|
|
_virtio_scsi_dev_scan_tgt(struct virtio_scsi_scan_base *base, uint8_t target)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
memset(&base->info, 0, sizeof(base->info));
|
|
|
|
base->info.target = target;
|
|
|
|
|
|
|
|
rc = send_inquiry(base);
|
|
|
|
if (rc) {
|
|
|
|
/* Let response poller do the resend */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-19 08:48:51 +00:00
|
|
|
static int
|
|
|
|
virtio_scsi_dev_scan(struct virtio_scsi_dev *svdev, bdev_virtio_create_cb cb_fn,
|
|
|
|
void *cb_arg)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_scan_base *base;
|
2017-12-19 09:28:05 +00:00
|
|
|
struct virtio_scsi_scan_info *tgt, *next_tgt;
|
2017-12-19 08:48:51 +00:00
|
|
|
int rc;
|
|
|
|
|
2017-12-19 09:28:05 +00:00
|
|
|
if (svdev->scan_ctx) {
|
|
|
|
if (svdev->scan_ctx->full_scan) {
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We're about to start a full rescan, so there's no need
|
|
|
|
* to scan particular targets afterwards.
|
|
|
|
*/
|
|
|
|
TAILQ_FOREACH_SAFE(tgt, &svdev->scan_ctx->scan_queue, tailq, next_tgt) {
|
|
|
|
TAILQ_REMOVE(&svdev->scan_ctx->scan_queue, tgt, tailq);
|
|
|
|
free(tgt);
|
|
|
|
}
|
|
|
|
|
|
|
|
svdev->scan_ctx->cb_fn = cb_fn;
|
|
|
|
svdev->scan_ctx->cb_arg = cb_arg;
|
|
|
|
svdev->scan_ctx->restart = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-12-19 08:48:51 +00:00
|
|
|
rc = _virtio_scsi_dev_scan_init(svdev);
|
|
|
|
if (rc != 0) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
base = svdev->scan_ctx;
|
|
|
|
base->cb_fn = cb_fn;
|
|
|
|
base->cb_arg = cb_arg;
|
|
|
|
base->full_scan = true;
|
|
|
|
|
2017-12-22 10:57:52 +00:00
|
|
|
_virtio_scsi_dev_scan_tgt(base, 0);
|
2017-12-19 08:48:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virtio_scsi_dev_scan_tgt(struct virtio_scsi_dev *svdev, uint8_t target)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_scan_base *base;
|
|
|
|
struct virtio_scsi_scan_info *info;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
base = svdev->scan_ctx;
|
|
|
|
if (base) {
|
|
|
|
info = calloc(1, sizeof(*info));
|
|
|
|
if (info == NULL) {
|
|
|
|
SPDK_ERRLOG("calloc failed\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
info->target = target;
|
|
|
|
TAILQ_INSERT_TAIL(&base->scan_queue, info, tailq);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = _virtio_scsi_dev_scan_init(svdev);
|
|
|
|
if (rc != 0) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
base = svdev->scan_ctx;
|
|
|
|
base->full_scan = true;
|
2017-12-22 10:57:52 +00:00
|
|
|
_virtio_scsi_dev_scan_tgt(base, target);
|
2017-12-18 17:41:35 +00:00
|
|
|
return 0;
|
2017-10-03 18:23:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-03-27 10:40:27 +00:00
|
|
|
bdev_virtio_initial_scan_complete(void *ctx, int result,
|
|
|
|
struct spdk_bdev **bdevs, size_t bdevs_cnt)
|
2017-10-03 18:23:37 +00:00
|
|
|
{
|
2018-03-23 12:49:35 +00:00
|
|
|
struct virtio_scsi_dev *svdev;
|
2017-11-30 15:13:38 +00:00
|
|
|
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_lock(&g_virtio_scsi_mutex);
|
2018-03-23 12:49:35 +00:00
|
|
|
TAILQ_FOREACH(svdev, &g_virtio_scsi_devs, tailq) {
|
|
|
|
if (svdev->scan_ctx) {
|
2017-11-30 15:13:38 +00:00
|
|
|
/* another device is still being scanned */
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
2017-11-30 15:13:38 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-10-03 18:23:37 +00:00
|
|
|
}
|
2017-11-30 15:13:38 +00:00
|
|
|
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
2018-03-06 18:52:46 +00:00
|
|
|
spdk_bdev_module_init_done(&virtio_scsi_if);
|
2017-10-03 18:23:37 +00:00
|
|
|
}
|
2017-10-12 18:48:18 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
bdev_virtio_initialize(void)
|
|
|
|
{
|
2018-03-23 12:49:35 +00:00
|
|
|
struct virtio_scsi_dev *svdev, *next_svdev;
|
2017-10-03 18:23:37 +00:00
|
|
|
int rc;
|
2017-10-12 18:48:18 +00:00
|
|
|
|
|
|
|
rc = bdev_virtio_process_config();
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_lock(&g_virtio_scsi_mutex);
|
|
|
|
|
2017-10-12 18:48:18 +00:00
|
|
|
if (rc != 0) {
|
2018-03-25 12:03:28 +00:00
|
|
|
goto err_unlock;
|
2017-10-12 18:48:18 +00:00
|
|
|
}
|
|
|
|
|
2018-03-23 12:49:35 +00:00
|
|
|
if (TAILQ_EMPTY(&g_virtio_scsi_devs)) {
|
2018-03-25 12:03:28 +00:00
|
|
|
goto out_unlock;
|
2017-08-22 17:16:39 +00:00
|
|
|
}
|
|
|
|
|
2017-10-11 11:45:53 +00:00
|
|
|
/* Initialize all created devices and scan available targets */
|
2018-03-23 12:49:35 +00:00
|
|
|
TAILQ_FOREACH(svdev, &g_virtio_scsi_devs, tailq) {
|
2017-12-01 17:17:06 +00:00
|
|
|
rc = virtio_scsi_dev_scan(svdev, bdev_virtio_initial_scan_complete, NULL);
|
2017-10-10 18:44:35 +00:00
|
|
|
if (rc != 0) {
|
2018-03-25 12:03:28 +00:00
|
|
|
goto err_unlock;
|
2017-10-17 12:36:39 +00:00
|
|
|
}
|
2017-09-21 18:28:51 +00:00
|
|
|
}
|
2017-08-24 19:13:12 +00:00
|
|
|
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
2017-05-30 21:13:50 +00:00
|
|
|
return 0;
|
2017-08-22 17:16:39 +00:00
|
|
|
|
2018-03-25 12:03:28 +00:00
|
|
|
err_unlock:
|
2017-10-11 11:45:53 +00:00
|
|
|
/* Remove any created devices */
|
2018-03-23 12:49:35 +00:00
|
|
|
TAILQ_FOREACH_SAFE(svdev, &g_virtio_scsi_devs, tailq, next_svdev) {
|
2018-01-10 05:28:40 +00:00
|
|
|
virtio_scsi_dev_remove(svdev, NULL, NULL);
|
2017-10-11 11:45:53 +00:00
|
|
|
}
|
|
|
|
|
2018-03-25 12:03:28 +00:00
|
|
|
out_unlock:
|
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
2018-03-06 18:52:46 +00:00
|
|
|
spdk_bdev_module_init_done(&virtio_scsi_if);
|
2017-08-22 17:16:39 +00:00
|
|
|
return rc;
|
2017-05-30 21:13:50 +00:00
|
|
|
}
|
|
|
|
|
2017-10-03 18:23:37 +00:00
|
|
|
static void
|
2018-03-25 12:03:28 +00:00
|
|
|
_virtio_scsi_dev_unregister_cb(void *io_device)
|
2017-05-30 21:13:50 +00:00
|
|
|
{
|
2017-11-30 10:58:25 +00:00
|
|
|
struct virtio_scsi_dev *svdev = io_device;
|
|
|
|
struct virtio_dev *vdev = &svdev->vdev;
|
2017-11-23 19:34:44 +00:00
|
|
|
bool finish_module;
|
2018-01-10 05:28:40 +00:00
|
|
|
bdev_virtio_remove_cb remove_cb;
|
|
|
|
void *remove_ctx;
|
2017-11-23 19:34:44 +00:00
|
|
|
|
2017-12-02 09:34:55 +00:00
|
|
|
assert(spdk_ring_count(svdev->ctrlq_ring) == 0);
|
|
|
|
spdk_ring_free(svdev->ctrlq_ring);
|
|
|
|
spdk_poller_unregister(&svdev->mgmt_poller);
|
|
|
|
|
2017-12-02 12:08:07 +00:00
|
|
|
virtio_dev_release_queue(vdev, VIRTIO_SCSI_EVENTQ);
|
2017-12-02 09:34:55 +00:00
|
|
|
virtio_dev_release_queue(vdev, VIRTIO_SCSI_CONTROLQ);
|
2017-11-21 20:58:37 +00:00
|
|
|
|
2017-11-20 18:24:24 +00:00
|
|
|
virtio_dev_stop(vdev);
|
|
|
|
virtio_dev_destruct(vdev);
|
2018-01-10 05:28:40 +00:00
|
|
|
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_lock(&g_virtio_scsi_mutex);
|
2018-03-23 12:49:35 +00:00
|
|
|
TAILQ_REMOVE(&g_virtio_scsi_devs, svdev, tailq);
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
|
|
|
|
2018-01-10 05:28:40 +00:00
|
|
|
remove_cb = svdev->remove_cb;
|
|
|
|
remove_ctx = svdev->remove_ctx;
|
2019-03-15 14:35:49 +00:00
|
|
|
spdk_free(svdev->eventq_ios);
|
2017-11-30 10:58:25 +00:00
|
|
|
free(svdev);
|
2017-11-23 19:34:44 +00:00
|
|
|
|
2018-01-10 05:28:40 +00:00
|
|
|
if (remove_cb) {
|
|
|
|
remove_cb(remove_ctx, 0);
|
|
|
|
}
|
|
|
|
|
2018-03-23 12:49:35 +00:00
|
|
|
finish_module = TAILQ_EMPTY(&g_virtio_scsi_devs);
|
2017-11-23 19:34:44 +00:00
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
if (g_bdev_virtio_finish && finish_module) {
|
2017-11-23 19:34:44 +00:00
|
|
|
spdk_bdev_module_finish_done();
|
|
|
|
}
|
2017-11-21 20:58:37 +00:00
|
|
|
}
|
|
|
|
|
2018-03-25 12:03:28 +00:00
|
|
|
static void
|
|
|
|
virtio_scsi_dev_unregister_cb(void *io_device)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_dev *svdev = io_device;
|
|
|
|
struct spdk_thread *thread;
|
|
|
|
|
|
|
|
thread = virtio_dev_queue_get_thread(&svdev->vdev, VIRTIO_SCSI_CONTROLQ);
|
|
|
|
spdk_thread_send_msg(thread, _virtio_scsi_dev_unregister_cb, io_device);
|
|
|
|
}
|
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
static void
|
2018-01-10 05:28:40 +00:00
|
|
|
virtio_scsi_dev_remove(struct virtio_scsi_dev *svdev,
|
|
|
|
bdev_virtio_remove_cb cb_fn, void *cb_arg)
|
2017-12-01 00:46:59 +00:00
|
|
|
{
|
|
|
|
struct virtio_scsi_disk *disk, *disk_tmp;
|
|
|
|
bool do_remove = true;
|
|
|
|
|
|
|
|
if (svdev->removed) {
|
2018-01-10 05:28:40 +00:00
|
|
|
if (cb_fn) {
|
|
|
|
cb_fn(cb_arg, -EBUSY);
|
|
|
|
}
|
2017-12-01 00:46:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-10 05:28:40 +00:00
|
|
|
svdev->remove_cb = cb_fn;
|
|
|
|
svdev->remove_ctx = cb_arg;
|
2017-12-01 00:46:59 +00:00
|
|
|
svdev->removed = true;
|
|
|
|
|
2017-12-18 20:55:33 +00:00
|
|
|
if (svdev->scan_ctx) {
|
|
|
|
/* The removal will continue after we receive a pending scan I/O. */
|
|
|
|
return;
|
2017-12-01 00:46:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_FOREACH_SAFE(disk, &svdev->luns, link, disk_tmp) {
|
2018-01-10 06:43:11 +00:00
|
|
|
if (!disk->removed) {
|
|
|
|
spdk_bdev_unregister(&disk->bdev, NULL, NULL);
|
|
|
|
}
|
2017-12-01 00:46:59 +00:00
|
|
|
do_remove = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (do_remove) {
|
|
|
|
spdk_io_device_unregister(svdev, virtio_scsi_dev_unregister_cb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-21 20:58:37 +00:00
|
|
|
static void
|
|
|
|
bdev_virtio_finish(void)
|
|
|
|
{
|
2018-03-23 12:49:35 +00:00
|
|
|
struct virtio_scsi_dev *svdev, *next;
|
2017-11-21 20:58:37 +00:00
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
g_bdev_virtio_finish = true;
|
|
|
|
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_lock(&g_virtio_scsi_mutex);
|
2018-03-23 12:49:35 +00:00
|
|
|
if (TAILQ_EMPTY(&g_virtio_scsi_devs)) {
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
2017-11-23 19:34:44 +00:00
|
|
|
spdk_bdev_module_finish_done();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
/* Defer module finish until all controllers are removed. */
|
2018-03-23 12:49:35 +00:00
|
|
|
TAILQ_FOREACH_SAFE(svdev, &g_virtio_scsi_devs, tailq, next) {
|
|
|
|
virtio_scsi_dev_remove(svdev, NULL, NULL);
|
2017-10-03 18:58:58 +00:00
|
|
|
}
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
2017-05-30 21:13:50 +00:00
|
|
|
}
|
|
|
|
|
2017-10-03 18:23:37 +00:00
|
|
|
int
|
2018-01-11 18:28:49 +00:00
|
|
|
bdev_virtio_user_scsi_dev_create(const char *base_name, const char *path,
|
|
|
|
unsigned num_queues, unsigned queue_size,
|
|
|
|
bdev_virtio_create_cb cb_fn, void *cb_arg)
|
2017-10-03 18:23:37 +00:00
|
|
|
{
|
2017-11-30 10:58:25 +00:00
|
|
|
struct virtio_scsi_dev *svdev;
|
2017-10-03 18:23:37 +00:00
|
|
|
int rc;
|
|
|
|
|
2017-12-01 00:46:59 +00:00
|
|
|
svdev = virtio_user_scsi_dev_create(base_name, path, num_queues, queue_size);
|
2017-11-30 10:58:25 +00:00
|
|
|
if (svdev == NULL) {
|
2017-12-01 00:46:59 +00:00
|
|
|
return -1;
|
2017-10-03 18:23:37 +00:00
|
|
|
}
|
|
|
|
|
2017-12-01 17:17:06 +00:00
|
|
|
rc = virtio_scsi_dev_scan(svdev, cb_fn, cb_arg);
|
2017-10-03 18:23:37 +00:00
|
|
|
if (rc) {
|
2018-01-10 05:28:40 +00:00
|
|
|
virtio_scsi_dev_remove(svdev, NULL, NULL);
|
2017-10-03 18:23:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-01-11 18:28:49 +00:00
|
|
|
struct bdev_virtio_pci_dev_create_ctx {
|
2018-01-11 18:42:04 +00:00
|
|
|
const char *name;
|
2018-01-11 18:28:49 +00:00
|
|
|
bdev_virtio_create_cb cb_fn;
|
|
|
|
void *cb_arg;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
bdev_virtio_pci_scsi_dev_create_cb(struct virtio_pci_ctx *pci_ctx, void *ctx)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_dev *svdev;
|
|
|
|
struct bdev_virtio_pci_dev_create_ctx *create_ctx = ctx;
|
|
|
|
int rc;
|
|
|
|
|
2018-01-11 18:42:04 +00:00
|
|
|
svdev = virtio_pci_scsi_dev_create(create_ctx->name, pci_ctx);
|
2018-01-11 18:28:49 +00:00
|
|
|
if (svdev == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = virtio_scsi_dev_scan(svdev, create_ctx->cb_fn, create_ctx->cb_arg);
|
|
|
|
if (rc) {
|
2020-07-29 15:45:42 +00:00
|
|
|
svdev->vdev.ctx = NULL;
|
2018-01-11 18:28:49 +00:00
|
|
|
virtio_scsi_dev_remove(svdev, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2018-01-11 18:42:04 +00:00
|
|
|
bdev_virtio_pci_scsi_dev_create(const char *name, struct spdk_pci_addr *pci_addr,
|
2018-01-11 18:28:49 +00:00
|
|
|
bdev_virtio_create_cb cb_fn, void *cb_arg)
|
|
|
|
{
|
|
|
|
struct bdev_virtio_pci_dev_create_ctx create_ctx;
|
|
|
|
|
2018-01-11 18:42:04 +00:00
|
|
|
create_ctx.name = name;
|
2018-01-11 18:28:49 +00:00
|
|
|
create_ctx.cb_fn = cb_fn;
|
|
|
|
create_ctx.cb_arg = cb_arg;
|
|
|
|
|
|
|
|
return virtio_pci_dev_attach(bdev_virtio_pci_scsi_dev_create_cb, &create_ctx,
|
|
|
|
PCI_DEVICE_ID_VIRTIO_SCSI_MODERN, pci_addr);
|
|
|
|
}
|
|
|
|
|
2018-07-26 14:08:16 +00:00
|
|
|
int
|
2018-01-10 05:28:40 +00:00
|
|
|
bdev_virtio_scsi_dev_remove(const char *name, bdev_virtio_remove_cb cb_fn, void *cb_arg)
|
|
|
|
{
|
2018-03-23 12:49:35 +00:00
|
|
|
struct virtio_scsi_dev *svdev;
|
2018-01-10 05:28:40 +00:00
|
|
|
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_lock(&g_virtio_scsi_mutex);
|
2018-03-23 12:49:35 +00:00
|
|
|
TAILQ_FOREACH(svdev, &g_virtio_scsi_devs, tailq) {
|
|
|
|
if (strcmp(svdev->vdev.name, name) == 0) {
|
2018-01-10 05:28:40 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (svdev == NULL) {
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
2018-01-10 05:28:40 +00:00
|
|
|
SPDK_ERRLOG("Cannot find Virtio-SCSI device named '%s'\n", name);
|
2018-07-26 14:08:16 +00:00
|
|
|
return -ENODEV;
|
2018-01-10 05:28:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtio_scsi_dev_remove(svdev, cb_fn, cb_arg);
|
2018-03-25 12:03:28 +00:00
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
2018-07-26 14:08:16 +00:00
|
|
|
|
|
|
|
return 0;
|
2018-01-10 05:28:40 +00:00
|
|
|
}
|
2017-10-03 18:23:37 +00:00
|
|
|
|
2018-03-25 18:17:11 +00:00
|
|
|
void
|
|
|
|
bdev_virtio_scsi_dev_list(struct spdk_json_write_ctx *w)
|
|
|
|
{
|
|
|
|
struct virtio_scsi_dev *svdev;
|
|
|
|
|
|
|
|
spdk_json_write_array_begin(w);
|
|
|
|
|
|
|
|
pthread_mutex_lock(&g_virtio_scsi_mutex);
|
|
|
|
TAILQ_FOREACH(svdev, &g_virtio_scsi_devs, tailq) {
|
|
|
|
spdk_json_write_object_begin(w);
|
|
|
|
|
2019-02-01 05:34:45 +00:00
|
|
|
spdk_json_write_named_string(w, "name", svdev->vdev.name);
|
2018-03-25 18:17:11 +00:00
|
|
|
|
2018-03-27 13:45:10 +00:00
|
|
|
virtio_dev_dump_json_info(&svdev->vdev, w);
|
2018-03-25 18:17:11 +00:00
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_virtio_scsi_mutex);
|
|
|
|
|
|
|
|
spdk_json_write_array_end(w);
|
|
|
|
}
|
|
|
|
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_LOG_REGISTER_COMPONENT(virtio)
|