Date: Tue, 26 May 2026 16:07:17 +0000 From: Mark Johnston <markj@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> Subject: git: 9542ddb21dc1 - main - bhyve/virtio-scsi: Support multiple backends Message-ID: <6a15c535.30e3a.7895c705@gitrepo.freebsd.org>
index | next in thread | raw e-mail
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 ***home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a15c535.30e3a.7895c705>
