linux/drivers/vhost/scsi.c

// SPDX-License-Identifier: GPL-2.0+
/*******************************************************************************
 * Vhost kernel TCM fabric driver for virtio SCSI initiators
 *
 * (C) Copyright 2010-2013 Datera, Inc.
 * (C) Copyright 2010-2012 IBM Corp.
 *
 * Authors: Nicholas A. Bellinger <[email protected]>
 *          Stefan Hajnoczi <[email protected]>
 ****************************************************************************/

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/configfs.h>
#include <linux/ctype.h>
#include <linux/compat.h>
#include <linux/eventfd.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/miscdevice.h>
#include <linux/blk_types.h>
#include <linux/bio.h>
#include <linux/unaligned.h>
#include <scsi/scsi_common.h>
#include <scsi/scsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
#include <linux/vhost.h>
#include <linux/virtio_scsi.h>
#include <linux/llist.h>
#include <linux/bitmap.h>

#include "vhost.h"

#define VHOST_SCSI_VERSION
#define VHOST_SCSI_NAMELEN
#define VHOST_SCSI_MAX_CDB_SIZE
#define VHOST_SCSI_PREALLOC_SGLS
#define VHOST_SCSI_PREALLOC_UPAGES
#define VHOST_SCSI_PREALLOC_PROT_SGLS

/* Max number of requests before requeueing the job.
 * Using this limit prevents one virtqueue from starving others with
 * request.
 */
#define VHOST_SCSI_WEIGHT

struct vhost_scsi_inflight {};

struct vhost_scsi_cmd {};

struct vhost_scsi_nexus {};

struct vhost_scsi_tpg {};

struct vhost_scsi_tport {};

struct vhost_scsi_evt {};

enum {};

/* Note: can't set VIRTIO_F_VERSION_1 yet, since that implies ANY_LAYOUT. */
enum {};

#define VHOST_SCSI_MAX_TARGET
#define VHOST_SCSI_MAX_IO_VQ
#define VHOST_SCSI_MAX_EVENT

static unsigned vhost_scsi_max_io_vqs =;
module_param_named(max_io_vqs, vhost_scsi_max_io_vqs, uint, 0644);
MODULE_PARM_DESC();

struct vhost_scsi_virtqueue {};

struct vhost_scsi {};

struct vhost_scsi_tmf {};

/*
 * Context for processing request and control queue operations.
 */
struct vhost_scsi_ctx {};

/*
 * Global mutex to protect vhost_scsi TPG list for vhost IOCTLs and LIO
 * configfs management operations.
 */
static DEFINE_MUTEX(vhost_scsi_mutex);
static LIST_HEAD(vhost_scsi_list);

static void vhost_scsi_done_inflight(struct kref *kref)
{}

static void vhost_scsi_init_inflight(struct vhost_scsi *vs,
				    struct vhost_scsi_inflight *old_inflight[])
{}

static struct vhost_scsi_inflight *
vhost_scsi_get_inflight(struct vhost_virtqueue *vq)
{}

static void vhost_scsi_put_inflight(struct vhost_scsi_inflight *inflight)
{}

static int vhost_scsi_check_true(struct se_portal_group *se_tpg)
{}

static char *vhost_scsi_get_fabric_wwn(struct se_portal_group *se_tpg)
{}

static u16 vhost_scsi_get_tpgt(struct se_portal_group *se_tpg)
{}

static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg)
{}

static void vhost_scsi_release_cmd_res(struct se_cmd *se_cmd)
{}

static void vhost_scsi_release_tmf_res(struct vhost_scsi_tmf *tmf)
{}

static void vhost_scsi_drop_cmds(struct vhost_scsi_virtqueue *svq)
{}

static void vhost_scsi_release_cmd(struct se_cmd *se_cmd)
{}

static int vhost_scsi_write_pending(struct se_cmd *se_cmd)
{}

static int vhost_scsi_queue_data_in(struct se_cmd *se_cmd)
{}

static int vhost_scsi_queue_status(struct se_cmd *se_cmd)
{}

static void vhost_scsi_queue_tm_rsp(struct se_cmd *se_cmd)
{}

static void vhost_scsi_aborted_task(struct se_cmd *se_cmd)
{}

