git: 9542ddb21dc1 - main - bhyve/virtio-scsi: Support multiple backends
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 26 May 2026 16:07:17 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=9542ddb21dc15986843708d3f845eb23e7090107
commit 9542ddb21dc15986843708d3f845eb23e7090107
Author: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
AuthorDate: 2025-09-16 15:34:12 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-05-26 16:03:12 +0000
bhyve/virtio-scsi: Support multiple backends
In order to support multiple backends for virtio-scsi, we should isolate
the core of virtio-scsi from the backend-specific code. The existing
interface to CTL will become the new "CTL" backend for virtio-scsi.
Care has been taken to keep compatibility with previous configurations:
The first backend linked (CTL) will be the default backend if none is
specified, and it does provide a default configuration if no further
options such as targets are explicitly configured.
Reviewed by: markj
MFC after: 1 month
Differential Revision: https://reviews.freebsd.org/D53223
---
usr.sbin/bhyve/Makefile | 1 +
usr.sbin/bhyve/bhyve.8 | 44 ++-
usr.sbin/bhyve/bhyve_config.5 | 29 +-
usr.sbin/bhyve/pci_virtio_scsi.c | 617 ++++++-----------------------------
usr.sbin/bhyve/pci_virtio_scsi.h | 394 ++++++++++++++++++++++
usr.sbin/bhyve/pci_virtio_scsi_ctl.c | 377 +++++++++++++++++++++
6 files changed, 927 insertions(+), 535 deletions(-)
diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile
index 25fb71b5768f..b86c56991039 100644
--- a/usr.sbin/bhyve/Makefile
+++ b/usr.sbin/bhyve/Makefile
@@ -53,6 +53,7 @@ SRCS= \
pci_virtio_net.c \
pci_virtio_rnd.c \
pci_virtio_scsi.c \
+ pci_virtio_scsi_ctl.c \
pci_xhci.c \
qemu_fwcfg.c \
qemu_loader.c \
diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
index b5b03dd9c211..01b7dba941ac 100644
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -681,8 +681,9 @@ In that case, this feature doesn't work as expected.
.Bl -bullet
.Sm off
.It
-.Oo Cm target Ns = Ns Oo ID : Oc Ar /dev/cam/ctl Oo Ar pp Cm \&. Ar vp Oc Oc
+.Oo Cm target Ns = Ns Oo ID : Oc Ar path Ns Oc
.Oo Cm \&, Ar scsi-device-options Oc
+.Oo Cm \&, Ar backend-specific-options Oc
.Sm on
.El
.Pp
@@ -708,25 +709,28 @@ All
.Pa target
.Ar ID Ns s
must be unique per instance.
-The
+The meaning of the
.Ar path
-must point to a valid CAM target layer
-.Po CTL
-.Pc
-device node.
-If no
-.Pa target
-is configured, a single default target backed by
-.Sy /dev/cam/ctl
-will be created.
+argument is specific to each backend:
+.Bl -column "Backend" "/dev/cam/ctl[pp.vp]"
+.It Sy Backend Ta Sy Path Ta Sy Description
+.It ctl Ta Pa /dev/cam/ctl Ns Oo Ar pp . Ns Ar vp Oc Ta
+The path of a CAM target layer (CTL) device node.
+If no target is configured, a single target backed by
+.Qq /dev/cam/ctl
+will be configured by default.
+.El
.Pp
The
.Ar scsi-device-options
are:
.Bl -tag -width 10n
-.It Cm iid= Ns Ar IID
-Initiator ID to use when sending requests to specified CTL port.
-The default value is 0.
+.It Cm backend= Ns Ar backend
+The virtio-scsi backend to use.
+The backend name is case-insensitive.
+There is currently only one backend
+.Qq ctl ,
+which is also the default backend.
.It Li bootindex= Ns Ar index
Add the device to the boot order at
.Ar index .
@@ -734,6 +738,18 @@ A fw_cfg file is used to specify the boot order.
The guest firmware may ignore or not support this fw_cfg file.
In that case, this feature doesn't work as expected.
.El
+.Pp
+The
+.Ar backend-specific-options
+for the
+.Sy CTL
+backend are:
+.Bl -tag -width 10n
+.It Cm iid= Ns Ar IID
+Initiator ID to use when sending requests to
+.Sy CTL .
+The default value is 0.
+.El
.Ss 9P device backends
.Bl -bullet
.Sm off
diff --git a/usr.sbin/bhyve/bhyve_config.5 b/usr.sbin/bhyve/bhyve_config.5
index ea3157cb54d6..d4361468bc22 100644
--- a/usr.sbin/bhyve/bhyve_config.5
+++ b/usr.sbin/bhyve/bhyve_config.5
@@ -762,13 +762,14 @@ If specified, it must be a unicast MAC address.
The largest supported MTU advertised to the guest.
.El
.Ss VirtIO SCSI Settings
-.Bl -column "target" "integer" "/dev/cam/ctl"
+.Bl -column "backend" "string" "/dev/cam/ctl"
.It Sy Name Ta Sy Format Ta Sy Default Ta Sy Description
-.It Va iid Ta integer Ta 0 Ta
-Initiator ID to use when sending requests to the CTL port.
-.It Va target Ta Oo Va ID : Oc Ns path Ta Sy /dev/cam/ctl Ta
-The path of a CAM target layer (CTL) device to use:
-.Pa /dev/cam/ctl Ns Oo Ar pp . Ns Ar vp Oc
+.It Va backend Ta string Ta ctl Ta
+The virtio-scsi backend to use (case-insensitive).
+.It Va target Ta Oo Va ID : Oc Ns path Ta /dev/cam/ctl Ta
+The backend
+.Ar path
+of a target to configure.
Optionally, a numeric target
.Ar ID
in the range from 0 to 255 may be specified before the
@@ -789,6 +790,22 @@ configured so far, or 0 for the first target configured.
The target
.Ar ID Ns s
must be unique within each virtio-scsi instance.
+.Pp
+The meaning of the
+.Ar path
+argument is specific to each backend:
+.Bl -column "Backend" "/dev/cam/ctl[pp.vp]"
+.It Sy Backend Ta Sy Path Ta Sy Description
+.It ctl Ta Pa /dev/cam/ctl Ns Oo Ar pp . Ns Ar vp Oc Ta
+The path of a CAM target layer (CTL) device to configure as a target.
+.El
+.Pp
+The following backend-specific variables are supported for VirtIO SCSI:
+.Bl -column "Backend" "Name" "integer" "Default"
+.It Sy Backend Ta Sy Name Ta Sy Format Ta Sy Default Ta Sy Description
+.It ctl Ta Va iid Ta integer Ta 0 Ta
+Initiator ID to use when sending requests to CTL.
+.El
.Sh SEE ALSO
.Xr expand_number 3 ,
.Xr getaddrinfo 3 ,
diff --git a/usr.sbin/bhyve/pci_virtio_scsi.c b/usr.sbin/bhyve/pci_virtio_scsi.c
index a77fadf71aff..47b90184fe08 100644
--- a/usr.sbin/bhyve/pci_virtio_scsi.c
+++ b/usr.sbin/bhyve/pci_virtio_scsi.c
@@ -35,7 +35,6 @@
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/queue.h>
-#include <sys/sbuf.h>
#include <errno.h>
#include <fcntl.h>
@@ -48,16 +47,6 @@
#include <pthread.h>
#include <pthread_np.h>
-#include <cam/scsi/scsi_all.h>
-#include <cam/scsi/scsi_message.h>
-#include <cam/ctl/ctl.h>
-#include <cam/ctl/ctl_io.h>
-#include <cam/ctl/ctl_backend.h>
-#include <cam/ctl/ctl_ioctl.h>
-#include <cam/ctl/ctl_util.h>
-#include <cam/ctl/ctl_scsi_all.h>
-#include <camlib.h>
-
#include "bhyverun.h"
#include "config.h"
#include "debug.h"
@@ -65,216 +54,7 @@
#include "virtio.h"
#include "iov.h"
-#define VTSCSI_RINGSZ 64
-#define VTSCSI_REQUESTQ 1
-#define VTSCSI_THR_PER_Q 16
-#define VTSCSI_MAXQ (VTSCSI_REQUESTQ + 2)
-#define VTSCSI_MAXSEG 64
-
-#define VTSCSI_IN_HEADER_LEN(_sc) \
- (sizeof(struct pci_vtscsi_req_cmd_rd) + _sc->vss_config.cdb_size)
-
-#define VTSCSI_OUT_HEADER_LEN(_sc) \
- (sizeof(struct pci_vtscsi_req_cmd_wr) + _sc->vss_config.sense_size)
-
-#define VIRTIO_SCSI_MAX_CHANNEL 0
-#define VIRTIO_SCSI_MAX_TARGET 255
-#define VIRTIO_SCSI_MAX_LUN 16383
-
-#define VIRTIO_SCSI_F_INOUT (1 << 0)
-#define VIRTIO_SCSI_F_HOTPLUG (1 << 1)
-#define VIRTIO_SCSI_F_CHANGE (1 << 2)
-
-static int pci_vtscsi_debug = 0;
-#define WPRINTF(msg, params...) PRINTLN("virtio-scsi: " msg, ##params)
-#define DPRINTF(msg, params...) if (pci_vtscsi_debug) WPRINTF(msg, ##params)
-
-struct pci_vtscsi_config {
- uint32_t num_queues;
- uint32_t seg_max;
- uint32_t max_sectors;
- uint32_t cmd_per_lun;
- uint32_t event_info_size;
- uint32_t sense_size;
- uint32_t cdb_size;
- uint16_t max_channel;
- uint16_t max_target;
- uint32_t max_lun;
-} __attribute__((packed));
-
-/*
- * I/O request state and I/O request queues
- *
- * In addition to the control queue and notification queues, each virtio-scsi
- * device instance has at least one I/O request queue, the state of which is
- * is kept in an array of struct pci_vtscsi_queue in the device softc.
- *
- * Currently there is only one I/O request queue, but it's trivial to support
- * more than one.
- *
- * Each pci_vtscsi_queue has VTSCSI_RINGSZ pci_vtscsi_request structures pre-
- * allocated on vsq_free_requests. For each I/O request coming in on the I/O
- * virtqueue, the request queue handler will take a pci_vtscsi_request off
- * vsq_free_requests, fills in the data from the I/O virtqueue, puts it on
- * vsq_requests, and signals vsq_cv.
- *
- * There are VTSCSI_THR_PER_Q worker threads for each pci_vtscsi_queue which
- * wait on vsq_cv. When signalled, they repeatedly take one pci_vtscsi_request
- * off vsq_requests, construct a ctl_io for it, and hand it off to the CTL ioctl
- * Interface, which processes it synchronously. After completion of the request,
- * the pci_vtscsi_request is re-initialized and put back onto vsq_free_requests.
- *
- * The worker threads exit when vsq_cv is signalled after vsw_exiting was set.
- *
- * There are three mutexes to coordinate the accesses to an I/O request queue:
- * - vsq_rmtx protects vsq_requests and must be held when waiting on vsq_cv
- * - vsq_fmtx protects vsq_free_requests
- * - vsq_qmtx must be held when operating on the underlying virtqueue, vsq_vq
- */
-STAILQ_HEAD(pci_vtscsi_req_queue, pci_vtscsi_request);
-
-struct pci_vtscsi_queue {
- struct pci_vtscsi_softc * vsq_sc;
- struct vqueue_info * vsq_vq;
- pthread_mutex_t vsq_rmtx;
- pthread_mutex_t vsq_fmtx;
- pthread_mutex_t vsq_qmtx;
- pthread_cond_t vsq_cv;
- struct pci_vtscsi_req_queue vsq_requests;
- struct pci_vtscsi_req_queue vsq_free_requests;
- LIST_HEAD(, pci_vtscsi_worker) vsq_workers;
-};
-
-struct pci_vtscsi_worker {
- struct pci_vtscsi_queue * vsw_queue;
- pthread_t vsw_thread;
- bool vsw_exiting;
- LIST_ENTRY(pci_vtscsi_worker) vsw_link;
-};
-
-struct pci_vtscsi_request {
- struct pci_vtscsi_queue * vsr_queue;
- struct iovec vsr_iov[VTSCSI_MAXSEG + SPLIT_IOV_ADDL_IOV];
- struct iovec * vsr_iov_in;
- struct iovec * vsr_iov_out;
- struct iovec * vsr_data_iov_in;
- struct iovec * vsr_data_iov_out;
- struct pci_vtscsi_req_cmd_rd * vsr_cmd_rd;
- struct pci_vtscsi_req_cmd_wr * vsr_cmd_wr;
- union ctl_io * vsr_ctl_io;
- size_t vsr_niov_in;
- size_t vsr_niov_out;
- size_t vsr_data_niov_in;
- size_t vsr_data_niov_out;
- uint32_t vsr_idx;
- STAILQ_ENTRY(pci_vtscsi_request) vsr_link;
-};
-
-struct pci_vtscsi_target {
- uint8_t vst_target;
- int vst_fd;
- int vst_max_sectors;
-};
-
-/*
- * Per-device softc
- */
-struct pci_vtscsi_softc {
- struct virtio_softc vss_vs;
- struct vqueue_info vss_vq[VTSCSI_MAXQ];
- struct pci_vtscsi_queue vss_queues[VTSCSI_REQUESTQ];
- pthread_mutex_t vss_mtx;
- int vss_iid;
- int vss_ctl_fd;
- uint32_t vss_features;
- size_t vss_num_target;
- struct pci_vtscsi_config vss_config;
- struct pci_vtscsi_target *vss_targets;
-};
-
-#define VIRTIO_SCSI_T_TMF 0
-#define VIRTIO_SCSI_T_TMF_ABORT_TASK 0
-#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1
-#define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2
-#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3
-#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4
-#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5
-#define VIRTIO_SCSI_T_TMF_QUERY_TASK 6
-#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7
-
-#define VIRTIO_SCSI_T_TMF_MAX_FUNC VIRTIO_SCSI_T_TMF_QUERY_TASK_SET
-
-/* command-specific response values */
-#define VIRTIO_SCSI_S_FUNCTION_COMPLETE 0
-#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10
-#define VIRTIO_SCSI_S_FUNCTION_REJECTED 11
-
-struct pci_vtscsi_ctrl_tmf {
- const uint32_t type;
- const uint32_t subtype;
- const uint8_t lun[8];
- const uint64_t id;
- uint8_t response;
-} __attribute__((packed));
-
-#define VIRTIO_SCSI_T_AN_QUERY 1
-#define VIRTIO_SCSI_EVT_ASYNC_OPERATIONAL_CHANGE 2
-#define VIRTIO_SCSI_EVT_ASYNC_POWER_MGMT 4
-#define VIRTIO_SCSI_EVT_ASYNC_EXTERNAL_REQUEST 8
-#define VIRTIO_SCSI_EVT_ASYNC_MEDIA_CHANGE 16
-#define VIRTIO_SCSI_EVT_ASYNC_MULTI_HOST 32
-#define VIRTIO_SCSI_EVT_ASYNC_DEVICE_BUSY 64
-
-struct pci_vtscsi_ctrl_an {
- const uint32_t type;
- const uint8_t lun[8];
- const uint32_t event_requested;
- uint32_t event_actual;
- uint8_t response;
-} __attribute__((packed));
-
-/* command-specific response values */
-#define VIRTIO_SCSI_S_OK 0
-#define VIRTIO_SCSI_S_OVERRUN 1
-#define VIRTIO_SCSI_S_ABORTED 2
-#define VIRTIO_SCSI_S_BAD_TARGET 3
-#define VIRTIO_SCSI_S_RESET 4
-#define VIRTIO_SCSI_S_BUSY 5
-#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6
-#define VIRTIO_SCSI_S_TARGET_FAILURE 7
-#define VIRTIO_SCSI_S_NEXUS_FAILURE 8
-#define VIRTIO_SCSI_S_FAILURE 9
-#define VIRTIO_SCSI_S_INCORRECT_LUN 12
-
-/* task_attr */
-#define VIRTIO_SCSI_S_SIMPLE 0
-#define VIRTIO_SCSI_S_ORDERED 1
-#define VIRTIO_SCSI_S_HEAD 2
-#define VIRTIO_SCSI_S_ACA 3
-
-struct pci_vtscsi_event {
- uint32_t event;
- uint8_t lun[8];
- uint32_t reason;
-} __attribute__((packed));
-
-struct pci_vtscsi_req_cmd_rd {
- const uint8_t lun[8];
- const uint64_t id;
- const uint8_t task_attr;
- const uint8_t prio;
- const uint8_t crn;
- const uint8_t cdb[];
-} __attribute__((packed));
-
-struct pci_vtscsi_req_cmd_wr {
- uint32_t sense_len;
- uint32_t residual;
- uint16_t status_qualifier;
- uint8_t status;
- uint8_t response;
- uint8_t sense[];
-} __attribute__((packed));
+#include "pci_virtio_scsi.h"
enum pci_vtscsi_walk {
PCI_VTSCSI_WALK_CONTINUE = 0,
@@ -285,19 +65,14 @@ typedef enum pci_vtscsi_walk pci_vtscsi_walk_t;
typedef pci_vtscsi_walk_t pci_vtscsi_walk_request_queue_cb_t(
struct pci_vtscsi_queue *, struct pci_vtscsi_request *, void *);
+static void pci_vtscsi_print_supported_backends(void);
+
static void *pci_vtscsi_proc(void *);
static void pci_vtscsi_reset(void *);
static void pci_vtscsi_neg_features(void *, uint64_t);
static int pci_vtscsi_cfgread(void *, int, int, uint32_t *);
static int pci_vtscsi_cfgwrite(void *, int, int, uint32_t);
-static inline bool pci_vtscsi_check_lun(struct pci_vtscsi_softc *,
- const uint8_t *);
-static inline uint8_t pci_vtscsi_get_target(struct pci_vtscsi_softc *,
- const uint8_t *);
-static inline uint16_t pci_vtscsi_get_lun(struct pci_vtscsi_softc *,
- const uint8_t *);
-
static pci_vtscsi_walk_request_queue_cb_t pci_vtscsi_tmf_handle_abort_task;
static pci_vtscsi_walk_request_queue_cb_t pci_vtscsi_tmf_handle_abort_task_set;
static pci_vtscsi_walk_request_queue_cb_t pci_vtscsi_tmf_handle_clear_aca;
@@ -319,7 +94,8 @@ static void pci_vtscsi_control_handle(struct pci_vtscsi_softc *, void *,
static struct pci_vtscsi_request *pci_vtscsi_alloc_request(
struct pci_vtscsi_softc *);
-static void pci_vtscsi_free_request(struct pci_vtscsi_request *);
+static void pci_vtscsi_free_request(struct pci_vtscsi_softc *,
+ struct pci_vtscsi_request *);
static struct pci_vtscsi_request *pci_vtscsi_get_request(
struct pci_vtscsi_req_queue *);
static void pci_vtscsi_put_request(struct pci_vtscsi_req_queue *,
@@ -341,6 +117,8 @@ static int pci_vtscsi_init_queue(struct pci_vtscsi_softc *,
static void pci_vtscsi_destroy_queue(struct pci_vtscsi_queue *);
static int pci_vtscsi_init(struct pci_devinst *, nvlist_t *);
+SET_DECLARE(pci_vtscsi_backend_set, struct pci_vtscsi_backend);
+
static struct virtio_consts vtscsi_vi_consts = {
.vc_name = "vtscsi",
.vc_nvq = VTSCSI_MAXQ,
@@ -352,6 +130,25 @@ static struct virtio_consts vtscsi_vi_consts = {
.vc_hv_caps = VIRTIO_RING_F_INDIRECT_DESC,
};
+int pci_vtscsi_debug = 0;
+
+
+static void
+pci_vtscsi_print_supported_backends(void)
+{
+ struct pci_vtscsi_backend **vbpp;
+
+ if (SET_COUNT(pci_vtscsi_backend_set) == 0) {
+ printf("No virtio-scsi backends available");
+ return;
+ }
+
+ SET_FOREACH(vbpp, pci_vtscsi_backend_set) {
+ struct pci_vtscsi_backend *vbp = *vbpp;
+ printf("%s\n", vbp->vsb_name);
+ }
+}
+
static void *
pci_vtscsi_proc(void *arg)
{
@@ -407,8 +204,7 @@ pci_vtscsi_reset(void *vsc)
.num_queues = VTSCSI_REQUESTQ,
/* Leave room for the request and the response. */
.seg_max = VTSCSI_MAXSEG - 2,
- /* CTL apparently doesn't have a limit here */
- .max_sectors = INT32_MAX,
+ .max_sectors = 0, /* overridden by backend reset() */
.cmd_per_lun = 1,
.event_info_size = sizeof(struct pci_vtscsi_event),
.sense_size = 96,
@@ -417,6 +213,8 @@ pci_vtscsi_reset(void *vsc)
.max_target = MAX(1, sc->vss_num_target) - 1,
.max_lun = VIRTIO_SCSI_MAX_LUN
};
+
+ sc->vss_backend->vsb_reset(sc);
}
static void
@@ -445,105 +243,6 @@ pci_vtscsi_cfgwrite(void *vsc __unused, int offset __unused, int size __unused,
return (0);
}
-/*
- * LUN address parsing
- *
- * The LUN address consists of 8 bytes. While the spec describes this as 0x01,
- * followed by the target byte, followed by a "single-level LUN structure",
- * this is actually the same as a hierarchical LUN address as defined by SAM-5,
- * consisting of four levels of addressing, where in each level the two MSB of
- * byte 0 select the address mode used in the remaining bits and bytes.
- *
- *
- * Only the first two levels are acutally used by virtio-scsi:
- *
- * Level 1: 0x01, 0xTT: Peripheral Device Addressing: Bus 1, Target 0-255
- * Level 2: 0xLL, 0xLL: Peripheral Device Addressing: Bus MBZ, LUN 0-255
- * or: Flat Space Addressing: LUN (0-16383)
- * Level 3 and 4: not used, MBZ
- *
- *
- * Alternatively, the first level may contain an extended LUN address to select
- * the REPORT_LUNS well-known logical unit:
- *
- * Level 1: 0xC1, 0x01: Extended LUN Adressing, Well-Known LUN 1 (REPORT_LUNS)
- * Level 2, 3, and 4: not used, MBZ
- *
- * The virtio spec says that we SHOULD implement the REPORT_LUNS well-known
- * logical unit but we currently don't.
- *
- * According to the virtio spec, these are the only LUNS address formats to be
- * used with virtio-scsi.
- */
-
-/*
- * Check that the given LUN address conforms to the virtio spec, does not
- * address an unknown target, and especially does not address the REPORT_LUNS
- * well-known logical unit.
- */
-static inline bool
-pci_vtscsi_check_lun(struct pci_vtscsi_softc *sc, const uint8_t *lun)
-{
- if (lun[0] == 0xC1)
- return (false);
-
- if (lun[0] != 0x01)
- return (false);
-
- if (lun[1] >= sc->vss_num_target)
- return (false);
-
- if (lun[1] != sc->vss_targets[lun[1]].vst_target)
- return (false);
-
- if (sc->vss_targets[lun[1]].vst_fd < 0)
- return (false);
-
- if (lun[2] != 0x00 && (lun[2] & 0xc0) != 0x40)
- return (false);
-
- if (lun[4] != 0 || lun[5] != 0 || lun[6] != 0 || lun[7] != 0)
- return (false);
-
- return (true);
-}
-
-/*
- * Get the target id from a LUN address.
- *
- * Every code path using this function must have called pci_vtscsi_check_lun()
- * before to make sure the LUN address is valid.
- */
-static inline uint8_t
-pci_vtscsi_get_target(struct pci_vtscsi_softc *sc, const uint8_t *lun)
-{
- assert(lun[0] == 0x01);
- assert(lun[1] < sc->vss_num_target);
- assert(lun[1] == sc->vss_targets[lun[1]].vst_target);
- assert(sc->vss_targets[lun[1]].vst_fd >= 0);
- assert(lun[2] == 0x00 || (lun[2] & 0xc0) == 0x40);
-
- return (lun[1]);
-}
-
-/*
- * Get the LUN id from a LUN address.
- *
- * Every code path using this function must have called pci_vtscsi_check_lun()
- * before to make sure the LUN address is valid.
- */
-static inline uint16_t
-pci_vtscsi_get_lun(struct pci_vtscsi_softc *sc, const uint8_t *lun)
-{
- assert(lun[0] == 0x01);
- assert(lun[1] < sc->vss_num_target);
- assert(lun[1] == sc->vss_targets[lun[1]].vst_target);
- assert(sc->vss_targets[lun[1]].vst_fd >= 0);
- assert(lun[2] == 0x00 || (lun[2] & 0xc0) == 0x40);
-
- return (((lun[2] << 8) | lun[3]) & 0x3fff);
-}
-
/*
* ABORT TASK: Abort the specifed task queued for this LUN.
*
@@ -722,8 +421,8 @@ pci_vtscsi_tmf_handle_lun_reset(struct pci_vtscsi_queue *q,
* (1) the specified task is still in the virtqueue, not yet having been
* processed by pci_vtscsi_requestq_notify()
* (2) the specified task was actively being processed by a worker thread
- * but not yet processed by CTL by the time the QUERY TASK request was
- * handled by CTL
+ * but not yet processed by the backend by the time the QUERY TASK
+ * request was handled by the backend
*
* While a false negative may be confusing for a guest OS looking for the
* state of an I/O request it sent, it is not considered a fatal error of
@@ -812,9 +511,7 @@ static void
pci_vtscsi_tmf_handle(struct pci_vtscsi_softc *sc,
struct pci_vtscsi_ctrl_tmf *tmf)
{
- union ctl_io *io;
uint8_t target;
- int err;
int fd;
if (tmf->subtype > VIRTIO_SCSI_T_TMF_MAX_FUNC) {
@@ -848,9 +545,10 @@ pci_vtscsi_tmf_handle(struct pci_vtscsi_softc *sc,
* request queue. This in turn means we will miss any I/O requests which
* may still be in the virtqueue.
*
- * This does not prevent any requests currently being processed by CTL
- * from being completed and returned, which we must guarantee to adhere
- * to the ordering requirements for any TMF function which aborts tasks.
+ * This does not prevent any requests currently being processed by the
+ * backend from being completed and returned, which we must guarantee to
+ * adhere to the ordering requirements for any TMF function which aborts
+ * tasks.
*/
for (int i = 0; i < VTSCSI_REQUESTQ; i++) {
struct pci_vtscsi_queue *q = &sc->vss_queues[i];
@@ -859,7 +557,7 @@ pci_vtscsi_tmf_handle(struct pci_vtscsi_softc *sc,
}
/*
- * CTL may set response to FAILURE for the TMF request.
+ * The backend may set response to FAILURE for the TMF request.
*
* The default response of all TMF functions is FUNCTION COMPLETE if
* there was no error, regardless of whether it actually succeeded or
@@ -867,82 +565,14 @@ pci_vtscsi_tmf_handle(struct pci_vtscsi_softc *sc,
* which will explicitly return FUNCTION SUCCEEDED if the specified
* task or any task was active in the target/LUN, respectively.
*
- * Thus, we will call CTL first. Only if the response we get is
- * FUNCTION COMPLETE we'll continue processing the TMF function
- * on our queues. Note that there's a slim chance that we're racing
- * against a worker thread that is actively processing an I/O request,
- * which may lead to our TMF request being processed by CTL before the
+ * Thus, we will call the backend first. Only if the response we get is
+ * FUNCTION COMPLETE we'll continue processing the TMF function on our
+ * queues. Note that there's a slim chance that we're racing against a
+ * worker thread that is actively processing an I/O request, which may
+ * lead to our TMF request being processed by the backend before the
* same I/O request, in which case it won't be on any queue either.
*/
- io = ctl_scsi_alloc_io(sc->vss_iid);
- if (io == NULL) {
- WPRINTF("failed to allocate ctl_io: err=%d (%s)",
- errno, strerror(errno));
-
- tmf->response = VIRTIO_SCSI_S_FAILURE;
- goto out;
- }
-
- ctl_scsi_zero_io(io);
-
- io->io_hdr.io_type = CTL_IO_TASK;
- io->io_hdr.nexus.initid = sc->vss_iid;
- io->io_hdr.nexus.targ_lun = pci_vtscsi_get_lun(sc, tmf->lun);
- io->taskio.tag_type = CTL_TAG_SIMPLE;
- io->taskio.tag_num = tmf->id;
- io->io_hdr.flags |= CTL_FLAG_USER_TAG;
-
- switch (tmf->subtype) {
- case VIRTIO_SCSI_T_TMF_ABORT_TASK:
- io->taskio.task_action = CTL_TASK_ABORT_TASK;
- break;
-
- case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
- io->taskio.task_action = CTL_TASK_ABORT_TASK_SET;
- break;
-
- case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
- io->taskio.task_action = CTL_TASK_CLEAR_ACA;
- break;
-
- case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
- io->taskio.task_action = CTL_TASK_CLEAR_TASK_SET;
- break;
-
- case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
- io->taskio.task_action = CTL_TASK_I_T_NEXUS_RESET;
- break;
-
- case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
- io->taskio.task_action = CTL_TASK_LUN_RESET;
- break;
-
- case VIRTIO_SCSI_T_TMF_QUERY_TASK:
- io->taskio.task_action = CTL_TASK_QUERY_TASK;
- break;
-
- case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
- io->taskio.task_action = CTL_TASK_QUERY_TASK_SET;
- break;
- }
-
- if (pci_vtscsi_debug) {
- struct sbuf *sb = sbuf_new_auto();
- ctl_io_sbuf(io, sb);
- sbuf_finish(sb);
- DPRINTF("%s", sbuf_data(sb));
- sbuf_delete(sb);
- }
-
- err = ioctl(fd, CTL_IO, io);
- if (err != 0) {
- WPRINTF("CTL_IO: err=%d (%s)", errno, strerror(errno));
- tmf->response = VIRTIO_SCSI_S_FAILURE;
- } else {
- tmf->response = io->taskio.task_status;
- }
-
- ctl_scsi_free_io(io);
+ sc->vss_backend->vsb_tmf_hdl(sc, fd, tmf);
if (tmf->response != VIRTIO_SCSI_S_FUNCTION_COMPLETE) {
/*
@@ -960,7 +590,7 @@ pci_vtscsi_tmf_handle(struct pci_vtscsi_softc *sc,
tmf->response != VIRTIO_SCSI_S_FUNCTION_REJECTED &&
tmf->response != VIRTIO_SCSI_S_FUNCTION_SUCCEEDED) {
WPRINTF("pci_vtscsi_tmf_hdl: unexpected response from "
- "CTL: %d", tmf->response);
+ "backend: %d", tmf->response);
}
} else {
pci_vtscsi_walk_t ret = PCI_VTSCSI_WALK_CONTINUE;
@@ -976,7 +606,6 @@ pci_vtscsi_tmf_handle(struct pci_vtscsi_softc *sc,
}
}
-out:
/* Unlock the request queues before we return. */
for (int i = 0; i < VTSCSI_REQUESTQ; i++) {
struct pci_vtscsi_queue *q = &sc->vss_queues[i];
@@ -989,6 +618,7 @@ static void
pci_vtscsi_an_handle(struct pci_vtscsi_softc *sc, struct pci_vtscsi_ctrl_an *an)
{
int target;
+ int fd;
if (pci_vtscsi_check_lun(sc, an->lun) == false) {
DPRINTF("AN request to invalid LUN %.2hhx%.2hhx-%.2hhx%.2hhx-"
@@ -1001,10 +631,12 @@ pci_vtscsi_an_handle(struct pci_vtscsi_softc *sc, struct pci_vtscsi_ctrl_an *an)
target = pci_vtscsi_get_target(sc, an->lun);
+ fd = sc->vss_targets[target].vst_fd;
+
DPRINTF("AN request tgt %d, lun %d, event requested %x",
target, pci_vtscsi_get_lun(sc, an->lun), an->event_requested);
- an->response = VIRTIO_SCSI_S_FAILURE;
+ sc->vss_backend->vsb_an_hdl(sc, fd, an);
}
static void
@@ -1055,10 +687,9 @@ pci_vtscsi_alloc_request(struct pci_vtscsi_softc *sc)
if (req->vsr_cmd_wr == NULL)
goto fail;
- req->vsr_ctl_io = ctl_scsi_alloc_io(sc->vss_iid);
- if (req->vsr_ctl_io == NULL)
+ req->vsr_backend = sc->vss_backend->vsb_req_alloc(sc);
+ if (req->vsr_backend == NULL)
goto fail;
- ctl_scsi_zero_io(req->vsr_ctl_io);
return (req);
@@ -1066,16 +697,17 @@ fail:
EPRINTLN("failed to allocate request: %s", strerror(errno));
if (req != NULL)
- pci_vtscsi_free_request(req);
+ pci_vtscsi_free_request(sc, req);
return (NULL);
}
static void
-pci_vtscsi_free_request(struct pci_vtscsi_request *req)
+pci_vtscsi_free_request(struct pci_vtscsi_softc *sc,
+ struct pci_vtscsi_request *req)
{
- if (req->vsr_ctl_io != NULL)
- ctl_scsi_free_io(req->vsr_ctl_io);
+ if (req->vsr_backend != NULL)
+ sc->vss_backend->vsb_req_free(req->vsr_backend);
if (req->vsr_cmd_rd != NULL)
free(req->vsr_cmd_rd);
if (req->vsr_cmd_wr != NULL)
@@ -1218,9 +850,10 @@ static void
pci_vtscsi_return_request(struct pci_vtscsi_queue *q,
struct pci_vtscsi_request *req, int iolen)
{
+ struct pci_vtscsi_softc *sc = q->vsq_sc;
void *cmd_rd = req->vsr_cmd_rd;
void *cmd_wr = req->vsr_cmd_wr;
- void *ctl_io = req->vsr_ctl_io;
+ void *backend = req->vsr_backend;
int idx = req->vsr_idx;
DPRINTF("request <idx=%d> completed, response %d", idx,
@@ -1229,7 +862,7 @@ pci_vtscsi_return_request(struct pci_vtscsi_queue *q,
iolen += buf_to_iov(cmd_wr, VTSCSI_OUT_HEADER_LEN(q->vsq_sc),
req->vsr_iov_out, req->vsr_niov_out);
- ctl_scsi_zero_io(req->vsr_ctl_io);
+ sc->vss_backend->vsb_req_clear(backend);
memset(cmd_rd, 0, VTSCSI_IN_HEADER_LEN(q->vsq_sc));
memset(cmd_wr, 0, VTSCSI_OUT_HEADER_LEN(q->vsq_sc));
@@ -1237,7 +870,7 @@ pci_vtscsi_return_request(struct pci_vtscsi_queue *q,
req->vsr_cmd_rd = cmd_rd;
req->vsr_cmd_wr = cmd_wr;
- req->vsr_ctl_io = ctl_io;
+ req->vsr_backend = backend;
pthread_mutex_lock(&q->vsq_fmtx);
pci_vtscsi_put_request(&q->vsq_free_requests, req);
@@ -1253,81 +886,7 @@ static int
pci_vtscsi_request_handle(struct pci_vtscsi_softc *sc, int fd,
struct pci_vtscsi_request *req)
{
- union ctl_io *io = req->vsr_ctl_io;
- void *ext_data_ptr = NULL;
- uint32_t ext_data_len = 0, ext_sg_entries = 0;
- int err, nxferred;
-
- io->io_hdr.nexus.initid = sc->vss_iid;
- io->io_hdr.nexus.targ_lun =
- pci_vtscsi_get_lun(sc, req->vsr_cmd_rd->lun);
-
- io->io_hdr.io_type = CTL_IO_SCSI;
-
- if (req->vsr_data_niov_in > 0) {
- ext_data_ptr = (void *)req->vsr_data_iov_in;
- ext_sg_entries = req->vsr_data_niov_in;
- ext_data_len = count_iov(req->vsr_data_iov_in,
- req->vsr_data_niov_in);
- io->io_hdr.flags |= CTL_FLAG_DATA_OUT;
- } else if (req->vsr_data_niov_out > 0) {
- ext_data_ptr = (void *)req->vsr_data_iov_out;
- ext_sg_entries = req->vsr_data_niov_out;
- ext_data_len = count_iov(req->vsr_data_iov_out,
- req->vsr_data_niov_out);
- io->io_hdr.flags |= CTL_FLAG_DATA_IN;
- }
-
- io->scsiio.sense_len = sc->vss_config.sense_size;
- io->scsiio.tag_num = req->vsr_cmd_rd->id;
- io->io_hdr.flags |= CTL_FLAG_USER_TAG;
- switch (req->vsr_cmd_rd->task_attr) {
- case VIRTIO_SCSI_S_ORDERED:
- io->scsiio.tag_type = CTL_TAG_ORDERED;
- break;
- case VIRTIO_SCSI_S_HEAD:
- io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
- break;
- case VIRTIO_SCSI_S_ACA:
- io->scsiio.tag_type = CTL_TAG_ACA;
- break;
- case VIRTIO_SCSI_S_SIMPLE:
- default:
- io->scsiio.tag_type = CTL_TAG_SIMPLE;
- break;
- }
- io->scsiio.ext_sg_entries = ext_sg_entries;
- io->scsiio.ext_data_ptr = ext_data_ptr;
- io->scsiio.ext_data_len = ext_data_len;
- io->scsiio.ext_data_filled = 0;
- io->scsiio.cdb_len = sc->vss_config.cdb_size;
- memcpy(io->scsiio.cdb, req->vsr_cmd_rd->cdb, sc->vss_config.cdb_size);
-
- if (pci_vtscsi_debug) {
- struct sbuf *sb = sbuf_new_auto();
- ctl_io_sbuf(io, sb);
- sbuf_finish(sb);
- DPRINTF("%s", sbuf_data(sb));
- sbuf_delete(sb);
- }
-
- err = ioctl(fd, CTL_IO, io);
- if (err != 0) {
- WPRINTF("CTL_IO: err=%d (%s)", errno, strerror(errno));
- req->vsr_cmd_wr->response = VIRTIO_SCSI_S_FAILURE;
- } else {
- req->vsr_cmd_wr->sense_len =
- MIN(io->scsiio.sense_len, sc->vss_config.sense_size);
- req->vsr_cmd_wr->residual = ext_data_len -
- io->scsiio.ext_data_filled;
- req->vsr_cmd_wr->status = io->scsiio.scsi_status;
- req->vsr_cmd_wr->response = VIRTIO_SCSI_S_OK;
- memcpy(&req->vsr_cmd_wr->sense, &io->scsiio.sense_data,
- req->vsr_cmd_wr->sense_len);
- }
-
- nxferred = io->scsiio.ext_data_filled;
- return (nxferred);
+ return (sc->vss_backend->vsb_req_hdl(sc, fd, req));
}
static void
@@ -1439,7 +998,7 @@ pci_vtscsi_destroy_queue(struct pci_vtscsi_queue *queue)
break;
req = pci_vtscsi_get_request(&queue->vsq_free_requests);
- pci_vtscsi_free_request(req);
+ pci_vtscsi_free_request(queue->vsq_sc, req);
}
pthread_cond_destroy(&queue->vsq_cv);
@@ -1534,10 +1093,13 @@ pci_vtscsi_legacy_config(nvlist_t *nvl, const char *opts)
targets = create_relative_config_node(nvl, "target");
- /* Handle legacy form (0). */
- if (opts == NULL) {
- pci_vtscsi_add_target_config(targets, "/dev/cam/ctl", 0);
+ /* Legacy form (0) is handled in pci_vtscsi_init(). */
+ if (opts == NULL)
return (0);
+
+ if (strcmp("help", opts) == 0) {
+ pci_vtscsi_print_supported_backends();
+ exit(0);
}
n = strcspn(opts, ",=");
@@ -1633,6 +1195,7 @@ pci_vtscsi_init_target(const char *prefix __unused, const nvlist_t *parent,
const char *value;
const char *errstr;
uint64_t target;
+ int ret;
assert(type == NV_TYPE_STRING);
@@ -1644,23 +1207,21 @@ pci_vtscsi_init_target(const char *prefix __unused, const nvlist_t *parent,
sc->vss_targets[target].vst_target = target;
/*
- * 'value' contains the CTL device node path of this target.
+ * 'value' contains the backend path. Call the backend to open it.
*/
value = nvlist_get_string(parent, name);
- sc->vss_targets[target].vst_fd = open(value, O_RDWR);
- if (sc->vss_targets[target].vst_fd < 0) {
+ ret = sc->vss_backend->vsb_open(sc, value, target);
+ if (ret != 0)
EPRINTLN("cannot open target %lu at %s: %s", target, value,
strerror(errno));
- return (-1);
- }
-
- return (0);
+ return (ret);
}
static int
pci_vtscsi_init(struct pci_devinst *pi, nvlist_t *nvl)
{
*** 843 LINES SKIPPED ***