xref: /openbmc/linux/drivers/vhost/scsi.c (revision fac59652993f075d57860769c99045b3ca18780d)
123b228cbSCai Huoqing // SPDX-License-Identifier: GPL-2.0+
2eb62b74eSMichael S. Tsirkin /*******************************************************************************
3eb62b74eSMichael S. Tsirkin  * Vhost kernel TCM fabric driver for virtio SCSI initiators
4eb62b74eSMichael S. Tsirkin  *
54c76251eSNicholas Bellinger  * (C) Copyright 2010-2013 Datera, Inc.
6eb62b74eSMichael S. Tsirkin  * (C) Copyright 2010-2012 IBM Corp.
7eb62b74eSMichael S. Tsirkin  *
84c76251eSNicholas Bellinger  * Authors: Nicholas A. Bellinger <nab@daterainc.com>
9eb62b74eSMichael S. Tsirkin  *          Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
10eb62b74eSMichael S. Tsirkin  ****************************************************************************/
11eb62b74eSMichael S. Tsirkin 
12eb62b74eSMichael S. Tsirkin #include <linux/module.h>
13eb62b74eSMichael S. Tsirkin #include <linux/moduleparam.h>
14eb62b74eSMichael S. Tsirkin #include <generated/utsrelease.h>
15eb62b74eSMichael S. Tsirkin #include <linux/utsname.h>
16eb62b74eSMichael S. Tsirkin #include <linux/init.h>
17eb62b74eSMichael S. Tsirkin #include <linux/slab.h>
18eb62b74eSMichael S. Tsirkin #include <linux/kthread.h>
19eb62b74eSMichael S. Tsirkin #include <linux/types.h>
20eb62b74eSMichael S. Tsirkin #include <linux/string.h>
21eb62b74eSMichael S. Tsirkin #include <linux/configfs.h>
22eb62b74eSMichael S. Tsirkin #include <linux/ctype.h>
23eb62b74eSMichael S. Tsirkin #include <linux/compat.h>
24eb62b74eSMichael S. Tsirkin #include <linux/eventfd.h>
25eb62b74eSMichael S. Tsirkin #include <linux/fs.h>
265538d294SDavid S. Miller #include <linux/vmalloc.h>
27eb62b74eSMichael S. Tsirkin #include <linux/miscdevice.h>
285ced58bfSMike Christie #include <linux/blk_types.h>
295ced58bfSMike Christie #include <linux/bio.h>
30eb62b74eSMichael S. Tsirkin #include <asm/unaligned.h>
31ba929992SBart Van Assche #include <scsi/scsi_common.h>
32ba929992SBart Van Assche #include <scsi/scsi_proto.h>
33eb62b74eSMichael S. Tsirkin #include <target/target_core_base.h>
34eb62b74eSMichael S. Tsirkin #include <target/target_core_fabric.h>
35eb62b74eSMichael S. Tsirkin #include <linux/vhost.h>
36eb62b74eSMichael S. Tsirkin #include <linux/virtio_scsi.h>
37eb62b74eSMichael S. Tsirkin #include <linux/llist.h>
38eb62b74eSMichael S. Tsirkin #include <linux/bitmap.h>
39eb62b74eSMichael S. Tsirkin 
40eb62b74eSMichael S. Tsirkin #include "vhost.h"
415012a3a3SMichael S. Tsirkin 
421a1ff825SNicholas Bellinger #define VHOST_SCSI_VERSION  "v0.1"
431a1ff825SNicholas Bellinger #define VHOST_SCSI_NAMELEN 256
441a1ff825SNicholas Bellinger #define VHOST_SCSI_MAX_CDB_SIZE 32
451a1ff825SNicholas Bellinger #define VHOST_SCSI_PREALLOC_SGLS 2048
461a1ff825SNicholas Bellinger #define VHOST_SCSI_PREALLOC_UPAGES 2048
47864d39dfSGreg Edwards #define VHOST_SCSI_PREALLOC_PROT_SGLS 2048
485012a3a3SMichael S. Tsirkin 
49e82b9b07SJason Wang /* Max number of requests before requeueing the job.
50e82b9b07SJason Wang  * Using this limit prevents one virtqueue from starving others with
51e82b9b07SJason Wang  * request.
52e82b9b07SJason Wang  */
53e82b9b07SJason Wang #define VHOST_SCSI_WEIGHT 256
54e82b9b07SJason Wang 
555012a3a3SMichael S. Tsirkin struct vhost_scsi_inflight {
565012a3a3SMichael S. Tsirkin 	/* Wait for the flush operation to finish */
575012a3a3SMichael S. Tsirkin 	struct completion comp;
585012a3a3SMichael S. Tsirkin 	/* Refcount for the inflight reqs */
595012a3a3SMichael S. Tsirkin 	struct kref kref;
605012a3a3SMichael S. Tsirkin };
615012a3a3SMichael S. Tsirkin 
621a1ff825SNicholas Bellinger struct vhost_scsi_cmd {
635012a3a3SMichael S. Tsirkin 	/* Descriptor from vhost_get_vq_desc() for virt_queue segment */
645012a3a3SMichael S. Tsirkin 	int tvc_vq_desc;
655012a3a3SMichael S. Tsirkin 	/* virtio-scsi initiator task attribute */
665012a3a3SMichael S. Tsirkin 	int tvc_task_attr;
6779c14141SNicholas Bellinger 	/* virtio-scsi response incoming iovecs */
6879c14141SNicholas Bellinger 	int tvc_in_iovs;
695012a3a3SMichael S. Tsirkin 	/* virtio-scsi initiator data direction */
705012a3a3SMichael S. Tsirkin 	enum dma_data_direction tvc_data_direction;
715012a3a3SMichael S. Tsirkin 	/* Expected data transfer length from virtio-scsi header */
725012a3a3SMichael S. Tsirkin 	u32 tvc_exp_data_len;
735012a3a3SMichael S. Tsirkin 	/* The Tag from include/linux/virtio_scsi.h:struct virtio_scsi_cmd_req */
745012a3a3SMichael S. Tsirkin 	u64 tvc_tag;
755012a3a3SMichael S. Tsirkin 	/* The number of scatterlists associated with this cmd */
765012a3a3SMichael S. Tsirkin 	u32 tvc_sgl_count;
77e31885ddSNicholas Bellinger 	u32 tvc_prot_sgl_count;
786ec29cb8SMike Christie 	/* Saved unpacked SCSI LUN for vhost_scsi_target_queue_cmd() */
795012a3a3SMichael S. Tsirkin 	u32 tvc_lun;
805ced58bfSMike Christie 	u32 copied_iov:1;
815ced58bfSMike Christie 	const void *saved_iter_addr;
825ced58bfSMike Christie 	struct iov_iter saved_iter;
835012a3a3SMichael S. Tsirkin 	/* Pointer to the SGL formatted memory from virtio-scsi */
845012a3a3SMichael S. Tsirkin 	struct scatterlist *tvc_sgl;
85b1935f68SNicholas Bellinger 	struct scatterlist *tvc_prot_sgl;
863aee26b4SNicholas Bellinger 	struct page **tvc_upages;
8779c14141SNicholas Bellinger 	/* Pointer to response header iovec */
886dd88fd5SJason Wang 	struct iovec *tvc_resp_iov;
895012a3a3SMichael S. Tsirkin 	/* Pointer to vhost_scsi for our device */
905012a3a3SMichael S. Tsirkin 	struct vhost_scsi *tvc_vhost;
915012a3a3SMichael S. Tsirkin 	/* Pointer to vhost_virtqueue for the cmd */
925012a3a3SMichael S. Tsirkin 	struct vhost_virtqueue *tvc_vq;
935012a3a3SMichael S. Tsirkin 	/* Pointer to vhost nexus memory */
941a1ff825SNicholas Bellinger 	struct vhost_scsi_nexus *tvc_nexus;
955012a3a3SMichael S. Tsirkin 	/* The TCM I/O descriptor that is accessed via container_of() */
965012a3a3SMichael S. Tsirkin 	struct se_cmd tvc_se_cmd;
975012a3a3SMichael S. Tsirkin 	/* Copy of the incoming SCSI command descriptor block (CDB) */
981a1ff825SNicholas Bellinger 	unsigned char tvc_cdb[VHOST_SCSI_MAX_CDB_SIZE];
995012a3a3SMichael S. Tsirkin 	/* Sense buffer that will be mapped into outgoing status */
1005012a3a3SMichael S. Tsirkin 	unsigned char tvc_sense_buf[TRANSPORT_SENSE_BUFFER];
1015012a3a3SMichael S. Tsirkin 	/* Completed commands list, serviced from vhost worker thread */
1025012a3a3SMichael S. Tsirkin 	struct llist_node tvc_completion_list;
1035012a3a3SMichael S. Tsirkin 	/* Used to track inflight cmd */
1045012a3a3SMichael S. Tsirkin 	struct vhost_scsi_inflight *inflight;
1055012a3a3SMichael S. Tsirkin };
1065012a3a3SMichael S. Tsirkin 
1071a1ff825SNicholas Bellinger struct vhost_scsi_nexus {
1085012a3a3SMichael S. Tsirkin 	/* Pointer to TCM session for I_T Nexus */
1095012a3a3SMichael S. Tsirkin 	struct se_session *tvn_se_sess;
1105012a3a3SMichael S. Tsirkin };
1115012a3a3SMichael S. Tsirkin 
1121a1ff825SNicholas Bellinger struct vhost_scsi_tpg {
1135012a3a3SMichael S. Tsirkin 	/* Vhost port target portal group tag for TCM */
1145012a3a3SMichael S. Tsirkin 	u16 tport_tpgt;
1155012a3a3SMichael S. Tsirkin 	/* Used to track number of TPG Port/Lun Links wrt to explict I_T Nexus shutdown */
1165012a3a3SMichael S. Tsirkin 	int tv_tpg_port_count;
1175012a3a3SMichael S. Tsirkin 	/* Used for vhost_scsi device reference to tpg_nexus, protected by tv_tpg_mutex */
1185012a3a3SMichael S. Tsirkin 	int tv_tpg_vhost_count;
119b1d75fe5SNicholas Bellinger 	/* Used for enabling T10-PI with legacy devices */
120b1d75fe5SNicholas Bellinger 	int tv_fabric_prot_type;
1211a1ff825SNicholas Bellinger 	/* list for vhost_scsi_list */
1225012a3a3SMichael S. Tsirkin 	struct list_head tv_tpg_list;
1235012a3a3SMichael S. Tsirkin 	/* Used to protect access for tpg_nexus */
1245012a3a3SMichael S. Tsirkin 	struct mutex tv_tpg_mutex;
1255012a3a3SMichael S. Tsirkin 	/* Pointer to the TCM VHost I_T Nexus for this TPG endpoint */
1261a1ff825SNicholas Bellinger 	struct vhost_scsi_nexus *tpg_nexus;
1271a1ff825SNicholas Bellinger 	/* Pointer back to vhost_scsi_tport */
1281a1ff825SNicholas Bellinger 	struct vhost_scsi_tport *tport;
1291a1ff825SNicholas Bellinger 	/* Returned by vhost_scsi_make_tpg() */
1305012a3a3SMichael S. Tsirkin 	struct se_portal_group se_tpg;
1315012a3a3SMichael S. Tsirkin 	/* Pointer back to vhost_scsi, protected by tv_tpg_mutex */
1325012a3a3SMichael S. Tsirkin 	struct vhost_scsi *vhost_scsi;
1335012a3a3SMichael S. Tsirkin };
1345012a3a3SMichael S. Tsirkin 
1351a1ff825SNicholas Bellinger struct vhost_scsi_tport {
1365012a3a3SMichael S. Tsirkin 	/* SCSI protocol the tport is providing */
1375012a3a3SMichael S. Tsirkin 	u8 tport_proto_id;
1385012a3a3SMichael S. Tsirkin 	/* Binary World Wide unique Port Name for Vhost Target port */
1395012a3a3SMichael S. Tsirkin 	u64 tport_wwpn;
1405012a3a3SMichael S. Tsirkin 	/* ASCII formatted WWPN for Vhost Target port */
1411a1ff825SNicholas Bellinger 	char tport_name[VHOST_SCSI_NAMELEN];
1421a1ff825SNicholas Bellinger 	/* Returned by vhost_scsi_make_tport() */
1435012a3a3SMichael S. Tsirkin 	struct se_wwn tport_wwn;
1445012a3a3SMichael S. Tsirkin };
1455012a3a3SMichael S. Tsirkin 
1461a1ff825SNicholas Bellinger struct vhost_scsi_evt {
1475012a3a3SMichael S. Tsirkin 	/* event to be sent to guest */
1485012a3a3SMichael S. Tsirkin 	struct virtio_scsi_event event;
1495012a3a3SMichael S. Tsirkin 	/* event list, serviced from vhost worker thread */
1505012a3a3SMichael S. Tsirkin 	struct llist_node list;
1515012a3a3SMichael S. Tsirkin };
152eb62b74eSMichael S. Tsirkin 
153eb62b74eSMichael S. Tsirkin enum {
154eb62b74eSMichael S. Tsirkin 	VHOST_SCSI_VQ_CTL = 0,
155eb62b74eSMichael S. Tsirkin 	VHOST_SCSI_VQ_EVT = 1,
156eb62b74eSMichael S. Tsirkin 	VHOST_SCSI_VQ_IO = 2,
157eb62b74eSMichael S. Tsirkin };
158eb62b74eSMichael S. Tsirkin 
159e72fd72eSMichael S. Tsirkin /* Note: can't set VIRTIO_F_VERSION_1 yet, since that implies ANY_LAYOUT. */
160eb62b74eSMichael S. Tsirkin enum {
16195e7c434SNicholas Bellinger 	VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) |
1624e9fa50cSMichael S. Tsirkin 					       (1ULL << VIRTIO_SCSI_F_T10_PI)
163eb62b74eSMichael S. Tsirkin };
164eb62b74eSMichael S. Tsirkin 
165eb62b74eSMichael S. Tsirkin #define VHOST_SCSI_MAX_TARGET	256
166f49c2226SMike Christie #define VHOST_SCSI_MAX_IO_VQ	1024
167eb62b74eSMichael S. Tsirkin #define VHOST_SCSI_MAX_EVENT	128
168eb62b74eSMichael S. Tsirkin 
169f49c2226SMike Christie static unsigned vhost_scsi_max_io_vqs = 128;
170f49c2226SMike Christie module_param_named(max_io_vqs, vhost_scsi_max_io_vqs, uint, 0644);
171f49c2226SMike Christie MODULE_PARM_DESC(max_io_vqs, "Set the max number of IO virtqueues a vhost scsi device can support. The default is 128. The max is 1024.");
172f49c2226SMike Christie 
173eb62b74eSMichael S. Tsirkin struct vhost_scsi_virtqueue {
174eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue vq;
17548ae70ddSMike Christie 	struct vhost_scsi *vs;
176eb62b74eSMichael S. Tsirkin 	/*
177eb62b74eSMichael S. Tsirkin 	 * Reference counting for inflight reqs, used for flush operation. At
178eb62b74eSMichael S. Tsirkin 	 * each time, one reference tracks new commands submitted, while we
179eb62b74eSMichael S. Tsirkin 	 * wait for another one to reach 0.
180eb62b74eSMichael S. Tsirkin 	 */
181eb62b74eSMichael S. Tsirkin 	struct vhost_scsi_inflight inflights[2];
182eb62b74eSMichael S. Tsirkin 	/*
183eb62b74eSMichael S. Tsirkin 	 * Indicate current inflight in use, protected by vq->mutex.
184eb62b74eSMichael S. Tsirkin 	 * Writers must also take dev mutex and flush under it.
185eb62b74eSMichael S. Tsirkin 	 */
186eb62b74eSMichael S. Tsirkin 	int inflight_idx;
18725b98b64SMike Christie 	struct vhost_scsi_cmd *scsi_cmds;
18825b98b64SMike Christie 	struct sbitmap scsi_tags;
18925b98b64SMike Christie 	int max_cmds;
19048ae70ddSMike Christie 
19148ae70ddSMike Christie 	struct vhost_work completion_work;
19248ae70ddSMike Christie 	struct llist_head completion_list;
193eb62b74eSMichael S. Tsirkin };
194eb62b74eSMichael S. Tsirkin 
195eb62b74eSMichael S. Tsirkin struct vhost_scsi {
196eb62b74eSMichael S. Tsirkin 	/* Protected by vhost_scsi->dev.mutex */
1971a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg **vs_tpg;
198eb62b74eSMichael S. Tsirkin 	char vs_vhost_wwpn[TRANSPORT_IQN_LEN];
199eb62b74eSMichael S. Tsirkin 
200eb62b74eSMichael S. Tsirkin 	struct vhost_dev dev;
201f49c2226SMike Christie 	struct vhost_scsi_virtqueue *vqs;
202f49c2226SMike Christie 	struct vhost_scsi_inflight **old_inflight;
203eb62b74eSMichael S. Tsirkin 
204eb62b74eSMichael S. Tsirkin 	struct vhost_work vs_event_work; /* evt injection work item */
205eb62b74eSMichael S. Tsirkin 	struct llist_head vs_event_list; /* evt injection queue */
206eb62b74eSMichael S. Tsirkin 
207eb62b74eSMichael S. Tsirkin 	bool vs_events_missed; /* any missed events, protected by vq->mutex */
208eb62b74eSMichael S. Tsirkin 	int vs_events_nr; /* num of pending events, protected by vq->mutex */
209eb62b74eSMichael S. Tsirkin };
210eb62b74eSMichael S. Tsirkin 
211efd838feSMike Christie struct vhost_scsi_tmf {
212efd838feSMike Christie 	struct vhost_work vwork;
213efd838feSMike Christie 	struct vhost_scsi *vhost;
214efd838feSMike Christie 	struct vhost_scsi_virtqueue *svq;
215efd838feSMike Christie 
216efd838feSMike Christie 	struct se_cmd se_cmd;
217b4fffc17SMike Christie 	u8 scsi_resp;
218efd838feSMike Christie 	struct vhost_scsi_inflight *inflight;
219efd838feSMike Christie 	struct iovec resp_iov;
220efd838feSMike Christie 	int in_iovs;
221efd838feSMike Christie 	int vq_desc;
222efd838feSMike Christie };
223efd838feSMike Christie 
2243f8ca2e1SBijan Mottahedeh /*
2253f8ca2e1SBijan Mottahedeh  * Context for processing request and control queue operations.
2263f8ca2e1SBijan Mottahedeh  */
2273f8ca2e1SBijan Mottahedeh struct vhost_scsi_ctx {
2283f8ca2e1SBijan Mottahedeh 	int head;
2293f8ca2e1SBijan Mottahedeh 	unsigned int out, in;
2303f8ca2e1SBijan Mottahedeh 	size_t req_size, rsp_size;
2313f8ca2e1SBijan Mottahedeh 	size_t out_size, in_size;
2323f8ca2e1SBijan Mottahedeh 	u8 *target, *lunp;
2333f8ca2e1SBijan Mottahedeh 	void *req;
2343f8ca2e1SBijan Mottahedeh 	struct iov_iter out_iter;
2353f8ca2e1SBijan Mottahedeh };
2363f8ca2e1SBijan Mottahedeh 
237bea273c7SMike Christie /*
238bea273c7SMike Christie  * Global mutex to protect vhost_scsi TPG list for vhost IOCTLs and LIO
239bea273c7SMike Christie  * configfs management operations.
240bea273c7SMike Christie  */
2411a1ff825SNicholas Bellinger static DEFINE_MUTEX(vhost_scsi_mutex);
2421a1ff825SNicholas Bellinger static LIST_HEAD(vhost_scsi_list);
243eb62b74eSMichael S. Tsirkin 
vhost_scsi_done_inflight(struct kref * kref)2441a1ff825SNicholas Bellinger static void vhost_scsi_done_inflight(struct kref *kref)
245eb62b74eSMichael S. Tsirkin {
246eb62b74eSMichael S. Tsirkin 	struct vhost_scsi_inflight *inflight;
247eb62b74eSMichael S. Tsirkin 
248eb62b74eSMichael S. Tsirkin 	inflight = container_of(kref, struct vhost_scsi_inflight, kref);
249eb62b74eSMichael S. Tsirkin 	complete(&inflight->comp);
250eb62b74eSMichael S. Tsirkin }
251eb62b74eSMichael S. Tsirkin 
vhost_scsi_init_inflight(struct vhost_scsi * vs,struct vhost_scsi_inflight * old_inflight[])2521a1ff825SNicholas Bellinger static void vhost_scsi_init_inflight(struct vhost_scsi *vs,
253eb62b74eSMichael S. Tsirkin 				    struct vhost_scsi_inflight *old_inflight[])
254eb62b74eSMichael S. Tsirkin {
255eb62b74eSMichael S. Tsirkin 	struct vhost_scsi_inflight *new_inflight;
256eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue *vq;
257eb62b74eSMichael S. Tsirkin 	int idx, i;
258eb62b74eSMichael S. Tsirkin 
259f49c2226SMike Christie 	for (i = 0; i < vs->dev.nvqs;  i++) {
260eb62b74eSMichael S. Tsirkin 		vq = &vs->vqs[i].vq;
261eb62b74eSMichael S. Tsirkin 
262eb62b74eSMichael S. Tsirkin 		mutex_lock(&vq->mutex);
263eb62b74eSMichael S. Tsirkin 
264eb62b74eSMichael S. Tsirkin 		/* store old infight */
265eb62b74eSMichael S. Tsirkin 		idx = vs->vqs[i].inflight_idx;
266eb62b74eSMichael S. Tsirkin 		if (old_inflight)
267eb62b74eSMichael S. Tsirkin 			old_inflight[i] = &vs->vqs[i].inflights[idx];
268eb62b74eSMichael S. Tsirkin 
269eb62b74eSMichael S. Tsirkin 		/* setup new infight */
270eb62b74eSMichael S. Tsirkin 		vs->vqs[i].inflight_idx = idx ^ 1;
271eb62b74eSMichael S. Tsirkin 		new_inflight = &vs->vqs[i].inflights[idx ^ 1];
272eb62b74eSMichael S. Tsirkin 		kref_init(&new_inflight->kref);
273eb62b74eSMichael S. Tsirkin 		init_completion(&new_inflight->comp);
274eb62b74eSMichael S. Tsirkin 
275eb62b74eSMichael S. Tsirkin 		mutex_unlock(&vq->mutex);
276eb62b74eSMichael S. Tsirkin 	}
277eb62b74eSMichael S. Tsirkin }
278eb62b74eSMichael S. Tsirkin 
279eb62b74eSMichael S. Tsirkin static struct vhost_scsi_inflight *
vhost_scsi_get_inflight(struct vhost_virtqueue * vq)2801a1ff825SNicholas Bellinger vhost_scsi_get_inflight(struct vhost_virtqueue *vq)
281eb62b74eSMichael S. Tsirkin {
282eb62b74eSMichael S. Tsirkin 	struct vhost_scsi_inflight *inflight;
283eb62b74eSMichael S. Tsirkin 	struct vhost_scsi_virtqueue *svq;
284eb62b74eSMichael S. Tsirkin 
285eb62b74eSMichael S. Tsirkin 	svq = container_of(vq, struct vhost_scsi_virtqueue, vq);
286eb62b74eSMichael S. Tsirkin 	inflight = &svq->inflights[svq->inflight_idx];
287eb62b74eSMichael S. Tsirkin 	kref_get(&inflight->kref);
288eb62b74eSMichael S. Tsirkin 
289eb62b74eSMichael S. Tsirkin 	return inflight;
290eb62b74eSMichael S. Tsirkin }
291eb62b74eSMichael S. Tsirkin 
vhost_scsi_put_inflight(struct vhost_scsi_inflight * inflight)2921a1ff825SNicholas Bellinger static void vhost_scsi_put_inflight(struct vhost_scsi_inflight *inflight)
293eb62b74eSMichael S. Tsirkin {
2941a1ff825SNicholas Bellinger 	kref_put(&inflight->kref, vhost_scsi_done_inflight);
295eb62b74eSMichael S. Tsirkin }
296eb62b74eSMichael S. Tsirkin 
vhost_scsi_check_true(struct se_portal_group * se_tpg)2971a1ff825SNicholas Bellinger static int vhost_scsi_check_true(struct se_portal_group *se_tpg)
298eb62b74eSMichael S. Tsirkin {
299eb62b74eSMichael S. Tsirkin 	return 1;
300eb62b74eSMichael S. Tsirkin }
301eb62b74eSMichael S. Tsirkin 
vhost_scsi_get_fabric_wwn(struct se_portal_group * se_tpg)3021a1ff825SNicholas Bellinger static char *vhost_scsi_get_fabric_wwn(struct se_portal_group *se_tpg)
303eb62b74eSMichael S. Tsirkin {
3041a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
3051a1ff825SNicholas Bellinger 				struct vhost_scsi_tpg, se_tpg);
3061a1ff825SNicholas Bellinger 	struct vhost_scsi_tport *tport = tpg->tport;
307eb62b74eSMichael S. Tsirkin 
308eb62b74eSMichael S. Tsirkin 	return &tport->tport_name[0];
309eb62b74eSMichael S. Tsirkin }
310eb62b74eSMichael S. Tsirkin 
vhost_scsi_get_tpgt(struct se_portal_group * se_tpg)3111a1ff825SNicholas Bellinger static u16 vhost_scsi_get_tpgt(struct se_portal_group *se_tpg)
312eb62b74eSMichael S. Tsirkin {
3131a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
3141a1ff825SNicholas Bellinger 				struct vhost_scsi_tpg, se_tpg);
315eb62b74eSMichael S. Tsirkin 	return tpg->tport_tpgt;
316eb62b74eSMichael S. Tsirkin }
317eb62b74eSMichael S. Tsirkin 
vhost_scsi_check_prot_fabric_only(struct se_portal_group * se_tpg)318b1d75fe5SNicholas Bellinger static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg)
319b1d75fe5SNicholas Bellinger {
320b1d75fe5SNicholas Bellinger 	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
321b1d75fe5SNicholas Bellinger 				struct vhost_scsi_tpg, se_tpg);
322b1d75fe5SNicholas Bellinger 
323b1d75fe5SNicholas Bellinger 	return tpg->tv_fabric_prot_type;
324b1d75fe5SNicholas Bellinger }
325b1d75fe5SNicholas Bellinger 
vhost_scsi_release_cmd_res(struct se_cmd * se_cmd)32647a3565eSMike Christie static void vhost_scsi_release_cmd_res(struct se_cmd *se_cmd)
327eb62b74eSMichael S. Tsirkin {
3281a1ff825SNicholas Bellinger 	struct vhost_scsi_cmd *tv_cmd = container_of(se_cmd,
3291a1ff825SNicholas Bellinger 				struct vhost_scsi_cmd, tvc_se_cmd);
33025b98b64SMike Christie 	struct vhost_scsi_virtqueue *svq = container_of(tv_cmd->tvc_vq,
33125b98b64SMike Christie 				struct vhost_scsi_virtqueue, vq);
33225b98b64SMike Christie 	struct vhost_scsi_inflight *inflight = tv_cmd->inflight;
333e31885ddSNicholas Bellinger 	int i;
334084ed45bSNicholas Bellinger 
335084ed45bSNicholas Bellinger 	if (tv_cmd->tvc_sgl_count) {
3365ced58bfSMike Christie 		for (i = 0; i < tv_cmd->tvc_sgl_count; i++) {
3375ced58bfSMike Christie 			if (tv_cmd->copied_iov)
3385ced58bfSMike Christie 				__free_page(sg_page(&tv_cmd->tvc_sgl[i]));
3395ced58bfSMike Christie 			else
340084ed45bSNicholas Bellinger 				put_page(sg_page(&tv_cmd->tvc_sgl[i]));
341084ed45bSNicholas Bellinger 		}
3425ced58bfSMike Christie 		kfree(tv_cmd->saved_iter_addr);
3435ced58bfSMike Christie 	}
344e31885ddSNicholas Bellinger 	if (tv_cmd->tvc_prot_sgl_count) {
345e31885ddSNicholas Bellinger 		for (i = 0; i < tv_cmd->tvc_prot_sgl_count; i++)
346e31885ddSNicholas Bellinger 			put_page(sg_page(&tv_cmd->tvc_prot_sgl[i]));
347e31885ddSNicholas Bellinger 	}
348084ed45bSNicholas Bellinger 
34925b98b64SMike Christie 	sbitmap_clear_bit(&svq->scsi_tags, se_cmd->map_tag);
35025b98b64SMike Christie 	vhost_scsi_put_inflight(inflight);
351eb62b74eSMichael S. Tsirkin }
352eb62b74eSMichael S. Tsirkin 
vhost_scsi_release_tmf_res(struct vhost_scsi_tmf * tmf)353efd838feSMike Christie static void vhost_scsi_release_tmf_res(struct vhost_scsi_tmf *tmf)
354efd838feSMike Christie {
355efd838feSMike Christie 	struct vhost_scsi_inflight *inflight = tmf->inflight;
356efd838feSMike Christie 
3574c363c81SMike Christie 	kfree(tmf);
358efd838feSMike Christie 	vhost_scsi_put_inflight(inflight);
359efd838feSMike Christie }
360efd838feSMike Christie 
vhost_scsi_release_cmd(struct se_cmd * se_cmd)36147a3565eSMike Christie static void vhost_scsi_release_cmd(struct se_cmd *se_cmd)
36247a3565eSMike Christie {
363efd838feSMike Christie 	if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) {
364efd838feSMike Christie 		struct vhost_scsi_tmf *tmf = container_of(se_cmd,
365efd838feSMike Christie 					struct vhost_scsi_tmf, se_cmd);
36678af31ccSMike Christie 		struct vhost_virtqueue *vq = &tmf->svq->vq;
367efd838feSMike Christie 
36878af31ccSMike Christie 		vhost_vq_work_queue(vq, &tmf->vwork);
369efd838feSMike Christie 	} else {
37047a3565eSMike Christie 		struct vhost_scsi_cmd *cmd = container_of(se_cmd,
37147a3565eSMike Christie 					struct vhost_scsi_cmd, tvc_se_cmd);
37248ae70ddSMike Christie 		struct vhost_scsi_virtqueue *svq =  container_of(cmd->tvc_vq,
37348ae70ddSMike Christie 					struct vhost_scsi_virtqueue, vq);
37447a3565eSMike Christie 
37548ae70ddSMike Christie 		llist_add(&cmd->tvc_completion_list, &svq->completion_list);
37648ae70ddSMike Christie 		vhost_vq_work_queue(&svq->vq, &svq->completion_work);
37747a3565eSMike Christie 	}
378efd838feSMike Christie }
37947a3565eSMike Christie 
vhost_scsi_write_pending(struct se_cmd * se_cmd)3801a1ff825SNicholas Bellinger static int vhost_scsi_write_pending(struct se_cmd *se_cmd)
381eb62b74eSMichael S. Tsirkin {
382eb62b74eSMichael S. Tsirkin 	/* Go ahead and process the write immediately */
383eb62b74eSMichael S. Tsirkin 	target_execute_cmd(se_cmd);
384eb62b74eSMichael S. Tsirkin 	return 0;
385eb62b74eSMichael S. Tsirkin }
386eb62b74eSMichael S. Tsirkin 
vhost_scsi_queue_data_in(struct se_cmd * se_cmd)3871a1ff825SNicholas Bellinger static int vhost_scsi_queue_data_in(struct se_cmd *se_cmd)
388eb62b74eSMichael S. Tsirkin {
38947a3565eSMike Christie 	transport_generic_free_cmd(se_cmd, 0);
390eb62b74eSMichael S. Tsirkin 	return 0;
391eb62b74eSMichael S. Tsirkin }
392eb62b74eSMichael S. Tsirkin 
vhost_scsi_queue_status(struct se_cmd * se_cmd)3931a1ff825SNicholas Bellinger static int vhost_scsi_queue_status(struct se_cmd *se_cmd)
394eb62b74eSMichael S. Tsirkin {
39547a3565eSMike Christie 	transport_generic_free_cmd(se_cmd, 0);
396eb62b74eSMichael S. Tsirkin 	return 0;
397eb62b74eSMichael S. Tsirkin }
398eb62b74eSMichael S. Tsirkin 
vhost_scsi_queue_tm_rsp(struct se_cmd * se_cmd)3991a1ff825SNicholas Bellinger static void vhost_scsi_queue_tm_rsp(struct se_cmd *se_cmd)
400eb62b74eSMichael S. Tsirkin {
401efd838feSMike Christie 	struct vhost_scsi_tmf *tmf = container_of(se_cmd, struct vhost_scsi_tmf,
402efd838feSMike Christie 						  se_cmd);
403efd838feSMike Christie 
404b4fffc17SMike Christie 	tmf->scsi_resp = se_cmd->se_tmr_req->response;
405efd838feSMike Christie 	transport_generic_free_cmd(&tmf->se_cmd, 0);
406eb62b74eSMichael S. Tsirkin }
407eb62b74eSMichael S. Tsirkin 
vhost_scsi_aborted_task(struct se_cmd * se_cmd)4081a1ff825SNicholas Bellinger static void vhost_scsi_aborted_task(struct se_cmd *se_cmd)
409131e6abcSNicholas Bellinger {
410131e6abcSNicholas Bellinger 	return;
411131e6abcSNicholas Bellinger }
412131e6abcSNicholas Bellinger 
vhost_scsi_free_evt(struct vhost_scsi * vs,struct vhost_scsi_evt * evt)4131a1ff825SNicholas Bellinger static void vhost_scsi_free_evt(struct vhost_scsi *vs, struct vhost_scsi_evt *evt)
414eb62b74eSMichael S. Tsirkin {
415eb62b74eSMichael S. Tsirkin 	vs->vs_events_nr--;
416eb62b74eSMichael S. Tsirkin 	kfree(evt);
417eb62b74eSMichael S. Tsirkin }
418eb62b74eSMichael S. Tsirkin 
4191a1ff825SNicholas Bellinger static struct vhost_scsi_evt *
vhost_scsi_allocate_evt(struct vhost_scsi * vs,u32 event,u32 reason)4201a1ff825SNicholas Bellinger vhost_scsi_allocate_evt(struct vhost_scsi *vs,
421eb62b74eSMichael S. Tsirkin 		       u32 event, u32 reason)
422eb62b74eSMichael S. Tsirkin {
423eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
4241a1ff825SNicholas Bellinger 	struct vhost_scsi_evt *evt;
425eb62b74eSMichael S. Tsirkin 
426eb62b74eSMichael S. Tsirkin 	if (vs->vs_events_nr > VHOST_SCSI_MAX_EVENT) {
427eb62b74eSMichael S. Tsirkin 		vs->vs_events_missed = true;
428eb62b74eSMichael S. Tsirkin 		return NULL;
429eb62b74eSMichael S. Tsirkin 	}
430eb62b74eSMichael S. Tsirkin 
431eb62b74eSMichael S. Tsirkin 	evt = kzalloc(sizeof(*evt), GFP_KERNEL);
432eb62b74eSMichael S. Tsirkin 	if (!evt) {
4331a1ff825SNicholas Bellinger 		vq_err(vq, "Failed to allocate vhost_scsi_evt\n");
434eb62b74eSMichael S. Tsirkin 		vs->vs_events_missed = true;
435eb62b74eSMichael S. Tsirkin 		return NULL;
436eb62b74eSMichael S. Tsirkin 	}
437eb62b74eSMichael S. Tsirkin 
438e72fd72eSMichael S. Tsirkin 	evt->event.event = cpu_to_vhost32(vq, event);
439e72fd72eSMichael S. Tsirkin 	evt->event.reason = cpu_to_vhost32(vq, reason);
440eb62b74eSMichael S. Tsirkin 	vs->vs_events_nr++;
441eb62b74eSMichael S. Tsirkin 
442eb62b74eSMichael S. Tsirkin 	return evt;
443eb62b74eSMichael S. Tsirkin }
444eb62b74eSMichael S. Tsirkin 
vhost_scsi_check_stop_free(struct se_cmd * se_cmd)445084ed45bSNicholas Bellinger static int vhost_scsi_check_stop_free(struct se_cmd *se_cmd)
446084ed45bSNicholas Bellinger {
447afc16604SBart Van Assche 	return target_put_sess_cmd(se_cmd);
448eb62b74eSMichael S. Tsirkin }
449eb62b74eSMichael S. Tsirkin 
450683bd967SAsias He static void
vhost_scsi_do_evt_work(struct vhost_scsi * vs,struct vhost_scsi_evt * evt)4511a1ff825SNicholas Bellinger vhost_scsi_do_evt_work(struct vhost_scsi *vs, struct vhost_scsi_evt *evt)
452eb62b74eSMichael S. Tsirkin {
453eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
454eb62b74eSMichael S. Tsirkin 	struct virtio_scsi_event *event = &evt->event;
455eb62b74eSMichael S. Tsirkin 	struct virtio_scsi_event __user *eventp;
456eb62b74eSMichael S. Tsirkin 	unsigned out, in;
457eb62b74eSMichael S. Tsirkin 	int head, ret;
458eb62b74eSMichael S. Tsirkin 
459247643f8SEugenio Pérez 	if (!vhost_vq_get_backend(vq)) {
460eb62b74eSMichael S. Tsirkin 		vs->vs_events_missed = true;
461eb62b74eSMichael S. Tsirkin 		return;
462eb62b74eSMichael S. Tsirkin 	}
463eb62b74eSMichael S. Tsirkin 
464eb62b74eSMichael S. Tsirkin again:
465eb62b74eSMichael S. Tsirkin 	vhost_disable_notify(&vs->dev, vq);
46647283befSMichael S. Tsirkin 	head = vhost_get_vq_desc(vq, vq->iov,
467eb62b74eSMichael S. Tsirkin 			ARRAY_SIZE(vq->iov), &out, &in,
468eb62b74eSMichael S. Tsirkin 			NULL, NULL);
469eb62b74eSMichael S. Tsirkin 	if (head < 0) {
470eb62b74eSMichael S. Tsirkin 		vs->vs_events_missed = true;
471eb62b74eSMichael S. Tsirkin 		return;
472eb62b74eSMichael S. Tsirkin 	}
473eb62b74eSMichael S. Tsirkin 	if (head == vq->num) {
474eb62b74eSMichael S. Tsirkin 		if (vhost_enable_notify(&vs->dev, vq))
475eb62b74eSMichael S. Tsirkin 			goto again;
476eb62b74eSMichael S. Tsirkin 		vs->vs_events_missed = true;
477eb62b74eSMichael S. Tsirkin 		return;
478eb62b74eSMichael S. Tsirkin 	}
479eb62b74eSMichael S. Tsirkin 
480eb62b74eSMichael S. Tsirkin 	if ((vq->iov[out].iov_len != sizeof(struct virtio_scsi_event))) {
481eb62b74eSMichael S. Tsirkin 		vq_err(vq, "Expecting virtio_scsi_event, got %zu bytes\n",
482eb62b74eSMichael S. Tsirkin 				vq->iov[out].iov_len);
483eb62b74eSMichael S. Tsirkin 		vs->vs_events_missed = true;
484eb62b74eSMichael S. Tsirkin 		return;
485eb62b74eSMichael S. Tsirkin 	}
486eb62b74eSMichael S. Tsirkin 
487eb62b74eSMichael S. Tsirkin 	if (vs->vs_events_missed) {
488e72fd72eSMichael S. Tsirkin 		event->event |= cpu_to_vhost32(vq, VIRTIO_SCSI_T_EVENTS_MISSED);
489eb62b74eSMichael S. Tsirkin 		vs->vs_events_missed = false;
490eb62b74eSMichael S. Tsirkin 	}
491eb62b74eSMichael S. Tsirkin 
492eb62b74eSMichael S. Tsirkin 	eventp = vq->iov[out].iov_base;
493eb62b74eSMichael S. Tsirkin 	ret = __copy_to_user(eventp, event, sizeof(*event));
494eb62b74eSMichael S. Tsirkin 	if (!ret)
495eb62b74eSMichael S. Tsirkin 		vhost_add_used_and_signal(&vs->dev, vq, head, 0);
496eb62b74eSMichael S. Tsirkin 	else
4971a1ff825SNicholas Bellinger 		vq_err(vq, "Faulted on vhost_scsi_send_event\n");
498eb62b74eSMichael S. Tsirkin }
499eb62b74eSMichael S. Tsirkin 
vhost_scsi_complete_events(struct vhost_scsi * vs,bool drop)5008f174c5dSMike Christie static void vhost_scsi_complete_events(struct vhost_scsi *vs, bool drop)
501eb62b74eSMichael S. Tsirkin {
502eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
50312bdcbd5SByungchul Park 	struct vhost_scsi_evt *evt, *t;
504eb62b74eSMichael S. Tsirkin 	struct llist_node *llnode;
505eb62b74eSMichael S. Tsirkin 
506eb62b74eSMichael S. Tsirkin 	mutex_lock(&vq->mutex);
507eb62b74eSMichael S. Tsirkin 	llnode = llist_del_all(&vs->vs_event_list);
50812bdcbd5SByungchul Park 	llist_for_each_entry_safe(evt, t, llnode, list) {
5098f174c5dSMike Christie 		if (!drop)
5101a1ff825SNicholas Bellinger 			vhost_scsi_do_evt_work(vs, evt);
5111a1ff825SNicholas Bellinger 		vhost_scsi_free_evt(vs, evt);
512eb62b74eSMichael S. Tsirkin 	}
513eb62b74eSMichael S. Tsirkin 	mutex_unlock(&vq->mutex);
514eb62b74eSMichael S. Tsirkin }
515eb62b74eSMichael S. Tsirkin 
vhost_scsi_evt_work(struct vhost_work * work)5168f174c5dSMike Christie static void vhost_scsi_evt_work(struct vhost_work *work)
5178f174c5dSMike Christie {
5188f174c5dSMike Christie 	struct vhost_scsi *vs = container_of(work, struct vhost_scsi,
5198f174c5dSMike Christie 					     vs_event_work);
5208f174c5dSMike Christie 	vhost_scsi_complete_events(vs, false);
5218f174c5dSMike Christie }
5228f174c5dSMike Christie 
vhost_scsi_copy_sgl_to_iov(struct vhost_scsi_cmd * cmd)5235ced58bfSMike Christie static int vhost_scsi_copy_sgl_to_iov(struct vhost_scsi_cmd *cmd)
5245ced58bfSMike Christie {
5255ced58bfSMike Christie 	struct iov_iter *iter = &cmd->saved_iter;
5265ced58bfSMike Christie 	struct scatterlist *sg = cmd->tvc_sgl;
5275ced58bfSMike Christie 	struct page *page;
5285ced58bfSMike Christie 	size_t len;
5295ced58bfSMike Christie 	int i;
5305ced58bfSMike Christie 
5315ced58bfSMike Christie 	for (i = 0; i < cmd->tvc_sgl_count; i++) {
5325ced58bfSMike Christie 		page = sg_page(&sg[i]);
5335ced58bfSMike Christie 		len = sg[i].length;
5345ced58bfSMike Christie 
5355ced58bfSMike Christie 		if (copy_page_to_iter(page, 0, len, iter) != len) {
5365ced58bfSMike Christie 			pr_err("Could not copy data while handling misaligned cmd. Error %zu\n",
5375ced58bfSMike Christie 			       len);
5385ced58bfSMike Christie 			return -1;
5395ced58bfSMike Christie 		}
5405ced58bfSMike Christie 	}
5415ced58bfSMike Christie 
5425ced58bfSMike Christie 	return 0;
5435ced58bfSMike Christie }
5445ced58bfSMike Christie 
545eb62b74eSMichael S. Tsirkin /* Fill in status and signal that we are done processing this command
546eb62b74eSMichael S. Tsirkin  *
547eb62b74eSMichael S. Tsirkin  * This is scheduled in the vhost work queue so we are called with the owner
548eb62b74eSMichael S. Tsirkin  * process mm and can access the vring.
549eb62b74eSMichael S. Tsirkin  */
vhost_scsi_complete_cmd_work(struct vhost_work * work)550eb62b74eSMichael S. Tsirkin static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
551eb62b74eSMichael S. Tsirkin {
55248ae70ddSMike Christie 	struct vhost_scsi_virtqueue *svq = container_of(work,
55348ae70ddSMike Christie 				struct vhost_scsi_virtqueue, completion_work);
554eb62b74eSMichael S. Tsirkin 	struct virtio_scsi_cmd_resp v_rsp;
555816e85edSByungchul Park 	struct vhost_scsi_cmd *cmd, *t;
556eb62b74eSMichael S. Tsirkin 	struct llist_node *llnode;
557eb62b74eSMichael S. Tsirkin 	struct se_cmd *se_cmd;
55879c14141SNicholas Bellinger 	struct iov_iter iov_iter;
55948ae70ddSMike Christie 	bool signal = false;
56048ae70ddSMike Christie 	int ret;
561eb62b74eSMichael S. Tsirkin 
56248ae70ddSMike Christie 	llnode = llist_del_all(&svq->completion_list);
563816e85edSByungchul Park 	llist_for_each_entry_safe(cmd, t, llnode, tvc_completion_list) {
5643c63f66aSAsias He 		se_cmd = &cmd->tvc_se_cmd;
565eb62b74eSMichael S. Tsirkin 
566eb62b74eSMichael S. Tsirkin 		pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__,
5673c63f66aSAsias He 			cmd, se_cmd->residual_count, se_cmd->scsi_status);
568eb62b74eSMichael S. Tsirkin 		memset(&v_rsp, 0, sizeof(v_rsp));
5695ced58bfSMike Christie 
5705ced58bfSMike Christie 		if (cmd->saved_iter_addr && vhost_scsi_copy_sgl_to_iov(cmd)) {
5715ced58bfSMike Christie 			v_rsp.response = VIRTIO_SCSI_S_BAD_TARGET;
5725ced58bfSMike Christie 		} else {
5735ced58bfSMike Christie 			v_rsp.resid = cpu_to_vhost32(cmd->tvc_vq,
5745ced58bfSMike Christie 						     se_cmd->residual_count);
575eb62b74eSMichael S. Tsirkin 			/* TODO is status_qualifier field needed? */
576eb62b74eSMichael S. Tsirkin 			v_rsp.status = se_cmd->scsi_status;
577e72fd72eSMichael S. Tsirkin 			v_rsp.sense_len = cpu_to_vhost32(cmd->tvc_vq,
578e72fd72eSMichael S. Tsirkin 							 se_cmd->scsi_sense_length);
5793c63f66aSAsias He 			memcpy(v_rsp.sense, cmd->tvc_sense_buf,
580e72fd72eSMichael S. Tsirkin 			       se_cmd->scsi_sense_length);
5815ced58bfSMike Christie 		}
58279c14141SNicholas Bellinger 
5836dd88fd5SJason Wang 		iov_iter_init(&iov_iter, ITER_DEST, cmd->tvc_resp_iov,
58479c14141SNicholas Bellinger 			      cmd->tvc_in_iovs, sizeof(v_rsp));
58579c14141SNicholas Bellinger 		ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter);
58679c14141SNicholas Bellinger 		if (likely(ret == sizeof(v_rsp))) {
58748ae70ddSMike Christie 			signal = true;
58848ae70ddSMike Christie 
5893c63f66aSAsias He 			vhost_add_used(cmd->tvc_vq, cmd->tvc_vq_desc, 0);
590eb62b74eSMichael S. Tsirkin 		} else
591eb62b74eSMichael S. Tsirkin 			pr_err("Faulted on virtio_scsi_cmd_resp\n");
592eb62b74eSMichael S. Tsirkin 
59347a3565eSMike Christie 		vhost_scsi_release_cmd_res(se_cmd);
594eb62b74eSMichael S. Tsirkin 	}
595eb62b74eSMichael S. Tsirkin 
59648ae70ddSMike Christie 	if (signal)
59748ae70ddSMike Christie 		vhost_signal(&svq->vs->dev, &svq->vq);
598eb62b74eSMichael S. Tsirkin }
599eb62b74eSMichael S. Tsirkin 
6001a1ff825SNicholas Bellinger 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)60125b98b64SMike Christie vhost_scsi_get_cmd(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg,
60295e7c434SNicholas Bellinger 		   unsigned char *cdb, u64 scsi_tag, u16 lun, u8 task_attr,
60395e7c434SNicholas Bellinger 		   u32 exp_data_len, int data_direction)
604eb62b74eSMichael S. Tsirkin {
60525b98b64SMike Christie 	struct vhost_scsi_virtqueue *svq = container_of(vq,
60625b98b64SMike Christie 					struct vhost_scsi_virtqueue, vq);
6071a1ff825SNicholas Bellinger 	struct vhost_scsi_cmd *cmd;
6081a1ff825SNicholas Bellinger 	struct vhost_scsi_nexus *tv_nexus;
609b1935f68SNicholas Bellinger 	struct scatterlist *sg, *prot_sg;
6106dd88fd5SJason Wang 	struct iovec *tvc_resp_iov;
6113aee26b4SNicholas Bellinger 	struct page **pages;
61225b98b64SMike Christie 	int tag;
613eb62b74eSMichael S. Tsirkin 
61498718312SAsias He 	tv_nexus = tpg->tpg_nexus;
615eb62b74eSMichael S. Tsirkin 	if (!tv_nexus) {
6161a1ff825SNicholas Bellinger 		pr_err("Unable to locate active struct vhost_scsi_nexus\n");
617eb62b74eSMichael S. Tsirkin 		return ERR_PTR(-EIO);
618eb62b74eSMichael S. Tsirkin 	}
619eb62b74eSMichael S. Tsirkin 
620c548e62bSMing Lei 	tag = sbitmap_get(&svq->scsi_tags);
6214a47d3a1SNicholas Bellinger 	if (tag < 0) {
6221a1ff825SNicholas Bellinger 		pr_err("Unable to obtain tag for vhost_scsi_cmd\n");
6234a47d3a1SNicholas Bellinger 		return ERR_PTR(-ENOMEM);
6244a47d3a1SNicholas Bellinger 	}
6254a47d3a1SNicholas Bellinger 
62625b98b64SMike Christie 	cmd = &svq->scsi_cmds[tag];
6273aee26b4SNicholas Bellinger 	sg = cmd->tvc_sgl;
628b1935f68SNicholas Bellinger 	prot_sg = cmd->tvc_prot_sgl;
6293aee26b4SNicholas Bellinger 	pages = cmd->tvc_upages;
6306dd88fd5SJason Wang 	tvc_resp_iov = cmd->tvc_resp_iov;
631473f0b15SMarkus Elfring 	memset(cmd, 0, sizeof(*cmd));
6323aee26b4SNicholas Bellinger 	cmd->tvc_sgl = sg;
633b1935f68SNicholas Bellinger 	cmd->tvc_prot_sgl = prot_sg;
6343aee26b4SNicholas Bellinger 	cmd->tvc_upages = pages;
6354824d3bfSNicholas Bellinger 	cmd->tvc_se_cmd.map_tag = tag;
63695e7c434SNicholas Bellinger 	cmd->tvc_tag = scsi_tag;
63795e7c434SNicholas Bellinger 	cmd->tvc_lun = lun;
63895e7c434SNicholas Bellinger 	cmd->tvc_task_attr = task_attr;
6393c63f66aSAsias He 	cmd->tvc_exp_data_len = exp_data_len;
6403c63f66aSAsias He 	cmd->tvc_data_direction = data_direction;
6413c63f66aSAsias He 	cmd->tvc_nexus = tv_nexus;
6421a1ff825SNicholas Bellinger 	cmd->inflight = vhost_scsi_get_inflight(vq);
6436dd88fd5SJason Wang 	cmd->tvc_resp_iov = tvc_resp_iov;
644eb62b74eSMichael S. Tsirkin 
6451a1ff825SNicholas Bellinger 	memcpy(cmd->tvc_cdb, cdb, VHOST_SCSI_MAX_CDB_SIZE);
64695e7c434SNicholas Bellinger 
6473c63f66aSAsias He 	return cmd;
648eb62b74eSMichael S. Tsirkin }
649eb62b74eSMichael S. Tsirkin 
650eb62b74eSMichael S. Tsirkin /*
651eb62b74eSMichael S. Tsirkin  * Map a user memory range into a scatterlist
652eb62b74eSMichael S. Tsirkin  *
653eb62b74eSMichael S. Tsirkin  * Returns the number of scatterlist entries used or -errno on error.
654eb62b74eSMichael S. Tsirkin  */
655683bd967SAsias He static int
vhost_scsi_map_to_sgl(struct vhost_scsi_cmd * cmd,struct iov_iter * iter,struct scatterlist * sgl,bool is_prot)6561a1ff825SNicholas Bellinger vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd,
6572f240c4aSAl Viro 		      struct iov_iter *iter,
6583aee26b4SNicholas Bellinger 		      struct scatterlist *sgl,
6595ced58bfSMike Christie 		      bool is_prot)
660eb62b74eSMichael S. Tsirkin {
661b4078b5fSNicholas Bellinger 	struct page **pages = cmd->tvc_upages;
6622f240c4aSAl Viro 	struct scatterlist *sg = sgl;
6635ced58bfSMike Christie 	ssize_t bytes, mapped_bytes;
6645ced58bfSMike Christie 	size_t offset, mapped_offset;
6652f240c4aSAl Viro 	unsigned int npages = 0;
666eb62b74eSMichael S. Tsirkin 
6671ef255e2SAl Viro 	bytes = iov_iter_get_pages2(iter, pages, LONG_MAX,
6682f240c4aSAl Viro 				VHOST_SCSI_PREALLOC_UPAGES, &offset);
669eb62b74eSMichael S. Tsirkin 	/* No pages were pinned */
6702f240c4aSAl Viro 	if (bytes <= 0)
6712f240c4aSAl Viro 		return bytes < 0 ? bytes : -EFAULT;
672eb62b74eSMichael S. Tsirkin 
6735ced58bfSMike Christie 	mapped_bytes = bytes;
6745ced58bfSMike Christie 	mapped_offset = offset;
6755ced58bfSMike Christie 
6762f240c4aSAl Viro 	while (bytes) {
6772f240c4aSAl Viro 		unsigned n = min_t(unsigned, PAGE_SIZE - offset, bytes);
6785ced58bfSMike Christie 		/*
6795ced58bfSMike Christie 		 * The block layer requires bios/requests to be a multiple of
6805ced58bfSMike Christie 		 * 512 bytes, but Windows can send us vecs that are misaligned.
6815ced58bfSMike Christie 		 * This can result in bios and later requests with misaligned
6825ced58bfSMike Christie 		 * sizes if we have to break up a cmd/scatterlist into multiple
6835ced58bfSMike Christie 		 * bios.
6845ced58bfSMike Christie 		 *
6855ced58bfSMike Christie 		 * We currently only break up a command into multiple bios if
6865ced58bfSMike Christie 		 * we hit the vec/seg limit, so check if our sgl_count is
6875ced58bfSMike Christie 		 * greater than the max and if a vec in the cmd has a
6885ced58bfSMike Christie 		 * misaligned offset/size.
6895ced58bfSMike Christie 		 */
6905ced58bfSMike Christie 		if (!is_prot &&
6915ced58bfSMike Christie 		    (offset & (SECTOR_SIZE - 1) || n & (SECTOR_SIZE - 1)) &&
6925ced58bfSMike Christie 		    cmd->tvc_sgl_count > BIO_MAX_VECS) {
6935ced58bfSMike Christie 			WARN_ONCE(true,
6945ced58bfSMike Christie 				  "vhost-scsi detected misaligned IO. Performance may be degraded.");
6955ced58bfSMike Christie 			goto revert_iter_get_pages;
6965ced58bfSMike Christie 		}
6975ced58bfSMike Christie 
6982f240c4aSAl Viro 		sg_set_page(sg++, pages[npages++], n, offset);
6992f240c4aSAl Viro 		bytes -= n;
7002f240c4aSAl Viro 		offset = 0;
7012f240c4aSAl Viro 	}
7025ced58bfSMike Christie 
7032f240c4aSAl Viro 	return npages;
7045ced58bfSMike Christie 
7055ced58bfSMike Christie revert_iter_get_pages:
7065ced58bfSMike Christie 	iov_iter_revert(iter, mapped_bytes);
7075ced58bfSMike Christie 
7085ced58bfSMike Christie 	npages = 0;
7095ced58bfSMike Christie 	while (mapped_bytes) {
7105ced58bfSMike Christie 		unsigned int n = min_t(unsigned int, PAGE_SIZE - mapped_offset,
7115ced58bfSMike Christie 				       mapped_bytes);
7125ced58bfSMike Christie 
7135ced58bfSMike Christie 		put_page(pages[npages++]);
7145ced58bfSMike Christie 
7155ced58bfSMike Christie 		mapped_bytes -= n;
7165ced58bfSMike Christie 		mapped_offset = 0;
7175ced58bfSMike Christie 	}
7185ced58bfSMike Christie 
7195ced58bfSMike Christie 	return -EINVAL;
720eb62b74eSMichael S. Tsirkin }
721eb62b74eSMichael S. Tsirkin 
722683bd967SAsias He static int
vhost_scsi_calc_sgls(struct iov_iter * iter,size_t bytes,int max_sgls)723e8de56b5SNicholas Bellinger vhost_scsi_calc_sgls(struct iov_iter *iter, size_t bytes, int max_sgls)
724eb62b74eSMichael S. Tsirkin {
725e8de56b5SNicholas Bellinger 	int sgl_count = 0;
726eb62b74eSMichael S. Tsirkin 
727de4f5fedSJens Axboe 	if (!iter || !iter_iov(iter)) {
728e8de56b5SNicholas Bellinger 		pr_err("%s: iter->iov is NULL, but expected bytes: %zu"
729e8de56b5SNicholas Bellinger 		       " present\n", __func__, bytes);
730e8de56b5SNicholas Bellinger 		return -EINVAL;
7315a01d082SNicholas Bellinger 	}
732eb62b74eSMichael S. Tsirkin 
733e8de56b5SNicholas Bellinger 	sgl_count = iov_iter_npages(iter, 0xffff);
734e8de56b5SNicholas Bellinger 	if (sgl_count > max_sgls) {
735e8de56b5SNicholas Bellinger 		pr_err("%s: requested sgl_count: %d exceeds pre-allocated"
736e8de56b5SNicholas Bellinger 		       " max_sgls: %d\n", __func__, sgl_count, max_sgls);
737e8de56b5SNicholas Bellinger 		return -EINVAL;
738e8de56b5SNicholas Bellinger 	}
739e8de56b5SNicholas Bellinger 	return sgl_count;
740e8de56b5SNicholas Bellinger }
741eb62b74eSMichael S. Tsirkin 
742e8de56b5SNicholas Bellinger static int
vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd * cmd,struct iov_iter * iter,struct scatterlist * sg,int sg_count)7435ced58bfSMike Christie vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter,
7441a1ff825SNicholas Bellinger 			   struct scatterlist *sg, int sg_count)
745e8de56b5SNicholas Bellinger {
7465ced58bfSMike Christie 	size_t len = iov_iter_count(iter);
7475ced58bfSMike Christie 	unsigned int nbytes = 0;
7485ced58bfSMike Christie 	struct page *page;
7495ced58bfSMike Christie 	int i;
7505ced58bfSMike Christie 
7515ced58bfSMike Christie 	if (cmd->tvc_data_direction == DMA_FROM_DEVICE) {
7525ced58bfSMike Christie 		cmd->saved_iter_addr = dup_iter(&cmd->saved_iter, iter,
7535ced58bfSMike Christie 						GFP_KERNEL);
7545ced58bfSMike Christie 		if (!cmd->saved_iter_addr)
7555ced58bfSMike Christie 			return -ENOMEM;
7565ced58bfSMike Christie 	}
7575ced58bfSMike Christie 
7585ced58bfSMike Christie 	for (i = 0; i < sg_count; i++) {
7595ced58bfSMike Christie 		page = alloc_page(GFP_KERNEL);
7605ced58bfSMike Christie 		if (!page) {
7615ced58bfSMike Christie 			i--;
7625ced58bfSMike Christie 			goto err;
7635ced58bfSMike Christie 		}
7645ced58bfSMike Christie 
7655ced58bfSMike Christie 		nbytes = min_t(unsigned int, PAGE_SIZE, len);
7665ced58bfSMike Christie 		sg_set_page(&sg[i], page, nbytes, 0);
7675ced58bfSMike Christie 
7685ced58bfSMike Christie 		if (cmd->tvc_data_direction == DMA_TO_DEVICE &&
7695ced58bfSMike Christie 		    copy_page_from_iter(page, 0, nbytes, iter) != nbytes)
7705ced58bfSMike Christie 			goto err;
7715ced58bfSMike Christie 
7725ced58bfSMike Christie 		len -= nbytes;
7735ced58bfSMike Christie 	}
7745ced58bfSMike Christie 
7755ced58bfSMike Christie 	cmd->copied_iov = 1;
7765ced58bfSMike Christie 	return 0;
7775ced58bfSMike Christie 
7785ced58bfSMike Christie err:
7795ced58bfSMike Christie 	pr_err("Could not read %u bytes while handling misaligned cmd\n",
7805ced58bfSMike Christie 	       nbytes);
7815ced58bfSMike Christie 
7825ced58bfSMike Christie 	for (; i >= 0; i--)
7835ced58bfSMike Christie 		__free_page(sg_page(&sg[i]));
7845ced58bfSMike Christie 	kfree(cmd->saved_iter_addr);
7855ced58bfSMike Christie 	return -ENOMEM;
7865ced58bfSMike Christie }
7875ced58bfSMike Christie 
7885ced58bfSMike Christie 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)789c5ace19eSMike Christie vhost_scsi_map_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter,
7905ced58bfSMike Christie 			  struct scatterlist *sg, int sg_count, bool is_prot)
7915ced58bfSMike Christie {
79211d49e9dSAl Viro 	struct scatterlist *p = sg;
7935ced58bfSMike Christie 	size_t revert_bytes;
7942f240c4aSAl Viro 	int ret;
7955a01d082SNicholas Bellinger 
7962f240c4aSAl Viro 	while (iov_iter_count(iter)) {
7975ced58bfSMike Christie 		ret = vhost_scsi_map_to_sgl(cmd, iter, sg, is_prot);
798eb62b74eSMichael S. Tsirkin 		if (ret < 0) {
7995ced58bfSMike Christie 			revert_bytes = 0;
8005ced58bfSMike Christie 
80111d49e9dSAl Viro 			while (p < sg) {
8025ced58bfSMike Christie 				struct page *page = sg_page(p);
8035ced58bfSMike Christie 
8045ced58bfSMike Christie 				if (page) {
805e8de56b5SNicholas Bellinger 					put_page(page);
8065ced58bfSMike Christie 					revert_bytes += p->length;
807e8de56b5SNicholas Bellinger 				}
8085ced58bfSMike Christie 				p++;
8095ced58bfSMike Christie 			}
8105ced58bfSMike Christie 
8115ced58bfSMike Christie 			iov_iter_revert(iter, revert_bytes);
812eb62b74eSMichael S. Tsirkin 			return ret;
813eb62b74eSMichael S. Tsirkin 		}
814eb62b74eSMichael S. Tsirkin 		sg += ret;
815eb62b74eSMichael S. Tsirkin 	}
8165ced58bfSMike Christie 
817eb62b74eSMichael S. Tsirkin 	return 0;
818eb62b74eSMichael S. Tsirkin }
819eb62b74eSMichael S. Tsirkin 
820e31885ddSNicholas Bellinger 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)8211a1ff825SNicholas Bellinger vhost_scsi_mapal(struct vhost_scsi_cmd *cmd,
822e8de56b5SNicholas Bellinger 		 size_t prot_bytes, struct iov_iter *prot_iter,
823e8de56b5SNicholas Bellinger 		 size_t data_bytes, struct iov_iter *data_iter)
824e31885ddSNicholas Bellinger {
825e8de56b5SNicholas Bellinger 	int sgl_count, ret;
826e31885ddSNicholas Bellinger 
827e8de56b5SNicholas Bellinger 	if (prot_bytes) {
828e8de56b5SNicholas Bellinger 		sgl_count = vhost_scsi_calc_sgls(prot_iter, prot_bytes,
8291a1ff825SNicholas Bellinger 						 VHOST_SCSI_PREALLOC_PROT_SGLS);
830e8de56b5SNicholas Bellinger 		if (sgl_count < 0)
831e8de56b5SNicholas Bellinger 			return sgl_count;
832e31885ddSNicholas Bellinger 
833e8de56b5SNicholas Bellinger 		sg_init_table(cmd->tvc_prot_sgl, sgl_count);
834e8de56b5SNicholas Bellinger 		cmd->tvc_prot_sgl_count = sgl_count;
835e31885ddSNicholas Bellinger 		pr_debug("%s prot_sg %p prot_sgl_count %u\n", __func__,
836e8de56b5SNicholas Bellinger 			 cmd->tvc_prot_sgl, cmd->tvc_prot_sgl_count);
837e31885ddSNicholas Bellinger 
838c5ace19eSMike Christie 		ret = vhost_scsi_map_iov_to_sgl(cmd, prot_iter,
839c5ace19eSMike Christie 						cmd->tvc_prot_sgl,
8405ced58bfSMike Christie 						cmd->tvc_prot_sgl_count, true);
841e31885ddSNicholas Bellinger 		if (ret < 0) {
842e31885ddSNicholas Bellinger 			cmd->tvc_prot_sgl_count = 0;
843e31885ddSNicholas Bellinger 			return ret;
844e31885ddSNicholas Bellinger 		}
845e8de56b5SNicholas Bellinger 	}
846e8de56b5SNicholas Bellinger 	sgl_count = vhost_scsi_calc_sgls(data_iter, data_bytes,
8471a1ff825SNicholas Bellinger 					 VHOST_SCSI_PREALLOC_SGLS);
848e8de56b5SNicholas Bellinger 	if (sgl_count < 0)
849e8de56b5SNicholas Bellinger 		return sgl_count;
850e8de56b5SNicholas Bellinger 
851e8de56b5SNicholas Bellinger 	sg_init_table(cmd->tvc_sgl, sgl_count);
852e8de56b5SNicholas Bellinger 	cmd->tvc_sgl_count = sgl_count;
853e8de56b5SNicholas Bellinger 	pr_debug("%s data_sg %p data_sgl_count %u\n", __func__,
854e8de56b5SNicholas Bellinger 		  cmd->tvc_sgl, cmd->tvc_sgl_count);
855e8de56b5SNicholas Bellinger 
856c5ace19eSMike Christie 	ret = vhost_scsi_map_iov_to_sgl(cmd, data_iter, cmd->tvc_sgl,
8575ced58bfSMike Christie 					cmd->tvc_sgl_count, false);
8585ced58bfSMike Christie 	if (ret == -EINVAL) {
8595ced58bfSMike Christie 		sg_init_table(cmd->tvc_sgl, cmd->tvc_sgl_count);
8605ced58bfSMike Christie 		ret = vhost_scsi_copy_iov_to_sgl(cmd, data_iter, cmd->tvc_sgl,
8615ced58bfSMike Christie 						 cmd->tvc_sgl_count);
8625ced58bfSMike Christie 	}
8635ced58bfSMike Christie 
864e8de56b5SNicholas Bellinger 	if (ret < 0) {
865e8de56b5SNicholas Bellinger 		cmd->tvc_sgl_count = 0;
866e8de56b5SNicholas Bellinger 		return ret;
867e31885ddSNicholas Bellinger 	}
868e31885ddSNicholas Bellinger 	return 0;
869e31885ddSNicholas Bellinger }
870e31885ddSNicholas Bellinger 
vhost_scsi_to_tcm_attr(int attr)87146243860SNicholas Bellinger static int vhost_scsi_to_tcm_attr(int attr)
87246243860SNicholas Bellinger {
87346243860SNicholas Bellinger 	switch (attr) {
87446243860SNicholas Bellinger 	case VIRTIO_SCSI_S_SIMPLE:
87546243860SNicholas Bellinger 		return TCM_SIMPLE_TAG;
87646243860SNicholas Bellinger 	case VIRTIO_SCSI_S_ORDERED:
87746243860SNicholas Bellinger 		return TCM_ORDERED_TAG;
87846243860SNicholas Bellinger 	case VIRTIO_SCSI_S_HEAD:
87946243860SNicholas Bellinger 		return TCM_HEAD_TAG;
88046243860SNicholas Bellinger 	case VIRTIO_SCSI_S_ACA:
88146243860SNicholas Bellinger 		return TCM_ACA_TAG;
88246243860SNicholas Bellinger 	default:
88346243860SNicholas Bellinger 		break;
88446243860SNicholas Bellinger 	}
88546243860SNicholas Bellinger 	return TCM_SIMPLE_TAG;
88646243860SNicholas Bellinger }
88746243860SNicholas Bellinger 
vhost_scsi_target_queue_cmd(struct vhost_scsi_cmd * cmd)8886ec29cb8SMike Christie static void vhost_scsi_target_queue_cmd(struct vhost_scsi_cmd *cmd)
889eb62b74eSMichael S. Tsirkin {
8903c63f66aSAsias He 	struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
8916ec29cb8SMike Christie 	struct vhost_scsi_nexus *tv_nexus;
89295e7c434SNicholas Bellinger 	struct scatterlist *sg_ptr, *sg_prot_ptr = NULL;
893eb62b74eSMichael S. Tsirkin 
89495e7c434SNicholas Bellinger 	/* FIXME: BIDI operation */
8953c63f66aSAsias He 	if (cmd->tvc_sgl_count) {
8963c63f66aSAsias He 		sg_ptr = cmd->tvc_sgl;
89795e7c434SNicholas Bellinger 
89895e7c434SNicholas Bellinger 		if (cmd->tvc_prot_sgl_count)
89995e7c434SNicholas Bellinger 			sg_prot_ptr = cmd->tvc_prot_sgl;
90095e7c434SNicholas Bellinger 		else
90195e7c434SNicholas Bellinger 			se_cmd->prot_pto = true;
902eb62b74eSMichael S. Tsirkin 	} else {
903eb62b74eSMichael S. Tsirkin 		sg_ptr = NULL;
904eb62b74eSMichael S. Tsirkin 	}
9053c63f66aSAsias He 	tv_nexus = cmd->tvc_nexus;
906eb62b74eSMichael S. Tsirkin 
907649ee054SBart Van Assche 	se_cmd->tag = 0;
908eb929804SMike Christie 	target_init_cmd(se_cmd, tv_nexus->tvn_se_sess, &cmd->tvc_sense_buf[0],
9093c63f66aSAsias He 			cmd->tvc_lun, cmd->tvc_exp_data_len,
91046243860SNicholas Bellinger 			vhost_scsi_to_tcm_attr(cmd->tvc_task_attr),
911eb929804SMike Christie 			cmd->tvc_data_direction, TARGET_SCF_ACK_KREF);
912eb929804SMike Christie 
913eb929804SMike Christie 	if (target_submit_prep(se_cmd, cmd->tvc_cdb, sg_ptr,
914eb929804SMike Christie 			       cmd->tvc_sgl_count, NULL, 0, sg_prot_ptr,
91508694199SMike Christie 			       cmd->tvc_prot_sgl_count, GFP_KERNEL))
916eb929804SMike Christie 		return;
917eb929804SMike Christie 
9186ec29cb8SMike Christie 	target_queue_submission(se_cmd);
919eb62b74eSMichael S. Tsirkin }
920eb62b74eSMichael S. Tsirkin 
921683bd967SAsias He static void
vhost_scsi_send_bad_target(struct vhost_scsi * vs,struct vhost_virtqueue * vq,int head,unsigned out)922683bd967SAsias He vhost_scsi_send_bad_target(struct vhost_scsi *vs,
923683bd967SAsias He 			   struct vhost_virtqueue *vq,
924683bd967SAsias He 			   int head, unsigned out)
925eb62b74eSMichael S. Tsirkin {
926eb62b74eSMichael S. Tsirkin 	struct virtio_scsi_cmd_resp __user *resp;
927eb62b74eSMichael S. Tsirkin 	struct virtio_scsi_cmd_resp rsp;
928eb62b74eSMichael S. Tsirkin 	int ret;
929eb62b74eSMichael S. Tsirkin 
930eb62b74eSMichael S. Tsirkin 	memset(&rsp, 0, sizeof(rsp));
931eb62b74eSMichael S. Tsirkin 	rsp.response = VIRTIO_SCSI_S_BAD_TARGET;
932eb62b74eSMichael S. Tsirkin 	resp = vq->iov[out].iov_base;
933eb62b74eSMichael S. Tsirkin 	ret = __copy_to_user(resp, &rsp, sizeof(rsp));
934eb62b74eSMichael S. Tsirkin 	if (!ret)
935eb62b74eSMichael S. Tsirkin 		vhost_add_used_and_signal(&vs->dev, vq, head, 0);
936eb62b74eSMichael S. Tsirkin 	else
937eb62b74eSMichael S. Tsirkin 		pr_err("Faulted on virtio_scsi_cmd_resp\n");
938eb62b74eSMichael S. Tsirkin }
939eb62b74eSMichael S. Tsirkin 
9403f8ca2e1SBijan Mottahedeh static int
vhost_scsi_get_desc(struct vhost_scsi * vs,struct vhost_virtqueue * vq,struct vhost_scsi_ctx * vc)9413f8ca2e1SBijan Mottahedeh vhost_scsi_get_desc(struct vhost_scsi *vs, struct vhost_virtqueue *vq,
9423f8ca2e1SBijan Mottahedeh 		    struct vhost_scsi_ctx *vc)
9433f8ca2e1SBijan Mottahedeh {
9443f8ca2e1SBijan Mottahedeh 	int ret = -ENXIO;
9453f8ca2e1SBijan Mottahedeh 
9463f8ca2e1SBijan Mottahedeh 	vc->head = vhost_get_vq_desc(vq, vq->iov,
9473f8ca2e1SBijan Mottahedeh 				     ARRAY_SIZE(vq->iov), &vc->out, &vc->in,
9483f8ca2e1SBijan Mottahedeh 				     NULL, NULL);
9493f8ca2e1SBijan Mottahedeh 
9503f8ca2e1SBijan Mottahedeh 	pr_debug("vhost_get_vq_desc: head: %d, out: %u in: %u\n",
9513f8ca2e1SBijan Mottahedeh 		 vc->head, vc->out, vc->in);
9523f8ca2e1SBijan Mottahedeh 
9533f8ca2e1SBijan Mottahedeh 	/* On error, stop handling until the next kick. */
9543f8ca2e1SBijan Mottahedeh 	if (unlikely(vc->head < 0))
9553f8ca2e1SBijan Mottahedeh 		goto done;
9563f8ca2e1SBijan Mottahedeh 
9573f8ca2e1SBijan Mottahedeh 	/* Nothing new?  Wait for eventfd to tell us they refilled. */
9583f8ca2e1SBijan Mottahedeh 	if (vc->head == vq->num) {
9593f8ca2e1SBijan Mottahedeh 		if (unlikely(vhost_enable_notify(&vs->dev, vq))) {
9603f8ca2e1SBijan Mottahedeh 			vhost_disable_notify(&vs->dev, vq);
9613f8ca2e1SBijan Mottahedeh 			ret = -EAGAIN;
9623f8ca2e1SBijan Mottahedeh 		}
9633f8ca2e1SBijan Mottahedeh 		goto done;
9643f8ca2e1SBijan Mottahedeh 	}
9653f8ca2e1SBijan Mottahedeh 
9663f8ca2e1SBijan Mottahedeh 	/*
9673f8ca2e1SBijan Mottahedeh 	 * Get the size of request and response buffers.
96809d75832SBijan Mottahedeh 	 * FIXME: Not correct for BIDI operation
9693f8ca2e1SBijan Mottahedeh 	 */
9703f8ca2e1SBijan Mottahedeh 	vc->out_size = iov_length(vq->iov, vc->out);
9713f8ca2e1SBijan Mottahedeh 	vc->in_size = iov_length(&vq->iov[vc->out], vc->in);
9723f8ca2e1SBijan Mottahedeh 
9733f8ca2e1SBijan Mottahedeh 	/*
9743f8ca2e1SBijan Mottahedeh 	 * Copy over the virtio-scsi request header, which for a
9753f8ca2e1SBijan Mottahedeh 	 * ANY_LAYOUT enabled guest may span multiple iovecs, or a
9763f8ca2e1SBijan Mottahedeh 	 * single iovec may contain both the header + outgoing
9773f8ca2e1SBijan Mottahedeh 	 * WRITE payloads.
9783f8ca2e1SBijan Mottahedeh 	 *
9793f8ca2e1SBijan Mottahedeh 	 * copy_from_iter() will advance out_iter, so that it will
9803f8ca2e1SBijan Mottahedeh 	 * point at the start of the outgoing WRITE payload, if
9813f8ca2e1SBijan Mottahedeh 	 * DMA_TO_DEVICE is set.
9823f8ca2e1SBijan Mottahedeh 	 */
983de4eda9dSAl Viro 	iov_iter_init(&vc->out_iter, ITER_SOURCE, vq->iov, vc->out, vc->out_size);
9843f8ca2e1SBijan Mottahedeh 	ret = 0;
9853f8ca2e1SBijan Mottahedeh 
9863f8ca2e1SBijan Mottahedeh done:
9873f8ca2e1SBijan Mottahedeh 	return ret;
9883f8ca2e1SBijan Mottahedeh }
9893f8ca2e1SBijan Mottahedeh 
9903f8ca2e1SBijan Mottahedeh static int
vhost_scsi_chk_size(struct vhost_virtqueue * vq,struct vhost_scsi_ctx * vc)9913f8ca2e1SBijan Mottahedeh vhost_scsi_chk_size(struct vhost_virtqueue *vq, struct vhost_scsi_ctx *vc)
9923f8ca2e1SBijan Mottahedeh {
9933f8ca2e1SBijan Mottahedeh 	if (unlikely(vc->in_size < vc->rsp_size)) {
9943f8ca2e1SBijan Mottahedeh 		vq_err(vq,
9953f8ca2e1SBijan Mottahedeh 		       "Response buf too small, need min %zu bytes got %zu",
9963f8ca2e1SBijan Mottahedeh 		       vc->rsp_size, vc->in_size);
9973f8ca2e1SBijan Mottahedeh 		return -EINVAL;
9983f8ca2e1SBijan Mottahedeh 	} else if (unlikely(vc->out_size < vc->req_size)) {
9993f8ca2e1SBijan Mottahedeh 		vq_err(vq,
10003f8ca2e1SBijan Mottahedeh 		       "Request buf too small, need min %zu bytes got %zu",
10013f8ca2e1SBijan Mottahedeh 		       vc->req_size, vc->out_size);
10023f8ca2e1SBijan Mottahedeh 		return -EIO;
10033f8ca2e1SBijan Mottahedeh 	}
10043f8ca2e1SBijan Mottahedeh 
10053f8ca2e1SBijan Mottahedeh 	return 0;
10063f8ca2e1SBijan Mottahedeh }
10073f8ca2e1SBijan Mottahedeh 
10083f8ca2e1SBijan Mottahedeh static int
vhost_scsi_get_req(struct vhost_virtqueue * vq,struct vhost_scsi_ctx * vc,struct vhost_scsi_tpg ** tpgp)10093f8ca2e1SBijan Mottahedeh vhost_scsi_get_req(struct vhost_virtqueue *vq, struct vhost_scsi_ctx *vc,
10103f8ca2e1SBijan Mottahedeh 		   struct vhost_scsi_tpg **tpgp)
10113f8ca2e1SBijan Mottahedeh {
10123f8ca2e1SBijan Mottahedeh 	int ret = -EIO;
10133f8ca2e1SBijan Mottahedeh 
10143f8ca2e1SBijan Mottahedeh 	if (unlikely(!copy_from_iter_full(vc->req, vc->req_size,
101509d75832SBijan Mottahedeh 					  &vc->out_iter))) {
1016a691ffb4Swangyan 		vq_err(vq, "Faulted on copy_from_iter_full\n");
101709d75832SBijan Mottahedeh 	} else if (unlikely(*vc->lunp != 1)) {
10183f8ca2e1SBijan Mottahedeh 		/* virtio-scsi spec requires byte 0 of the lun to be 1 */
10193f8ca2e1SBijan Mottahedeh 		vq_err(vq, "Illegal virtio-scsi lun: %u\n", *vc->lunp);
102009d75832SBijan Mottahedeh 	} else {
1021*25613e6dSHaoran Zhang 		struct vhost_scsi_tpg **vs_tpg, *tpg = NULL;
10223f8ca2e1SBijan Mottahedeh 
1023*25613e6dSHaoran Zhang 		if (vc->target) {
1024*25613e6dSHaoran Zhang 			/* validated at handler entry */
1025*25613e6dSHaoran Zhang 			vs_tpg = vhost_vq_get_backend(vq);
10263f8ca2e1SBijan Mottahedeh 			tpg = READ_ONCE(vs_tpg[*vc->target]);
102709d75832SBijan Mottahedeh 			if (unlikely(!tpg)) {
10283f8ca2e1SBijan Mottahedeh 				vq_err(vq, "Target 0x%x does not exist\n", *vc->target);
1029*25613e6dSHaoran Zhang 				goto out;
1030*25613e6dSHaoran Zhang 			}
1031*25613e6dSHaoran Zhang 		}
1032*25613e6dSHaoran Zhang 
10333f8ca2e1SBijan Mottahedeh 		if (tpgp)
10343f8ca2e1SBijan Mottahedeh 			*tpgp = tpg;
10353f8ca2e1SBijan Mottahedeh 		ret = 0;
10363f8ca2e1SBijan Mottahedeh 	}
1037*25613e6dSHaoran Zhang out:
10383f8ca2e1SBijan Mottahedeh 	return ret;
10393f8ca2e1SBijan Mottahedeh }
10403f8ca2e1SBijan Mottahedeh 
vhost_buf_to_lun(u8 * lun_buf)104118f1becbSMike Christie static u16 vhost_buf_to_lun(u8 *lun_buf)
104218f1becbSMike Christie {
104318f1becbSMike Christie 	return ((lun_buf[2] << 8) | lun_buf[3]) & 0x3FFF;
104418f1becbSMike Christie }
104518f1becbSMike Christie 
10460d02dbd6SBijan Mottahedeh static void
vhost_scsi_handle_vq(struct vhost_scsi * vs,struct vhost_virtqueue * vq)104709d75832SBijan Mottahedeh vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
104809d75832SBijan Mottahedeh {
104909d75832SBijan Mottahedeh 	struct vhost_scsi_tpg **vs_tpg, *tpg;
105009d75832SBijan Mottahedeh 	struct virtio_scsi_cmd_req v_req;
105109d75832SBijan Mottahedeh 	struct virtio_scsi_cmd_req_pi v_req_pi;
105209d75832SBijan Mottahedeh 	struct vhost_scsi_ctx vc;
105309d75832SBijan Mottahedeh 	struct vhost_scsi_cmd *cmd;
105409d75832SBijan Mottahedeh 	struct iov_iter in_iter, prot_iter, data_iter;
105509d75832SBijan Mottahedeh 	u64 tag;
105609d75832SBijan Mottahedeh 	u32 exp_data_len, data_direction;
10576dd88fd5SJason Wang 	int ret, prot_bytes, i, c = 0;
105809d75832SBijan Mottahedeh 	u16 lun;
105909d75832SBijan Mottahedeh 	u8 task_attr;
106009d75832SBijan Mottahedeh 	bool t10_pi = vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI);
106109d75832SBijan Mottahedeh 	void *cdb;
106209d75832SBijan Mottahedeh 
106309d75832SBijan Mottahedeh 	mutex_lock(&vq->mutex);
106409d75832SBijan Mottahedeh 	/*
106509d75832SBijan Mottahedeh 	 * We can handle the vq only after the endpoint is setup by calling the
106609d75832SBijan Mottahedeh 	 * VHOST_SCSI_SET_ENDPOINT ioctl.
106709d75832SBijan Mottahedeh 	 */
1068247643f8SEugenio Pérez 	vs_tpg = vhost_vq_get_backend(vq);
106909d75832SBijan Mottahedeh 	if (!vs_tpg)
107009d75832SBijan Mottahedeh 		goto out;
107109d75832SBijan Mottahedeh 
107209d75832SBijan Mottahedeh 	memset(&vc, 0, sizeof(vc));
107309d75832SBijan Mottahedeh 	vc.rsp_size = sizeof(struct virtio_scsi_cmd_resp);
107409d75832SBijan Mottahedeh 
107509d75832SBijan Mottahedeh 	vhost_disable_notify(&vs->dev, vq);
107609d75832SBijan Mottahedeh 
1077c1ea02f1SJason Wang 	do {
107809d75832SBijan Mottahedeh 		ret = vhost_scsi_get_desc(vs, vq, &vc);
107909d75832SBijan Mottahedeh 		if (ret)
108009d75832SBijan Mottahedeh 			goto err;
108109d75832SBijan Mottahedeh 
108209d75832SBijan Mottahedeh 		/*
108309d75832SBijan Mottahedeh 		 * Setup pointers and values based upon different virtio-scsi
108409d75832SBijan Mottahedeh 		 * request header if T10_PI is enabled in KVM guest.
108509d75832SBijan Mottahedeh 		 */
108609d75832SBijan Mottahedeh 		if (t10_pi) {
108709d75832SBijan Mottahedeh 			vc.req = &v_req_pi;
108809d75832SBijan Mottahedeh 			vc.req_size = sizeof(v_req_pi);
108909d75832SBijan Mottahedeh 			vc.lunp = &v_req_pi.lun[0];
109009d75832SBijan Mottahedeh 			vc.target = &v_req_pi.lun[1];
109109d75832SBijan Mottahedeh 		} else {
109209d75832SBijan Mottahedeh 			vc.req = &v_req;
109309d75832SBijan Mottahedeh 			vc.req_size = sizeof(v_req);
109409d75832SBijan Mottahedeh 			vc.lunp = &v_req.lun[0];
109509d75832SBijan Mottahedeh 			vc.target = &v_req.lun[1];
109609d75832SBijan Mottahedeh 		}
109709d75832SBijan Mottahedeh 
109809d75832SBijan Mottahedeh 		/*
109909d75832SBijan Mottahedeh 		 * Validate the size of request and response buffers.
110009d75832SBijan Mottahedeh 		 * Check for a sane response buffer so we can report
110109d75832SBijan Mottahedeh 		 * early errors back to the guest.
110209d75832SBijan Mottahedeh 		 */
110309d75832SBijan Mottahedeh 		ret = vhost_scsi_chk_size(vq, &vc);
110409d75832SBijan Mottahedeh 		if (ret)
110509d75832SBijan Mottahedeh 			goto err;
110609d75832SBijan Mottahedeh 
110709d75832SBijan Mottahedeh 		ret = vhost_scsi_get_req(vq, &vc, &tpg);
110809d75832SBijan Mottahedeh 		if (ret)
110909d75832SBijan Mottahedeh 			goto err;
111009d75832SBijan Mottahedeh 
111109d75832SBijan Mottahedeh 		ret = -EIO;	/* bad target on any error from here on */
111209d75832SBijan Mottahedeh 
111309d75832SBijan Mottahedeh 		/*
111409d75832SBijan Mottahedeh 		 * Determine data_direction by calculating the total outgoing
111509d75832SBijan Mottahedeh 		 * iovec sizes + incoming iovec sizes vs. virtio-scsi request +
111609d75832SBijan Mottahedeh 		 * response headers respectively.
111709d75832SBijan Mottahedeh 		 *
111809d75832SBijan Mottahedeh 		 * For DMA_TO_DEVICE this is out_iter, which is already pointing
111909d75832SBijan Mottahedeh 		 * to the right place.
112009d75832SBijan Mottahedeh 		 *
112109d75832SBijan Mottahedeh 		 * For DMA_FROM_DEVICE, the iovec will be just past the end
112209d75832SBijan Mottahedeh 		 * of the virtio-scsi response header in either the same
112309d75832SBijan Mottahedeh 		 * or immediately following iovec.
112409d75832SBijan Mottahedeh 		 *
112509d75832SBijan Mottahedeh 		 * Any associated T10_PI bytes for the outgoing / incoming
112609d75832SBijan Mottahedeh 		 * payloads are included in calculation of exp_data_len here.
112709d75832SBijan Mottahedeh 		 */
112809d75832SBijan Mottahedeh 		prot_bytes = 0;
112909d75832SBijan Mottahedeh 
113009d75832SBijan Mottahedeh 		if (vc.out_size > vc.req_size) {
113109d75832SBijan Mottahedeh 			data_direction = DMA_TO_DEVICE;
113209d75832SBijan Mottahedeh 			exp_data_len = vc.out_size - vc.req_size;
113309d75832SBijan Mottahedeh 			data_iter = vc.out_iter;
113409d75832SBijan Mottahedeh 		} else if (vc.in_size > vc.rsp_size) {
113509d75832SBijan Mottahedeh 			data_direction = DMA_FROM_DEVICE;
113609d75832SBijan Mottahedeh 			exp_data_len = vc.in_size - vc.rsp_size;
113709d75832SBijan Mottahedeh 
1138de4eda9dSAl Viro 			iov_iter_init(&in_iter, ITER_DEST, &vq->iov[vc.out], vc.in,
113909d75832SBijan Mottahedeh 				      vc.rsp_size + exp_data_len);
114009d75832SBijan Mottahedeh 			iov_iter_advance(&in_iter, vc.rsp_size);
114109d75832SBijan Mottahedeh 			data_iter = in_iter;
114209d75832SBijan Mottahedeh 		} else {
114309d75832SBijan Mottahedeh 			data_direction = DMA_NONE;
114409d75832SBijan Mottahedeh 			exp_data_len = 0;
114509d75832SBijan Mottahedeh 		}
114609d75832SBijan Mottahedeh 		/*
114709d75832SBijan Mottahedeh 		 * If T10_PI header + payload is present, setup prot_iter values
114809d75832SBijan Mottahedeh 		 * and recalculate data_iter for vhost_scsi_mapal() mapping to
114909d75832SBijan Mottahedeh 		 * host scatterlists via get_user_pages_fast().
115009d75832SBijan Mottahedeh 		 */
115109d75832SBijan Mottahedeh 		if (t10_pi) {
115209d75832SBijan Mottahedeh 			if (v_req_pi.pi_bytesout) {
115309d75832SBijan Mottahedeh 				if (data_direction != DMA_TO_DEVICE) {
115409d75832SBijan Mottahedeh 					vq_err(vq, "Received non zero pi_bytesout,"
115509d75832SBijan Mottahedeh 						" but wrong data_direction\n");
115609d75832SBijan Mottahedeh 					goto err;
115709d75832SBijan Mottahedeh 				}
115809d75832SBijan Mottahedeh 				prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesout);
115909d75832SBijan Mottahedeh 			} else if (v_req_pi.pi_bytesin) {
116009d75832SBijan Mottahedeh 				if (data_direction != DMA_FROM_DEVICE) {
116109d75832SBijan Mottahedeh 					vq_err(vq, "Received non zero pi_bytesin,"
116209d75832SBijan Mottahedeh 						" but wrong data_direction\n");
116309d75832SBijan Mottahedeh 					goto err;
116409d75832SBijan Mottahedeh 				}
116509d75832SBijan Mottahedeh 				prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesin);
116609d75832SBijan Mottahedeh 			}
116709d75832SBijan Mottahedeh 			/*
116809d75832SBijan Mottahedeh 			 * Set prot_iter to data_iter and truncate it to
116909d75832SBijan Mottahedeh 			 * prot_bytes, and advance data_iter past any
117009d75832SBijan Mottahedeh 			 * preceeding prot_bytes that may be present.
117109d75832SBijan Mottahedeh 			 *
117209d75832SBijan Mottahedeh 			 * Also fix up the exp_data_len to reflect only the
117309d75832SBijan Mottahedeh 			 * actual data payload length.
117409d75832SBijan Mottahedeh 			 */
117509d75832SBijan Mottahedeh 			if (prot_bytes) {
117609d75832SBijan Mottahedeh 				exp_data_len -= prot_bytes;
117709d75832SBijan Mottahedeh 				prot_iter = data_iter;
117809d75832SBijan Mottahedeh 				iov_iter_truncate(&prot_iter, prot_bytes);
117909d75832SBijan Mottahedeh 				iov_iter_advance(&data_iter, prot_bytes);
118009d75832SBijan Mottahedeh 			}
118109d75832SBijan Mottahedeh 			tag = vhost64_to_cpu(vq, v_req_pi.tag);
118209d75832SBijan Mottahedeh 			task_attr = v_req_pi.task_attr;
118309d75832SBijan Mottahedeh 			cdb = &v_req_pi.cdb[0];
118418f1becbSMike Christie 			lun = vhost_buf_to_lun(v_req_pi.lun);
118509d75832SBijan Mottahedeh 		} else {
118609d75832SBijan Mottahedeh 			tag = vhost64_to_cpu(vq, v_req.tag);
118709d75832SBijan Mottahedeh 			task_attr = v_req.task_attr;
118809d75832SBijan Mottahedeh 			cdb = &v_req.cdb[0];
118918f1becbSMike Christie 			lun = vhost_buf_to_lun(v_req.lun);
119009d75832SBijan Mottahedeh 		}
119109d75832SBijan Mottahedeh 		/*
119209d75832SBijan Mottahedeh 		 * Check that the received CDB size does not exceeded our
119309d75832SBijan Mottahedeh 		 * hardcoded max for vhost-scsi, then get a pre-allocated
119409d75832SBijan Mottahedeh 		 * cmd descriptor for the new virtio-scsi tag.
119509d75832SBijan Mottahedeh 		 *
119609d75832SBijan Mottahedeh 		 * TODO what if cdb was too small for varlen cdb header?
119709d75832SBijan Mottahedeh 		 */
119809d75832SBijan Mottahedeh 		if (unlikely(scsi_command_size(cdb) > VHOST_SCSI_MAX_CDB_SIZE)) {
119909d75832SBijan Mottahedeh 			vq_err(vq, "Received SCSI CDB with command_size: %d that"
120009d75832SBijan Mottahedeh 				" exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
120109d75832SBijan Mottahedeh 				scsi_command_size(cdb), VHOST_SCSI_MAX_CDB_SIZE);
120209d75832SBijan Mottahedeh 				goto err;
120309d75832SBijan Mottahedeh 		}
120425b98b64SMike Christie 		cmd = vhost_scsi_get_cmd(vq, tpg, cdb, tag, lun, task_attr,
120509d75832SBijan Mottahedeh 					 exp_data_len + prot_bytes,
120609d75832SBijan Mottahedeh 					 data_direction);
120709d75832SBijan Mottahedeh 		if (IS_ERR(cmd)) {
120825b98b64SMike Christie 			vq_err(vq, "vhost_scsi_get_cmd failed %ld\n",
120909d75832SBijan Mottahedeh 			       PTR_ERR(cmd));
121009d75832SBijan Mottahedeh 			goto err;
121109d75832SBijan Mottahedeh 		}
121209d75832SBijan Mottahedeh 		cmd->tvc_vhost = vs;
121309d75832SBijan Mottahedeh 		cmd->tvc_vq = vq;
12146dd88fd5SJason Wang 		for (i = 0; i < vc.in ; i++)
12156dd88fd5SJason Wang 			cmd->tvc_resp_iov[i] = vq->iov[vc.out + i];
121609d75832SBijan Mottahedeh 		cmd->tvc_in_iovs = vc.in;
121709d75832SBijan Mottahedeh 
121809d75832SBijan Mottahedeh 		pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
121909d75832SBijan Mottahedeh 			 cmd->tvc_cdb[0], cmd->tvc_lun);
122009d75832SBijan Mottahedeh 		pr_debug("cmd: %p exp_data_len: %d, prot_bytes: %d data_direction:"
122109d75832SBijan Mottahedeh 			 " %d\n", cmd, exp_data_len, prot_bytes, data_direction);
122209d75832SBijan Mottahedeh 
122309d75832SBijan Mottahedeh 		if (data_direction != DMA_NONE) {
122409d75832SBijan Mottahedeh 			if (unlikely(vhost_scsi_mapal(cmd, prot_bytes,
122509d75832SBijan Mottahedeh 						      &prot_iter, exp_data_len,
122609d75832SBijan Mottahedeh 						      &data_iter))) {
122709d75832SBijan Mottahedeh 				vq_err(vq, "Failed to map iov to sgl\n");
122847a3565eSMike Christie 				vhost_scsi_release_cmd_res(&cmd->tvc_se_cmd);
122909d75832SBijan Mottahedeh 				goto err;
123009d75832SBijan Mottahedeh 			}
123109d75832SBijan Mottahedeh 		}
123209d75832SBijan Mottahedeh 		/*
123309d75832SBijan Mottahedeh 		 * Save the descriptor from vhost_get_vq_desc() to be used to
123409d75832SBijan Mottahedeh 		 * complete the virtio-scsi request in TCM callback context via
123509d75832SBijan Mottahedeh 		 * vhost_scsi_queue_data_in() and vhost_scsi_queue_status()
123609d75832SBijan Mottahedeh 		 */
123709d75832SBijan Mottahedeh 		cmd->tvc_vq_desc = vc.head;
12386ec29cb8SMike Christie 		vhost_scsi_target_queue_cmd(cmd);
123909d75832SBijan Mottahedeh 		ret = 0;
124009d75832SBijan Mottahedeh err:
124109d75832SBijan Mottahedeh 		/*
124209d75832SBijan Mottahedeh 		 * ENXIO:  No more requests, or read error, wait for next kick
124309d75832SBijan Mottahedeh 		 * EINVAL: Invalid response buffer, drop the request
124409d75832SBijan Mottahedeh 		 * EIO:    Respond with bad target
124509d75832SBijan Mottahedeh 		 * EAGAIN: Pending request
124609d75832SBijan Mottahedeh 		 */
124709d75832SBijan Mottahedeh 		if (ret == -ENXIO)
124809d75832SBijan Mottahedeh 			break;
124909d75832SBijan Mottahedeh 		else if (ret == -EIO)
125009d75832SBijan Mottahedeh 			vhost_scsi_send_bad_target(vs, vq, vc.head, vc.out);
1251c1ea02f1SJason Wang 	} while (likely(!vhost_exceeds_weight(vq, ++c, 0)));
125209d75832SBijan Mottahedeh out:
125309d75832SBijan Mottahedeh 	mutex_unlock(&vq->mutex);
125409d75832SBijan Mottahedeh }
125509d75832SBijan Mottahedeh 
125609d75832SBijan Mottahedeh 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)1257efd838feSMike Christie vhost_scsi_send_tmf_resp(struct vhost_scsi *vs, struct vhost_virtqueue *vq,
1258efd838feSMike Christie 			 int in_iovs, int vq_desc, struct iovec *resp_iov,
1259efd838feSMike Christie 			 int tmf_resp_code)
12600d02dbd6SBijan Mottahedeh {
12610d02dbd6SBijan Mottahedeh 	struct virtio_scsi_ctrl_tmf_resp rsp;
12628e5dadfeSBijan Mottahedeh 	struct iov_iter iov_iter;
12630d02dbd6SBijan Mottahedeh 	int ret;
12640d02dbd6SBijan Mottahedeh 
12650d02dbd6SBijan Mottahedeh 	pr_debug("%s\n", __func__);
12660d02dbd6SBijan Mottahedeh 	memset(&rsp, 0, sizeof(rsp));
1267efd838feSMike Christie 	rsp.response = tmf_resp_code;
12688e5dadfeSBijan Mottahedeh 
1269de4eda9dSAl Viro 	iov_iter_init(&iov_iter, ITER_DEST, resp_iov, in_iovs, sizeof(rsp));
12708e5dadfeSBijan Mottahedeh 
12718e5dadfeSBijan Mottahedeh 	ret = copy_to_iter(&rsp, sizeof(rsp), &iov_iter);
12728e5dadfeSBijan Mottahedeh 	if (likely(ret == sizeof(rsp)))
1273efd838feSMike Christie 		vhost_add_used_and_signal(&vs->dev, vq, vq_desc, 0);
12740d02dbd6SBijan Mottahedeh 	else
12750d02dbd6SBijan Mottahedeh 		pr_err("Faulted on virtio_scsi_ctrl_tmf_resp\n");
12760d02dbd6SBijan Mottahedeh }
12770d02dbd6SBijan Mottahedeh 
vhost_scsi_tmf_resp_work(struct vhost_work * work)1278efd838feSMike Christie static void vhost_scsi_tmf_resp_work(struct vhost_work *work)
1279efd838feSMike Christie {
1280efd838feSMike Christie 	struct vhost_scsi_tmf *tmf = container_of(work, struct vhost_scsi_tmf,
1281efd838feSMike Christie 						  vwork);
12820a3eac52SMike Christie 	struct vhost_virtqueue *ctl_vq, *vq;
12830a3eac52SMike Christie 	int resp_code, i;
1284efd838feSMike Christie 
12850a3eac52SMike Christie 	if (tmf->scsi_resp == TMR_FUNCTION_COMPLETE) {
12860a3eac52SMike Christie 		/*
12870a3eac52SMike Christie 		 * Flush IO vqs that don't share a worker with the ctl to make
12880a3eac52SMike Christie 		 * sure they have sent their responses before us.
12890a3eac52SMike Christie 		 */
12900a3eac52SMike Christie 		ctl_vq = &tmf->vhost->vqs[VHOST_SCSI_VQ_CTL].vq;
12910a3eac52SMike Christie 		for (i = VHOST_SCSI_VQ_IO; i < tmf->vhost->dev.nvqs; i++) {
12920a3eac52SMike Christie 			vq = &tmf->vhost->vqs[i].vq;
12930a3eac52SMike Christie 
12940a3eac52SMike Christie 			if (vhost_vq_is_setup(vq) &&
12950a3eac52SMike Christie 			    vq->worker != ctl_vq->worker)
12960a3eac52SMike Christie 				vhost_vq_flush(vq);
12970a3eac52SMike Christie 		}
12980a3eac52SMike Christie 
1299efd838feSMike Christie 		resp_code = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
13000a3eac52SMike Christie 	} else {
1301efd838feSMike Christie 		resp_code = VIRTIO_SCSI_S_FUNCTION_REJECTED;
13020a3eac52SMike Christie 	}
1303efd838feSMike Christie 
1304efd838feSMike Christie 	vhost_scsi_send_tmf_resp(tmf->vhost, &tmf->svq->vq, tmf->in_iovs,
1305efd838feSMike Christie 				 tmf->vq_desc, &tmf->resp_iov, resp_code);
1306efd838feSMike Christie 	vhost_scsi_release_tmf_res(tmf);
1307efd838feSMike Christie }
1308efd838feSMike Christie 
1309efd838feSMike Christie 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)1310efd838feSMike Christie vhost_scsi_handle_tmf(struct vhost_scsi *vs, struct vhost_scsi_tpg *tpg,
1311efd838feSMike Christie 		      struct vhost_virtqueue *vq,
1312efd838feSMike Christie 		      struct virtio_scsi_ctrl_tmf_req *vtmf,
1313efd838feSMike Christie 		      struct vhost_scsi_ctx *vc)
1314efd838feSMike Christie {
1315efd838feSMike Christie 	struct vhost_scsi_virtqueue *svq = container_of(vq,
1316efd838feSMike Christie 					struct vhost_scsi_virtqueue, vq);
1317efd838feSMike Christie 	struct vhost_scsi_tmf *tmf;
1318efd838feSMike Christie 
1319efd838feSMike Christie 	if (vhost32_to_cpu(vq, vtmf->subtype) !=
1320efd838feSMike Christie 	    VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET)
1321efd838feSMike Christie 		goto send_reject;
1322efd838feSMike Christie 
1323efd838feSMike Christie 	if (!tpg->tpg_nexus || !tpg->tpg_nexus->tvn_se_sess) {
1324efd838feSMike Christie 		pr_err("Unable to locate active struct vhost_scsi_nexus for LUN RESET.\n");
1325efd838feSMike Christie 		goto send_reject;
1326efd838feSMike Christie 	}
1327efd838feSMike Christie 
13284c363c81SMike Christie 	tmf = kzalloc(sizeof(*tmf), GFP_KERNEL);
13294c363c81SMike Christie 	if (!tmf)
1330efd838feSMike Christie 		goto send_reject;
1331efd838feSMike Christie 
13324c363c81SMike Christie 	vhost_work_init(&tmf->vwork, vhost_scsi_tmf_resp_work);
1333efd838feSMike Christie 	tmf->vhost = vs;
1334efd838feSMike Christie 	tmf->svq = svq;
1335efd838feSMike Christie 	tmf->resp_iov = vq->iov[vc->out];
1336efd838feSMike Christie 	tmf->vq_desc = vc->head;
1337efd838feSMike Christie 	tmf->in_iovs = vc->in;
1338efd838feSMike Christie 	tmf->inflight = vhost_scsi_get_inflight(vq);
1339efd838feSMike Christie 
1340efd838feSMike Christie 	if (target_submit_tmr(&tmf->se_cmd, tpg->tpg_nexus->tvn_se_sess, NULL,
1341efd838feSMike Christie 			      vhost_buf_to_lun(vtmf->lun), NULL,
1342efd838feSMike Christie 			      TMR_LUN_RESET, GFP_KERNEL, 0,
1343efd838feSMike Christie 			      TARGET_SCF_ACK_KREF) < 0) {
1344efd838feSMike Christie 		vhost_scsi_release_tmf_res(tmf);
1345efd838feSMike Christie 		goto send_reject;
1346efd838feSMike Christie 	}
1347efd838feSMike Christie 
1348efd838feSMike Christie 	return;
1349efd838feSMike Christie 
1350efd838feSMike Christie send_reject:
1351efd838feSMike Christie 	vhost_scsi_send_tmf_resp(vs, vq, vc->in, vc->head, &vq->iov[vc->out],
1352efd838feSMike Christie 				 VIRTIO_SCSI_S_FUNCTION_REJECTED);
1353efd838feSMike Christie }
1354efd838feSMike Christie 
13550d02dbd6SBijan Mottahedeh static void
vhost_scsi_send_an_resp(struct vhost_scsi * vs,struct vhost_virtqueue * vq,struct vhost_scsi_ctx * vc)13560d02dbd6SBijan Mottahedeh vhost_scsi_send_an_resp(struct vhost_scsi *vs,
13570d02dbd6SBijan Mottahedeh 			struct vhost_virtqueue *vq,
13583f8ca2e1SBijan Mottahedeh 			struct vhost_scsi_ctx *vc)
13590d02dbd6SBijan Mottahedeh {
13600d02dbd6SBijan Mottahedeh 	struct virtio_scsi_ctrl_an_resp rsp;
13618e5dadfeSBijan Mottahedeh 	struct iov_iter iov_iter;
13620d02dbd6SBijan Mottahedeh 	int ret;
13630d02dbd6SBijan Mottahedeh 
13640d02dbd6SBijan Mottahedeh 	pr_debug("%s\n", __func__);
13650d02dbd6SBijan Mottahedeh 	memset(&rsp, 0, sizeof(rsp));	/* event_actual = 0 */
13660d02dbd6SBijan Mottahedeh 	rsp.response = VIRTIO_SCSI_S_OK;
13678e5dadfeSBijan Mottahedeh 
1368de4eda9dSAl Viro 	iov_iter_init(&iov_iter, ITER_DEST, &vq->iov[vc->out], vc->in, sizeof(rsp));
13698e5dadfeSBijan Mottahedeh 
13708e5dadfeSBijan Mottahedeh 	ret = copy_to_iter(&rsp, sizeof(rsp), &iov_iter);
13718e5dadfeSBijan Mottahedeh 	if (likely(ret == sizeof(rsp)))
13723f8ca2e1SBijan Mottahedeh 		vhost_add_used_and_signal(&vs->dev, vq, vc->head, 0);
13730d02dbd6SBijan Mottahedeh 	else
13740d02dbd6SBijan Mottahedeh 		pr_err("Faulted on virtio_scsi_ctrl_an_resp\n");
13750d02dbd6SBijan Mottahedeh }
13760d02dbd6SBijan Mottahedeh 
13770d02dbd6SBijan Mottahedeh static void
vhost_scsi_ctl_handle_vq(struct vhost_scsi * vs,struct vhost_virtqueue * vq)13780d02dbd6SBijan Mottahedeh vhost_scsi_ctl_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
13790d02dbd6SBijan Mottahedeh {
1380efd838feSMike Christie 	struct vhost_scsi_tpg *tpg;
13810d02dbd6SBijan Mottahedeh 	union {
13820d02dbd6SBijan Mottahedeh 		__virtio32 type;
13830d02dbd6SBijan Mottahedeh 		struct virtio_scsi_ctrl_an_req an;
13840d02dbd6SBijan Mottahedeh 		struct virtio_scsi_ctrl_tmf_req tmf;
13850d02dbd6SBijan Mottahedeh 	} v_req;
13863f8ca2e1SBijan Mottahedeh 	struct vhost_scsi_ctx vc;
13873f8ca2e1SBijan Mottahedeh 	size_t typ_size;
1388c1ea02f1SJason Wang 	int ret, c = 0;
13890d02dbd6SBijan Mottahedeh 
13900d02dbd6SBijan Mottahedeh 	mutex_lock(&vq->mutex);
13910d02dbd6SBijan Mottahedeh 	/*
13920d02dbd6SBijan Mottahedeh 	 * We can handle the vq only after the endpoint is setup by calling the
13930d02dbd6SBijan Mottahedeh 	 * VHOST_SCSI_SET_ENDPOINT ioctl.
13940d02dbd6SBijan Mottahedeh 	 */
1395247643f8SEugenio Pérez 	if (!vhost_vq_get_backend(vq))
13960d02dbd6SBijan Mottahedeh 		goto out;
13970d02dbd6SBijan Mottahedeh 
13983f8ca2e1SBijan Mottahedeh 	memset(&vc, 0, sizeof(vc));
13993f8ca2e1SBijan Mottahedeh 
14000d02dbd6SBijan Mottahedeh 	vhost_disable_notify(&vs->dev, vq);
14010d02dbd6SBijan Mottahedeh 
1402c1ea02f1SJason Wang 	do {
14033f8ca2e1SBijan Mottahedeh 		ret = vhost_scsi_get_desc(vs, vq, &vc);
14043f8ca2e1SBijan Mottahedeh 		if (ret)
14053f8ca2e1SBijan Mottahedeh 			goto err;
14060d02dbd6SBijan Mottahedeh 
14070d02dbd6SBijan Mottahedeh 		/*
14083f8ca2e1SBijan Mottahedeh 		 * Get the request type first in order to setup
14093f8ca2e1SBijan Mottahedeh 		 * other parameters dependent on the type.
14100d02dbd6SBijan Mottahedeh 		 */
14113f8ca2e1SBijan Mottahedeh 		vc.req = &v_req.type;
14120d02dbd6SBijan Mottahedeh 		typ_size = sizeof(v_req.type);
14130d02dbd6SBijan Mottahedeh 
14143f8ca2e1SBijan Mottahedeh 		if (unlikely(!copy_from_iter_full(vc.req, typ_size,
14153f8ca2e1SBijan Mottahedeh 						  &vc.out_iter))) {
14160d02dbd6SBijan Mottahedeh 			vq_err(vq, "Faulted on copy_from_iter tmf type\n");
14170d02dbd6SBijan Mottahedeh 			/*
14183f8ca2e1SBijan Mottahedeh 			 * The size of the response buffer depends on the
14193f8ca2e1SBijan Mottahedeh 			 * request type and must be validated against it.
14200d02dbd6SBijan Mottahedeh 			 * Since the request type is not known, don't send
14210d02dbd6SBijan Mottahedeh 			 * a response.
14220d02dbd6SBijan Mottahedeh 			 */
14230d02dbd6SBijan Mottahedeh 			continue;
14240d02dbd6SBijan Mottahedeh 		}
14250d02dbd6SBijan Mottahedeh 
1426295c1b98SMichael S. Tsirkin 		switch (vhost32_to_cpu(vq, v_req.type)) {
14270d02dbd6SBijan Mottahedeh 		case VIRTIO_SCSI_T_TMF:
14283f8ca2e1SBijan Mottahedeh 			vc.req = &v_req.tmf;
14293f8ca2e1SBijan Mottahedeh 			vc.req_size = sizeof(struct virtio_scsi_ctrl_tmf_req);
14303f8ca2e1SBijan Mottahedeh 			vc.rsp_size = sizeof(struct virtio_scsi_ctrl_tmf_resp);
14313f8ca2e1SBijan Mottahedeh 			vc.lunp = &v_req.tmf.lun[0];
14323f8ca2e1SBijan Mottahedeh 			vc.target = &v_req.tmf.lun[1];
14330d02dbd6SBijan Mottahedeh 			break;
14340d02dbd6SBijan Mottahedeh 		case VIRTIO_SCSI_T_AN_QUERY:
14350d02dbd6SBijan Mottahedeh 		case VIRTIO_SCSI_T_AN_SUBSCRIBE:
14363f8ca2e1SBijan Mottahedeh 			vc.req = &v_req.an;
14373f8ca2e1SBijan Mottahedeh 			vc.req_size = sizeof(struct virtio_scsi_ctrl_an_req);
14383f8ca2e1SBijan Mottahedeh 			vc.rsp_size = sizeof(struct virtio_scsi_ctrl_an_resp);
14393f8ca2e1SBijan Mottahedeh 			vc.lunp = &v_req.an.lun[0];
14403f8ca2e1SBijan Mottahedeh 			vc.target = NULL;
14410d02dbd6SBijan Mottahedeh 			break;
14420d02dbd6SBijan Mottahedeh 		default:
14430d02dbd6SBijan Mottahedeh 			vq_err(vq, "Unknown control request %d", v_req.type);
14440d02dbd6SBijan Mottahedeh 			continue;
14450d02dbd6SBijan Mottahedeh 		}
14460d02dbd6SBijan Mottahedeh 
14470d02dbd6SBijan Mottahedeh 		/*
14483f8ca2e1SBijan Mottahedeh 		 * Validate the size of request and response buffers.
14493f8ca2e1SBijan Mottahedeh 		 * Check for a sane response buffer so we can report
14503f8ca2e1SBijan Mottahedeh 		 * early errors back to the guest.
14510d02dbd6SBijan Mottahedeh 		 */
14523f8ca2e1SBijan Mottahedeh 		ret = vhost_scsi_chk_size(vq, &vc);
14533f8ca2e1SBijan Mottahedeh 		if (ret)
14543f8ca2e1SBijan Mottahedeh 			goto err;
14553f8ca2e1SBijan Mottahedeh 
14560d02dbd6SBijan Mottahedeh 		/*
14573f8ca2e1SBijan Mottahedeh 		 * Get the rest of the request now that its size is known.
14580d02dbd6SBijan Mottahedeh 		 */
14593f8ca2e1SBijan Mottahedeh 		vc.req += typ_size;
14603f8ca2e1SBijan Mottahedeh 		vc.req_size -= typ_size;
14610d02dbd6SBijan Mottahedeh 
1462efd838feSMike Christie 		ret = vhost_scsi_get_req(vq, &vc, &tpg);
14633f8ca2e1SBijan Mottahedeh 		if (ret)
14643f8ca2e1SBijan Mottahedeh 			goto err;
14650d02dbd6SBijan Mottahedeh 
14663f8ca2e1SBijan Mottahedeh 		if (v_req.type == VIRTIO_SCSI_T_TMF)
1467efd838feSMike Christie 			vhost_scsi_handle_tmf(vs, tpg, vq, &v_req.tmf, &vc);
14683f8ca2e1SBijan Mottahedeh 		else
14693f8ca2e1SBijan Mottahedeh 			vhost_scsi_send_an_resp(vs, vq, &vc);
14703f8ca2e1SBijan Mottahedeh err:
14713f8ca2e1SBijan Mottahedeh 		/*
14723f8ca2e1SBijan Mottahedeh 		 * ENXIO:  No more requests, or read error, wait for next kick
14733f8ca2e1SBijan Mottahedeh 		 * EINVAL: Invalid response buffer, drop the request
14743f8ca2e1SBijan Mottahedeh 		 * EIO:    Respond with bad target
14753f8ca2e1SBijan Mottahedeh 		 * EAGAIN: Pending request
14763f8ca2e1SBijan Mottahedeh 		 */
14773f8ca2e1SBijan Mottahedeh 		if (ret == -ENXIO)
14783f8ca2e1SBijan Mottahedeh 			break;
14793f8ca2e1SBijan Mottahedeh 		else if (ret == -EIO)
14803f8ca2e1SBijan Mottahedeh 			vhost_scsi_send_bad_target(vs, vq, vc.head, vc.out);
1481c1ea02f1SJason Wang 	} while (likely(!vhost_exceeds_weight(vq, ++c, 0)));
14820d02dbd6SBijan Mottahedeh out:
14830d02dbd6SBijan Mottahedeh 	mutex_unlock(&vq->mutex);
14840d02dbd6SBijan Mottahedeh }
14850d02dbd6SBijan Mottahedeh 
vhost_scsi_ctl_handle_kick(struct vhost_work * work)1486eb62b74eSMichael S. Tsirkin static void vhost_scsi_ctl_handle_kick(struct vhost_work *work)
1487eb62b74eSMichael S. Tsirkin {
14880d02dbd6SBijan Mottahedeh 	struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
14890d02dbd6SBijan Mottahedeh 						poll.work);
14900d02dbd6SBijan Mottahedeh 	struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);
14910d02dbd6SBijan Mottahedeh 
1492eb62b74eSMichael S. Tsirkin 	pr_debug("%s: The handling func for control queue.\n", __func__);
14930d02dbd6SBijan Mottahedeh 	vhost_scsi_ctl_handle_vq(vs, vq);
1494eb62b74eSMichael S. Tsirkin }
1495eb62b74eSMichael S. Tsirkin 
1496683bd967SAsias He 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)149778af31ccSMike Christie vhost_scsi_send_evt(struct vhost_scsi *vs, struct vhost_virtqueue *vq,
149878af31ccSMike Christie 		    struct vhost_scsi_tpg *tpg, struct se_lun *lun,
149978af31ccSMike Christie 		    u32 event, u32 reason)
1500eb62b74eSMichael S. Tsirkin {
15011a1ff825SNicholas Bellinger 	struct vhost_scsi_evt *evt;
1502eb62b74eSMichael S. Tsirkin 
15031a1ff825SNicholas Bellinger 	evt = vhost_scsi_allocate_evt(vs, event, reason);
1504eb62b74eSMichael S. Tsirkin 	if (!evt)
1505eb62b74eSMichael S. Tsirkin 		return;
1506eb62b74eSMichael S. Tsirkin 
1507eb62b74eSMichael S. Tsirkin 	if (tpg && lun) {
1508eb62b74eSMichael S. Tsirkin 		/* TODO: share lun setup code with virtio-scsi.ko */
1509eb62b74eSMichael S. Tsirkin 		/*
1510eb62b74eSMichael S. Tsirkin 		 * Note: evt->event is zeroed when we allocate it and
1511eb62b74eSMichael S. Tsirkin 		 * lun[4-7] need to be zero according to virtio-scsi spec.
1512eb62b74eSMichael S. Tsirkin 		 */
1513eb62b74eSMichael S. Tsirkin 		evt->event.lun[0] = 0x01;
151459c816c1SDan Carpenter 		evt->event.lun[1] = tpg->tport_tpgt;
1515eb62b74eSMichael S. Tsirkin 		if (lun->unpacked_lun >= 256)
1516eb62b74eSMichael S. Tsirkin 			evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ;
1517eb62b74eSMichael S. Tsirkin 		evt->event.lun[3] = lun->unpacked_lun & 0xFF;
1518eb62b74eSMichael S. Tsirkin 	}
1519eb62b74eSMichael S. Tsirkin 
1520eb62b74eSMichael S. Tsirkin 	llist_add(&evt->list, &vs->vs_event_list);
15218f174c5dSMike Christie 	if (!vhost_vq_work_queue(vq, &vs->vs_event_work))
15228f174c5dSMike Christie 		vhost_scsi_complete_events(vs, true);
1523eb62b74eSMichael S. Tsirkin }
1524eb62b74eSMichael S. Tsirkin 
vhost_scsi_evt_handle_kick(struct vhost_work * work)1525eb62b74eSMichael S. Tsirkin static void vhost_scsi_evt_handle_kick(struct vhost_work *work)
1526eb62b74eSMichael S. Tsirkin {
1527eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
1528eb62b74eSMichael S. Tsirkin 						poll.work);
1529eb62b74eSMichael S. Tsirkin 	struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);
1530eb62b74eSMichael S. Tsirkin 
1531eb62b74eSMichael S. Tsirkin 	mutex_lock(&vq->mutex);
1532247643f8SEugenio Pérez 	if (!vhost_vq_get_backend(vq))
1533eb62b74eSMichael S. Tsirkin 		goto out;
1534eb62b74eSMichael S. Tsirkin 
1535eb62b74eSMichael S. Tsirkin 	if (vs->vs_events_missed)
153678af31ccSMike Christie 		vhost_scsi_send_evt(vs, vq, NULL, NULL, VIRTIO_SCSI_T_NO_EVENT,
153778af31ccSMike Christie 				    0);
1538eb62b74eSMichael S. Tsirkin out:
1539eb62b74eSMichael S. Tsirkin 	mutex_unlock(&vq->mutex);
1540eb62b74eSMichael S. Tsirkin }
1541eb62b74eSMichael S. Tsirkin 
vhost_scsi_handle_kick(struct vhost_work * work)1542eb62b74eSMichael S. Tsirkin static void vhost_scsi_handle_kick(struct vhost_work *work)
1543eb62b74eSMichael S. Tsirkin {
1544eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
1545eb62b74eSMichael S. Tsirkin 						poll.work);
1546eb62b74eSMichael S. Tsirkin 	struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);
1547eb62b74eSMichael S. Tsirkin 
1548eb62b74eSMichael S. Tsirkin 	vhost_scsi_handle_vq(vs, vq);
1549eb62b74eSMichael S. Tsirkin }
1550eb62b74eSMichael S. Tsirkin 
1551eb62b74eSMichael S. Tsirkin /* Callers must hold dev mutex */
vhost_scsi_flush(struct vhost_scsi * vs)1552eb62b74eSMichael S. Tsirkin static void vhost_scsi_flush(struct vhost_scsi *vs)
1553eb62b74eSMichael S. Tsirkin {
1554eb62b74eSMichael S. Tsirkin 	int i;
1555eb62b74eSMichael S. Tsirkin 
1556eb62b74eSMichael S. Tsirkin 	/* Init new inflight and remember the old inflight */
1557f49c2226SMike Christie 	vhost_scsi_init_inflight(vs, vs->old_inflight);
1558eb62b74eSMichael S. Tsirkin 
1559eb62b74eSMichael S. Tsirkin 	/*
1560eb62b74eSMichael S. Tsirkin 	 * The inflight->kref was initialized to 1. We decrement it here to
1561eb62b74eSMichael S. Tsirkin 	 * indicate the start of the flush operation so that it will reach 0
1562eb62b74eSMichael S. Tsirkin 	 * when all the reqs are finished.
1563eb62b74eSMichael S. Tsirkin 	 */
1564f49c2226SMike Christie 	for (i = 0; i < vs->dev.nvqs; i++)
1565f49c2226SMike Christie 		kref_put(&vs->old_inflight[i]->kref, vhost_scsi_done_inflight);
1566eb62b74eSMichael S. Tsirkin 
1567eb62b74eSMichael S. Tsirkin 	/* Flush both the vhost poll and vhost work */
1568b2ffa407SMike Christie 	vhost_dev_flush(&vs->dev);
1569eb62b74eSMichael S. Tsirkin 
1570eb62b74eSMichael S. Tsirkin 	/* Wait for all reqs issued before the flush to be finished */
1571f49c2226SMike Christie 	for (i = 0; i < vs->dev.nvqs; i++)
1572f49c2226SMike Christie 		wait_for_completion(&vs->old_inflight[i]->comp);
1573eb62b74eSMichael S. Tsirkin }
1574eb62b74eSMichael S. Tsirkin 
vhost_scsi_destroy_vq_cmds(struct vhost_virtqueue * vq)157525b98b64SMike Christie static void vhost_scsi_destroy_vq_cmds(struct vhost_virtqueue *vq)
157625b98b64SMike Christie {
157725b98b64SMike Christie 	struct vhost_scsi_virtqueue *svq = container_of(vq,
157825b98b64SMike Christie 					struct vhost_scsi_virtqueue, vq);
157925b98b64SMike Christie 	struct vhost_scsi_cmd *tv_cmd;
158025b98b64SMike Christie 	unsigned int i;
158125b98b64SMike Christie 
158225b98b64SMike Christie 	if (!svq->scsi_cmds)
158325b98b64SMike Christie 		return;
158425b98b64SMike Christie 
158525b98b64SMike Christie 	for (i = 0; i < svq->max_cmds; i++) {
158625b98b64SMike Christie 		tv_cmd = &svq->scsi_cmds[i];
158725b98b64SMike Christie 
158825b98b64SMike Christie 		kfree(tv_cmd->tvc_sgl);
158925b98b64SMike Christie 		kfree(tv_cmd->tvc_prot_sgl);
159025b98b64SMike Christie 		kfree(tv_cmd->tvc_upages);
15916dd88fd5SJason Wang 		kfree(tv_cmd->tvc_resp_iov);
159225b98b64SMike Christie 	}
159325b98b64SMike Christie 
159425b98b64SMike Christie 	sbitmap_free(&svq->scsi_tags);
159525b98b64SMike Christie 	kfree(svq->scsi_cmds);
159625b98b64SMike Christie 	svq->scsi_cmds = NULL;
159725b98b64SMike Christie }
159825b98b64SMike Christie 
vhost_scsi_setup_vq_cmds(struct vhost_virtqueue * vq,int max_cmds)159925b98b64SMike Christie static int vhost_scsi_setup_vq_cmds(struct vhost_virtqueue *vq, int max_cmds)
160025b98b64SMike Christie {
160125b98b64SMike Christie 	struct vhost_scsi_virtqueue *svq = container_of(vq,
160225b98b64SMike Christie 					struct vhost_scsi_virtqueue, vq);
160325b98b64SMike Christie 	struct vhost_scsi_cmd *tv_cmd;
160425b98b64SMike Christie 	unsigned int i;
160525b98b64SMike Christie 
160625b98b64SMike Christie 	if (svq->scsi_cmds)
160725b98b64SMike Christie 		return 0;
160825b98b64SMike Christie 
160925b98b64SMike Christie 	if (sbitmap_init_node(&svq->scsi_tags, max_cmds, -1, GFP_KERNEL,
1610c548e62bSMing Lei 			      NUMA_NO_NODE, false, true))
161125b98b64SMike Christie 		return -ENOMEM;
161225b98b64SMike Christie 	svq->max_cmds = max_cmds;
161325b98b64SMike Christie 
161425b98b64SMike Christie 	svq->scsi_cmds = kcalloc(max_cmds, sizeof(*tv_cmd), GFP_KERNEL);
161525b98b64SMike Christie 	if (!svq->scsi_cmds) {
161625b98b64SMike Christie 		sbitmap_free(&svq->scsi_tags);
161725b98b64SMike Christie 		return -ENOMEM;
161825b98b64SMike Christie 	}
161925b98b64SMike Christie 
162025b98b64SMike Christie 	for (i = 0; i < max_cmds; i++) {
162125b98b64SMike Christie 		tv_cmd = &svq->scsi_cmds[i];
162225b98b64SMike Christie 
162325b98b64SMike Christie 		tv_cmd->tvc_sgl = kcalloc(VHOST_SCSI_PREALLOC_SGLS,
162425b98b64SMike Christie 					  sizeof(struct scatterlist),
162525b98b64SMike Christie 					  GFP_KERNEL);
162625b98b64SMike Christie 		if (!tv_cmd->tvc_sgl) {
162725b98b64SMike Christie 			pr_err("Unable to allocate tv_cmd->tvc_sgl\n");
162825b98b64SMike Christie 			goto out;
162925b98b64SMike Christie 		}
163025b98b64SMike Christie 
163125b98b64SMike Christie 		tv_cmd->tvc_upages = kcalloc(VHOST_SCSI_PREALLOC_UPAGES,
163225b98b64SMike Christie 					     sizeof(struct page *),
163325b98b64SMike Christie 					     GFP_KERNEL);
163425b98b64SMike Christie 		if (!tv_cmd->tvc_upages) {
163525b98b64SMike Christie 			pr_err("Unable to allocate tv_cmd->tvc_upages\n");
163625b98b64SMike Christie 			goto out;
163725b98b64SMike Christie 		}
163825b98b64SMike Christie 
16396dd88fd5SJason Wang 		tv_cmd->tvc_resp_iov = kcalloc(UIO_MAXIOV,
16406dd88fd5SJason Wang 					       sizeof(struct iovec),
16416dd88fd5SJason Wang 					       GFP_KERNEL);
16426dd88fd5SJason Wang 		if (!tv_cmd->tvc_resp_iov) {
16436dd88fd5SJason Wang 			pr_err("Unable to allocate tv_cmd->tvc_resp_iov\n");
16446dd88fd5SJason Wang 			goto out;
16456dd88fd5SJason Wang 		}
16466dd88fd5SJason Wang 
164725b98b64SMike Christie 		tv_cmd->tvc_prot_sgl = kcalloc(VHOST_SCSI_PREALLOC_PROT_SGLS,
164825b98b64SMike Christie 					       sizeof(struct scatterlist),
164925b98b64SMike Christie 					       GFP_KERNEL);
165025b98b64SMike Christie 		if (!tv_cmd->tvc_prot_sgl) {
165125b98b64SMike Christie 			pr_err("Unable to allocate tv_cmd->tvc_prot_sgl\n");
165225b98b64SMike Christie 			goto out;
165325b98b64SMike Christie 		}
165425b98b64SMike Christie 	}
165525b98b64SMike Christie 	return 0;
165625b98b64SMike Christie out:
165725b98b64SMike Christie 	vhost_scsi_destroy_vq_cmds(vq);
165825b98b64SMike Christie 	return -ENOMEM;
165925b98b64SMike Christie }
166025b98b64SMike Christie 
1661eb62b74eSMichael S. Tsirkin /*
1662eb62b74eSMichael S. Tsirkin  * Called from vhost_scsi_ioctl() context to walk the list of available
16631a1ff825SNicholas Bellinger  * vhost_scsi_tpg with an active struct vhost_scsi_nexus
1664eb62b74eSMichael S. Tsirkin  *
1665eb62b74eSMichael S. Tsirkin  *  The lock nesting rule is:
1666bea273c7SMike Christie  *    vs->dev.mutex -> vhost_scsi_mutex -> tpg->tv_tpg_mutex -> vq->mutex
1667eb62b74eSMichael S. Tsirkin  */
1668683bd967SAsias He static int
vhost_scsi_set_endpoint(struct vhost_scsi * vs,struct vhost_scsi_target * t)1669683bd967SAsias He vhost_scsi_set_endpoint(struct vhost_scsi *vs,
1670eb62b74eSMichael S. Tsirkin 			struct vhost_scsi_target *t)
1671eb62b74eSMichael S. Tsirkin {
1672ab8edab1SNicholas Bellinger 	struct se_portal_group *se_tpg;
16731a1ff825SNicholas Bellinger 	struct vhost_scsi_tport *tv_tport;
16741a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg *tpg;
16751a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg **vs_tpg;
1676eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue *vq;
1677eb62b74eSMichael S. Tsirkin 	int index, ret, i, len;
1678eb62b74eSMichael S. Tsirkin 	bool match = false;
1679eb62b74eSMichael S. Tsirkin 
1680eb62b74eSMichael S. Tsirkin 	mutex_lock(&vs->dev.mutex);
1681eb62b74eSMichael S. Tsirkin 
1682eb62b74eSMichael S. Tsirkin 	/* Verify that ring has been setup correctly. */
1683eb62b74eSMichael S. Tsirkin 	for (index = 0; index < vs->dev.nvqs; ++index) {
1684eb62b74eSMichael S. Tsirkin 		/* Verify that ring has been setup correctly. */
1685eb62b74eSMichael S. Tsirkin 		if (!vhost_vq_access_ok(&vs->vqs[index].vq)) {
1686eb62b74eSMichael S. Tsirkin 			ret = -EFAULT;
1687eb62b74eSMichael S. Tsirkin 			goto out;
1688eb62b74eSMichael S. Tsirkin 		}
1689eb62b74eSMichael S. Tsirkin 	}
1690eb62b74eSMichael S. Tsirkin 
1691eb62b74eSMichael S. Tsirkin 	len = sizeof(vs_tpg[0]) * VHOST_SCSI_MAX_TARGET;
1692eb62b74eSMichael S. Tsirkin 	vs_tpg = kzalloc(len, GFP_KERNEL);
1693eb62b74eSMichael S. Tsirkin 	if (!vs_tpg) {
1694eb62b74eSMichael S. Tsirkin 		ret = -ENOMEM;
1695eb62b74eSMichael S. Tsirkin 		goto out;
1696eb62b74eSMichael S. Tsirkin 	}
1697eb62b74eSMichael S. Tsirkin 	if (vs->vs_tpg)
1698eb62b74eSMichael S. Tsirkin 		memcpy(vs_tpg, vs->vs_tpg, len);
1699eb62b74eSMichael S. Tsirkin 
1700bea273c7SMike Christie 	mutex_lock(&vhost_scsi_mutex);
17011a1ff825SNicholas Bellinger 	list_for_each_entry(tpg, &vhost_scsi_list, tv_tpg_list) {
170298718312SAsias He 		mutex_lock(&tpg->tv_tpg_mutex);
170398718312SAsias He 		if (!tpg->tpg_nexus) {
170498718312SAsias He 			mutex_unlock(&tpg->tv_tpg_mutex);
1705eb62b74eSMichael S. Tsirkin 			continue;
1706eb62b74eSMichael S. Tsirkin 		}
170798718312SAsias He 		if (tpg->tv_tpg_vhost_count != 0) {
170898718312SAsias He 			mutex_unlock(&tpg->tv_tpg_mutex);
1709eb62b74eSMichael S. Tsirkin 			continue;
1710eb62b74eSMichael S. Tsirkin 		}
171198718312SAsias He 		tv_tport = tpg->tport;
1712eb62b74eSMichael S. Tsirkin 
1713eb62b74eSMichael S. Tsirkin 		if (!strcmp(tv_tport->tport_name, t->vhost_wwpn)) {
171498718312SAsias He 			if (vs->vs_tpg && vs->vs_tpg[tpg->tport_tpgt]) {
171598718312SAsias He 				mutex_unlock(&tpg->tv_tpg_mutex);
1716bea273c7SMike Christie 				mutex_unlock(&vhost_scsi_mutex);
1717eb62b74eSMichael S. Tsirkin 				ret = -EEXIST;
171825b98b64SMike Christie 				goto undepend;
1719eb62b74eSMichael S. Tsirkin 			}
1720ab8edab1SNicholas Bellinger 			/*
1721ab8edab1SNicholas Bellinger 			 * In order to ensure individual vhost-scsi configfs
1722ab8edab1SNicholas Bellinger 			 * groups cannot be removed while in use by vhost ioctl,
1723ab8edab1SNicholas Bellinger 			 * go ahead and take an explicit se_tpg->tpg_group.cg_item
1724ab8edab1SNicholas Bellinger 			 * dependency now.
1725ab8edab1SNicholas Bellinger 			 */
1726ab8edab1SNicholas Bellinger 			se_tpg = &tpg->se_tpg;
1727d588cf8fSChristoph Hellwig 			ret = target_depend_item(&se_tpg->tpg_group.cg_item);
1728ab8edab1SNicholas Bellinger 			if (ret) {
1729a691ffb4Swangyan 				pr_warn("target_depend_item() failed: %d\n", ret);
1730ab8edab1SNicholas Bellinger 				mutex_unlock(&tpg->tv_tpg_mutex);
1731bea273c7SMike Christie 				mutex_unlock(&vhost_scsi_mutex);
173225b98b64SMike Christie 				goto undepend;
1733ab8edab1SNicholas Bellinger 			}
173498718312SAsias He 			tpg->tv_tpg_vhost_count++;
173598718312SAsias He 			tpg->vhost_scsi = vs;
173698718312SAsias He 			vs_tpg[tpg->tport_tpgt] = tpg;
1737eb62b74eSMichael S. Tsirkin 			match = true;
1738eb62b74eSMichael S. Tsirkin 		}
173998718312SAsias He 		mutex_unlock(&tpg->tv_tpg_mutex);
1740eb62b74eSMichael S. Tsirkin 	}
1741bea273c7SMike Christie 	mutex_unlock(&vhost_scsi_mutex);
1742eb62b74eSMichael S. Tsirkin 
1743eb62b74eSMichael S. Tsirkin 	if (match) {
1744eb62b74eSMichael S. Tsirkin 		memcpy(vs->vs_vhost_wwpn, t->vhost_wwpn,
1745eb62b74eSMichael S. Tsirkin 		       sizeof(vs->vs_vhost_wwpn));
174625b98b64SMike Christie 
1747f49c2226SMike Christie 		for (i = VHOST_SCSI_VQ_IO; i < vs->dev.nvqs; i++) {
174825b98b64SMike Christie 			vq = &vs->vqs[i].vq;
174925b98b64SMike Christie 			if (!vhost_vq_is_setup(vq))
175025b98b64SMike Christie 				continue;
175125b98b64SMike Christie 
17522e1139d6SZhang Changzhong 			ret = vhost_scsi_setup_vq_cmds(vq, vq->num);
17532e1139d6SZhang Changzhong 			if (ret)
175425b98b64SMike Christie 				goto destroy_vq_cmds;
175525b98b64SMike Christie 		}
175625b98b64SMike Christie 
1757f49c2226SMike Christie 		for (i = 0; i < vs->dev.nvqs; i++) {
1758eb62b74eSMichael S. Tsirkin 			vq = &vs->vqs[i].vq;
1759eb62b74eSMichael S. Tsirkin 			mutex_lock(&vq->mutex);
1760247643f8SEugenio Pérez 			vhost_vq_set_backend(vq, vs_tpg);
176180f7d030SGreg Kurz 			vhost_vq_init_access(vq);
1762eb62b74eSMichael S. Tsirkin 			mutex_unlock(&vq->mutex);
1763eb62b74eSMichael S. Tsirkin 		}
1764eb62b74eSMichael S. Tsirkin 		ret = 0;
1765eb62b74eSMichael S. Tsirkin 	} else {
1766eb62b74eSMichael S. Tsirkin 		ret = -EEXIST;
1767eb62b74eSMichael S. Tsirkin 	}
1768eb62b74eSMichael S. Tsirkin 
1769eb62b74eSMichael S. Tsirkin 	/*
1770eb62b74eSMichael S. Tsirkin 	 * Act as synchronize_rcu to make sure access to
1771eb62b74eSMichael S. Tsirkin 	 * old vs->vs_tpg is finished.
1772eb62b74eSMichael S. Tsirkin 	 */
1773eb62b74eSMichael S. Tsirkin 	vhost_scsi_flush(vs);
1774eb62b74eSMichael S. Tsirkin 	kfree(vs->vs_tpg);
1775eb62b74eSMichael S. Tsirkin 	vs->vs_tpg = vs_tpg;
177625b98b64SMike Christie 	goto out;
1777eb62b74eSMichael S. Tsirkin 
177825b98b64SMike Christie destroy_vq_cmds:
177925b98b64SMike Christie 	for (i--; i >= VHOST_SCSI_VQ_IO; i--) {
178025b98b64SMike Christie 		if (!vhost_vq_get_backend(&vs->vqs[i].vq))
178125b98b64SMike Christie 			vhost_scsi_destroy_vq_cmds(&vs->vqs[i].vq);
178225b98b64SMike Christie 	}
178325b98b64SMike Christie undepend:
178425b98b64SMike Christie 	for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) {
178525b98b64SMike Christie 		tpg = vs_tpg[i];
178625b98b64SMike Christie 		if (tpg) {
1787e508efc3SMike Christie 			mutex_lock(&tpg->tv_tpg_mutex);
1788e508efc3SMike Christie 			tpg->vhost_scsi = NULL;
178925b98b64SMike Christie 			tpg->tv_tpg_vhost_count--;
1790e508efc3SMike Christie 			mutex_unlock(&tpg->tv_tpg_mutex);
179125b98b64SMike Christie 			target_undepend_item(&tpg->se_tpg.tpg_group.cg_item);
179225b98b64SMike Christie 		}
179325b98b64SMike Christie 	}
179425b98b64SMike Christie 	kfree(vs_tpg);
1795eb62b74eSMichael S. Tsirkin out:
1796eb62b74eSMichael S. Tsirkin 	mutex_unlock(&vs->dev.mutex);
1797eb62b74eSMichael S. Tsirkin 	return ret;
1798eb62b74eSMichael S. Tsirkin }
1799eb62b74eSMichael S. Tsirkin 
1800683bd967SAsias He static int
vhost_scsi_clear_endpoint(struct vhost_scsi * vs,struct vhost_scsi_target * t)1801683bd967SAsias He vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
1802eb62b74eSMichael S. Tsirkin 			  struct vhost_scsi_target *t)
1803eb62b74eSMichael S. Tsirkin {
1804ab8edab1SNicholas Bellinger 	struct se_portal_group *se_tpg;
18051a1ff825SNicholas Bellinger 	struct vhost_scsi_tport *tv_tport;
18061a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg *tpg;
1807eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue *vq;
1808eb62b74eSMichael S. Tsirkin 	bool match = false;
1809eb62b74eSMichael S. Tsirkin 	int index, ret, i;
1810eb62b74eSMichael S. Tsirkin 	u8 target;
1811eb62b74eSMichael S. Tsirkin 
1812eb62b74eSMichael S. Tsirkin 	mutex_lock(&vs->dev.mutex);
1813eb62b74eSMichael S. Tsirkin 	/* Verify that ring has been setup correctly. */
1814eb62b74eSMichael S. Tsirkin 	for (index = 0; index < vs->dev.nvqs; ++index) {
1815eb62b74eSMichael S. Tsirkin 		if (!vhost_vq_access_ok(&vs->vqs[index].vq)) {
1816eb62b74eSMichael S. Tsirkin 			ret = -EFAULT;
1817eb62b74eSMichael S. Tsirkin 			goto err_dev;
1818eb62b74eSMichael S. Tsirkin 		}
1819eb62b74eSMichael S. Tsirkin 	}
1820eb62b74eSMichael S. Tsirkin 
1821eb62b74eSMichael S. Tsirkin 	if (!vs->vs_tpg) {
1822eb62b74eSMichael S. Tsirkin 		ret = 0;
1823eb62b74eSMichael S. Tsirkin 		goto err_dev;
1824eb62b74eSMichael S. Tsirkin 	}
1825eb62b74eSMichael S. Tsirkin 
1826eb62b74eSMichael S. Tsirkin 	for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) {
1827eb62b74eSMichael S. Tsirkin 		target = i;
182898718312SAsias He 		tpg = vs->vs_tpg[target];
182998718312SAsias He 		if (!tpg)
1830eb62b74eSMichael S. Tsirkin 			continue;
1831eb62b74eSMichael S. Tsirkin 
183298718312SAsias He 		tv_tport = tpg->tport;
1833eb62b74eSMichael S. Tsirkin 		if (!tv_tport) {
1834eb62b74eSMichael S. Tsirkin 			ret = -ENODEV;
18359a10cb4dSMike Christie 			goto err_dev;
1836eb62b74eSMichael S. Tsirkin 		}
1837eb62b74eSMichael S. Tsirkin 
1838eb62b74eSMichael S. Tsirkin 		if (strcmp(tv_tport->tport_name, t->vhost_wwpn)) {
183998718312SAsias He 			pr_warn("tv_tport->tport_name: %s, tpg->tport_tpgt: %hu"
1840eb62b74eSMichael S. Tsirkin 				" does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n",
184198718312SAsias He 				tv_tport->tport_name, tpg->tport_tpgt,
1842eb62b74eSMichael S. Tsirkin 				t->vhost_wwpn, t->vhost_tpgt);
1843eb62b74eSMichael S. Tsirkin 			ret = -EINVAL;
18449a10cb4dSMike Christie 			goto err_dev;
1845eb62b74eSMichael S. Tsirkin 		}
1846eb62b74eSMichael S. Tsirkin 		match = true;
1847eb62b74eSMichael S. Tsirkin 	}
18489a10cb4dSMike Christie 	if (!match)
18499a10cb4dSMike Christie 		goto free_vs_tpg;
18509a10cb4dSMike Christie 
18519a10cb4dSMike Christie 	/* Prevent new cmds from starting and accessing the tpgs/sessions */
1852f49c2226SMike Christie 	for (i = 0; i < vs->dev.nvqs; i++) {
1853eb62b74eSMichael S. Tsirkin 		vq = &vs->vqs[i].vq;
1854eb62b74eSMichael S. Tsirkin 		mutex_lock(&vq->mutex);
1855247643f8SEugenio Pérez 		vhost_vq_set_backend(vq, NULL);
1856eb62b74eSMichael S. Tsirkin 		mutex_unlock(&vq->mutex);
1857d60146c1SMike Christie 	}
1858d60146c1SMike Christie 	/* Make sure cmds are not running before tearing them down. */
185925b98b64SMike Christie 	vhost_scsi_flush(vs);
1860d60146c1SMike Christie 
1861f49c2226SMike Christie 	for (i = 0; i < vs->dev.nvqs; i++) {
1862d60146c1SMike Christie 		vq = &vs->vqs[i].vq;
186325b98b64SMike Christie 		vhost_scsi_destroy_vq_cmds(vq);
1864eb62b74eSMichael S. Tsirkin 	}
18659a10cb4dSMike Christie 
18669a10cb4dSMike Christie 	/*
18679a10cb4dSMike Christie 	 * We can now release our hold on the tpg and sessions and userspace
18689a10cb4dSMike Christie 	 * can free them after this point.
18699a10cb4dSMike Christie 	 */
18709a10cb4dSMike Christie 	for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) {
18719a10cb4dSMike Christie 		target = i;
18729a10cb4dSMike Christie 		tpg = vs->vs_tpg[target];
18739a10cb4dSMike Christie 		if (!tpg)
18749a10cb4dSMike Christie 			continue;
18759a10cb4dSMike Christie 
18769a10cb4dSMike Christie 		mutex_lock(&tpg->tv_tpg_mutex);
18779a10cb4dSMike Christie 
18789a10cb4dSMike Christie 		tpg->tv_tpg_vhost_count--;
18799a10cb4dSMike Christie 		tpg->vhost_scsi = NULL;
18809a10cb4dSMike Christie 		vs->vs_tpg[target] = NULL;
18819a10cb4dSMike Christie 
18829a10cb4dSMike Christie 		mutex_unlock(&tpg->tv_tpg_mutex);
18839a10cb4dSMike Christie 
18849a10cb4dSMike Christie 		se_tpg = &tpg->se_tpg;
18859a10cb4dSMike Christie 		target_undepend_item(&se_tpg->tpg_group.cg_item);
1886eb62b74eSMichael S. Tsirkin 	}
18879a10cb4dSMike Christie 
18889a10cb4dSMike Christie free_vs_tpg:
1889eb62b74eSMichael S. Tsirkin 	/*
1890eb62b74eSMichael S. Tsirkin 	 * Act as synchronize_rcu to make sure access to
1891eb62b74eSMichael S. Tsirkin 	 * old vs->vs_tpg is finished.
1892eb62b74eSMichael S. Tsirkin 	 */
1893eb62b74eSMichael S. Tsirkin 	vhost_scsi_flush(vs);
1894eb62b74eSMichael S. Tsirkin 	kfree(vs->vs_tpg);
1895eb62b74eSMichael S. Tsirkin 	vs->vs_tpg = NULL;
1896eb62b74eSMichael S. Tsirkin 	WARN_ON(vs->vs_events_nr);
1897eb62b74eSMichael S. Tsirkin 	mutex_unlock(&vs->dev.mutex);
1898eb62b74eSMichael S. Tsirkin 	return 0;
1899eb62b74eSMichael S. Tsirkin 
1900eb62b74eSMichael S. Tsirkin err_dev:
1901eb62b74eSMichael S. Tsirkin 	mutex_unlock(&vs->dev.mutex);
1902eb62b74eSMichael S. Tsirkin 	return ret;
1903eb62b74eSMichael S. Tsirkin }
1904eb62b74eSMichael S. Tsirkin 
vhost_scsi_set_features(struct vhost_scsi * vs,u64 features)1905eb62b74eSMichael S. Tsirkin static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
1906eb62b74eSMichael S. Tsirkin {
1907ea16c514SMichael S. Tsirkin 	struct vhost_virtqueue *vq;
1908ea16c514SMichael S. Tsirkin 	int i;
1909ea16c514SMichael S. Tsirkin 
1910eb62b74eSMichael S. Tsirkin 	if (features & ~VHOST_SCSI_FEATURES)
1911eb62b74eSMichael S. Tsirkin 		return -EOPNOTSUPP;
1912eb62b74eSMichael S. Tsirkin 
1913eb62b74eSMichael S. Tsirkin 	mutex_lock(&vs->dev.mutex);
1914eb62b74eSMichael S. Tsirkin 	if ((features & (1 << VHOST_F_LOG_ALL)) &&
1915eb62b74eSMichael S. Tsirkin 	    !vhost_log_access_ok(&vs->dev)) {
1916eb62b74eSMichael S. Tsirkin 		mutex_unlock(&vs->dev.mutex);
1917eb62b74eSMichael S. Tsirkin 		return -EFAULT;
1918eb62b74eSMichael S. Tsirkin 	}
1919ea16c514SMichael S. Tsirkin 
1920f49c2226SMike Christie 	for (i = 0; i < vs->dev.nvqs; i++) {
1921ea16c514SMichael S. Tsirkin 		vq = &vs->vqs[i].vq;
1922ea16c514SMichael S. Tsirkin 		mutex_lock(&vq->mutex);
1923ea16c514SMichael S. Tsirkin 		vq->acked_features = features;
1924ea16c514SMichael S. Tsirkin 		mutex_unlock(&vq->mutex);
1925ea16c514SMichael S. Tsirkin 	}
1926eb62b74eSMichael S. Tsirkin 	mutex_unlock(&vs->dev.mutex);
1927eb62b74eSMichael S. Tsirkin 	return 0;
1928eb62b74eSMichael S. Tsirkin }
1929eb62b74eSMichael S. Tsirkin 
vhost_scsi_open(struct inode * inode,struct file * f)1930eb62b74eSMichael S. Tsirkin static int vhost_scsi_open(struct inode *inode, struct file *f)
1931eb62b74eSMichael S. Tsirkin {
193248ae70ddSMike Christie 	struct vhost_scsi_virtqueue *svq;
1933c7289312SAsias He 	struct vhost_scsi *vs;
1934eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue **vqs;
1935f49c2226SMike Christie 	int r = -ENOMEM, i, nvqs = vhost_scsi_max_io_vqs;
1936eb62b74eSMichael S. Tsirkin 
1937489084ddSDongli Zhang 	vs = kvzalloc(sizeof(*vs), GFP_KERNEL);
1938c7289312SAsias He 	if (!vs)
1939595cb754SMichael S. Tsirkin 		goto err_vs;
1940eb62b74eSMichael S. Tsirkin 
1941f49c2226SMike Christie 	if (nvqs > VHOST_SCSI_MAX_IO_VQ) {
1942f49c2226SMike Christie 		pr_err("Invalid max_io_vqs of %d. Using %d.\n", nvqs,
1943f49c2226SMike Christie 		       VHOST_SCSI_MAX_IO_VQ);
1944f49c2226SMike Christie 		nvqs = VHOST_SCSI_MAX_IO_VQ;
1945f49c2226SMike Christie 	} else if (nvqs == 0) {
1946f49c2226SMike Christie 		pr_err("Invalid max_io_vqs of %d. Using 1.\n", nvqs);
1947f49c2226SMike Christie 		nvqs = 1;
1948f49c2226SMike Christie 	}
1949f49c2226SMike Christie 	nvqs += VHOST_SCSI_VQ_IO;
1950f49c2226SMike Christie 
1951f49c2226SMike Christie 	vs->old_inflight = kmalloc_array(nvqs, sizeof(*vs->old_inflight),
1952f49c2226SMike Christie 					 GFP_KERNEL | __GFP_ZERO);
1953f49c2226SMike Christie 	if (!vs->old_inflight)
1954f49c2226SMike Christie 		goto err_inflight;
1955f49c2226SMike Christie 
1956f49c2226SMike Christie 	vs->vqs = kmalloc_array(nvqs, sizeof(*vs->vqs),
1957f49c2226SMike Christie 				GFP_KERNEL | __GFP_ZERO);
1958f49c2226SMike Christie 	if (!vs->vqs)
1959595cb754SMichael S. Tsirkin 		goto err_vqs;
1960eb62b74eSMichael S. Tsirkin 
1961f49c2226SMike Christie 	vqs = kmalloc_array(nvqs, sizeof(*vqs), GFP_KERNEL);
1962f49c2226SMike Christie 	if (!vqs)
1963f49c2226SMike Christie 		goto err_local_vqs;
1964f49c2226SMike Christie 
19651a1ff825SNicholas Bellinger 	vhost_work_init(&vs->vs_event_work, vhost_scsi_evt_work);
1966eb62b74eSMichael S. Tsirkin 
1967c7289312SAsias He 	vs->vs_events_nr = 0;
1968c7289312SAsias He 	vs->vs_events_missed = false;
1969eb62b74eSMichael S. Tsirkin 
1970c7289312SAsias He 	vqs[VHOST_SCSI_VQ_CTL] = &vs->vqs[VHOST_SCSI_VQ_CTL].vq;
1971c7289312SAsias He 	vqs[VHOST_SCSI_VQ_EVT] = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
1972c7289312SAsias He 	vs->vqs[VHOST_SCSI_VQ_CTL].vq.handle_kick = vhost_scsi_ctl_handle_kick;
1973c7289312SAsias He 	vs->vqs[VHOST_SCSI_VQ_EVT].vq.handle_kick = vhost_scsi_evt_handle_kick;
1974f49c2226SMike Christie 	for (i = VHOST_SCSI_VQ_IO; i < nvqs; i++) {
197548ae70ddSMike Christie 		svq = &vs->vqs[i];
197648ae70ddSMike Christie 
197748ae70ddSMike Christie 		vqs[i] = &svq->vq;
197848ae70ddSMike Christie 		svq->vs = vs;
197948ae70ddSMike Christie 		init_llist_head(&svq->completion_list);
198048ae70ddSMike Christie 		vhost_work_init(&svq->completion_work,
198148ae70ddSMike Christie 				vhost_scsi_complete_cmd_work);
198248ae70ddSMike Christie 		svq->vq.handle_kick = vhost_scsi_handle_kick;
1983eb62b74eSMichael S. Tsirkin 	}
1984f49c2226SMike Christie 	vhost_dev_init(&vs->dev, vqs, nvqs, UIO_MAXIOV,
198501fcb1cbSJason Wang 		       VHOST_SCSI_WEIGHT, 0, true, NULL);
1986eb62b74eSMichael S. Tsirkin 
19871a1ff825SNicholas Bellinger 	vhost_scsi_init_inflight(vs, NULL);
1988eb62b74eSMichael S. Tsirkin 
1989c7289312SAsias He 	f->private_data = vs;
1990eb62b74eSMichael S. Tsirkin 	return 0;
1991595cb754SMichael S. Tsirkin 
1992f49c2226SMike Christie err_local_vqs:
1993f49c2226SMike Christie 	kfree(vs->vqs);
1994595cb754SMichael S. Tsirkin err_vqs:
1995f49c2226SMike Christie 	kfree(vs->old_inflight);
1996f49c2226SMike Christie err_inflight:
199768404441SMichael S. Tsirkin 	kvfree(vs);
1998595cb754SMichael S. Tsirkin err_vs:
1999595cb754SMichael S. Tsirkin 	return r;
2000eb62b74eSMichael S. Tsirkin }
2001eb62b74eSMichael S. Tsirkin 
vhost_scsi_release(struct inode * inode,struct file * f)2002eb62b74eSMichael S. Tsirkin static int vhost_scsi_release(struct inode *inode, struct file *f)
2003eb62b74eSMichael S. Tsirkin {
2004c7289312SAsias He 	struct vhost_scsi *vs = f->private_data;
2005eb62b74eSMichael S. Tsirkin 	struct vhost_scsi_target t;
2006eb62b74eSMichael S. Tsirkin 
2007c7289312SAsias He 	mutex_lock(&vs->dev.mutex);
2008c7289312SAsias He 	memcpy(t.vhost_wwpn, vs->vs_vhost_wwpn, sizeof(t.vhost_wwpn));
2009c7289312SAsias He 	mutex_unlock(&vs->dev.mutex);
2010c7289312SAsias He 	vhost_scsi_clear_endpoint(vs, &t);
2011c7289312SAsias He 	vhost_dev_stop(&vs->dev);
2012f6f93f75S夷则(Caspar) 	vhost_dev_cleanup(&vs->dev);
2013c7289312SAsias He 	kfree(vs->dev.vqs);
2014f49c2226SMike Christie 	kfree(vs->vqs);
2015f49c2226SMike Christie 	kfree(vs->old_inflight);
201668404441SMichael S. Tsirkin 	kvfree(vs);
2017eb62b74eSMichael S. Tsirkin 	return 0;
2018eb62b74eSMichael S. Tsirkin }
2019eb62b74eSMichael S. Tsirkin 
2020683bd967SAsias He static long
vhost_scsi_ioctl(struct file * f,unsigned int ioctl,unsigned long arg)2021683bd967SAsias He vhost_scsi_ioctl(struct file *f,
2022683bd967SAsias He 		 unsigned int ioctl,
2023eb62b74eSMichael S. Tsirkin 		 unsigned long arg)
2024eb62b74eSMichael S. Tsirkin {
2025eb62b74eSMichael S. Tsirkin 	struct vhost_scsi *vs = f->private_data;
2026eb62b74eSMichael S. Tsirkin 	struct vhost_scsi_target backend;
2027eb62b74eSMichael S. Tsirkin 	void __user *argp = (void __user *)arg;
2028eb62b74eSMichael S. Tsirkin 	u64 __user *featurep = argp;
2029eb62b74eSMichael S. Tsirkin 	u32 __user *eventsp = argp;
2030eb62b74eSMichael S. Tsirkin 	u32 events_missed;
2031eb62b74eSMichael S. Tsirkin 	u64 features;
2032eb62b74eSMichael S. Tsirkin 	int r, abi_version = VHOST_SCSI_ABI_VERSION;
2033eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
2034eb62b74eSMichael S. Tsirkin 
2035eb62b74eSMichael S. Tsirkin 	switch (ioctl) {
2036eb62b74eSMichael S. Tsirkin 	case VHOST_SCSI_SET_ENDPOINT:
2037eb62b74eSMichael S. Tsirkin 		if (copy_from_user(&backend, argp, sizeof backend))
2038eb62b74eSMichael S. Tsirkin 			return -EFAULT;
2039eb62b74eSMichael S. Tsirkin 		if (backend.reserved != 0)
2040eb62b74eSMichael S. Tsirkin 			return -EOPNOTSUPP;
2041eb62b74eSMichael S. Tsirkin 
2042eb62b74eSMichael S. Tsirkin 		return vhost_scsi_set_endpoint(vs, &backend);
2043eb62b74eSMichael S. Tsirkin 	case VHOST_SCSI_CLEAR_ENDPOINT:
2044eb62b74eSMichael S. Tsirkin 		if (copy_from_user(&backend, argp, sizeof backend))
2045eb62b74eSMichael S. Tsirkin 			return -EFAULT;
2046eb62b74eSMichael S. Tsirkin 		if (backend.reserved != 0)
2047eb62b74eSMichael S. Tsirkin 			return -EOPNOTSUPP;
2048eb62b74eSMichael S. Tsirkin 
2049eb62b74eSMichael S. Tsirkin 		return vhost_scsi_clear_endpoint(vs, &backend);
2050eb62b74eSMichael S. Tsirkin 	case VHOST_SCSI_GET_ABI_VERSION:
2051eb62b74eSMichael S. Tsirkin 		if (copy_to_user(argp, &abi_version, sizeof abi_version))
2052eb62b74eSMichael S. Tsirkin 			return -EFAULT;
2053eb62b74eSMichael S. Tsirkin 		return 0;
2054eb62b74eSMichael S. Tsirkin 	case VHOST_SCSI_SET_EVENTS_MISSED:
2055eb62b74eSMichael S. Tsirkin 		if (get_user(events_missed, eventsp))
2056eb62b74eSMichael S. Tsirkin 			return -EFAULT;
2057eb62b74eSMichael S. Tsirkin 		mutex_lock(&vq->mutex);
2058eb62b74eSMichael S. Tsirkin 		vs->vs_events_missed = events_missed;
2059eb62b74eSMichael S. Tsirkin 		mutex_unlock(&vq->mutex);
2060eb62b74eSMichael S. Tsirkin 		return 0;
2061eb62b74eSMichael S. Tsirkin 	case VHOST_SCSI_GET_EVENTS_MISSED:
2062eb62b74eSMichael S. Tsirkin 		mutex_lock(&vq->mutex);
2063eb62b74eSMichael S. Tsirkin 		events_missed = vs->vs_events_missed;
2064eb62b74eSMichael S. Tsirkin 		mutex_unlock(&vq->mutex);
2065eb62b74eSMichael S. Tsirkin 		if (put_user(events_missed, eventsp))
2066eb62b74eSMichael S. Tsirkin 			return -EFAULT;
2067eb62b74eSMichael S. Tsirkin 		return 0;
2068eb62b74eSMichael S. Tsirkin 	case VHOST_GET_FEATURES:
2069eb62b74eSMichael S. Tsirkin 		features = VHOST_SCSI_FEATURES;
2070eb62b74eSMichael S. Tsirkin 		if (copy_to_user(featurep, &features, sizeof features))
2071eb62b74eSMichael S. Tsirkin 			return -EFAULT;
2072eb62b74eSMichael S. Tsirkin 		return 0;
2073eb62b74eSMichael S. Tsirkin 	case VHOST_SET_FEATURES:
2074eb62b74eSMichael S. Tsirkin 		if (copy_from_user(&features, featurep, sizeof features))
2075eb62b74eSMichael S. Tsirkin 			return -EFAULT;
2076eb62b74eSMichael S. Tsirkin 		return vhost_scsi_set_features(vs, features);
2077d74b55e6SMike Christie 	case VHOST_NEW_WORKER:
2078d74b55e6SMike Christie 	case VHOST_FREE_WORKER:
2079d74b55e6SMike Christie 	case VHOST_ATTACH_VRING_WORKER:
2080d74b55e6SMike Christie 	case VHOST_GET_VRING_WORKER:
2081d74b55e6SMike Christie 		mutex_lock(&vs->dev.mutex);
2082d74b55e6SMike Christie 		r = vhost_worker_ioctl(&vs->dev, ioctl, argp);
2083d74b55e6SMike Christie 		mutex_unlock(&vs->dev.mutex);
2084d74b55e6SMike Christie 		return r;
2085eb62b74eSMichael S. Tsirkin 	default:
2086eb62b74eSMichael S. Tsirkin 		mutex_lock(&vs->dev.mutex);
2087eb62b74eSMichael S. Tsirkin 		r = vhost_dev_ioctl(&vs->dev, ioctl, argp);
2088eb62b74eSMichael S. Tsirkin 		/* TODO: flush backend after dev ioctl. */
2089eb62b74eSMichael S. Tsirkin 		if (r == -ENOIOCTLCMD)
2090eb62b74eSMichael S. Tsirkin 			r = vhost_vring_ioctl(&vs->dev, ioctl, argp);
2091eb62b74eSMichael S. Tsirkin 		mutex_unlock(&vs->dev.mutex);
2092eb62b74eSMichael S. Tsirkin 		return r;
2093eb62b74eSMichael S. Tsirkin 	}
2094eb62b74eSMichael S. Tsirkin }
2095eb62b74eSMichael S. Tsirkin 
2096eb62b74eSMichael S. Tsirkin static const struct file_operations vhost_scsi_fops = {
2097eb62b74eSMichael S. Tsirkin 	.owner          = THIS_MODULE,
2098eb62b74eSMichael S. Tsirkin 	.release        = vhost_scsi_release,
2099eb62b74eSMichael S. Tsirkin 	.unlocked_ioctl = vhost_scsi_ioctl,
2100407e9ef7SArnd Bergmann 	.compat_ioctl	= compat_ptr_ioctl,
2101eb62b74eSMichael S. Tsirkin 	.open           = vhost_scsi_open,
2102eb62b74eSMichael S. Tsirkin 	.llseek		= noop_llseek,
2103eb62b74eSMichael S. Tsirkin };
2104eb62b74eSMichael S. Tsirkin 
2105eb62b74eSMichael S. Tsirkin static struct miscdevice vhost_scsi_misc = {
2106eb62b74eSMichael S. Tsirkin 	MISC_DYNAMIC_MINOR,
2107eb62b74eSMichael S. Tsirkin 	"vhost-scsi",
2108eb62b74eSMichael S. Tsirkin 	&vhost_scsi_fops,
2109eb62b74eSMichael S. Tsirkin };
2110eb62b74eSMichael S. Tsirkin 
vhost_scsi_register(void)2111eb62b74eSMichael S. Tsirkin static int __init vhost_scsi_register(void)
2112eb62b74eSMichael S. Tsirkin {
2113eb62b74eSMichael S. Tsirkin 	return misc_register(&vhost_scsi_misc);
2114eb62b74eSMichael S. Tsirkin }
2115eb62b74eSMichael S. Tsirkin 
vhost_scsi_deregister(void)2116f368ed60SGreg Kroah-Hartman static void vhost_scsi_deregister(void)
2117eb62b74eSMichael S. Tsirkin {
2118f368ed60SGreg Kroah-Hartman 	misc_deregister(&vhost_scsi_misc);
2119eb62b74eSMichael S. Tsirkin }
2120eb62b74eSMichael S. Tsirkin 
vhost_scsi_dump_proto_id(struct vhost_scsi_tport * tport)21211a1ff825SNicholas Bellinger static char *vhost_scsi_dump_proto_id(struct vhost_scsi_tport *tport)
2122eb62b74eSMichael S. Tsirkin {
2123eb62b74eSMichael S. Tsirkin 	switch (tport->tport_proto_id) {
2124eb62b74eSMichael S. Tsirkin 	case SCSI_PROTOCOL_SAS:
2125eb62b74eSMichael S. Tsirkin 		return "SAS";
2126eb62b74eSMichael S. Tsirkin 	case SCSI_PROTOCOL_FCP:
2127eb62b74eSMichael S. Tsirkin 		return "FCP";
2128eb62b74eSMichael S. Tsirkin 	case SCSI_PROTOCOL_ISCSI:
2129eb62b74eSMichael S. Tsirkin 		return "iSCSI";
2130eb62b74eSMichael S. Tsirkin 	default:
2131eb62b74eSMichael S. Tsirkin 		break;
2132eb62b74eSMichael S. Tsirkin 	}
2133eb62b74eSMichael S. Tsirkin 
2134eb62b74eSMichael S. Tsirkin 	return "Unknown";
2135eb62b74eSMichael S. Tsirkin }
2136eb62b74eSMichael S. Tsirkin 
2137683bd967SAsias He static void
vhost_scsi_do_plug(struct vhost_scsi_tpg * tpg,struct se_lun * lun,bool plug)21381a1ff825SNicholas Bellinger vhost_scsi_do_plug(struct vhost_scsi_tpg *tpg,
2139eb62b74eSMichael S. Tsirkin 		  struct se_lun *lun, bool plug)
2140eb62b74eSMichael S. Tsirkin {
2141eb62b74eSMichael S. Tsirkin 
2142eb62b74eSMichael S. Tsirkin 	struct vhost_scsi *vs = tpg->vhost_scsi;
2143eb62b74eSMichael S. Tsirkin 	struct vhost_virtqueue *vq;
2144eb62b74eSMichael S. Tsirkin 	u32 reason;
2145eb62b74eSMichael S. Tsirkin 
2146eb62b74eSMichael S. Tsirkin 	if (!vs)
2147eb62b74eSMichael S. Tsirkin 		return;
2148eb62b74eSMichael S. Tsirkin 
2149eb62b74eSMichael S. Tsirkin 	if (plug)
2150eb62b74eSMichael S. Tsirkin 		reason = VIRTIO_SCSI_EVT_RESET_RESCAN;
2151eb62b74eSMichael S. Tsirkin 	else
2152eb62b74eSMichael S. Tsirkin 		reason = VIRTIO_SCSI_EVT_RESET_REMOVED;
2153eb62b74eSMichael S. Tsirkin 
2154eb62b74eSMichael S. Tsirkin 	vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
2155eb62b74eSMichael S. Tsirkin 	mutex_lock(&vq->mutex);
2156ced9eb37SMike Christie 	/*
2157ced9eb37SMike Christie 	 * We can't queue events if the backend has been cleared, because
2158ced9eb37SMike Christie 	 * we could end up queueing an event after the flush.
2159ced9eb37SMike Christie 	 */
2160ced9eb37SMike Christie 	if (!vhost_vq_get_backend(vq))
2161ced9eb37SMike Christie 		goto unlock;
2162ced9eb37SMike Christie 
2163ea16c514SMichael S. Tsirkin 	if (vhost_has_feature(vq, VIRTIO_SCSI_F_HOTPLUG))
216478af31ccSMike Christie 		vhost_scsi_send_evt(vs, vq, tpg, lun,
2165eb62b74eSMichael S. Tsirkin 				   VIRTIO_SCSI_T_TRANSPORT_RESET, reason);
2166ced9eb37SMike Christie unlock:
2167eb62b74eSMichael S. Tsirkin 	mutex_unlock(&vq->mutex);
2168eb62b74eSMichael S. Tsirkin }
2169eb62b74eSMichael S. Tsirkin 
vhost_scsi_hotplug(struct vhost_scsi_tpg * tpg,struct se_lun * lun)21701a1ff825SNicholas Bellinger static void vhost_scsi_hotplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun)
2171eb62b74eSMichael S. Tsirkin {
21721a1ff825SNicholas Bellinger 	vhost_scsi_do_plug(tpg, lun, true);
2173eb62b74eSMichael S. Tsirkin }
2174eb62b74eSMichael S. Tsirkin 
vhost_scsi_hotunplug(struct vhost_scsi_tpg * tpg,struct se_lun * lun)21751a1ff825SNicholas Bellinger static void vhost_scsi_hotunplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun)
2176eb62b74eSMichael S. Tsirkin {
21771a1ff825SNicholas Bellinger 	vhost_scsi_do_plug(tpg, lun, false);
2178eb62b74eSMichael S. Tsirkin }
2179eb62b74eSMichael S. Tsirkin 
vhost_scsi_port_link(struct se_portal_group * se_tpg,struct se_lun * lun)21801a1ff825SNicholas Bellinger static int vhost_scsi_port_link(struct se_portal_group *se_tpg,
2181eb62b74eSMichael S. Tsirkin 			       struct se_lun *lun)
2182eb62b74eSMichael S. Tsirkin {
21831a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
21841a1ff825SNicholas Bellinger 				struct vhost_scsi_tpg, se_tpg);
2185eb62b74eSMichael S. Tsirkin 
218698718312SAsias He 	mutex_lock(&tpg->tv_tpg_mutex);
218798718312SAsias He 	tpg->tv_tpg_port_count++;
21881a1ff825SNicholas Bellinger 	vhost_scsi_hotplug(tpg, lun);
2189f5ed6f9eSMike Christie 	mutex_unlock(&tpg->tv_tpg_mutex);
2190eb62b74eSMichael S. Tsirkin 
2191eb62b74eSMichael S. Tsirkin 	return 0;
2192eb62b74eSMichael S. Tsirkin }
2193eb62b74eSMichael S. Tsirkin 
vhost_scsi_port_unlink(struct se_portal_group * se_tpg,struct se_lun * lun)21941a1ff825SNicholas Bellinger static void vhost_scsi_port_unlink(struct se_portal_group *se_tpg,
2195eb62b74eSMichael S. Tsirkin 				  struct se_lun *lun)
2196eb62b74eSMichael S. Tsirkin {
21971a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
21981a1ff825SNicholas Bellinger 				struct vhost_scsi_tpg, se_tpg);
2199eb62b74eSMichael S. Tsirkin 
220098718312SAsias He 	mutex_lock(&tpg->tv_tpg_mutex);
220198718312SAsias He 	tpg->tv_tpg_port_count--;
22021a1ff825SNicholas Bellinger 	vhost_scsi_hotunplug(tpg, lun);
2203f5ed6f9eSMike Christie 	mutex_unlock(&tpg->tv_tpg_mutex);
2204eb62b74eSMichael S. Tsirkin }
2205eb62b74eSMichael S. Tsirkin 
vhost_scsi_tpg_attrib_fabric_prot_type_store(struct config_item * item,const char * page,size_t count)22062eafd729SChristoph Hellwig static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_store(
22072eafd729SChristoph Hellwig 		struct config_item *item, const char *page, size_t count)
2208b1d75fe5SNicholas Bellinger {
22092eafd729SChristoph Hellwig 	struct se_portal_group *se_tpg = attrib_to_tpg(item);
2210b1d75fe5SNicholas Bellinger 	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
2211b1d75fe5SNicholas Bellinger 				struct vhost_scsi_tpg, se_tpg);
2212b1d75fe5SNicholas Bellinger 	unsigned long val;
2213b1d75fe5SNicholas Bellinger 	int ret = kstrtoul(page, 0, &val);
2214b1d75fe5SNicholas Bellinger 
2215b1d75fe5SNicholas Bellinger 	if (ret) {
2216b1d75fe5SNicholas Bellinger 		pr_err("kstrtoul() returned %d for fabric_prot_type\n", ret);
2217b1d75fe5SNicholas Bellinger 		return ret;
2218b1d75fe5SNicholas Bellinger 	}
2219b1d75fe5SNicholas Bellinger 	if (val != 0 && val != 1 && val != 3) {
2220b1d75fe5SNicholas Bellinger 		pr_err("Invalid vhost_scsi fabric_prot_type: %lu\n", val);
2221b1d75fe5SNicholas Bellinger 		return -EINVAL;
2222b1d75fe5SNicholas Bellinger 	}
2223b1d75fe5SNicholas Bellinger 	tpg->tv_fabric_prot_type = val;
2224b1d75fe5SNicholas Bellinger 
2225b1d75fe5SNicholas Bellinger 	return count;
2226b1d75fe5SNicholas Bellinger }
2227b1d75fe5SNicholas Bellinger 
vhost_scsi_tpg_attrib_fabric_prot_type_show(struct config_item * item,char * page)22282eafd729SChristoph Hellwig static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_show(
22292eafd729SChristoph Hellwig 		struct config_item *item, char *page)
2230b1d75fe5SNicholas Bellinger {
22312eafd729SChristoph Hellwig 	struct se_portal_group *se_tpg = attrib_to_tpg(item);
2232b1d75fe5SNicholas Bellinger 	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
2233b1d75fe5SNicholas Bellinger 				struct vhost_scsi_tpg, se_tpg);
2234b1d75fe5SNicholas Bellinger 
2235b3d4f02eSBo Liu 	return sysfs_emit(page, "%d\n", tpg->tv_fabric_prot_type);
2236b1d75fe5SNicholas Bellinger }
22372eafd729SChristoph Hellwig 
22382eafd729SChristoph Hellwig CONFIGFS_ATTR(vhost_scsi_tpg_attrib_, fabric_prot_type);
2239b1d75fe5SNicholas Bellinger 
2240b1d75fe5SNicholas Bellinger static struct configfs_attribute *vhost_scsi_tpg_attrib_attrs[] = {
22412eafd729SChristoph Hellwig 	&vhost_scsi_tpg_attrib_attr_fabric_prot_type,
2242b1d75fe5SNicholas Bellinger 	NULL,
2243b1d75fe5SNicholas Bellinger };
2244b1d75fe5SNicholas Bellinger 
vhost_scsi_make_nexus(struct vhost_scsi_tpg * tpg,const char * name)22451a1ff825SNicholas Bellinger static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
2246eb62b74eSMichael S. Tsirkin 				const char *name)
2247eb62b74eSMichael S. Tsirkin {
22481a1ff825SNicholas Bellinger 	struct vhost_scsi_nexus *tv_nexus;
2249eb62b74eSMichael S. Tsirkin 
225098718312SAsias He 	mutex_lock(&tpg->tv_tpg_mutex);
225198718312SAsias He 	if (tpg->tpg_nexus) {
225298718312SAsias He 		mutex_unlock(&tpg->tv_tpg_mutex);
225398718312SAsias He 		pr_debug("tpg->tpg_nexus already exists\n");
2254eb62b74eSMichael S. Tsirkin 		return -EEXIST;
2255eb62b74eSMichael S. Tsirkin 	}
2256eb62b74eSMichael S. Tsirkin 
2257473f0b15SMarkus Elfring 	tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
2258eb62b74eSMichael S. Tsirkin 	if (!tv_nexus) {
225998718312SAsias He 		mutex_unlock(&tpg->tv_tpg_mutex);
22601a1ff825SNicholas Bellinger 		pr_err("Unable to allocate struct vhost_scsi_nexus\n");
2261eb62b74eSMichael S. Tsirkin 		return -ENOMEM;
2262eb62b74eSMichael S. Tsirkin 	}
2263eb62b74eSMichael S. Tsirkin 	/*
226465ea7898SNicholas Bellinger 	 * Since we are running in 'demo mode' this call with generate a
226565ea7898SNicholas Bellinger 	 * struct se_node_acl for the vhost_scsi struct se_portal_group with
226665ea7898SNicholas Bellinger 	 * the SCSI Initiator port name of the passed configfs group 'name'.
2267eb62b74eSMichael S. Tsirkin 	 */
226825b98b64SMike Christie 	tv_nexus->tvn_se_sess = target_setup_session(&tpg->se_tpg, 0, 0,
226965ea7898SNicholas Bellinger 					TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS,
227025b98b64SMike Christie 					(unsigned char *)name, tv_nexus, NULL);
2271eb62b74eSMichael S. Tsirkin 	if (IS_ERR(tv_nexus->tvn_se_sess)) {
227298718312SAsias He 		mutex_unlock(&tpg->tv_tpg_mutex);
2273eb62b74eSMichael S. Tsirkin 		kfree(tv_nexus);
2274eb62b74eSMichael S. Tsirkin 		return -ENOMEM;
2275eb62b74eSMichael S. Tsirkin 	}
227698718312SAsias He 	tpg->tpg_nexus = tv_nexus;
2277eb62b74eSMichael S. Tsirkin 
227898718312SAsias He 	mutex_unlock(&tpg->tv_tpg_mutex);
2279eb62b74eSMichael S. Tsirkin 	return 0;
2280eb62b74eSMichael S. Tsirkin }
2281eb62b74eSMichael S. Tsirkin 
vhost_scsi_drop_nexus(struct vhost_scsi_tpg * tpg)22821a1ff825SNicholas Bellinger static int vhost_scsi_drop_nexus(struct vhost_scsi_tpg *tpg)
2283eb62b74eSMichael S. Tsirkin {
2284eb62b74eSMichael S. Tsirkin 	struct se_session *se_sess;
22851a1ff825SNicholas Bellinger 	struct vhost_scsi_nexus *tv_nexus;
2286eb62b74eSMichael S. Tsirkin 
2287eb62b74eSMichael S. Tsirkin 	mutex_lock(&tpg->tv_tpg_mutex);
2288eb62b74eSMichael S. Tsirkin 	tv_nexus = tpg->tpg_nexus;
2289eb62b74eSMichael S. Tsirkin 	if (!tv_nexus) {
2290eb62b74eSMichael S. Tsirkin 		mutex_unlock(&tpg->tv_tpg_mutex);
2291eb62b74eSMichael S. Tsirkin 		return -ENODEV;
2292eb62b74eSMichael S. Tsirkin 	}
2293eb62b74eSMichael S. Tsirkin 
2294eb62b74eSMichael S. Tsirkin 	se_sess = tv_nexus->tvn_se_sess;
2295eb62b74eSMichael S. Tsirkin 	if (!se_sess) {
2296eb62b74eSMichael S. Tsirkin 		mutex_unlock(&tpg->tv_tpg_mutex);
2297eb62b74eSMichael S. Tsirkin 		return -ENODEV;
2298eb62b74eSMichael S. Tsirkin 	}
2299eb62b74eSMichael S. Tsirkin 
2300eb62b74eSMichael S. Tsirkin 	if (tpg->tv_tpg_port_count != 0) {
2301eb62b74eSMichael S. Tsirkin 		mutex_unlock(&tpg->tv_tpg_mutex);
2302eb62b74eSMichael S. Tsirkin 		pr_err("Unable to remove TCM_vhost I_T Nexus with"
2303eb62b74eSMichael S. Tsirkin 			" active TPG port count: %d\n",
2304eb62b74eSMichael S. Tsirkin 			tpg->tv_tpg_port_count);
2305eb62b74eSMichael S. Tsirkin 		return -EBUSY;
2306eb62b74eSMichael S. Tsirkin 	}
2307eb62b74eSMichael S. Tsirkin 
2308eb62b74eSMichael S. Tsirkin 	if (tpg->tv_tpg_vhost_count != 0) {
2309eb62b74eSMichael S. Tsirkin 		mutex_unlock(&tpg->tv_tpg_mutex);
2310eb62b74eSMichael S. Tsirkin 		pr_err("Unable to remove TCM_vhost I_T Nexus with"
2311eb62b74eSMichael S. Tsirkin 			" active TPG vhost count: %d\n",
2312eb62b74eSMichael S. Tsirkin 			tpg->tv_tpg_vhost_count);
2313eb62b74eSMichael S. Tsirkin 		return -EBUSY;
2314eb62b74eSMichael S. Tsirkin 	}
2315eb62b74eSMichael S. Tsirkin 
2316eb62b74eSMichael S. Tsirkin 	pr_debug("TCM_vhost_ConfigFS: Removing I_T Nexus to emulated"
23171a1ff825SNicholas Bellinger 		" %s Initiator Port: %s\n", vhost_scsi_dump_proto_id(tpg->tport),
2318eb62b74eSMichael S. Tsirkin 		tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
23193aee26b4SNicholas Bellinger 
2320eb62b74eSMichael S. Tsirkin 	/*
2321eb62b74eSMichael S. Tsirkin 	 * Release the SCSI I_T Nexus to the emulated vhost Target Port
2322eb62b74eSMichael S. Tsirkin 	 */
232325b88550SMike Christie 	target_remove_session(se_sess);
2324eb62b74eSMichael S. Tsirkin 	tpg->tpg_nexus = NULL;
2325eb62b74eSMichael S. Tsirkin 	mutex_unlock(&tpg->tv_tpg_mutex);
2326eb62b74eSMichael S. Tsirkin 
2327eb62b74eSMichael S. Tsirkin 	kfree(tv_nexus);
2328eb62b74eSMichael S. Tsirkin 	return 0;
2329eb62b74eSMichael S. Tsirkin }
2330eb62b74eSMichael S. Tsirkin 
vhost_scsi_tpg_nexus_show(struct config_item * item,char * page)23312eafd729SChristoph Hellwig static ssize_t vhost_scsi_tpg_nexus_show(struct config_item *item, char *page)
2332eb62b74eSMichael S. Tsirkin {
23332eafd729SChristoph Hellwig 	struct se_portal_group *se_tpg = to_tpg(item);
23341a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
23351a1ff825SNicholas Bellinger 				struct vhost_scsi_tpg, se_tpg);
23361a1ff825SNicholas Bellinger 	struct vhost_scsi_nexus *tv_nexus;
2337eb62b74eSMichael S. Tsirkin 	ssize_t ret;
2338eb62b74eSMichael S. Tsirkin 
233998718312SAsias He 	mutex_lock(&tpg->tv_tpg_mutex);
234098718312SAsias He 	tv_nexus = tpg->tpg_nexus;
2341eb62b74eSMichael S. Tsirkin 	if (!tv_nexus) {
234298718312SAsias He 		mutex_unlock(&tpg->tv_tpg_mutex);
2343eb62b74eSMichael S. Tsirkin 		return -ENODEV;
2344eb62b74eSMichael S. Tsirkin 	}
2345b3d4f02eSBo Liu 	ret = sysfs_emit(page, "%s\n",
2346eb62b74eSMichael S. Tsirkin 			tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
234798718312SAsias He 	mutex_unlock(&tpg->tv_tpg_mutex);
2348eb62b74eSMichael S. Tsirkin 
2349eb62b74eSMichael S. Tsirkin 	return ret;
2350eb62b74eSMichael S. Tsirkin }
2351eb62b74eSMichael S. Tsirkin 
vhost_scsi_tpg_nexus_store(struct config_item * item,const char * page,size_t count)23522eafd729SChristoph Hellwig static ssize_t vhost_scsi_tpg_nexus_store(struct config_item *item,
23532eafd729SChristoph Hellwig 		const char *page, size_t count)
2354eb62b74eSMichael S. Tsirkin {
23552eafd729SChristoph Hellwig 	struct se_portal_group *se_tpg = to_tpg(item);
23561a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
23571a1ff825SNicholas Bellinger 				struct vhost_scsi_tpg, se_tpg);
23581a1ff825SNicholas Bellinger 	struct vhost_scsi_tport *tport_wwn = tpg->tport;
23591a1ff825SNicholas Bellinger 	unsigned char i_port[VHOST_SCSI_NAMELEN], *ptr, *port_ptr;
2360eb62b74eSMichael S. Tsirkin 	int ret;
2361eb62b74eSMichael S. Tsirkin 	/*
2362eb62b74eSMichael S. Tsirkin 	 * Shutdown the active I_T nexus if 'NULL' is passed..
2363eb62b74eSMichael S. Tsirkin 	 */
2364eb62b74eSMichael S. Tsirkin 	if (!strncmp(page, "NULL", 4)) {
23651a1ff825SNicholas Bellinger 		ret = vhost_scsi_drop_nexus(tpg);
2366eb62b74eSMichael S. Tsirkin 		return (!ret) ? count : ret;
2367eb62b74eSMichael S. Tsirkin 	}
2368eb62b74eSMichael S. Tsirkin 	/*
2369eb62b74eSMichael S. Tsirkin 	 * Otherwise make sure the passed virtual Initiator port WWN matches
23701a1ff825SNicholas Bellinger 	 * the fabric protocol_id set in vhost_scsi_make_tport(), and call
23711a1ff825SNicholas Bellinger 	 * vhost_scsi_make_nexus().
2372eb62b74eSMichael S. Tsirkin 	 */
23731a1ff825SNicholas Bellinger 	if (strlen(page) >= VHOST_SCSI_NAMELEN) {
2374eb62b74eSMichael S. Tsirkin 		pr_err("Emulated NAA Sas Address: %s, exceeds"
23751a1ff825SNicholas Bellinger 				" max: %d\n", page, VHOST_SCSI_NAMELEN);
2376eb62b74eSMichael S. Tsirkin 		return -EINVAL;
2377eb62b74eSMichael S. Tsirkin 	}
23781a1ff825SNicholas Bellinger 	snprintf(&i_port[0], VHOST_SCSI_NAMELEN, "%s", page);
2379eb62b74eSMichael S. Tsirkin 
2380eb62b74eSMichael S. Tsirkin 	ptr = strstr(i_port, "naa.");
2381eb62b74eSMichael S. Tsirkin 	if (ptr) {
2382eb62b74eSMichael S. Tsirkin 		if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_SAS) {
2383eb62b74eSMichael S. Tsirkin 			pr_err("Passed SAS Initiator Port %s does not"
2384eb62b74eSMichael S. Tsirkin 				" match target port protoid: %s\n", i_port,
23851a1ff825SNicholas Bellinger 				vhost_scsi_dump_proto_id(tport_wwn));
2386eb62b74eSMichael S. Tsirkin 			return -EINVAL;
2387eb62b74eSMichael S. Tsirkin 		}
2388eb62b74eSMichael S. Tsirkin 		port_ptr = &i_port[0];
2389eb62b74eSMichael S. Tsirkin 		goto check_newline;
2390eb62b74eSMichael S. Tsirkin 	}
2391eb62b74eSMichael S. Tsirkin 	ptr = strstr(i_port, "fc.");
2392eb62b74eSMichael S. Tsirkin 	if (ptr) {
2393eb62b74eSMichael S. Tsirkin 		if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_FCP) {
2394eb62b74eSMichael S. Tsirkin 			pr_err("Passed FCP Initiator Port %s does not"
2395eb62b74eSMichael S. Tsirkin 				" match target port protoid: %s\n", i_port,
23961a1ff825SNicholas Bellinger 				vhost_scsi_dump_proto_id(tport_wwn));
2397eb62b74eSMichael S. Tsirkin 			return -EINVAL;
2398eb62b74eSMichael S. Tsirkin 		}
2399eb62b74eSMichael S. Tsirkin 		port_ptr = &i_port[3]; /* Skip over "fc." */
2400eb62b74eSMichael S. Tsirkin 		goto check_newline;
2401eb62b74eSMichael S. Tsirkin 	}
2402eb62b74eSMichael S. Tsirkin 	ptr = strstr(i_port, "iqn.");
2403eb62b74eSMichael S. Tsirkin 	if (ptr) {
2404eb62b74eSMichael S. Tsirkin 		if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_ISCSI) {
2405eb62b74eSMichael S. Tsirkin 			pr_err("Passed iSCSI Initiator Port %s does not"
2406eb62b74eSMichael S. Tsirkin 				" match target port protoid: %s\n", i_port,
24071a1ff825SNicholas Bellinger 				vhost_scsi_dump_proto_id(tport_wwn));
2408eb62b74eSMichael S. Tsirkin 			return -EINVAL;
2409eb62b74eSMichael S. Tsirkin 		}
2410eb62b74eSMichael S. Tsirkin 		port_ptr = &i_port[0];
2411eb62b74eSMichael S. Tsirkin 		goto check_newline;
2412eb62b74eSMichael S. Tsirkin 	}
2413eb62b74eSMichael S. Tsirkin 	pr_err("Unable to locate prefix for emulated Initiator Port:"
2414eb62b74eSMichael S. Tsirkin 			" %s\n", i_port);
2415eb62b74eSMichael S. Tsirkin 	return -EINVAL;
2416eb62b74eSMichael S. Tsirkin 	/*
2417eb62b74eSMichael S. Tsirkin 	 * Clear any trailing newline for the NAA WWN
2418eb62b74eSMichael S. Tsirkin 	 */
2419eb62b74eSMichael S. Tsirkin check_newline:
2420eb62b74eSMichael S. Tsirkin 	if (i_port[strlen(i_port)-1] == '\n')
2421eb62b74eSMichael S. Tsirkin 		i_port[strlen(i_port)-1] = '\0';
2422eb62b74eSMichael S. Tsirkin 
24231a1ff825SNicholas Bellinger 	ret = vhost_scsi_make_nexus(tpg, port_ptr);
2424eb62b74eSMichael S. Tsirkin 	if (ret < 0)
2425eb62b74eSMichael S. Tsirkin 		return ret;
2426eb62b74eSMichael S. Tsirkin 
2427eb62b74eSMichael S. Tsirkin 	return count;
2428eb62b74eSMichael S. Tsirkin }
2429eb62b74eSMichael S. Tsirkin 
24302eafd729SChristoph Hellwig CONFIGFS_ATTR(vhost_scsi_tpg_, nexus);
2431eb62b74eSMichael S. Tsirkin 
24321a1ff825SNicholas Bellinger static struct configfs_attribute *vhost_scsi_tpg_attrs[] = {
24332eafd729SChristoph Hellwig 	&vhost_scsi_tpg_attr_nexus,
2434eb62b74eSMichael S. Tsirkin 	NULL,
2435eb62b74eSMichael S. Tsirkin };
2436eb62b74eSMichael S. Tsirkin 
2437683bd967SAsias He static struct se_portal_group *
vhost_scsi_make_tpg(struct se_wwn * wwn,const char * name)2438aa090eabSBart Van Assche vhost_scsi_make_tpg(struct se_wwn *wwn, const char *name)
2439eb62b74eSMichael S. Tsirkin {
24401a1ff825SNicholas Bellinger 	struct vhost_scsi_tport *tport = container_of(wwn,
24411a1ff825SNicholas Bellinger 			struct vhost_scsi_tport, tport_wwn);
2442eb62b74eSMichael S. Tsirkin 
24431a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg *tpg;
244459c816c1SDan Carpenter 	u16 tpgt;
2445eb62b74eSMichael S. Tsirkin 	int ret;
2446eb62b74eSMichael S. Tsirkin 
2447eb62b74eSMichael S. Tsirkin 	if (strstr(name, "tpgt_") != name)
2448eb62b74eSMichael S. Tsirkin 		return ERR_PTR(-EINVAL);
244959c816c1SDan Carpenter 	if (kstrtou16(name + 5, 10, &tpgt) || tpgt >= VHOST_SCSI_MAX_TARGET)
2450eb62b74eSMichael S. Tsirkin 		return ERR_PTR(-EINVAL);
2451eb62b74eSMichael S. Tsirkin 
2452473f0b15SMarkus Elfring 	tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
2453eb62b74eSMichael S. Tsirkin 	if (!tpg) {
24541a1ff825SNicholas Bellinger 		pr_err("Unable to allocate struct vhost_scsi_tpg");
2455eb62b74eSMichael S. Tsirkin 		return ERR_PTR(-ENOMEM);
2456eb62b74eSMichael S. Tsirkin 	}
2457eb62b74eSMichael S. Tsirkin 	mutex_init(&tpg->tv_tpg_mutex);
2458eb62b74eSMichael S. Tsirkin 	INIT_LIST_HEAD(&tpg->tv_tpg_list);
2459eb62b74eSMichael S. Tsirkin 	tpg->tport = tport;
2460eb62b74eSMichael S. Tsirkin 	tpg->tport_tpgt = tpgt;
2461eb62b74eSMichael S. Tsirkin 
2462bc0c94b1SNicholas Bellinger 	ret = core_tpg_register(wwn, &tpg->se_tpg, tport->tport_proto_id);
2463eb62b74eSMichael S. Tsirkin 	if (ret < 0) {
2464eb62b74eSMichael S. Tsirkin 		kfree(tpg);
2465eb62b74eSMichael S. Tsirkin 		return NULL;
2466eb62b74eSMichael S. Tsirkin 	}
24671a1ff825SNicholas Bellinger 	mutex_lock(&vhost_scsi_mutex);
24681a1ff825SNicholas Bellinger 	list_add_tail(&tpg->tv_tpg_list, &vhost_scsi_list);
24691a1ff825SNicholas Bellinger 	mutex_unlock(&vhost_scsi_mutex);
2470eb62b74eSMichael S. Tsirkin 
2471eb62b74eSMichael S. Tsirkin 	return &tpg->se_tpg;
2472eb62b74eSMichael S. Tsirkin }
2473eb62b74eSMichael S. Tsirkin 
vhost_scsi_drop_tpg(struct se_portal_group * se_tpg)24741a1ff825SNicholas Bellinger static void vhost_scsi_drop_tpg(struct se_portal_group *se_tpg)
2475eb62b74eSMichael S. Tsirkin {
24761a1ff825SNicholas Bellinger 	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
24771a1ff825SNicholas Bellinger 				struct vhost_scsi_tpg, se_tpg);
2478eb62b74eSMichael S. Tsirkin 
24791a1ff825SNicholas Bellinger 	mutex_lock(&vhost_scsi_mutex);
2480eb62b74eSMichael S. Tsirkin 	list_del(&tpg->tv_tpg_list);
24811a1ff825SNicholas Bellinger 	mutex_unlock(&vhost_scsi_mutex);
2482eb62b74eSMichael S. Tsirkin 	/*
2483eb62b74eSMichael S. Tsirkin 	 * Release the virtual I_T Nexus for this vhost TPG
2484eb62b74eSMichael S. Tsirkin 	 */
24851a1ff825SNicholas Bellinger 	vhost_scsi_drop_nexus(tpg);
2486eb62b74eSMichael S. Tsirkin 	/*
2487eb62b74eSMichael S. Tsirkin 	 * Deregister the se_tpg from TCM..
2488eb62b74eSMichael S. Tsirkin 	 */
2489eb62b74eSMichael S. Tsirkin 	core_tpg_deregister(se_tpg);
2490eb62b74eSMichael S. Tsirkin 	kfree(tpg);
2491eb62b74eSMichael S. Tsirkin }
2492eb62b74eSMichael S. Tsirkin 
2493683bd967SAsias He static struct se_wwn *
vhost_scsi_make_tport(struct target_fabric_configfs * tf,struct config_group * group,const char * name)24941a1ff825SNicholas Bellinger vhost_scsi_make_tport(struct target_fabric_configfs *tf,
2495eb62b74eSMichael S. Tsirkin 		     struct config_group *group,
2496eb62b74eSMichael S. Tsirkin 		     const char *name)
2497eb62b74eSMichael S. Tsirkin {
24981a1ff825SNicholas Bellinger 	struct vhost_scsi_tport *tport;
2499eb62b74eSMichael S. Tsirkin 	char *ptr;
2500eb62b74eSMichael S. Tsirkin 	u64 wwpn = 0;
2501eb62b74eSMichael S. Tsirkin 	int off = 0;
2502eb62b74eSMichael S. Tsirkin 
25031a1ff825SNicholas Bellinger 	/* if (vhost_scsi_parse_wwn(name, &wwpn, 1) < 0)
2504eb62b74eSMichael S. Tsirkin 		return ERR_PTR(-EINVAL); */
2505eb62b74eSMichael S. Tsirkin 
2506473f0b15SMarkus Elfring 	tport = kzalloc(sizeof(*tport), GFP_KERNEL);
2507eb62b74eSMichael S. Tsirkin 	if (!tport) {
25081a1ff825SNicholas Bellinger 		pr_err("Unable to allocate struct vhost_scsi_tport");
2509eb62b74eSMichael S. Tsirkin 		return ERR_PTR(-ENOMEM);
2510eb62b74eSMichael S. Tsirkin 	}
2511eb62b74eSMichael S. Tsirkin 	tport->tport_wwpn = wwpn;
2512eb62b74eSMichael S. Tsirkin 	/*
2513eb62b74eSMichael S. Tsirkin 	 * Determine the emulated Protocol Identifier and Target Port Name
2514eb62b74eSMichael S. Tsirkin 	 * based on the incoming configfs directory name.
2515eb62b74eSMichael S. Tsirkin 	 */
2516eb62b74eSMichael S. Tsirkin 	ptr = strstr(name, "naa.");
2517eb62b74eSMichael S. Tsirkin 	if (ptr) {
2518eb62b74eSMichael S. Tsirkin 		tport->tport_proto_id = SCSI_PROTOCOL_SAS;
2519eb62b74eSMichael S. Tsirkin 		goto check_len;
2520eb62b74eSMichael S. Tsirkin 	}
2521eb62b74eSMichael S. Tsirkin 	ptr = strstr(name, "fc.");
2522eb62b74eSMichael S. Tsirkin 	if (ptr) {
2523eb62b74eSMichael S. Tsirkin 		tport->tport_proto_id = SCSI_PROTOCOL_FCP;
2524eb62b74eSMichael S. Tsirkin 		off = 3; /* Skip over "fc." */
2525eb62b74eSMichael S. Tsirkin 		goto check_len;
2526eb62b74eSMichael S. Tsirkin 	}
2527eb62b74eSMichael S. Tsirkin 	ptr = strstr(name, "iqn.");
2528eb62b74eSMichael S. Tsirkin 	if (ptr) {
2529eb62b74eSMichael S. Tsirkin 		tport->tport_proto_id = SCSI_PROTOCOL_ISCSI;
2530eb62b74eSMichael S. Tsirkin 		goto check_len;
2531eb62b74eSMichael S. Tsirkin 	}
2532eb62b74eSMichael S. Tsirkin 
2533eb62b74eSMichael S. Tsirkin 	pr_err("Unable to locate prefix for emulated Target Port:"
2534eb62b74eSMichael S. Tsirkin 			" %s\n", name);
2535eb62b74eSMichael S. Tsirkin 	kfree(tport);
2536eb62b74eSMichael S. Tsirkin 	return ERR_PTR(-EINVAL);
2537eb62b74eSMichael S. Tsirkin 
2538eb62b74eSMichael S. Tsirkin check_len:
25391a1ff825SNicholas Bellinger 	if (strlen(name) >= VHOST_SCSI_NAMELEN) {
2540eb62b74eSMichael S. Tsirkin 		pr_err("Emulated %s Address: %s, exceeds"
25411a1ff825SNicholas Bellinger 			" max: %d\n", name, vhost_scsi_dump_proto_id(tport),
25421a1ff825SNicholas Bellinger 			VHOST_SCSI_NAMELEN);
2543eb62b74eSMichael S. Tsirkin 		kfree(tport);
2544eb62b74eSMichael S. Tsirkin 		return ERR_PTR(-EINVAL);
2545eb62b74eSMichael S. Tsirkin 	}
25461a1ff825SNicholas Bellinger 	snprintf(&tport->tport_name[0], VHOST_SCSI_NAMELEN, "%s", &name[off]);
2547eb62b74eSMichael S. Tsirkin 
2548eb62b74eSMichael S. Tsirkin 	pr_debug("TCM_VHost_ConfigFS: Allocated emulated Target"
25491a1ff825SNicholas Bellinger 		" %s Address: %s\n", vhost_scsi_dump_proto_id(tport), name);
2550eb62b74eSMichael S. Tsirkin 
2551eb62b74eSMichael S. Tsirkin 	return &tport->tport_wwn;
2552eb62b74eSMichael S. Tsirkin }
2553eb62b74eSMichael S. Tsirkin 
vhost_scsi_drop_tport(struct se_wwn * wwn)25541a1ff825SNicholas Bellinger static void vhost_scsi_drop_tport(struct se_wwn *wwn)
2555eb62b74eSMichael S. Tsirkin {
25561a1ff825SNicholas Bellinger 	struct vhost_scsi_tport *tport = container_of(wwn,
25571a1ff825SNicholas Bellinger 				struct vhost_scsi_tport, tport_wwn);
2558eb62b74eSMichael S. Tsirkin 
2559eb62b74eSMichael S. Tsirkin 	pr_debug("TCM_VHost_ConfigFS: Deallocating emulated Target"
25601a1ff825SNicholas Bellinger 		" %s Address: %s\n", vhost_scsi_dump_proto_id(tport),
2561eb62b74eSMichael S. Tsirkin 		tport->tport_name);
2562eb62b74eSMichael S. Tsirkin 
2563eb62b74eSMichael S. Tsirkin 	kfree(tport);
2564eb62b74eSMichael S. Tsirkin }
2565eb62b74eSMichael S. Tsirkin 
2566683bd967SAsias He static ssize_t
vhost_scsi_wwn_version_show(struct config_item * item,char * page)25672eafd729SChristoph Hellwig vhost_scsi_wwn_version_show(struct config_item *item, char *page)
2568eb62b74eSMichael S. Tsirkin {
2569b3d4f02eSBo Liu 	return sysfs_emit(page, "TCM_VHOST fabric module %s on %s/%s"
25701a1ff825SNicholas Bellinger 		"on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
2571eb62b74eSMichael S. Tsirkin 		utsname()->machine);
2572eb62b74eSMichael S. Tsirkin }
2573eb62b74eSMichael S. Tsirkin 
25742eafd729SChristoph Hellwig CONFIGFS_ATTR_RO(vhost_scsi_wwn_, version);
2575eb62b74eSMichael S. Tsirkin 
25761a1ff825SNicholas Bellinger static struct configfs_attribute *vhost_scsi_wwn_attrs[] = {
25772eafd729SChristoph Hellwig 	&vhost_scsi_wwn_attr_version,
2578eb62b74eSMichael S. Tsirkin 	NULL,
2579eb62b74eSMichael S. Tsirkin };
2580eb62b74eSMichael S. Tsirkin 
25811d822a40SBhumika Goyal static const struct target_core_fabric_ops vhost_scsi_ops = {
25829ac8928eSChristoph Hellwig 	.module				= THIS_MODULE,
258330c7ca93SDavid Disseldorp 	.fabric_name			= "vhost",
25845ae6a6a9SSudhakar Panneerselvam 	.max_data_sg_nents		= VHOST_SCSI_PREALLOC_SGLS,
25851a1ff825SNicholas Bellinger 	.tpg_get_wwn			= vhost_scsi_get_fabric_wwn,
25861a1ff825SNicholas Bellinger 	.tpg_get_tag			= vhost_scsi_get_tpgt,
25871a1ff825SNicholas Bellinger 	.tpg_check_demo_mode		= vhost_scsi_check_true,
25881a1ff825SNicholas Bellinger 	.tpg_check_demo_mode_cache	= vhost_scsi_check_true,
2589b1d75fe5SNicholas Bellinger 	.tpg_check_prot_fabric_only	= vhost_scsi_check_prot_fabric_only,
25901a1ff825SNicholas Bellinger 	.release_cmd			= vhost_scsi_release_cmd,
2591084ed45bSNicholas Bellinger 	.check_stop_free		= vhost_scsi_check_stop_free,
2592eb62b74eSMichael S. Tsirkin 	.sess_get_initiator_sid		= NULL,
25931a1ff825SNicholas Bellinger 	.write_pending			= vhost_scsi_write_pending,
25941a1ff825SNicholas Bellinger 	.queue_data_in			= vhost_scsi_queue_data_in,
25951a1ff825SNicholas Bellinger 	.queue_status			= vhost_scsi_queue_status,
25961a1ff825SNicholas Bellinger 	.queue_tm_rsp			= vhost_scsi_queue_tm_rsp,
25971a1ff825SNicholas Bellinger 	.aborted_task			= vhost_scsi_aborted_task,
2598eb62b74eSMichael S. Tsirkin 	/*
2599eb62b74eSMichael S. Tsirkin 	 * Setup callers for generic logic in target_core_fabric_configfs.c
2600eb62b74eSMichael S. Tsirkin 	 */
26011a1ff825SNicholas Bellinger 	.fabric_make_wwn		= vhost_scsi_make_tport,
26021a1ff825SNicholas Bellinger 	.fabric_drop_wwn		= vhost_scsi_drop_tport,
26031a1ff825SNicholas Bellinger 	.fabric_make_tpg		= vhost_scsi_make_tpg,
26041a1ff825SNicholas Bellinger 	.fabric_drop_tpg		= vhost_scsi_drop_tpg,
26051a1ff825SNicholas Bellinger 	.fabric_post_link		= vhost_scsi_port_link,
26061a1ff825SNicholas Bellinger 	.fabric_pre_unlink		= vhost_scsi_port_unlink,
2607eb62b74eSMichael S. Tsirkin 
26089ac8928eSChristoph Hellwig 	.tfc_wwn_attrs			= vhost_scsi_wwn_attrs,
26099ac8928eSChristoph Hellwig 	.tfc_tpg_base_attrs		= vhost_scsi_tpg_attrs,
26109ac8928eSChristoph Hellwig 	.tfc_tpg_attrib_attrs		= vhost_scsi_tpg_attrib_attrs,
2611eb62b74eSMichael S. Tsirkin };
2612eb62b74eSMichael S. Tsirkin 
vhost_scsi_init(void)26131a1ff825SNicholas Bellinger static int __init vhost_scsi_init(void)
2614eb62b74eSMichael S. Tsirkin {
2615eb62b74eSMichael S. Tsirkin 	int ret = -ENOMEM;
26169ac8928eSChristoph Hellwig 
26179ac8928eSChristoph Hellwig 	pr_debug("TCM_VHOST fabric module %s on %s/%s"
26189ac8928eSChristoph Hellwig 		" on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
26199ac8928eSChristoph Hellwig 		utsname()->machine);
26209ac8928eSChristoph Hellwig 
2621eb62b74eSMichael S. Tsirkin 	ret = vhost_scsi_register();
2622eb62b74eSMichael S. Tsirkin 	if (ret < 0)
26236ec29cb8SMike Christie 		goto out;
2624eb62b74eSMichael S. Tsirkin 
26259ac8928eSChristoph Hellwig 	ret = target_register_template(&vhost_scsi_ops);
2626eb62b74eSMichael S. Tsirkin 	if (ret < 0)
2627eb62b74eSMichael S. Tsirkin 		goto out_vhost_scsi_deregister;
2628eb62b74eSMichael S. Tsirkin 
2629eb62b74eSMichael S. Tsirkin 	return 0;
2630eb62b74eSMichael S. Tsirkin 
2631eb62b74eSMichael S. Tsirkin out_vhost_scsi_deregister:
2632eb62b74eSMichael S. Tsirkin 	vhost_scsi_deregister();
2633eb62b74eSMichael S. Tsirkin out:
2634eb62b74eSMichael S. Tsirkin 	return ret;
2635eb62b74eSMichael S. Tsirkin };
2636eb62b74eSMichael S. Tsirkin 
vhost_scsi_exit(void)26371a1ff825SNicholas Bellinger static void vhost_scsi_exit(void)
2638eb62b74eSMichael S. Tsirkin {
26399ac8928eSChristoph Hellwig 	target_unregister_template(&vhost_scsi_ops);
2640eb62b74eSMichael S. Tsirkin 	vhost_scsi_deregister();
2641eb62b74eSMichael S. Tsirkin };
2642eb62b74eSMichael S. Tsirkin 
2643181c04a3SMichael S. Tsirkin MODULE_DESCRIPTION("VHOST_SCSI series fabric driver");
2644181c04a3SMichael S. Tsirkin MODULE_ALIAS("tcm_vhost");
2645eb62b74eSMichael S. Tsirkin MODULE_LICENSE("GPL");
26461a1ff825SNicholas Bellinger module_init(vhost_scsi_init);
26471a1ff825SNicholas Bellinger module_exit(vhost_scsi_exit);
2648