static void vhost_scsi_free_evt(struct vhost_scsi *vs, struct vhost_scsi_evt *evt)
{}

static struct vhost_scsi_evt *
vhost_scsi_allocate_evt(struct vhost_scsi *vs,
		       u32 event, u32 reason)
{}

static int vhost_scsi_check_stop_free(struct se_cmd *se_cmd)
{}

static void
vhost_scsi_do_evt_work(struct vhost_scsi *vs, struct vhost_scsi_evt *evt)
{}

static void vhost_scsi_complete_events(struct vhost_scsi *vs, bool drop)
{}

static void vhost_scsi_evt_work(struct vhost_work *work)
{}

static int vhost_scsi_copy_sgl_to_iov(struct vhost_scsi_cmd *cmd)
{}

/* Fill in status and signal that we are done processing this command
 *
 * This is scheduled in the vhost work queue so we are called with the owner
 * process mm and can access the vring.
 */
static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
{}

static struct vhost_scsi_cmd *
vhost_scsi_get_cmd(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg,
		   unsigned char *cdb, u64 scsi_tag, u16 lun, u8 task_attr,
		   u32 exp_data_len, int data_direction)
{}

/*
 * Map a user memory range into a scatterlist
 *
 * Returns the number of scatterlist entries used or -errno on error.
 */
static int
vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd,
		      struct iov_iter *iter,
		      struct scatterlist *sgl,
		      bool is_prot)
{}

static int
vhost_scsi_calc_sgls(struct iov_iter *iter, size_t bytes, int max_sgls)
{}

static int
vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter,
			   struct scatterlist *sg, int sg_count)
{}

static int
vhost_scsi_map_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter,
			  struct scatterlist *sg, int sg_count, bool is_prot)
{}

static int
vhost_scsi_mapal(struct vhost_scsi_cmd *cmd,
		 size_t prot_bytes, struct iov_iter *prot_iter,
		 size_t data_bytes, struct iov_iter *data_iter)
{}

static int vhost_scsi_to_tcm_attr(int attr)
{}

static void vhost_scsi_target_queue_cmd(struct vhost_scsi_cmd *cmd)
{}

static void
vhost_scsi_send_bad_target(struct vhost_scsi *vs,
			   struct vhost_virtqueue *vq,
			   int head, unsigned out)
{}

static int
vhost_scsi_get_desc(struct vhost_scsi *vs, struct vhost_virtqueue *vq,
		    struct vhost_scsi_ctx *vc)
{}

static int
vhost_scsi_chk_size(struct vhost_virtqueue *vq, struct vhost_scsi_ctx *vc)
{}

static int
vhost_scsi_get_req(struct vhost_virtqueue *vq, struct vhost_scsi_ctx *vc,
		   struct vhost_scsi_tpg **tpgp)
{}

static u16 vhost_buf_to_lun(u8 *lun_buf)
{}

static void
vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
{}

static void
vhost_scsi_send_tmf_resp(struct vhost_scsi *vs, struct vhost_virtqueue *vq,
			 int in_iovs, int vq_desc, struct iovec *resp_iov,
			 int tmf_resp_code)
{}

static void vhost_scsi_tmf_resp_work(struct vhost_work *work)
{}

static void vhost_scsi_tmf_flush_work(struct work_struct *work)
{}

static void
vhost_scsi_handle_tmf(struct vhost_scsi *vs, struct vhost_scsi_tpg *tpg,
		      struct vhost_virtqueue *vq,
		      struct virtio_scsi_ctrl_tmf_req *vtmf,
		      struct vhost_scsi_ctx *vc)
{}

static void
vhost_scsi_send_an_resp(struct vhost_scsi *vs,
			struct vhost_virtqueue *vq,
			struct vhost_scsi_ctx *vc)
{}

static void
vhost_scsi_ctl_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
{}

static void vhost_scsi_ctl_handle_kick(struct vhost_work *work)
{}

static void
vhost_scsi_send_evt(struct vhost_scsi *vs, struct vhost_virtqueue *vq,
		    struct vhost_scsi_tpg *tpg, struct se_lun *lun,
		    u32 event, u32 reason)
{}

static void vhost_scsi_evt_handle_kick(struct vhost_work *work)
{}

static void vhost_scsi_handle_kick(struct vhost_work *work)
{}

/* Callers must hold dev mutex */
static void vhost_scsi_flush(struct vhost_scsi *vs)
{}

static void vhost_scsi_destroy_vq_cmds(struct vhost_virtqueue *vq)
{}

static int vhost_scsi_setup_vq_cmds(struct vhost_virtqueue *vq, int max_cmds)
{}

/*
 * Called from vhost_scsi_ioctl() context to walk the list of available
 * vhost_scsi_tpg with an active struct vhost_scsi_nexus
 *
 *  The lock nesting rule is:
 *    vs->dev.mutex -> vhost_scsi_mutex -> tpg->tv_tpg_mutex -> vq->mutex
 */
static int
vhost_scsi_set_endpoint(struct vhost_scsi *vs,
			struct vhost_scsi_target *t)
{}

static int
vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
			  struct vhost_scsi_target *t)
{}

static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
{}

static int vhost_scsi_open(struct inode *inode, struct file *f)
{}

static int vhost_scsi_release(struct inode *inode, struct file *f)
{}

static long
vhost_scsi_ioctl(struct file *f,
		 unsigned int ioctl,
		 unsigned long arg)
{}

static const struct file_operations vhost_scsi_fops =;

static struct miscdevice vhost_scsi_misc =;

static int __init vhost_scsi_register(void)
{}

static void vhost_scsi_deregister(void)
{}

static char *vhost_scsi_dump_proto_id(struct vhost_scsi_tport *tport)
{}

static void
vhost_scsi_do_plug(struct vhost_scsi_tpg *tpg,
		  struct se_lun *lun, bool plug)
{}

static void vhost_scsi_hotplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun)
{}

static void vhost_scsi_hotunplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun)
{}

static int vhost_scsi_port_link(struct se_portal_group *se_tpg,
			       struct se_lun *lun)
{}

static void vhost_scsi_port_unlink(struct se_portal_group *se_tpg,
				  struct se_lun *lun)
{}

static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_store(
		struct config_item *item, const char *page, size_t count)
{}

static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_show(
		struct config_item *item, char *page)
{}

CONFIGFS_ATTR();

static struct configfs_attribute *vhost_scsi_tpg_attrib_attrs[] =;

static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
				const char *name)
{}

static int vhost_scsi_drop_nexus(struct vhost_scsi_tpg *tpg)
{}

static ssize_t vhost_scsi_tpg_nexus_show(struct config_item *item, char *page)
{}

static ssize_t vhost_scsi_tpg_nexus_store(struct config_item *item,
		const char *page, size_t count)
{}

CONFIGFS_ATTR();

static struct configfs_attribute *vhost_scsi_tpg_attrs[] =;

static struct se_portal_group *
vhost_scsi_make_tpg(struct se_wwn *wwn, const char *name)
{}

static void vhost_scsi_drop_tpg(struct se_portal_group *se_tpg)
{}

static struct se_wwn *
vhost_scsi_make_tport(struct target_fabric_configfs *tf,
		     struct config_group *group,
		     const char *name)
{}

static void vhost_scsi_drop_tport(struct se_wwn *wwn)
{}

static ssize_t
vhost_scsi_wwn_version_show(struct config_item *item, char *page)
{}

CONFIGFS_ATTR_RO();

static struct configfs_attribute *vhost_scsi_wwn_attrs[] =;

static const struct target_core_fabric_ops vhost_scsi_ops =;

static int __init vhost_scsi_init(void)
{
	int ret = -ENOMEM;

	pr_debug("TCM_VHOST fabric module %s on %s/%s"
		" on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
		utsname()->machine);

	ret = vhost_scsi_register();
	if (ret < 0)
		goto out;

	ret = target_register_template(&vhost_scsi_ops);
	if (ret < 0)
		goto out_vhost_scsi_deregister;

	return 0;

out_vhost_scsi_deregister:
	vhost_scsi_deregister();
out:
	return ret;
};

static void vhost_scsi_exit(void)
{
	target_unregister_template(&vhost_scsi_ops);
	vhost_scsi_deregister();
};

MODULE_DESCRIPTION();
MODULE_ALIAS();
MODULE_LICENSE();
module_init();
module_exit(vhost_scsi_exit);