Blame view

drivers/vhost/scsi.c 61.5 KB
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1
2
3
  /*******************************************************************************
   * Vhost kernel TCM fabric driver for virtio SCSI initiators
   *
4c76251e8   Nicholas Bellinger   target: Update co...
4
   * (C) Copyright 2010-2013 Datera, Inc.
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
5
6
7
8
   * (C) Copyright 2010-2012 IBM Corp.
   *
   * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
   *
4c76251e8   Nicholas Bellinger   target: Update co...
9
   * Authors: Nicholas A. Bellinger <nab@daterainc.com>
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
   *          Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   ****************************************************************************/
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <generated/utsrelease.h>
  #include <linux/utsname.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/kthread.h>
  #include <linux/types.h>
  #include <linux/string.h>
  #include <linux/configfs.h>
  #include <linux/ctype.h>
  #include <linux/compat.h>
  #include <linux/eventfd.h>
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
37
  #include <linux/fs.h>
5538d294d   David S. Miller   treewide: Add mis...
38
  #include <linux/vmalloc.h>
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
39
40
  #include <linux/miscdevice.h>
  #include <asm/unaligned.h>
ba9299925   Bart Van Assche   target: Minimize ...
41
42
  #include <scsi/scsi_common.h>
  #include <scsi/scsi_proto.h>
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
43
44
  #include <target/target_core_base.h>
  #include <target/target_core_fabric.h>
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
45
  #include <linux/vhost.h>
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
46
  #include <linux/virtio_scsi.h>
9d6064a34   Asias He   tcm_vhost: Use ll...
47
  #include <linux/llist.h>
1b7f390eb   Asias He   tcm_vhost: Multi-...
48
  #include <linux/bitmap.h>
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
49

057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
50
  #include "vhost.h"
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
51

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
52
53
54
55
56
57
  #define VHOST_SCSI_VERSION  "v0.1"
  #define VHOST_SCSI_NAMELEN 256
  #define VHOST_SCSI_MAX_CDB_SIZE 32
  #define VHOST_SCSI_DEFAULT_TAGS 256
  #define VHOST_SCSI_PREALLOC_SGLS 2048
  #define VHOST_SCSI_PREALLOC_UPAGES 2048
864d39df0   Greg Edwards   vhost/scsi: incre...
58
  #define VHOST_SCSI_PREALLOC_PROT_SGLS 2048
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
59
60
61
62
63
64
65
  
  struct vhost_scsi_inflight {
  	/* Wait for the flush operation to finish */
  	struct completion comp;
  	/* Refcount for the inflight reqs */
  	struct kref kref;
  };
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
66
  struct vhost_scsi_cmd {
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
67
68
69
70
  	/* Descriptor from vhost_get_vq_desc() for virt_queue segment */
  	int tvc_vq_desc;
  	/* virtio-scsi initiator task attribute */
  	int tvc_task_attr;
79c14141a   Nicholas Bellinger   vhost/scsi: Conve...
71
72
  	/* virtio-scsi response incoming iovecs */
  	int tvc_in_iovs;
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
73
74
75
76
77
78
79
80
  	/* virtio-scsi initiator data direction */
  	enum dma_data_direction tvc_data_direction;
  	/* Expected data transfer length from virtio-scsi header */
  	u32 tvc_exp_data_len;
  	/* The Tag from include/linux/virtio_scsi.h:struct virtio_scsi_cmd_req */
  	u64 tvc_tag;
  	/* The number of scatterlists associated with this cmd */
  	u32 tvc_sgl_count;
e31885dd9   Nicholas Bellinger   vhost/scsi: Add T...
81
  	u32 tvc_prot_sgl_count;
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
82
  	/* Saved unpacked SCSI LUN for vhost_scsi_submission_work() */
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
83
84
85
  	u32 tvc_lun;
  	/* Pointer to the SGL formatted memory from virtio-scsi */
  	struct scatterlist *tvc_sgl;
b1935f687   Nicholas Bellinger   vhost/scsi: Add p...
86
  	struct scatterlist *tvc_prot_sgl;
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
87
  	struct page **tvc_upages;
79c14141a   Nicholas Bellinger   vhost/scsi: Conve...
88
  	/* Pointer to response header iovec */
a77ec83a5   Benjamin Coddington   vhost/scsi: fix r...
89
  	struct iovec tvc_resp_iov;
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
90
91
92
93
94
  	/* Pointer to vhost_scsi for our device */
  	struct vhost_scsi *tvc_vhost;
  	/* Pointer to vhost_virtqueue for the cmd */
  	struct vhost_virtqueue *tvc_vq;
  	/* Pointer to vhost nexus memory */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
95
  	struct vhost_scsi_nexus *tvc_nexus;
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
96
97
  	/* The TCM I/O descriptor that is accessed via container_of() */
  	struct se_cmd tvc_se_cmd;
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
98
  	/* work item used for cmwq dispatch to vhost_scsi_submission_work() */
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
99
100
  	struct work_struct work;
  	/* Copy of the incoming SCSI command descriptor block (CDB) */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
101
  	unsigned char tvc_cdb[VHOST_SCSI_MAX_CDB_SIZE];
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
102
103
104
105
106
107
108
  	/* Sense buffer that will be mapped into outgoing status */
  	unsigned char tvc_sense_buf[TRANSPORT_SENSE_BUFFER];
  	/* Completed commands list, serviced from vhost worker thread */
  	struct llist_node tvc_completion_list;
  	/* Used to track inflight cmd */
  	struct vhost_scsi_inflight *inflight;
  };
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
109
  struct vhost_scsi_nexus {
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
110
111
112
  	/* Pointer to TCM session for I_T Nexus */
  	struct se_session *tvn_se_sess;
  };
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
113
  struct vhost_scsi_tpg {
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
114
115
116
117
118
119
  	/* Vhost port target portal group tag for TCM */
  	u16 tport_tpgt;
  	/* Used to track number of TPG Port/Lun Links wrt to explict I_T Nexus shutdown */
  	int tv_tpg_port_count;
  	/* Used for vhost_scsi device reference to tpg_nexus, protected by tv_tpg_mutex */
  	int tv_tpg_vhost_count;
b1d75fe53   Nicholas Bellinger   vhost/scsi: Add f...
120
121
  	/* Used for enabling T10-PI with legacy devices */
  	int tv_fabric_prot_type;
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
122
  	/* list for vhost_scsi_list */
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
123
124
125
126
  	struct list_head tv_tpg_list;
  	/* Used to protect access for tpg_nexus */
  	struct mutex tv_tpg_mutex;
  	/* Pointer to the TCM VHost I_T Nexus for this TPG endpoint */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
127
128
129
130
  	struct vhost_scsi_nexus *tpg_nexus;
  	/* Pointer back to vhost_scsi_tport */
  	struct vhost_scsi_tport *tport;
  	/* Returned by vhost_scsi_make_tpg() */
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
131
132
133
134
  	struct se_portal_group se_tpg;
  	/* Pointer back to vhost_scsi, protected by tv_tpg_mutex */
  	struct vhost_scsi *vhost_scsi;
  };
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
135
  struct vhost_scsi_tport {
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
136
137
138
139
140
  	/* SCSI protocol the tport is providing */
  	u8 tport_proto_id;
  	/* Binary World Wide unique Port Name for Vhost Target port */
  	u64 tport_wwpn;
  	/* ASCII formatted WWPN for Vhost Target port */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
141
142
  	char tport_name[VHOST_SCSI_NAMELEN];
  	/* Returned by vhost_scsi_make_tport() */
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
143
144
  	struct se_wwn tport_wwn;
  };
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
145
  struct vhost_scsi_evt {
5012a3a38   Michael S. Tsirkin   tcm_vhost: header...
146
147
148
149
150
  	/* event to be sent to guest */
  	struct virtio_scsi_event event;
  	/* event list, serviced from vhost worker thread */
  	struct llist_node list;
  };
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
151

101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
152
153
154
155
156
  enum {
  	VHOST_SCSI_VQ_CTL = 0,
  	VHOST_SCSI_VQ_EVT = 1,
  	VHOST_SCSI_VQ_IO = 2,
  };
e72fd72e2   Michael S. Tsirkin   vhost/scsi: parti...
157
  /* Note: can't set VIRTIO_F_VERSION_1 yet, since that implies ANY_LAYOUT. */
5dade7105   Nicholas Bellinger   tcm_vhost: Avoid ...
158
  enum {
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
159
  	VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) |
4e9fa50c6   Michael S. Tsirkin   vhost: move featu...
160
  					       (1ULL << VIRTIO_SCSI_F_T10_PI)
5dade7105   Nicholas Bellinger   tcm_vhost: Avoid ...
161
  };
1b7f390eb   Asias He   tcm_vhost: Multi-...
162
163
  #define VHOST_SCSI_MAX_TARGET	256
  #define VHOST_SCSI_MAX_VQ	128
a6c9af873   Asias He   tcm_vhost: Add ho...
164
  #define VHOST_SCSI_MAX_EVENT	128
67e18cf9a   Asias He   tcm_vhost: Multi-...
165

3ab2e420e   Asias He   vhost: Allow devi...
166
167
  struct vhost_scsi_virtqueue {
  	struct vhost_virtqueue vq;
3dfbff328   Michael S. Tsirkin   tcm_vhost: docume...
168
169
170
171
172
  	/*
  	 * Reference counting for inflight reqs, used for flush operation. At
  	 * each time, one reference tracks new commands submitted, while we
  	 * wait for another one to reach 0.
  	 */
f2f0173d6   Asias He   tcm_vhost: Wait f...
173
  	struct vhost_scsi_inflight inflights[2];
3dfbff328   Michael S. Tsirkin   tcm_vhost: docume...
174
175
176
177
  	/*
  	 * Indicate current inflight in use, protected by vq->mutex.
  	 * Writers must also take dev mutex and flush under it.
  	 */
f2f0173d6   Asias He   tcm_vhost: Wait f...
178
  	int inflight_idx;
3ab2e420e   Asias He   vhost: Allow devi...
179
  };
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
180
  struct vhost_scsi {
67e18cf9a   Asias He   tcm_vhost: Multi-...
181
  	/* Protected by vhost_scsi->dev.mutex */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
182
  	struct vhost_scsi_tpg **vs_tpg;
67e18cf9a   Asias He   tcm_vhost: Multi-...
183
  	char vs_vhost_wwpn[TRANSPORT_IQN_LEN];
67e18cf9a   Asias He   tcm_vhost: Multi-...
184

057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
185
  	struct vhost_dev dev;
3ab2e420e   Asias He   vhost: Allow devi...
186
  	struct vhost_scsi_virtqueue vqs[VHOST_SCSI_MAX_VQ];
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
187
188
  
  	struct vhost_work vs_completion_work; /* cmd completion work item */
9d6064a34   Asias He   tcm_vhost: Use ll...
189
  	struct llist_head vs_completion_list; /* cmd completion queue */
a6c9af873   Asias He   tcm_vhost: Add ho...
190
191
192
193
194
195
  
  	struct vhost_work vs_event_work; /* evt injection work item */
  	struct llist_head vs_event_list; /* evt injection queue */
  
  	bool vs_events_missed; /* any missed events, protected by vq->mutex */
  	int vs_events_nr; /* num of pending events, protected by vq->mutex */
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
196
  };
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
197
198
199
200
201
202
203
204
205
206
207
208
  /*
   * Context for processing request and control queue operations.
   */
  struct vhost_scsi_ctx {
  	int head;
  	unsigned int out, in;
  	size_t req_size, rsp_size;
  	size_t out_size, in_size;
  	u8 *target, *lunp;
  	void *req;
  	struct iov_iter out_iter;
  };
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
209
  static struct workqueue_struct *vhost_scsi_workqueue;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
210

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
211
212
213
  /* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */
  static DEFINE_MUTEX(vhost_scsi_mutex);
  static LIST_HEAD(vhost_scsi_list);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
214

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
215
  static void vhost_scsi_done_inflight(struct kref *kref)
f2f0173d6   Asias He   tcm_vhost: Wait f...
216
217
218
219
220
221
  {
  	struct vhost_scsi_inflight *inflight;
  
  	inflight = container_of(kref, struct vhost_scsi_inflight, kref);
  	complete(&inflight->comp);
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
222
  static void vhost_scsi_init_inflight(struct vhost_scsi *vs,
f2f0173d6   Asias He   tcm_vhost: Wait f...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  				    struct vhost_scsi_inflight *old_inflight[])
  {
  	struct vhost_scsi_inflight *new_inflight;
  	struct vhost_virtqueue *vq;
  	int idx, i;
  
  	for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
  		vq = &vs->vqs[i].vq;
  
  		mutex_lock(&vq->mutex);
  
  		/* store old infight */
  		idx = vs->vqs[i].inflight_idx;
  		if (old_inflight)
  			old_inflight[i] = &vs->vqs[i].inflights[idx];
  
  		/* setup new infight */
  		vs->vqs[i].inflight_idx = idx ^ 1;
  		new_inflight = &vs->vqs[i].inflights[idx ^ 1];
  		kref_init(&new_inflight->kref);
  		init_completion(&new_inflight->comp);
  
  		mutex_unlock(&vq->mutex);
  	}
  }
  
  static struct vhost_scsi_inflight *
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
250
  vhost_scsi_get_inflight(struct vhost_virtqueue *vq)
f2f0173d6   Asias He   tcm_vhost: Wait f...
251
252
253
254
255
256
257
258
259
260
  {
  	struct vhost_scsi_inflight *inflight;
  	struct vhost_scsi_virtqueue *svq;
  
  	svq = container_of(vq, struct vhost_scsi_virtqueue, vq);
  	inflight = &svq->inflights[svq->inflight_idx];
  	kref_get(&inflight->kref);
  
  	return inflight;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
261
  static void vhost_scsi_put_inflight(struct vhost_scsi_inflight *inflight)
f2f0173d6   Asias He   tcm_vhost: Wait f...
262
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
263
  	kref_put(&inflight->kref, vhost_scsi_done_inflight);
f2f0173d6   Asias He   tcm_vhost: Wait f...
264
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
265
  static int vhost_scsi_check_true(struct se_portal_group *se_tpg)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
266
267
268
  {
  	return 1;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
269
  static int vhost_scsi_check_false(struct se_portal_group *se_tpg)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
270
271
272
  {
  	return 0;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
273
  static char *vhost_scsi_get_fabric_name(void)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
274
275
276
  {
  	return "vhost";
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
277
  static char *vhost_scsi_get_fabric_wwn(struct se_portal_group *se_tpg)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
278
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
279
280
281
  	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
  				struct vhost_scsi_tpg, se_tpg);
  	struct vhost_scsi_tport *tport = tpg->tport;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
282
283
284
  
  	return &tport->tport_name[0];
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
285
  static u16 vhost_scsi_get_tpgt(struct se_portal_group *se_tpg)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
286
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
287
288
  	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
  				struct vhost_scsi_tpg, se_tpg);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
289
290
  	return tpg->tport_tpgt;
  }
b1d75fe53   Nicholas Bellinger   vhost/scsi: Add f...
291
292
293
294
295
296
297
  static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg)
  {
  	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
  				struct vhost_scsi_tpg, se_tpg);
  
  	return tpg->tv_fabric_prot_type;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
298
  static u32 vhost_scsi_tpg_get_inst_index(struct se_portal_group *se_tpg)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
299
300
301
  {
  	return 1;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
302
  static void vhost_scsi_release_cmd(struct se_cmd *se_cmd)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
303
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
304
305
  	struct vhost_scsi_cmd *tv_cmd = container_of(se_cmd,
  				struct vhost_scsi_cmd, tvc_se_cmd);
de1419e42   Nicholas Bellinger   vhost/scsi: Fix i...
306
  	struct se_session *se_sess = tv_cmd->tvc_nexus->tvn_se_sess;
e31885dd9   Nicholas Bellinger   vhost/scsi: Add T...
307
  	int i;
084ed45b3   Nicholas Bellinger   vhost/scsi: Conve...
308
309
  
  	if (tv_cmd->tvc_sgl_count) {
084ed45b3   Nicholas Bellinger   vhost/scsi: Conve...
310
311
  		for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
  			put_page(sg_page(&tv_cmd->tvc_sgl[i]));
d3d665a65   Michael S. Tsirkin   vhost-scsi: white...
312
  	}
e31885dd9   Nicholas Bellinger   vhost/scsi: Add T...
313
314
315
316
  	if (tv_cmd->tvc_prot_sgl_count) {
  		for (i = 0; i < tv_cmd->tvc_prot_sgl_count; i++)
  			put_page(sg_page(&tv_cmd->tvc_prot_sgl[i]));
  	}
084ed45b3   Nicholas Bellinger   vhost/scsi: Conve...
317

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
318
  	vhost_scsi_put_inflight(tv_cmd->inflight);
83c2b54b9   Matthew Wilcox   scsi: target: Abs...
319
  	target_free_tag(se_sess, se_cmd);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
320
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
321
  static u32 vhost_scsi_sess_get_index(struct se_session *se_sess)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
322
323
324
  {
  	return 0;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
325
  static int vhost_scsi_write_pending(struct se_cmd *se_cmd)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
326
327
328
329
330
  {
  	/* Go ahead and process the write immediately */
  	target_execute_cmd(se_cmd);
  	return 0;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
331
  static int vhost_scsi_write_pending_status(struct se_cmd *se_cmd)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
332
333
334
  {
  	return 0;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
335
  static void vhost_scsi_set_default_node_attrs(struct se_node_acl *nacl)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
336
337
338
  {
  	return;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
339
  static int vhost_scsi_get_cmd_state(struct se_cmd *se_cmd)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
340
341
342
  {
  	return 0;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
343
  static void vhost_scsi_complete_cmd(struct vhost_scsi_cmd *cmd)
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
344
  {
3c63f66a0   Asias He   vhost-scsi: Renam...
345
  	struct vhost_scsi *vs = cmd->tvc_vhost;
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
346

3c63f66a0   Asias He   vhost-scsi: Renam...
347
  	llist_add(&cmd->tvc_completion_list, &vs->vs_completion_list);
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
348
349
350
  
  	vhost_work_queue(&vs->dev, &vs->vs_completion_work);
  }
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
351

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
352
  static int vhost_scsi_queue_data_in(struct se_cmd *se_cmd)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
353
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
354
355
  	struct vhost_scsi_cmd *cmd = container_of(se_cmd,
  				struct vhost_scsi_cmd, tvc_se_cmd);
3c63f66a0   Asias He   vhost-scsi: Renam...
356
  	vhost_scsi_complete_cmd(cmd);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
357
358
  	return 0;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
359
  static int vhost_scsi_queue_status(struct se_cmd *se_cmd)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
360
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
361
362
  	struct vhost_scsi_cmd *cmd = container_of(se_cmd,
  				struct vhost_scsi_cmd, tvc_se_cmd);
3c63f66a0   Asias He   vhost-scsi: Renam...
363
  	vhost_scsi_complete_cmd(cmd);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
364
365
  	return 0;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
366
  static void vhost_scsi_queue_tm_rsp(struct se_cmd *se_cmd)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
367
  {
b79fafac7   Joern Engel   target: make queu...
368
  	return;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
369
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
370
  static void vhost_scsi_aborted_task(struct se_cmd *se_cmd)
131e6abc6   Nicholas Bellinger   target: Add TFO->...
371
372
373
  {
  	return;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
374
  static void vhost_scsi_free_evt(struct vhost_scsi *vs, struct vhost_scsi_evt *evt)
a6c9af873   Asias He   tcm_vhost: Add ho...
375
376
377
378
  {
  	vs->vs_events_nr--;
  	kfree(evt);
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
379
380
  static struct vhost_scsi_evt *
  vhost_scsi_allocate_evt(struct vhost_scsi *vs,
683bd967d   Asias He   vhost-scsi: Make ...
381
  		       u32 event, u32 reason)
a6c9af873   Asias He   tcm_vhost: Add ho...
382
  {
3ab2e420e   Asias He   vhost: Allow devi...
383
  	struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
384
  	struct vhost_scsi_evt *evt;
a6c9af873   Asias He   tcm_vhost: Add ho...
385
386
387
388
389
390
391
392
  
  	if (vs->vs_events_nr > VHOST_SCSI_MAX_EVENT) {
  		vs->vs_events_missed = true;
  		return NULL;
  	}
  
  	evt = kzalloc(sizeof(*evt), GFP_KERNEL);
  	if (!evt) {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
393
394
  		vq_err(vq, "Failed to allocate vhost_scsi_evt
  ");
a6c9af873   Asias He   tcm_vhost: Add ho...
395
396
397
  		vs->vs_events_missed = true;
  		return NULL;
  	}
e72fd72e2   Michael S. Tsirkin   vhost/scsi: parti...
398
399
  	evt->event.event = cpu_to_vhost32(vq, event);
  	evt->event.reason = cpu_to_vhost32(vq, reason);
a6c9af873   Asias He   tcm_vhost: Add ho...
400
401
402
403
  	vs->vs_events_nr++;
  
  	return evt;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
404
  static void vhost_scsi_free_cmd(struct vhost_scsi_cmd *cmd)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
405
  {
3c63f66a0   Asias He   vhost-scsi: Renam...
406
  	struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
407
408
  
  	/* TODO locking against target/backend threads? */
6c131d0c5   Nicholas Bellinger   vhost/scsi: Drop ...
409
  	transport_generic_free_cmd(se_cmd, 0);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
410

084ed45b3   Nicholas Bellinger   vhost/scsi: Conve...
411
  }
f2f0173d6   Asias He   tcm_vhost: Wait f...
412

084ed45b3   Nicholas Bellinger   vhost/scsi: Conve...
413
414
  static int vhost_scsi_check_stop_free(struct se_cmd *se_cmd)
  {
afc16604c   Bart Van Assche   target: Remove fi...
415
  	return target_put_sess_cmd(se_cmd);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
416
  }
683bd967d   Asias He   vhost-scsi: Make ...
417
  static void
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
418
  vhost_scsi_do_evt_work(struct vhost_scsi *vs, struct vhost_scsi_evt *evt)
a6c9af873   Asias He   tcm_vhost: Add ho...
419
  {
3ab2e420e   Asias He   vhost: Allow devi...
420
  	struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
a6c9af873   Asias He   tcm_vhost: Add ho...
421
422
423
424
425
426
427
428
429
430
431
432
  	struct virtio_scsi_event *event = &evt->event;
  	struct virtio_scsi_event __user *eventp;
  	unsigned out, in;
  	int head, ret;
  
  	if (!vq->private_data) {
  		vs->vs_events_missed = true;
  		return;
  	}
  
  again:
  	vhost_disable_notify(&vs->dev, vq);
47283bef7   Michael S. Tsirkin   vhost: move memor...
433
  	head = vhost_get_vq_desc(vq, vq->iov,
a6c9af873   Asias He   tcm_vhost: Add ho...
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
  			ARRAY_SIZE(vq->iov), &out, &in,
  			NULL, NULL);
  	if (head < 0) {
  		vs->vs_events_missed = true;
  		return;
  	}
  	if (head == vq->num) {
  		if (vhost_enable_notify(&vs->dev, vq))
  			goto again;
  		vs->vs_events_missed = true;
  		return;
  	}
  
  	if ((vq->iov[out].iov_len != sizeof(struct virtio_scsi_event))) {
  		vq_err(vq, "Expecting virtio_scsi_event, got %zu bytes
  ",
  				vq->iov[out].iov_len);
  		vs->vs_events_missed = true;
  		return;
  	}
  
  	if (vs->vs_events_missed) {
e72fd72e2   Michael S. Tsirkin   vhost/scsi: parti...
456
  		event->event |= cpu_to_vhost32(vq, VIRTIO_SCSI_T_EVENTS_MISSED);
a6c9af873   Asias He   tcm_vhost: Add ho...
457
458
459
460
461
462
463
464
  		vs->vs_events_missed = false;
  	}
  
  	eventp = vq->iov[out].iov_base;
  	ret = __copy_to_user(eventp, event, sizeof(*event));
  	if (!ret)
  		vhost_add_used_and_signal(&vs->dev, vq, head, 0);
  	else
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
465
466
  		vq_err(vq, "Faulted on vhost_scsi_send_event
  ");
a6c9af873   Asias He   tcm_vhost: Add ho...
467
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
468
  static void vhost_scsi_evt_work(struct vhost_work *work)
a6c9af873   Asias He   tcm_vhost: Add ho...
469
470
471
  {
  	struct vhost_scsi *vs = container_of(work, struct vhost_scsi,
  					vs_event_work);
3ab2e420e   Asias He   vhost: Allow devi...
472
  	struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
12bdcbd53   Byungchul Park   vhost/scsi: Don't...
473
  	struct vhost_scsi_evt *evt, *t;
a6c9af873   Asias He   tcm_vhost: Add ho...
474
475
476
477
  	struct llist_node *llnode;
  
  	mutex_lock(&vq->mutex);
  	llnode = llist_del_all(&vs->vs_event_list);
12bdcbd53   Byungchul Park   vhost/scsi: Don't...
478
  	llist_for_each_entry_safe(evt, t, llnode, list) {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
479
480
  		vhost_scsi_do_evt_work(vs, evt);
  		vhost_scsi_free_evt(vs, evt);
a6c9af873   Asias He   tcm_vhost: Add ho...
481
482
483
  	}
  	mutex_unlock(&vq->mutex);
  }
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
484
485
486
487
488
489
490
491
492
  /* Fill in status and signal that we are done processing this command
   *
   * This is scheduled in the vhost work queue so we are called with the owner
   * process mm and can access the vring.
   */
  static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
  {
  	struct vhost_scsi *vs = container_of(work, struct vhost_scsi,
  					vs_completion_work);
1b7f390eb   Asias He   tcm_vhost: Multi-...
493
  	DECLARE_BITMAP(signal, VHOST_SCSI_MAX_VQ);
9d6064a34   Asias He   tcm_vhost: Use ll...
494
  	struct virtio_scsi_cmd_resp v_rsp;
816e85edf   Byungchul Park   vhost/scsi: Use s...
495
  	struct vhost_scsi_cmd *cmd, *t;
9d6064a34   Asias He   tcm_vhost: Use ll...
496
497
  	struct llist_node *llnode;
  	struct se_cmd *se_cmd;
79c14141a   Nicholas Bellinger   vhost/scsi: Conve...
498
  	struct iov_iter iov_iter;
1b7f390eb   Asias He   tcm_vhost: Multi-...
499
  	int ret, vq;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
500

1b7f390eb   Asias He   tcm_vhost: Multi-...
501
  	bitmap_zero(signal, VHOST_SCSI_MAX_VQ);
9d6064a34   Asias He   tcm_vhost: Use ll...
502
  	llnode = llist_del_all(&vs->vs_completion_list);
816e85edf   Byungchul Park   vhost/scsi: Use s...
503
  	llist_for_each_entry_safe(cmd, t, llnode, tvc_completion_list) {
3c63f66a0   Asias He   vhost-scsi: Renam...
504
  		se_cmd = &cmd->tvc_se_cmd;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
505
506
507
  
  		pr_debug("%s tv_cmd %p resid %u status %#02x
  ", __func__,
3c63f66a0   Asias He   vhost-scsi: Renam...
508
  			cmd, se_cmd->residual_count, se_cmd->scsi_status);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
509
510
  
  		memset(&v_rsp, 0, sizeof(v_rsp));
e72fd72e2   Michael S. Tsirkin   vhost/scsi: parti...
511
  		v_rsp.resid = cpu_to_vhost32(cmd->tvc_vq, se_cmd->residual_count);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
512
513
  		/* TODO is status_qualifier field needed? */
  		v_rsp.status = se_cmd->scsi_status;
e72fd72e2   Michael S. Tsirkin   vhost/scsi: parti...
514
515
  		v_rsp.sense_len = cpu_to_vhost32(cmd->tvc_vq,
  						 se_cmd->scsi_sense_length);
3c63f66a0   Asias He   vhost-scsi: Renam...
516
  		memcpy(v_rsp.sense, cmd->tvc_sense_buf,
e72fd72e2   Michael S. Tsirkin   vhost/scsi: parti...
517
  		       se_cmd->scsi_sense_length);
79c14141a   Nicholas Bellinger   vhost/scsi: Conve...
518

a77ec83a5   Benjamin Coddington   vhost/scsi: fix r...
519
  		iov_iter_init(&iov_iter, READ, &cmd->tvc_resp_iov,
79c14141a   Nicholas Bellinger   vhost/scsi: Conve...
520
521
522
  			      cmd->tvc_in_iovs, sizeof(v_rsp));
  		ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter);
  		if (likely(ret == sizeof(v_rsp))) {
3ab2e420e   Asias He   vhost: Allow devi...
523
  			struct vhost_scsi_virtqueue *q;
3c63f66a0   Asias He   vhost-scsi: Renam...
524
525
  			vhost_add_used(cmd->tvc_vq, cmd->tvc_vq_desc, 0);
  			q = container_of(cmd->tvc_vq, struct vhost_scsi_virtqueue, vq);
3ab2e420e   Asias He   vhost: Allow devi...
526
  			vq = q - vs->vqs;
1b7f390eb   Asias He   tcm_vhost: Multi-...
527
528
  			__set_bit(vq, signal);
  		} else
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
529
530
  			pr_err("Faulted on virtio_scsi_cmd_resp
  ");
3c63f66a0   Asias He   vhost-scsi: Renam...
531
  		vhost_scsi_free_cmd(cmd);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
532
  	}
1b7f390eb   Asias He   tcm_vhost: Multi-...
533
534
535
  	vq = -1;
  	while ((vq = find_next_bit(signal, VHOST_SCSI_MAX_VQ, vq + 1))
  		< VHOST_SCSI_MAX_VQ)
3ab2e420e   Asias He   vhost: Allow devi...
536
  		vhost_signal(&vs->dev, &vs->vqs[vq].vq);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
537
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
538
539
  static struct vhost_scsi_cmd *
  vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg,
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
540
541
  		   unsigned char *cdb, u64 scsi_tag, u16 lun, u8 task_attr,
  		   u32 exp_data_len, int data_direction)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
542
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
543
544
  	struct vhost_scsi_cmd *cmd;
  	struct vhost_scsi_nexus *tv_nexus;
4824d3bfb   Nicholas Bellinger   vhost/scsi: Conve...
545
  	struct se_session *se_sess;
b1935f687   Nicholas Bellinger   vhost/scsi: Add p...
546
  	struct scatterlist *sg, *prot_sg;
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
547
  	struct page **pages;
10e9cbb6b   Matthew Wilcox   scsi: target: Con...
548
  	int tag, cpu;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
549

987183128   Asias He   vhost-scsi: Renam...
550
  	tv_nexus = tpg->tpg_nexus;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
551
  	if (!tv_nexus) {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
552
553
  		pr_err("Unable to locate active struct vhost_scsi_nexus
  ");
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
554
555
  		return ERR_PTR(-EIO);
  	}
4824d3bfb   Nicholas Bellinger   vhost/scsi: Conve...
556
  	se_sess = tv_nexus->tvn_se_sess;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
557

10e9cbb6b   Matthew Wilcox   scsi: target: Con...
558
  	tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
4a47d3a1f   Nicholas Bellinger   vhost/scsi: Use G...
559
  	if (tag < 0) {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
560
561
  		pr_err("Unable to obtain tag for vhost_scsi_cmd
  ");
4a47d3a1f   Nicholas Bellinger   vhost/scsi: Use G...
562
563
  		return ERR_PTR(-ENOMEM);
  	}
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
564
  	cmd = &((struct vhost_scsi_cmd *)se_sess->sess_cmd_map)[tag];
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
565
  	sg = cmd->tvc_sgl;
b1935f687   Nicholas Bellinger   vhost/scsi: Add p...
566
  	prot_sg = cmd->tvc_prot_sgl;
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
567
  	pages = cmd->tvc_upages;
473f0b15a   Markus Elfring   vhost/scsi: Impro...
568
  	memset(cmd, 0, sizeof(*cmd));
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
569
  	cmd->tvc_sgl = sg;
b1935f687   Nicholas Bellinger   vhost/scsi: Add p...
570
  	cmd->tvc_prot_sgl = prot_sg;
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
571
  	cmd->tvc_upages = pages;
4824d3bfb   Nicholas Bellinger   vhost/scsi: Conve...
572
  	cmd->tvc_se_cmd.map_tag = tag;
10e9cbb6b   Matthew Wilcox   scsi: target: Con...
573
  	cmd->tvc_se_cmd.map_cpu = cpu;
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
574
575
576
  	cmd->tvc_tag = scsi_tag;
  	cmd->tvc_lun = lun;
  	cmd->tvc_task_attr = task_attr;
3c63f66a0   Asias He   vhost-scsi: Renam...
577
578
579
  	cmd->tvc_exp_data_len = exp_data_len;
  	cmd->tvc_data_direction = data_direction;
  	cmd->tvc_nexus = tv_nexus;
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
580
  	cmd->inflight = vhost_scsi_get_inflight(vq);
3c63f66a0   Asias He   vhost-scsi: Renam...
581

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
582
  	memcpy(cmd->tvc_cdb, cdb, VHOST_SCSI_MAX_CDB_SIZE);
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
583

3c63f66a0   Asias He   vhost-scsi: Renam...
584
  	return cmd;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
585
586
587
588
589
590
591
  }
  
  /*
   * Map a user memory range into a scatterlist
   *
   * Returns the number of scatterlist entries used or -errno on error.
   */
683bd967d   Asias He   vhost-scsi: Make ...
592
  static int
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
593
  vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd,
2f240c4ae   Al Viro   vhost/scsi: switc...
594
  		      struct iov_iter *iter,
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
595
  		      struct scatterlist *sgl,
5a01d0821   Nicholas Bellinger   vhost/scsi: Move ...
596
  		      bool write)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
597
  {
b4078b5fa   Nicholas Bellinger   vhost/scsi: Chang...
598
  	struct page **pages = cmd->tvc_upages;
2f240c4ae   Al Viro   vhost/scsi: switc...
599
600
601
602
  	struct scatterlist *sg = sgl;
  	ssize_t bytes;
  	size_t offset;
  	unsigned int npages = 0;
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
603

2f240c4ae   Al Viro   vhost/scsi: switc...
604
605
  	bytes = iov_iter_get_pages(iter, pages, LONG_MAX,
  				VHOST_SCSI_PREALLOC_UPAGES, &offset);
1810053e8   Asias He   tcm_vhost: Optimi...
606
  	/* No pages were pinned */
2f240c4ae   Al Viro   vhost/scsi: switc...
607
608
  	if (bytes <= 0)
  		return bytes < 0 ? bytes : -EFAULT;
1810053e8   Asias He   tcm_vhost: Optimi...
609

2f240c4ae   Al Viro   vhost/scsi: switc...
610
  	iov_iter_advance(iter, bytes);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
611

2f240c4ae   Al Viro   vhost/scsi: switc...
612
613
614
615
616
617
618
  	while (bytes) {
  		unsigned n = min_t(unsigned, PAGE_SIZE - offset, bytes);
  		sg_set_page(sg++, pages[npages++], n, offset);
  		bytes -= n;
  		offset = 0;
  	}
  	return npages;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
619
  }
683bd967d   Asias He   vhost-scsi: Make ...
620
  static int
e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
621
  vhost_scsi_calc_sgls(struct iov_iter *iter, size_t bytes, int max_sgls)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
622
  {
e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
623
  	int sgl_count = 0;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
624

e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
625
626
627
628
629
630
  	if (!iter || !iter->iov) {
  		pr_err("%s: iter->iov is NULL, but expected bytes: %zu"
  		       " present
  ", __func__, bytes);
  		return -EINVAL;
  	}
f3158f362   Asias He   tcm_vhost: Use io...
631

e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
632
633
634
635
636
637
  	sgl_count = iov_iter_npages(iter, 0xffff);
  	if (sgl_count > max_sgls) {
  		pr_err("%s: requested sgl_count: %d exceeds pre-allocated"
  		       " max_sgls: %d
  ", __func__, sgl_count, max_sgls);
  		return -EINVAL;
5a01d0821   Nicholas Bellinger   vhost/scsi: Move ...
638
  	}
e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
639
640
  	return sgl_count;
  }
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
641

e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
642
  static int
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
643
644
645
  vhost_scsi_iov_to_sgl(struct vhost_scsi_cmd *cmd, bool write,
  		      struct iov_iter *iter,
  		      struct scatterlist *sg, int sg_count)
e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
646
  {
11d49e9d0   Al Viro   fix a page leak i...
647
  	struct scatterlist *p = sg;
2f240c4ae   Al Viro   vhost/scsi: switc...
648
  	int ret;
5a01d0821   Nicholas Bellinger   vhost/scsi: Move ...
649

2f240c4ae   Al Viro   vhost/scsi: switc...
650
651
  	while (iov_iter_count(iter)) {
  		ret = vhost_scsi_map_to_sgl(cmd, iter, sg, write);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
652
  		if (ret < 0) {
11d49e9d0   Al Viro   fix a page leak i...
653
654
  			while (p < sg) {
  				struct page *page = sg_page(p++);
e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
655
656
657
  				if (page)
  					put_page(page);
  			}
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
658
659
  			return ret;
  		}
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
660
  		sg += ret;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
661
662
663
  	}
  	return 0;
  }
e31885dd9   Nicholas Bellinger   vhost/scsi: Add T...
664
  static int
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
665
  vhost_scsi_mapal(struct vhost_scsi_cmd *cmd,
e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
666
667
668
669
670
671
672
673
  		 size_t prot_bytes, struct iov_iter *prot_iter,
  		 size_t data_bytes, struct iov_iter *data_iter)
  {
  	int sgl_count, ret;
  	bool write = (cmd->tvc_data_direction == DMA_FROM_DEVICE);
  
  	if (prot_bytes) {
  		sgl_count = vhost_scsi_calc_sgls(prot_iter, prot_bytes,
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
674
  						 VHOST_SCSI_PREALLOC_PROT_SGLS);
e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
675
676
677
678
679
680
681
682
683
684
685
686
  		if (sgl_count < 0)
  			return sgl_count;
  
  		sg_init_table(cmd->tvc_prot_sgl, sgl_count);
  		cmd->tvc_prot_sgl_count = sgl_count;
  		pr_debug("%s prot_sg %p prot_sgl_count %u
  ", __func__,
  			 cmd->tvc_prot_sgl, cmd->tvc_prot_sgl_count);
  
  		ret = vhost_scsi_iov_to_sgl(cmd, write, prot_iter,
  					    cmd->tvc_prot_sgl,
  					    cmd->tvc_prot_sgl_count);
e31885dd9   Nicholas Bellinger   vhost/scsi: Add T...
687
  		if (ret < 0) {
e31885dd9   Nicholas Bellinger   vhost/scsi: Add T...
688
689
690
  			cmd->tvc_prot_sgl_count = 0;
  			return ret;
  		}
e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
691
692
  	}
  	sgl_count = vhost_scsi_calc_sgls(data_iter, data_bytes,
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
693
  					 VHOST_SCSI_PREALLOC_SGLS);
e8de56b5e   Nicholas Bellinger   vhost/scsi: Add A...
694
695
696
697
698
699
700
701
702
703
704
705
706
707
  	if (sgl_count < 0)
  		return sgl_count;
  
  	sg_init_table(cmd->tvc_sgl, sgl_count);
  	cmd->tvc_sgl_count = sgl_count;
  	pr_debug("%s data_sg %p data_sgl_count %u
  ", __func__,
  		  cmd->tvc_sgl, cmd->tvc_sgl_count);
  
  	ret = vhost_scsi_iov_to_sgl(cmd, write, data_iter,
  				    cmd->tvc_sgl, cmd->tvc_sgl_count);
  	if (ret < 0) {
  		cmd->tvc_sgl_count = 0;
  		return ret;
e31885dd9   Nicholas Bellinger   vhost/scsi: Add T...
708
709
710
  	}
  	return 0;
  }
462438608   Nicholas Bellinger   vhost-scsi: Add m...
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
  static int vhost_scsi_to_tcm_attr(int attr)
  {
  	switch (attr) {
  	case VIRTIO_SCSI_S_SIMPLE:
  		return TCM_SIMPLE_TAG;
  	case VIRTIO_SCSI_S_ORDERED:
  		return TCM_ORDERED_TAG;
  	case VIRTIO_SCSI_S_HEAD:
  		return TCM_HEAD_TAG;
  	case VIRTIO_SCSI_S_ACA:
  		return TCM_ACA_TAG;
  	default:
  		break;
  	}
  	return TCM_SIMPLE_TAG;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
727
  static void vhost_scsi_submission_work(struct work_struct *work)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
728
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
729
730
731
  	struct vhost_scsi_cmd *cmd =
  		container_of(work, struct vhost_scsi_cmd, work);
  	struct vhost_scsi_nexus *tv_nexus;
3c63f66a0   Asias He   vhost-scsi: Renam...
732
  	struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
733
734
  	struct scatterlist *sg_ptr, *sg_prot_ptr = NULL;
  	int rc;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
735

95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
736
  	/* FIXME: BIDI operation */
3c63f66a0   Asias He   vhost-scsi: Renam...
737
738
  	if (cmd->tvc_sgl_count) {
  		sg_ptr = cmd->tvc_sgl;
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
739
740
741
742
743
  
  		if (cmd->tvc_prot_sgl_count)
  			sg_prot_ptr = cmd->tvc_prot_sgl;
  		else
  			se_cmd->prot_pto = true;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
744
745
746
  	} else {
  		sg_ptr = NULL;
  	}
3c63f66a0   Asias He   vhost-scsi: Renam...
747
  	tv_nexus = cmd->tvc_nexus;
9f0abc155   Nicholas Bellinger   tcm_vhost: Conver...
748

649ee0549   Bart Van Assche   target: Move task...
749
  	se_cmd->tag = 0;
9f0abc155   Nicholas Bellinger   tcm_vhost: Conver...
750
  	rc = target_submit_cmd_map_sgls(se_cmd, tv_nexus->tvn_se_sess,
3c63f66a0   Asias He   vhost-scsi: Renam...
751
752
  			cmd->tvc_cdb, &cmd->tvc_sense_buf[0],
  			cmd->tvc_lun, cmd->tvc_exp_data_len,
462438608   Nicholas Bellinger   vhost-scsi: Add m...
753
754
755
756
  			vhost_scsi_to_tcm_attr(cmd->tvc_task_attr),
  			cmd->tvc_data_direction, TARGET_SCF_ACK_KREF,
  			sg_ptr, cmd->tvc_sgl_count, NULL, 0, sg_prot_ptr,
  			cmd->tvc_prot_sgl_count);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
757
758
  	if (rc < 0) {
  		transport_send_check_condition_and_sense(se_cmd,
9f0abc155   Nicholas Bellinger   tcm_vhost: Conver...
759
  				TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
760
  		transport_generic_free_cmd(se_cmd, 0);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
761
  	}
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
762
  }
683bd967d   Asias He   vhost-scsi: Make ...
763
764
765
766
  static void
  vhost_scsi_send_bad_target(struct vhost_scsi *vs,
  			   struct vhost_virtqueue *vq,
  			   int head, unsigned out)
637ab21e2   Asias He   tcm_vhost: Add vh...
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
  {
  	struct virtio_scsi_cmd_resp __user *resp;
  	struct virtio_scsi_cmd_resp rsp;
  	int ret;
  
  	memset(&rsp, 0, sizeof(rsp));
  	rsp.response = VIRTIO_SCSI_S_BAD_TARGET;
  	resp = vq->iov[out].iov_base;
  	ret = __copy_to_user(resp, &rsp, sizeof(rsp));
  	if (!ret)
  		vhost_add_used_and_signal(&vs->dev, vq, head, 0);
  	else
  		pr_err("Faulted on virtio_scsi_cmd_resp
  ");
  }
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
  static int
  vhost_scsi_get_desc(struct vhost_scsi *vs, struct vhost_virtqueue *vq,
  		    struct vhost_scsi_ctx *vc)
  {
  	int ret = -ENXIO;
  
  	vc->head = vhost_get_vq_desc(vq, vq->iov,
  				     ARRAY_SIZE(vq->iov), &vc->out, &vc->in,
  				     NULL, NULL);
  
  	pr_debug("vhost_get_vq_desc: head: %d, out: %u in: %u
  ",
  		 vc->head, vc->out, vc->in);
  
  	/* On error, stop handling until the next kick. */
  	if (unlikely(vc->head < 0))
  		goto done;
  
  	/* Nothing new?  Wait for eventfd to tell us they refilled. */
  	if (vc->head == vq->num) {
  		if (unlikely(vhost_enable_notify(&vs->dev, vq))) {
  			vhost_disable_notify(&vs->dev, vq);
  			ret = -EAGAIN;
  		}
  		goto done;
  	}
  
  	/*
  	 * Get the size of request and response buffers.
  	 * FIXME: Not correct for BIDI operation
  	 */
  	vc->out_size = iov_length(vq->iov, vc->out);
  	vc->in_size = iov_length(&vq->iov[vc->out], vc->in);
  
  	/*
  	 * Copy over the virtio-scsi request header, which for a
  	 * ANY_LAYOUT enabled guest may span multiple iovecs, or a
  	 * single iovec may contain both the header + outgoing
  	 * WRITE payloads.
  	 *
  	 * copy_from_iter() will advance out_iter, so that it will
  	 * point at the start of the outgoing WRITE payload, if
  	 * DMA_TO_DEVICE is set.
  	 */
  	iov_iter_init(&vc->out_iter, WRITE, vq->iov, vc->out, vc->out_size);
  	ret = 0;
  
  done:
  	return ret;
  }
  
  static int
  vhost_scsi_chk_size(struct vhost_virtqueue *vq, struct vhost_scsi_ctx *vc)
  {
  	if (unlikely(vc->in_size < vc->rsp_size)) {
  		vq_err(vq,
  		       "Response buf too small, need min %zu bytes got %zu",
  		       vc->rsp_size, vc->in_size);
  		return -EINVAL;
  	} else if (unlikely(vc->out_size < vc->req_size)) {
  		vq_err(vq,
  		       "Request buf too small, need min %zu bytes got %zu",
  		       vc->req_size, vc->out_size);
  		return -EIO;
  	}
  
  	return 0;
  }
  
  static int
  vhost_scsi_get_req(struct vhost_virtqueue *vq, struct vhost_scsi_ctx *vc,
  		   struct vhost_scsi_tpg **tpgp)
  {
  	int ret = -EIO;
  
  	if (unlikely(!copy_from_iter_full(vc->req, vc->req_size,
  					  &vc->out_iter))) {
  		vq_err(vq, "Faulted on copy_from_iter
  ");
  	} else if (unlikely(*vc->lunp != 1)) {
  		/* virtio-scsi spec requires byte 0 of the lun to be 1 */
  		vq_err(vq, "Illegal virtio-scsi lun: %u
  ", *vc->lunp);
  	} else {
  		struct vhost_scsi_tpg **vs_tpg, *tpg;
  
  		vs_tpg = vq->private_data;	/* validated at handler entry */
  
  		tpg = READ_ONCE(vs_tpg[*vc->target]);
  		if (unlikely(!tpg)) {
  			vq_err(vq, "Target 0x%x does not exist
  ", *vc->target);
  		} else {
  			if (tpgp)
  				*tpgp = tpg;
  			ret = 0;
  		}
  	}
  
  	return ret;
  }
683bd967d   Asias He   vhost-scsi: Make ...
883
884
  static void
  vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
885
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
886
  	struct vhost_scsi_tpg **vs_tpg, *tpg;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
887
  	struct virtio_scsi_cmd_req v_req;
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
888
  	struct virtio_scsi_cmd_req_pi v_req_pi;
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
889
  	struct vhost_scsi_ctx vc;
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
890
  	struct vhost_scsi_cmd *cmd;
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
891
  	struct iov_iter in_iter, prot_iter, data_iter;
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
892
  	u64 tag;
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
893
  	u32 exp_data_len, data_direction;
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
894
  	int ret, prot_bytes;
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
895
  	u16 lun;
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
896
  	u8 task_attr;
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
897
  	bool t10_pi = vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI);
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
898
  	void *cdb;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
899

e7802212e   Asias He   vhost-scsi: Alway...
900
  	mutex_lock(&vq->mutex);
4f7f46d32   Asias He   tcm_vhost: Use vq...
901
902
903
  	/*
  	 * We can handle the vq only after the endpoint is setup by calling the
  	 * VHOST_SCSI_SET_ENDPOINT ioctl.
4f7f46d32   Asias He   tcm_vhost: Use vq...
904
  	 */
e7802212e   Asias He   vhost-scsi: Alway...
905
  	vs_tpg = vq->private_data;
4f7f46d32   Asias He   tcm_vhost: Use vq...
906
  	if (!vs_tpg)
e7802212e   Asias He   vhost-scsi: Alway...
907
  		goto out;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
908

09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
909
910
  	memset(&vc, 0, sizeof(vc));
  	vc.rsp_size = sizeof(struct virtio_scsi_cmd_resp);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
911
912
913
  	vhost_disable_notify(&vs->dev, vq);
  
  	for (;;) {
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
914
915
916
  		ret = vhost_scsi_get_desc(vs, vq, &vc);
  		if (ret)
  			goto err;
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
917
918
919
920
921
  		/*
  		 * Setup pointers and values based upon different virtio-scsi
  		 * request header if T10_PI is enabled in KVM guest.
  		 */
  		if (t10_pi) {
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
922
923
924
925
  			vc.req = &v_req_pi;
  			vc.req_size = sizeof(v_req_pi);
  			vc.lunp = &v_req_pi.lun[0];
  			vc.target = &v_req_pi.lun[1];
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
926
  		} else {
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
927
928
929
930
  			vc.req = &v_req;
  			vc.req_size = sizeof(v_req);
  			vc.lunp = &v_req.lun[0];
  			vc.target = &v_req.lun[1];
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
931
  		}
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
932
  		/*
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
933
934
935
  		 * Validate the size of request and response buffers.
  		 * Check for a sane response buffer so we can report
  		 * early errors back to the guest.
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
936
  		 */
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
937
938
939
  		ret = vhost_scsi_chk_size(vq, &vc);
  		if (ret)
  			goto err;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
940

09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
941
942
943
944
945
  		ret = vhost_scsi_get_req(vq, &vc, &tpg);
  		if (ret)
  			goto err;
  
  		ret = -EIO;	/* bad target on any error from here on */
7fe412d07   Venkatesh Srinivas   vhost/scsi: Check...
946

95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
947
  		/*
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
948
949
950
  		 * Determine data_direction by calculating the total outgoing
  		 * iovec sizes + incoming iovec sizes vs. virtio-scsi request +
  		 * response headers respectively.
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
951
  		 *
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
952
953
954
955
956
957
  		 * For DMA_TO_DEVICE this is out_iter, which is already pointing
  		 * to the right place.
  		 *
  		 * For DMA_FROM_DEVICE, the iovec will be just past the end
  		 * of the virtio-scsi response header in either the same
  		 * or immediately following iovec.
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
958
  		 *
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
959
960
  		 * Any associated T10_PI bytes for the outgoing / incoming
  		 * payloads are included in calculation of exp_data_len here.
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
961
  		 */
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
962
  		prot_bytes = 0;
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
963
  		if (vc.out_size > vc.req_size) {
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
964
  			data_direction = DMA_TO_DEVICE;
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
965
966
967
  			exp_data_len = vc.out_size - vc.req_size;
  			data_iter = vc.out_iter;
  		} else if (vc.in_size > vc.rsp_size) {
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
968
  			data_direction = DMA_FROM_DEVICE;
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
969
  			exp_data_len = vc.in_size - vc.rsp_size;
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
970

09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
971
972
973
  			iov_iter_init(&in_iter, READ, &vq->iov[vc.out], vc.in,
  				      vc.rsp_size + exp_data_len);
  			iov_iter_advance(&in_iter, vc.rsp_size);
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
974
975
976
977
978
979
980
981
982
  			data_iter = in_iter;
  		} else {
  			data_direction = DMA_NONE;
  			exp_data_len = 0;
  		}
  		/*
  		 * If T10_PI header + payload is present, setup prot_iter values
  		 * and recalculate data_iter for vhost_scsi_mapal() mapping to
  		 * host scatterlists via get_user_pages_fast().
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
983
  		 */
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
984
  		if (t10_pi) {
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
985
986
  			if (v_req_pi.pi_bytesout) {
  				if (data_direction != DMA_TO_DEVICE) {
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
987
988
989
  					vq_err(vq, "Received non zero pi_bytesout,"
  						" but wrong data_direction
  ");
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
990
  					goto err;
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
991
  				}
e72fd72e2   Michael S. Tsirkin   vhost/scsi: parti...
992
  				prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesout);
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
993
994
  			} else if (v_req_pi.pi_bytesin) {
  				if (data_direction != DMA_FROM_DEVICE) {
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
995
996
997
  					vq_err(vq, "Received non zero pi_bytesin,"
  						" but wrong data_direction
  ");
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
998
  					goto err;
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
999
  				}
e72fd72e2   Michael S. Tsirkin   vhost/scsi: parti...
1000
  				prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesin);
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
1001
  			}
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
1002
  			/*
4542d623c   Greg Edwards   vhost/scsi: trunc...
1003
1004
  			 * Set prot_iter to data_iter and truncate it to
  			 * prot_bytes, and advance data_iter past any
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
1005
1006
1007
1008
1009
  			 * preceeding prot_bytes that may be present.
  			 *
  			 * Also fix up the exp_data_len to reflect only the
  			 * actual data payload length.
  			 */
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
1010
  			if (prot_bytes) {
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
1011
1012
  				exp_data_len -= prot_bytes;
  				prot_iter = data_iter;
4542d623c   Greg Edwards   vhost/scsi: trunc...
1013
  				iov_iter_truncate(&prot_iter, prot_bytes);
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
1014
  				iov_iter_advance(&data_iter, prot_bytes);
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
1015
  			}
e72fd72e2   Michael S. Tsirkin   vhost/scsi: parti...
1016
  			tag = vhost64_to_cpu(vq, v_req_pi.tag);
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
1017
1018
1019
1020
  			task_attr = v_req_pi.task_attr;
  			cdb = &v_req_pi.cdb[0];
  			lun = ((v_req_pi.lun[2] << 8) | v_req_pi.lun[3]) & 0x3FFF;
  		} else {
e72fd72e2   Michael S. Tsirkin   vhost/scsi: parti...
1021
  			tag = vhost64_to_cpu(vq, v_req.tag);
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
1022
1023
1024
1025
  			task_attr = v_req.task_attr;
  			cdb = &v_req.cdb[0];
  			lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
  		}
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
1026
  		/*
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
1027
1028
1029
  		 * Check that the received CDB size does not exceeded our
  		 * hardcoded max for vhost-scsi, then get a pre-allocated
  		 * cmd descriptor for the new virtio-scsi tag.
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
1030
1031
1032
  		 *
  		 * TODO what if cdb was too small for varlen cdb header?
  		 */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1033
  		if (unlikely(scsi_command_size(cdb) > VHOST_SCSI_MAX_CDB_SIZE)) {
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
1034
1035
1036
  			vq_err(vq, "Received SCSI CDB with command_size: %d that"
  				" exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d
  ",
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1037
  				scsi_command_size(cdb), VHOST_SCSI_MAX_CDB_SIZE);
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
1038
  				goto err;
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
1039
  		}
95e7c4341   Nicholas Bellinger   vhost/scsi: Enabl...
1040
  		cmd = vhost_scsi_get_tag(vq, tpg, cdb, tag, lun, task_attr,
9f977ef7b   Nicholas Bellinger   vhost-scsi: Inclu...
1041
1042
  					 exp_data_len + prot_bytes,
  					 data_direction);
3c63f66a0   Asias He   vhost-scsi: Renam...
1043
  		if (IS_ERR(cmd)) {
4824d3bfb   Nicholas Bellinger   vhost/scsi: Conve...
1044
1045
  			vq_err(vq, "vhost_scsi_get_tag failed %ld
  ",
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
1046
  			       PTR_ERR(cmd));
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
1047
  			goto err;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1048
  		}
3c63f66a0   Asias He   vhost-scsi: Renam...
1049
1050
  		cmd->tvc_vhost = vs;
  		cmd->tvc_vq = vq;
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
1051
1052
  		cmd->tvc_resp_iov = vq->iov[vc.out];
  		cmd->tvc_in_iovs = vc.in;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1053

057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1054
1055
  		pr_debug("vhost_scsi got command opcode: %#02x, lun: %d
  ",
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
1056
1057
1058
1059
  			 cmd->tvc_cdb[0], cmd->tvc_lun);
  		pr_debug("cmd: %p exp_data_len: %d, prot_bytes: %d data_direction:"
  			 " %d
  ", cmd, exp_data_len, prot_bytes, data_direction);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1060
1061
  
  		if (data_direction != DMA_NONE) {
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
1062
1063
1064
  			if (unlikely(vhost_scsi_mapal(cmd, prot_bytes,
  						      &prot_iter, exp_data_len,
  						      &data_iter))) {
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1065
1066
  				vq_err(vq, "Failed to map iov to sgl
  ");
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1067
  				vhost_scsi_release_cmd(&cmd->tvc_se_cmd);
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
1068
  				goto err;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1069
1070
  			}
  		}
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1071
1072
1073
  		/*
  		 * Save the descriptor from vhost_get_vq_desc() to be used to
  		 * complete the virtio-scsi request in TCM callback context via
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
1074
  		 * vhost_scsi_queue_data_in() and vhost_scsi_queue_status()
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1075
  		 */
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
1076
  		cmd->tvc_vq_desc = vc.head;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1077
  		/*
09b13fa8c   Nicholas Bellinger   vhost/scsi: Add A...
1078
1079
1080
1081
  		 * Dispatch cmd descriptor for cmwq execution in process
  		 * context provided by vhost_scsi_workqueue.  This also ensures
  		 * cmd is executed on the same kworker CPU as this vhost
  		 * thread to gain positive L2 cache locality effects.
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1082
  		 */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1083
1084
  		INIT_WORK(&cmd->work, vhost_scsi_submission_work);
  		queue_work(vhost_scsi_workqueue, &cmd->work);
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
  		ret = 0;
  err:
  		/*
  		 * ENXIO:  No more requests, or read error, wait for next kick
  		 * EINVAL: Invalid response buffer, drop the request
  		 * EIO:    Respond with bad target
  		 * EAGAIN: Pending request
  		 */
  		if (ret == -ENXIO)
  			break;
  		else if (ret == -EIO)
  			vhost_scsi_send_bad_target(vs, vq, vc.head, vc.out);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1097
  	}
e7802212e   Asias He   vhost-scsi: Alway...
1098
  out:
7ea206cf3   Asias He   tcm_vhost: Fix tv...
1099
  	mutex_unlock(&vq->mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1100
  }
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1101
  static void
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
1102
1103
1104
  vhost_scsi_send_tmf_reject(struct vhost_scsi *vs,
  			   struct vhost_virtqueue *vq,
  			   struct vhost_scsi_ctx *vc)
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1105
1106
1107
1108
1109
1110
1111
1112
1113
  {
  	struct virtio_scsi_ctrl_tmf_resp __user *resp;
  	struct virtio_scsi_ctrl_tmf_resp rsp;
  	int ret;
  
  	pr_debug("%s
  ", __func__);
  	memset(&rsp, 0, sizeof(rsp));
  	rsp.response = VIRTIO_SCSI_S_FUNCTION_REJECTED;
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1114
  	resp = vq->iov[vc->out].iov_base;
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1115
1116
  	ret = __copy_to_user(resp, &rsp, sizeof(rsp));
  	if (!ret)
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1117
  		vhost_add_used_and_signal(&vs->dev, vq, vc->head, 0);
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1118
1119
1120
1121
1122
1123
1124
  	else
  		pr_err("Faulted on virtio_scsi_ctrl_tmf_resp
  ");
  }
  
  static void
  vhost_scsi_send_an_resp(struct vhost_scsi *vs,
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1125
1126
  			struct vhost_virtqueue *vq,
  			struct vhost_scsi_ctx *vc)
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1127
1128
1129
1130
1131
1132
1133
1134
1135
  {
  	struct virtio_scsi_ctrl_an_resp __user *resp;
  	struct virtio_scsi_ctrl_an_resp rsp;
  	int ret;
  
  	pr_debug("%s
  ", __func__);
  	memset(&rsp, 0, sizeof(rsp));	/* event_actual = 0 */
  	rsp.response = VIRTIO_SCSI_S_OK;
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1136
  	resp = vq->iov[vc->out].iov_base;
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1137
1138
  	ret = __copy_to_user(resp, &rsp, sizeof(rsp));
  	if (!ret)
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1139
  		vhost_add_used_and_signal(&vs->dev, vq, vc->head, 0);
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
  	else
  		pr_err("Faulted on virtio_scsi_ctrl_an_resp
  ");
  }
  
  static void
  vhost_scsi_ctl_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
  {
  	union {
  		__virtio32 type;
  		struct virtio_scsi_ctrl_an_req an;
  		struct virtio_scsi_ctrl_tmf_req tmf;
  	} v_req;
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1153
1154
1155
  	struct vhost_scsi_ctx vc;
  	size_t typ_size;
  	int ret;
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1156
1157
1158
1159
1160
1161
1162
1163
  
  	mutex_lock(&vq->mutex);
  	/*
  	 * We can handle the vq only after the endpoint is setup by calling the
  	 * VHOST_SCSI_SET_ENDPOINT ioctl.
  	 */
  	if (!vq->private_data)
  		goto out;
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1164
  	memset(&vc, 0, sizeof(vc));
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1165
1166
1167
  	vhost_disable_notify(&vs->dev, vq);
  
  	for (;;) {
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1168
1169
1170
  		ret = vhost_scsi_get_desc(vs, vq, &vc);
  		if (ret)
  			goto err;
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1171
1172
  
  		/*
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1173
1174
  		 * Get the request type first in order to setup
  		 * other parameters dependent on the type.
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1175
  		 */
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1176
  		vc.req = &v_req.type;
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1177
  		typ_size = sizeof(v_req.type);
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1178
1179
  		if (unlikely(!copy_from_iter_full(vc.req, typ_size,
  						  &vc.out_iter))) {
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1180
1181
1182
  			vq_err(vq, "Faulted on copy_from_iter tmf type
  ");
  			/*
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1183
1184
  			 * The size of the response buffer depends on the
  			 * request type and must be validated against it.
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1185
1186
1187
1188
1189
1190
1191
1192
  			 * Since the request type is not known, don't send
  			 * a response.
  			 */
  			continue;
  		}
  
  		switch (v_req.type) {
  		case VIRTIO_SCSI_T_TMF:
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1193
1194
1195
1196
1197
  			vc.req = &v_req.tmf;
  			vc.req_size = sizeof(struct virtio_scsi_ctrl_tmf_req);
  			vc.rsp_size = sizeof(struct virtio_scsi_ctrl_tmf_resp);
  			vc.lunp = &v_req.tmf.lun[0];
  			vc.target = &v_req.tmf.lun[1];
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1198
1199
1200
  			break;
  		case VIRTIO_SCSI_T_AN_QUERY:
  		case VIRTIO_SCSI_T_AN_SUBSCRIBE:
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1201
1202
1203
1204
1205
  			vc.req = &v_req.an;
  			vc.req_size = sizeof(struct virtio_scsi_ctrl_an_req);
  			vc.rsp_size = sizeof(struct virtio_scsi_ctrl_an_resp);
  			vc.lunp = &v_req.an.lun[0];
  			vc.target = NULL;
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1206
1207
1208
1209
1210
1211
1212
  			break;
  		default:
  			vq_err(vq, "Unknown control request %d", v_req.type);
  			continue;
  		}
  
  		/*
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1213
1214
1215
  		 * Validate the size of request and response buffers.
  		 * Check for a sane response buffer so we can report
  		 * early errors back to the guest.
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1216
  		 */
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1217
1218
1219
  		ret = vhost_scsi_chk_size(vq, &vc);
  		if (ret)
  			goto err;
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1220

3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1221
1222
1223
1224
1225
  		/*
  		 * Get the rest of the request now that its size is known.
  		 */
  		vc.req += typ_size;
  		vc.req_size -= typ_size;
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1226

3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1227
1228
1229
  		ret = vhost_scsi_get_req(vq, &vc, NULL);
  		if (ret)
  			goto err;
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1230

3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1231
  		if (v_req.type == VIRTIO_SCSI_T_TMF)
09d758329   Bijan Mottahedeh   vhost/scsi: Use c...
1232
  			vhost_scsi_send_tmf_reject(vs, vq, &vc);
3f8ca2e11   Bijan Mottahedeh   vhost/scsi: Extra...
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
  		else
  			vhost_scsi_send_an_resp(vs, vq, &vc);
  err:
  		/*
  		 * ENXIO:  No more requests, or read error, wait for next kick
  		 * EINVAL: Invalid response buffer, drop the request
  		 * EIO:    Respond with bad target
  		 * EAGAIN: Pending request
  		 */
  		if (ret == -ENXIO)
  			break;
  		else if (ret == -EIO)
  			vhost_scsi_send_bad_target(vs, vq, vc.head, vc.out);
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1246
1247
1248
1249
  	}
  out:
  	mutex_unlock(&vq->mutex);
  }
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1250
1251
  static void vhost_scsi_ctl_handle_kick(struct vhost_work *work)
  {
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1252
1253
1254
  	struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
  						poll.work);
  	struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1255
1256
  	pr_debug("%s: The handling func for control queue.
  ", __func__);
0d02dbd68   Bijan Mottahedeh   vhost/scsi: Respo...
1257
  	vhost_scsi_ctl_handle_vq(vs, vq);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1258
  }
683bd967d   Asias He   vhost-scsi: Make ...
1259
  static void
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1260
1261
  vhost_scsi_send_evt(struct vhost_scsi *vs,
  		   struct vhost_scsi_tpg *tpg,
683bd967d   Asias He   vhost-scsi: Make ...
1262
1263
1264
  		   struct se_lun *lun,
  		   u32 event,
  		   u32 reason)
a6c9af873   Asias He   tcm_vhost: Add ho...
1265
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1266
  	struct vhost_scsi_evt *evt;
a6c9af873   Asias He   tcm_vhost: Add ho...
1267

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1268
  	evt = vhost_scsi_allocate_evt(vs, event, reason);
a6c9af873   Asias He   tcm_vhost: Add ho...
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
  	if (!evt)
  		return;
  
  	if (tpg && lun) {
  		/* TODO: share lun setup code with virtio-scsi.ko */
  		/*
  		 * Note: evt->event is zeroed when we allocate it and
  		 * lun[4-7] need to be zero according to virtio-scsi spec.
  		 */
  		evt->event.lun[0] = 0x01;
59c816c1f   Dan Carpenter   vhost/scsi: poten...
1279
  		evt->event.lun[1] = tpg->tport_tpgt;
a6c9af873   Asias He   tcm_vhost: Add ho...
1280
1281
1282
1283
1284
1285
1286
1287
  		if (lun->unpacked_lun >= 256)
  			evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ;
  		evt->event.lun[3] = lun->unpacked_lun & 0xFF;
  	}
  
  	llist_add(&evt->list, &vs->vs_event_list);
  	vhost_work_queue(&vs->dev, &vs->vs_event_work);
  }
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1288
1289
  static void vhost_scsi_evt_handle_kick(struct vhost_work *work)
  {
a6c9af873   Asias He   tcm_vhost: Add ho...
1290
1291
1292
1293
1294
1295
1296
1297
1298
  	struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
  						poll.work);
  	struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);
  
  	mutex_lock(&vq->mutex);
  	if (!vq->private_data)
  		goto out;
  
  	if (vs->vs_events_missed)
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1299
  		vhost_scsi_send_evt(vs, NULL, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
a6c9af873   Asias He   tcm_vhost: Add ho...
1300
1301
  out:
  	mutex_unlock(&vq->mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1302
1303
1304
1305
1306
1307
1308
  }
  
  static void vhost_scsi_handle_kick(struct vhost_work *work)
  {
  	struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
  						poll.work);
  	struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);
1b7f390eb   Asias He   tcm_vhost: Multi-...
1309
  	vhost_scsi_handle_vq(vs, vq);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1310
  }
4f7f46d32   Asias He   tcm_vhost: Use vq...
1311
1312
  static void vhost_scsi_flush_vq(struct vhost_scsi *vs, int index)
  {
3ab2e420e   Asias He   vhost: Allow devi...
1313
  	vhost_poll_flush(&vs->vqs[index].vq.poll);
4f7f46d32   Asias He   tcm_vhost: Use vq...
1314
  }
3dfbff328   Michael S. Tsirkin   tcm_vhost: docume...
1315
  /* Callers must hold dev mutex */
4f7f46d32   Asias He   tcm_vhost: Use vq...
1316
1317
  static void vhost_scsi_flush(struct vhost_scsi *vs)
  {
f2f0173d6   Asias He   tcm_vhost: Wait f...
1318
  	struct vhost_scsi_inflight *old_inflight[VHOST_SCSI_MAX_VQ];
4f7f46d32   Asias He   tcm_vhost: Use vq...
1319
  	int i;
f2f0173d6   Asias He   tcm_vhost: Wait f...
1320
  	/* Init new inflight and remember the old inflight */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1321
  	vhost_scsi_init_inflight(vs, old_inflight);
f2f0173d6   Asias He   tcm_vhost: Wait f...
1322
1323
1324
1325
1326
1327
1328
  
  	/*
  	 * The inflight->kref was initialized to 1. We decrement it here to
  	 * indicate the start of the flush operation so that it will reach 0
  	 * when all the reqs are finished.
  	 */
  	for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1329
  		kref_put(&old_inflight[i]->kref, vhost_scsi_done_inflight);
f2f0173d6   Asias He   tcm_vhost: Wait f...
1330
1331
  
  	/* Flush both the vhost poll and vhost work */
4f7f46d32   Asias He   tcm_vhost: Use vq...
1332
1333
1334
  	for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
  		vhost_scsi_flush_vq(vs, i);
  	vhost_work_flush(&vs->dev, &vs->vs_completion_work);
a6c9af873   Asias He   tcm_vhost: Add ho...
1335
  	vhost_work_flush(&vs->dev, &vs->vs_event_work);
f2f0173d6   Asias He   tcm_vhost: Wait f...
1336
1337
1338
1339
  
  	/* Wait for all reqs issued before the flush to be finished */
  	for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
  		wait_for_completion(&old_inflight[i]->comp);
4f7f46d32   Asias He   tcm_vhost: Use vq...
1340
  }
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1341
1342
  /*
   * Called from vhost_scsi_ioctl() context to walk the list of available
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1343
   * vhost_scsi_tpg with an active struct vhost_scsi_nexus
f2b7daf5b   Asias He   tcm_vhost: Refact...
1344
1345
   *
   *  The lock nesting rule is:
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1346
   *    vhost_scsi_mutex -> vs->dev.mutex -> tpg->tv_tpg_mutex -> vq->mutex
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1347
   */
683bd967d   Asias He   vhost-scsi: Make ...
1348
1349
1350
  static int
  vhost_scsi_set_endpoint(struct vhost_scsi *vs,
  			struct vhost_scsi_target *t)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1351
  {
ab8edab13   Nicholas Bellinger   vhost-scsi: Take ...
1352
  	struct se_portal_group *se_tpg;
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1353
1354
1355
  	struct vhost_scsi_tport *tv_tport;
  	struct vhost_scsi_tpg *tpg;
  	struct vhost_scsi_tpg **vs_tpg;
4f7f46d32   Asias He   tcm_vhost: Use vq...
1356
1357
  	struct vhost_virtqueue *vq;
  	int index, ret, i, len;
67e18cf9a   Asias He   tcm_vhost: Multi-...
1358
  	bool match = false;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1359

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1360
  	mutex_lock(&vhost_scsi_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1361
  	mutex_lock(&vs->dev.mutex);
f2b7daf5b   Asias He   tcm_vhost: Refact...
1362

057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1363
1364
1365
  	/* Verify that ring has been setup correctly. */
  	for (index = 0; index < vs->dev.nvqs; ++index) {
  		/* Verify that ring has been setup correctly. */
3ab2e420e   Asias He   vhost: Allow devi...
1366
  		if (!vhost_vq_access_ok(&vs->vqs[index].vq)) {
f2b7daf5b   Asias He   tcm_vhost: Refact...
1367
1368
  			ret = -EFAULT;
  			goto out;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1369
1370
  		}
  	}
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1371

4f7f46d32   Asias He   tcm_vhost: Use vq...
1372
1373
1374
  	len = sizeof(vs_tpg[0]) * VHOST_SCSI_MAX_TARGET;
  	vs_tpg = kzalloc(len, GFP_KERNEL);
  	if (!vs_tpg) {
f2b7daf5b   Asias He   tcm_vhost: Refact...
1375
1376
  		ret = -ENOMEM;
  		goto out;
4f7f46d32   Asias He   tcm_vhost: Use vq...
1377
1378
1379
  	}
  	if (vs->vs_tpg)
  		memcpy(vs_tpg, vs->vs_tpg, len);
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1380
  	list_for_each_entry(tpg, &vhost_scsi_list, tv_tpg_list) {
987183128   Asias He   vhost-scsi: Renam...
1381
1382
1383
  		mutex_lock(&tpg->tv_tpg_mutex);
  		if (!tpg->tpg_nexus) {
  			mutex_unlock(&tpg->tv_tpg_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1384
1385
  			continue;
  		}
987183128   Asias He   vhost-scsi: Renam...
1386
1387
  		if (tpg->tv_tpg_vhost_count != 0) {
  			mutex_unlock(&tpg->tv_tpg_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1388
1389
  			continue;
  		}
987183128   Asias He   vhost-scsi: Renam...
1390
  		tv_tport = tpg->tport;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1391

67e18cf9a   Asias He   tcm_vhost: Multi-...
1392
  		if (!strcmp(tv_tport->tport_name, t->vhost_wwpn)) {
987183128   Asias He   vhost-scsi: Renam...
1393
  			if (vs->vs_tpg && vs->vs_tpg[tpg->tport_tpgt]) {
4f7f46d32   Asias He   tcm_vhost: Use vq...
1394
  				kfree(vs_tpg);
987183128   Asias He   vhost-scsi: Renam...
1395
  				mutex_unlock(&tpg->tv_tpg_mutex);
f2b7daf5b   Asias He   tcm_vhost: Refact...
1396
1397
  				ret = -EEXIST;
  				goto out;
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1398
  			}
ab8edab13   Nicholas Bellinger   vhost-scsi: Take ...
1399
1400
1401
1402
1403
1404
1405
  			/*
  			 * In order to ensure individual vhost-scsi configfs
  			 * groups cannot be removed while in use by vhost ioctl,
  			 * go ahead and take an explicit se_tpg->tpg_group.cg_item
  			 * dependency now.
  			 */
  			se_tpg = &tpg->se_tpg;
d588cf8f6   Christoph Hellwig   target: Fix se_tp...
1406
  			ret = target_depend_item(&se_tpg->tpg_group.cg_item);
ab8edab13   Nicholas Bellinger   vhost-scsi: Take ...
1407
1408
1409
1410
1411
1412
1413
  			if (ret) {
  				pr_warn("configfs_depend_item() failed: %d
  ", ret);
  				kfree(vs_tpg);
  				mutex_unlock(&tpg->tv_tpg_mutex);
  				goto out;
  			}
987183128   Asias He   vhost-scsi: Renam...
1414
1415
1416
  			tpg->tv_tpg_vhost_count++;
  			tpg->vhost_scsi = vs;
  			vs_tpg[tpg->tport_tpgt] = tpg;
4e857c58e   Peter Zijlstra   arch: Mass conver...
1417
  			smp_mb__after_atomic();
67e18cf9a   Asias He   tcm_vhost: Multi-...
1418
  			match = true;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1419
  		}
987183128   Asias He   vhost-scsi: Renam...
1420
  		mutex_unlock(&tpg->tv_tpg_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1421
  	}
67e18cf9a   Asias He   tcm_vhost: Multi-...
1422
1423
1424
1425
  
  	if (match) {
  		memcpy(vs->vs_vhost_wwpn, t->vhost_wwpn,
  		       sizeof(vs->vs_vhost_wwpn));
4f7f46d32   Asias He   tcm_vhost: Use vq...
1426
  		for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
3ab2e420e   Asias He   vhost: Allow devi...
1427
  			vq = &vs->vqs[i].vq;
4f7f46d32   Asias He   tcm_vhost: Use vq...
1428
  			mutex_lock(&vq->mutex);
22fa90c7f   Asias He   vhost: Remove cus...
1429
  			vq->private_data = vs_tpg;
80f7d0301   Greg Kurz   vhost: rename vho...
1430
  			vhost_vq_init_access(vq);
4f7f46d32   Asias He   tcm_vhost: Use vq...
1431
1432
  			mutex_unlock(&vq->mutex);
  		}
67e18cf9a   Asias He   tcm_vhost: Multi-...
1433
1434
1435
1436
  		ret = 0;
  	} else {
  		ret = -EEXIST;
  	}
4f7f46d32   Asias He   tcm_vhost: Use vq...
1437
1438
1439
1440
1441
1442
1443
  	/*
  	 * Act as synchronize_rcu to make sure access to
  	 * old vs->vs_tpg is finished.
  	 */
  	vhost_scsi_flush(vs);
  	kfree(vs->vs_tpg);
  	vs->vs_tpg = vs_tpg;
f2b7daf5b   Asias He   tcm_vhost: Refact...
1444
  out:
67e18cf9a   Asias He   tcm_vhost: Multi-...
1445
  	mutex_unlock(&vs->dev.mutex);
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1446
  	mutex_unlock(&vhost_scsi_mutex);
67e18cf9a   Asias He   tcm_vhost: Multi-...
1447
  	return ret;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1448
  }
683bd967d   Asias He   vhost-scsi: Make ...
1449
1450
1451
  static int
  vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
  			  struct vhost_scsi_target *t)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1452
  {
ab8edab13   Nicholas Bellinger   vhost-scsi: Take ...
1453
  	struct se_portal_group *se_tpg;
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1454
1455
  	struct vhost_scsi_tport *tv_tport;
  	struct vhost_scsi_tpg *tpg;
4f7f46d32   Asias He   tcm_vhost: Use vq...
1456
1457
  	struct vhost_virtqueue *vq;
  	bool match = false;
67e18cf9a   Asias He   tcm_vhost: Multi-...
1458
1459
  	int index, ret, i;
  	u8 target;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1460

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1461
  	mutex_lock(&vhost_scsi_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1462
1463
1464
  	mutex_lock(&vs->dev.mutex);
  	/* Verify that ring has been setup correctly. */
  	for (index = 0; index < vs->dev.nvqs; ++index) {
3ab2e420e   Asias He   vhost: Allow devi...
1465
  		if (!vhost_vq_access_ok(&vs->vqs[index].vq)) {
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1466
  			ret = -EFAULT;
038e0af4a   Asias He   tcm_vhost: Add mi...
1467
  			goto err_dev;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1468
1469
  		}
  	}
4f7f46d32   Asias He   tcm_vhost: Use vq...
1470
1471
  
  	if (!vs->vs_tpg) {
f2b7daf5b   Asias He   tcm_vhost: Refact...
1472
1473
  		ret = 0;
  		goto err_dev;
4f7f46d32   Asias He   tcm_vhost: Use vq...
1474
  	}
67e18cf9a   Asias He   tcm_vhost: Multi-...
1475
1476
  	for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) {
  		target = i;
987183128   Asias He   vhost-scsi: Renam...
1477
1478
  		tpg = vs->vs_tpg[target];
  		if (!tpg)
67e18cf9a   Asias He   tcm_vhost: Multi-...
1479
  			continue;
987183128   Asias He   vhost-scsi: Renam...
1480
1481
  		mutex_lock(&tpg->tv_tpg_mutex);
  		tv_tport = tpg->tport;
67e18cf9a   Asias He   tcm_vhost: Multi-...
1482
1483
  		if (!tv_tport) {
  			ret = -ENODEV;
038e0af4a   Asias He   tcm_vhost: Add mi...
1484
  			goto err_tpg;
67e18cf9a   Asias He   tcm_vhost: Multi-...
1485
1486
1487
  		}
  
  		if (strcmp(tv_tport->tport_name, t->vhost_wwpn)) {
987183128   Asias He   vhost-scsi: Renam...
1488
  			pr_warn("tv_tport->tport_name: %s, tpg->tport_tpgt: %hu"
67e18cf9a   Asias He   tcm_vhost: Multi-...
1489
1490
  				" does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu
  ",
987183128   Asias He   vhost-scsi: Renam...
1491
  				tv_tport->tport_name, tpg->tport_tpgt,
67e18cf9a   Asias He   tcm_vhost: Multi-...
1492
1493
  				t->vhost_wwpn, t->vhost_tpgt);
  			ret = -EINVAL;
038e0af4a   Asias He   tcm_vhost: Add mi...
1494
  			goto err_tpg;
67e18cf9a   Asias He   tcm_vhost: Multi-...
1495
  		}
987183128   Asias He   vhost-scsi: Renam...
1496
1497
  		tpg->tv_tpg_vhost_count--;
  		tpg->vhost_scsi = NULL;
67e18cf9a   Asias He   tcm_vhost: Multi-...
1498
  		vs->vs_tpg[target] = NULL;
4f7f46d32   Asias He   tcm_vhost: Use vq...
1499
  		match = true;
987183128   Asias He   vhost-scsi: Renam...
1500
  		mutex_unlock(&tpg->tv_tpg_mutex);
ab8edab13   Nicholas Bellinger   vhost-scsi: Take ...
1501
1502
1503
1504
1505
  		/*
  		 * Release se_tpg->tpg_group.cg_item configfs dependency now
  		 * to allow vhost-scsi WWPN se_tpg->tpg_group shutdown to occur.
  		 */
  		se_tpg = &tpg->se_tpg;
d588cf8f6   Christoph Hellwig   target: Fix se_tp...
1506
  		target_undepend_item(&se_tpg->tpg_group.cg_item);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1507
  	}
4f7f46d32   Asias He   tcm_vhost: Use vq...
1508
1509
  	if (match) {
  		for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
3ab2e420e   Asias He   vhost: Allow devi...
1510
  			vq = &vs->vqs[i].vq;
4f7f46d32   Asias He   tcm_vhost: Use vq...
1511
  			mutex_lock(&vq->mutex);
22fa90c7f   Asias He   vhost: Remove cus...
1512
  			vq->private_data = NULL;
4f7f46d32   Asias He   tcm_vhost: Use vq...
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
  			mutex_unlock(&vq->mutex);
  		}
  	}
  	/*
  	 * Act as synchronize_rcu to make sure access to
  	 * old vs->vs_tpg is finished.
  	 */
  	vhost_scsi_flush(vs);
  	kfree(vs->vs_tpg);
  	vs->vs_tpg = NULL;
a6c9af873   Asias He   tcm_vhost: Add ho...
1523
  	WARN_ON(vs->vs_events_nr);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1524
  	mutex_unlock(&vs->dev.mutex);
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1525
  	mutex_unlock(&vhost_scsi_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1526
  	return 0;
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1527

038e0af4a   Asias He   tcm_vhost: Add mi...
1528
  err_tpg:
987183128   Asias He   vhost-scsi: Renam...
1529
  	mutex_unlock(&tpg->tv_tpg_mutex);
038e0af4a   Asias He   tcm_vhost: Add mi...
1530
  err_dev:
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1531
  	mutex_unlock(&vs->dev.mutex);
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1532
  	mutex_unlock(&vhost_scsi_mutex);
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1533
  	return ret;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1534
  }
4f7f46d32   Asias He   tcm_vhost: Use vq...
1535
1536
  static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
  {
ea16c5143   Michael S. Tsirkin   vhost: move acked...
1537
1538
  	struct vhost_virtqueue *vq;
  	int i;
4f7f46d32   Asias He   tcm_vhost: Use vq...
1539
1540
1541
1542
1543
1544
1545
1546
1547
  	if (features & ~VHOST_SCSI_FEATURES)
  		return -EOPNOTSUPP;
  
  	mutex_lock(&vs->dev.mutex);
  	if ((features & (1 << VHOST_F_LOG_ALL)) &&
  	    !vhost_log_access_ok(&vs->dev)) {
  		mutex_unlock(&vs->dev.mutex);
  		return -EFAULT;
  	}
ea16c5143   Michael S. Tsirkin   vhost: move acked...
1548
1549
1550
1551
1552
1553
1554
  
  	for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
  		vq = &vs->vqs[i].vq;
  		mutex_lock(&vq->mutex);
  		vq->acked_features = features;
  		mutex_unlock(&vq->mutex);
  	}
4f7f46d32   Asias He   tcm_vhost: Use vq...
1555
1556
1557
  	mutex_unlock(&vs->dev.mutex);
  	return 0;
  }
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1558
1559
  static int vhost_scsi_open(struct inode *inode, struct file *f)
  {
c7289312f   Asias He   vhost-scsi: Renam...
1560
  	struct vhost_scsi *vs;
3ab2e420e   Asias He   vhost: Allow devi...
1561
  	struct vhost_virtqueue **vqs;
595cb7549   Michael S. Tsirkin   vhost/scsi: use v...
1562
  	int r = -ENOMEM, i;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1563

dcda9b047   Michal Hocko   mm, tree wide: re...
1564
  	vs = kzalloc(sizeof(*vs), GFP_KERNEL | __GFP_NOWARN | __GFP_RETRY_MAYFAIL);
595cb7549   Michael S. Tsirkin   vhost/scsi: use v...
1565
1566
1567
1568
1569
  	if (!vs) {
  		vs = vzalloc(sizeof(*vs));
  		if (!vs)
  			goto err_vs;
  	}
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1570

6da2ec560   Kees Cook   treewide: kmalloc...
1571
  	vqs = kmalloc_array(VHOST_SCSI_MAX_VQ, sizeof(*vqs), GFP_KERNEL);
595cb7549   Michael S. Tsirkin   vhost/scsi: use v...
1572
1573
  	if (!vqs)
  		goto err_vqs;
3ab2e420e   Asias He   vhost: Allow devi...
1574

c7289312f   Asias He   vhost-scsi: Renam...
1575
  	vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work);
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1576
  	vhost_work_init(&vs->vs_event_work, vhost_scsi_evt_work);
a6c9af873   Asias He   tcm_vhost: Add ho...
1577

c7289312f   Asias He   vhost-scsi: Renam...
1578
1579
  	vs->vs_events_nr = 0;
  	vs->vs_events_missed = false;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1580

c7289312f   Asias He   vhost-scsi: Renam...
1581
1582
1583
1584
  	vqs[VHOST_SCSI_VQ_CTL] = &vs->vqs[VHOST_SCSI_VQ_CTL].vq;
  	vqs[VHOST_SCSI_VQ_EVT] = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
  	vs->vqs[VHOST_SCSI_VQ_CTL].vq.handle_kick = vhost_scsi_ctl_handle_kick;
  	vs->vqs[VHOST_SCSI_VQ_EVT].vq.handle_kick = vhost_scsi_evt_handle_kick;
3ab2e420e   Asias He   vhost: Allow devi...
1585
  	for (i = VHOST_SCSI_VQ_IO; i < VHOST_SCSI_MAX_VQ; i++) {
c7289312f   Asias He   vhost-scsi: Renam...
1586
1587
  		vqs[i] = &vs->vqs[i].vq;
  		vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick;
3ab2e420e   Asias He   vhost: Allow devi...
1588
  	}
59566b6e8   Zhi Yong Wu   vhost: remove the...
1589
  	vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ);
f2f0173d6   Asias He   tcm_vhost: Wait f...
1590

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1591
  	vhost_scsi_init_inflight(vs, NULL);
f2f0173d6   Asias He   tcm_vhost: Wait f...
1592

c7289312f   Asias He   vhost-scsi: Renam...
1593
  	f->private_data = vs;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1594
  	return 0;
595cb7549   Michael S. Tsirkin   vhost/scsi: use v...
1595

595cb7549   Michael S. Tsirkin   vhost/scsi: use v...
1596
  err_vqs:
684044415   Michael S. Tsirkin   vhost-scsi: don't...
1597
  	kvfree(vs);
595cb7549   Michael S. Tsirkin   vhost/scsi: use v...
1598
1599
  err_vs:
  	return r;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1600
1601
1602
1603
  }
  
  static int vhost_scsi_release(struct inode *inode, struct file *f)
  {
c7289312f   Asias He   vhost-scsi: Renam...
1604
  	struct vhost_scsi *vs = f->private_data;
67e18cf9a   Asias He   tcm_vhost: Multi-...
1605
  	struct vhost_scsi_target t;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1606

c7289312f   Asias He   vhost-scsi: Renam...
1607
1608
1609
1610
1611
  	mutex_lock(&vs->dev.mutex);
  	memcpy(t.vhost_wwpn, vs->vs_vhost_wwpn, sizeof(t.vhost_wwpn));
  	mutex_unlock(&vs->dev.mutex);
  	vhost_scsi_clear_endpoint(vs, &t);
  	vhost_dev_stop(&vs->dev);
f6f93f75a   夷则(Caspar)   vhost: remove unu...
1612
  	vhost_dev_cleanup(&vs->dev);
a6c9af873   Asias He   tcm_vhost: Add ho...
1613
  	/* Jobs can re-queue themselves in evt kick handler. Do extra flush. */
c7289312f   Asias He   vhost-scsi: Renam...
1614
1615
  	vhost_scsi_flush(vs);
  	kfree(vs->dev.vqs);
684044415   Michael S. Tsirkin   vhost-scsi: don't...
1616
  	kvfree(vs);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1617
1618
  	return 0;
  }
683bd967d   Asias He   vhost-scsi: Make ...
1619
1620
1621
1622
  static long
  vhost_scsi_ioctl(struct file *f,
  		 unsigned int ioctl,
  		 unsigned long arg)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1623
1624
1625
1626
1627
  {
  	struct vhost_scsi *vs = f->private_data;
  	struct vhost_scsi_target backend;
  	void __user *argp = (void __user *)arg;
  	u64 __user *featurep = argp;
11c634183   Asias He   tcm_vhost: Add io...
1628
1629
  	u32 __user *eventsp = argp;
  	u32 events_missed;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1630
  	u64 features;
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1631
  	int r, abi_version = VHOST_SCSI_ABI_VERSION;
3ab2e420e   Asias He   vhost: Allow devi...
1632
  	struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1633
1634
1635
1636
1637
  
  	switch (ioctl) {
  	case VHOST_SCSI_SET_ENDPOINT:
  		if (copy_from_user(&backend, argp, sizeof backend))
  			return -EFAULT;
6de7145ca   Michael S. Tsirkin   tcm_vhost: Fix vh...
1638
1639
  		if (backend.reserved != 0)
  			return -EOPNOTSUPP;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1640
1641
1642
1643
1644
  
  		return vhost_scsi_set_endpoint(vs, &backend);
  	case VHOST_SCSI_CLEAR_ENDPOINT:
  		if (copy_from_user(&backend, argp, sizeof backend))
  			return -EFAULT;
6de7145ca   Michael S. Tsirkin   tcm_vhost: Fix vh...
1645
1646
  		if (backend.reserved != 0)
  			return -EOPNOTSUPP;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1647
1648
1649
  
  		return vhost_scsi_clear_endpoint(vs, &backend);
  	case VHOST_SCSI_GET_ABI_VERSION:
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1650
  		if (copy_to_user(argp, &abi_version, sizeof abi_version))
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1651
1652
  			return -EFAULT;
  		return 0;
11c634183   Asias He   tcm_vhost: Add io...
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
  	case VHOST_SCSI_SET_EVENTS_MISSED:
  		if (get_user(events_missed, eventsp))
  			return -EFAULT;
  		mutex_lock(&vq->mutex);
  		vs->vs_events_missed = events_missed;
  		mutex_unlock(&vq->mutex);
  		return 0;
  	case VHOST_SCSI_GET_EVENTS_MISSED:
  		mutex_lock(&vq->mutex);
  		events_missed = vs->vs_events_missed;
  		mutex_unlock(&vq->mutex);
  		if (put_user(events_missed, eventsp))
  			return -EFAULT;
  		return 0;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1667
  	case VHOST_GET_FEATURES:
5dade7105   Nicholas Bellinger   tcm_vhost: Avoid ...
1668
  		features = VHOST_SCSI_FEATURES;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1669
1670
1671
1672
1673
1674
1675
1676
1677
  		if (copy_to_user(featurep, &features, sizeof features))
  			return -EFAULT;
  		return 0;
  	case VHOST_SET_FEATURES:
  		if (copy_from_user(&features, featurep, sizeof features))
  			return -EFAULT;
  		return vhost_scsi_set_features(vs, features);
  	default:
  		mutex_lock(&vs->dev.mutex);
935cdee7e   Michael S. Tsirkin   vhost: avoid back...
1678
1679
1680
1681
  		r = vhost_dev_ioctl(&vs->dev, ioctl, argp);
  		/* TODO: flush backend after dev ioctl. */
  		if (r == -ENOIOCTLCMD)
  			r = vhost_vring_ioctl(&vs->dev, ioctl, argp);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1682
1683
1684
1685
  		mutex_unlock(&vs->dev.mutex);
  		return r;
  	}
  }
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1686
1687
1688
1689
1690
1691
1692
  #ifdef CONFIG_COMPAT
  static long vhost_scsi_compat_ioctl(struct file *f, unsigned int ioctl,
  				unsigned long arg)
  {
  	return vhost_scsi_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
  }
  #endif
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1693
1694
1695
1696
  static const struct file_operations vhost_scsi_fops = {
  	.owner          = THIS_MODULE,
  	.release        = vhost_scsi_release,
  	.unlocked_ioctl = vhost_scsi_ioctl,
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1697
1698
1699
  #ifdef CONFIG_COMPAT
  	.compat_ioctl	= vhost_scsi_compat_ioctl,
  #endif
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
  	.open           = vhost_scsi_open,
  	.llseek		= noop_llseek,
  };
  
  static struct miscdevice vhost_scsi_misc = {
  	MISC_DYNAMIC_MINOR,
  	"vhost-scsi",
  	&vhost_scsi_fops,
  };
  
  static int __init vhost_scsi_register(void)
  {
  	return misc_register(&vhost_scsi_misc);
  }
f368ed608   Greg Kroah-Hartman   char: make misc_d...
1714
  static void vhost_scsi_deregister(void)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1715
  {
f368ed608   Greg Kroah-Hartman   char: make misc_d...
1716
  	misc_deregister(&vhost_scsi_misc);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1717
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1718
  static char *vhost_scsi_dump_proto_id(struct vhost_scsi_tport *tport)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
  {
  	switch (tport->tport_proto_id) {
  	case SCSI_PROTOCOL_SAS:
  		return "SAS";
  	case SCSI_PROTOCOL_FCP:
  		return "FCP";
  	case SCSI_PROTOCOL_ISCSI:
  		return "iSCSI";
  	default:
  		break;
  	}
  
  	return "Unknown";
  }
683bd967d   Asias He   vhost-scsi: Make ...
1733
  static void
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1734
  vhost_scsi_do_plug(struct vhost_scsi_tpg *tpg,
683bd967d   Asias He   vhost-scsi: Make ...
1735
  		  struct se_lun *lun, bool plug)
a6c9af873   Asias He   tcm_vhost: Add ho...
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
  {
  
  	struct vhost_scsi *vs = tpg->vhost_scsi;
  	struct vhost_virtqueue *vq;
  	u32 reason;
  
  	if (!vs)
  		return;
  
  	mutex_lock(&vs->dev.mutex);
a6c9af873   Asias He   tcm_vhost: Add ho...
1746
1747
1748
1749
1750
  
  	if (plug)
  		reason = VIRTIO_SCSI_EVT_RESET_RESCAN;
  	else
  		reason = VIRTIO_SCSI_EVT_RESET_REMOVED;
3ab2e420e   Asias He   vhost: Allow devi...
1751
  	vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
a6c9af873   Asias He   tcm_vhost: Add ho...
1752
  	mutex_lock(&vq->mutex);
ea16c5143   Michael S. Tsirkin   vhost: move acked...
1753
  	if (vhost_has_feature(vq, VIRTIO_SCSI_F_HOTPLUG))
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1754
  		vhost_scsi_send_evt(vs, tpg, lun,
ea16c5143   Michael S. Tsirkin   vhost: move acked...
1755
  				   VIRTIO_SCSI_T_TRANSPORT_RESET, reason);
a6c9af873   Asias He   tcm_vhost: Add ho...
1756
1757
1758
  	mutex_unlock(&vq->mutex);
  	mutex_unlock(&vs->dev.mutex);
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1759
  static void vhost_scsi_hotplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun)
a6c9af873   Asias He   tcm_vhost: Add ho...
1760
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1761
  	vhost_scsi_do_plug(tpg, lun, true);
a6c9af873   Asias He   tcm_vhost: Add ho...
1762
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1763
  static void vhost_scsi_hotunplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun)
a6c9af873   Asias He   tcm_vhost: Add ho...
1764
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1765
  	vhost_scsi_do_plug(tpg, lun, false);
a6c9af873   Asias He   tcm_vhost: Add ho...
1766
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1767
  static int vhost_scsi_port_link(struct se_portal_group *se_tpg,
683bd967d   Asias He   vhost-scsi: Make ...
1768
  			       struct se_lun *lun)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1769
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1770
1771
  	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
  				struct vhost_scsi_tpg, se_tpg);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1772

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1773
  	mutex_lock(&vhost_scsi_mutex);
a6c9af873   Asias He   tcm_vhost: Add ho...
1774

987183128   Asias He   vhost-scsi: Renam...
1775
1776
1777
  	mutex_lock(&tpg->tv_tpg_mutex);
  	tpg->tv_tpg_port_count++;
  	mutex_unlock(&tpg->tv_tpg_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1778

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1779
  	vhost_scsi_hotplug(tpg, lun);
a6c9af873   Asias He   tcm_vhost: Add ho...
1780

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1781
  	mutex_unlock(&vhost_scsi_mutex);
a6c9af873   Asias He   tcm_vhost: Add ho...
1782

057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1783
1784
  	return 0;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1785
  static void vhost_scsi_port_unlink(struct se_portal_group *se_tpg,
683bd967d   Asias He   vhost-scsi: Make ...
1786
  				  struct se_lun *lun)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1787
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1788
1789
  	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
  				struct vhost_scsi_tpg, se_tpg);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1790

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1791
  	mutex_lock(&vhost_scsi_mutex);
a6c9af873   Asias He   tcm_vhost: Add ho...
1792

987183128   Asias He   vhost-scsi: Renam...
1793
1794
1795
  	mutex_lock(&tpg->tv_tpg_mutex);
  	tpg->tv_tpg_port_count--;
  	mutex_unlock(&tpg->tv_tpg_mutex);
a6c9af873   Asias He   tcm_vhost: Add ho...
1796

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1797
  	vhost_scsi_hotunplug(tpg, lun);
a6c9af873   Asias He   tcm_vhost: Add ho...
1798

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1799
  	mutex_unlock(&vhost_scsi_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1800
  }
65ea78986   Nicholas Bellinger   vhost/scsi: Conve...
1801
  static void vhost_scsi_free_cmd_map_res(struct se_session *se_sess)
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1802
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1803
  	struct vhost_scsi_cmd *tv_cmd;
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1804
1805
1806
1807
  	unsigned int i;
  
  	if (!se_sess->sess_cmd_map)
  		return;
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1808
1809
  	for (i = 0; i < VHOST_SCSI_DEFAULT_TAGS; i++) {
  		tv_cmd = &((struct vhost_scsi_cmd *)se_sess->sess_cmd_map)[i];
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1810
1811
  
  		kfree(tv_cmd->tvc_sgl);
b1935f687   Nicholas Bellinger   vhost/scsi: Add p...
1812
  		kfree(tv_cmd->tvc_prot_sgl);
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1813
1814
1815
  		kfree(tv_cmd->tvc_upages);
  	}
  }
2eafd7293   Christoph Hellwig   target: use per-a...
1816
1817
  static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_store(
  		struct config_item *item, const char *page, size_t count)
b1d75fe53   Nicholas Bellinger   vhost/scsi: Add f...
1818
  {
2eafd7293   Christoph Hellwig   target: use per-a...
1819
  	struct se_portal_group *se_tpg = attrib_to_tpg(item);
b1d75fe53   Nicholas Bellinger   vhost/scsi: Add f...
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
  	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
  				struct vhost_scsi_tpg, se_tpg);
  	unsigned long val;
  	int ret = kstrtoul(page, 0, &val);
  
  	if (ret) {
  		pr_err("kstrtoul() returned %d for fabric_prot_type
  ", ret);
  		return ret;
  	}
  	if (val != 0 && val != 1 && val != 3) {
  		pr_err("Invalid vhost_scsi fabric_prot_type: %lu
  ", val);
  		return -EINVAL;
  	}
  	tpg->tv_fabric_prot_type = val;
  
  	return count;
  }
2eafd7293   Christoph Hellwig   target: use per-a...
1839
1840
  static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_show(
  		struct config_item *item, char *page)
b1d75fe53   Nicholas Bellinger   vhost/scsi: Add f...
1841
  {
2eafd7293   Christoph Hellwig   target: use per-a...
1842
  	struct se_portal_group *se_tpg = attrib_to_tpg(item);
b1d75fe53   Nicholas Bellinger   vhost/scsi: Add f...
1843
1844
1845
1846
1847
1848
  	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
  				struct vhost_scsi_tpg, se_tpg);
  
  	return sprintf(page, "%d
  ", tpg->tv_fabric_prot_type);
  }
2eafd7293   Christoph Hellwig   target: use per-a...
1849
1850
  
  CONFIGFS_ATTR(vhost_scsi_tpg_attrib_, fabric_prot_type);
b1d75fe53   Nicholas Bellinger   vhost/scsi: Add f...
1851
1852
  
  static struct configfs_attribute *vhost_scsi_tpg_attrib_attrs[] = {
2eafd7293   Christoph Hellwig   target: use per-a...
1853
  	&vhost_scsi_tpg_attrib_attr_fabric_prot_type,
b1d75fe53   Nicholas Bellinger   vhost/scsi: Add f...
1854
1855
  	NULL,
  };
65ea78986   Nicholas Bellinger   vhost/scsi: Conve...
1856
1857
  static int vhost_scsi_nexus_cb(struct se_portal_group *se_tpg,
  			       struct se_session *se_sess, void *p)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1858
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1859
  	struct vhost_scsi_cmd *tv_cmd;
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1860
  	unsigned int i;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1861

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1862
1863
  	for (i = 0; i < VHOST_SCSI_DEFAULT_TAGS; i++) {
  		tv_cmd = &((struct vhost_scsi_cmd *)se_sess->sess_cmd_map)[i];
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1864

6396bb221   Kees Cook   treewide: kzalloc...
1865
1866
1867
  		tv_cmd->tvc_sgl = kcalloc(VHOST_SCSI_PREALLOC_SGLS,
  					  sizeof(struct scatterlist),
  					  GFP_KERNEL);
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1868
  		if (!tv_cmd->tvc_sgl) {
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1869
1870
1871
1872
  			pr_err("Unable to allocate tv_cmd->tvc_sgl
  ");
  			goto out;
  		}
6396bb221   Kees Cook   treewide: kzalloc...
1873
1874
1875
  		tv_cmd->tvc_upages = kcalloc(VHOST_SCSI_PREALLOC_UPAGES,
  					     sizeof(struct page *),
  					     GFP_KERNEL);
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1876
  		if (!tv_cmd->tvc_upages) {
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1877
1878
1879
1880
  			pr_err("Unable to allocate tv_cmd->tvc_upages
  ");
  			goto out;
  		}
b1935f687   Nicholas Bellinger   vhost/scsi: Add p...
1881

6396bb221   Kees Cook   treewide: kzalloc...
1882
1883
1884
  		tv_cmd->tvc_prot_sgl = kcalloc(VHOST_SCSI_PREALLOC_PROT_SGLS,
  					       sizeof(struct scatterlist),
  					       GFP_KERNEL);
b1935f687   Nicholas Bellinger   vhost/scsi: Add p...
1885
  		if (!tv_cmd->tvc_prot_sgl) {
b1935f687   Nicholas Bellinger   vhost/scsi: Add p...
1886
1887
1888
1889
  			pr_err("Unable to allocate tv_cmd->tvc_prot_sgl
  ");
  			goto out;
  		}
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1890
  	}
65ea78986   Nicholas Bellinger   vhost/scsi: Conve...
1891
1892
1893
1894
1895
1896
1897
1898
1899
  	return 0;
  out:
  	vhost_scsi_free_cmd_map_res(se_sess);
  	return -ENOMEM;
  }
  
  static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
  				const char *name)
  {
65ea78986   Nicholas Bellinger   vhost/scsi: Conve...
1900
1901
1902
1903
1904
1905
1906
1907
1908
  	struct vhost_scsi_nexus *tv_nexus;
  
  	mutex_lock(&tpg->tv_tpg_mutex);
  	if (tpg->tpg_nexus) {
  		mutex_unlock(&tpg->tv_tpg_mutex);
  		pr_debug("tpg->tpg_nexus already exists
  ");
  		return -EEXIST;
  	}
65ea78986   Nicholas Bellinger   vhost/scsi: Conve...
1909

473f0b15a   Markus Elfring   vhost/scsi: Impro...
1910
  	tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
65ea78986   Nicholas Bellinger   vhost/scsi: Conve...
1911
1912
1913
1914
1915
1916
  	if (!tv_nexus) {
  		mutex_unlock(&tpg->tv_tpg_mutex);
  		pr_err("Unable to allocate struct vhost_scsi_nexus
  ");
  		return -ENOMEM;
  	}
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1917
1918
  	/*
  	 * Since we are running in 'demo mode' this call with generate a
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1919
  	 * struct se_node_acl for the vhost_scsi struct se_portal_group with
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1920
1921
  	 * the SCSI Initiator port name of the passed configfs group 'name'.
  	 */
fa8342873   Mike Christie   scsi: target: ren...
1922
  	tv_nexus->tvn_se_sess = target_setup_session(&tpg->se_tpg,
65ea78986   Nicholas Bellinger   vhost/scsi: Conve...
1923
1924
1925
1926
1927
1928
  					VHOST_SCSI_DEFAULT_TAGS,
  					sizeof(struct vhost_scsi_cmd),
  					TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS,
  					(unsigned char *)name, tv_nexus,
  					vhost_scsi_nexus_cb);
  	if (IS_ERR(tv_nexus->tvn_se_sess)) {
987183128   Asias He   vhost-scsi: Renam...
1929
  		mutex_unlock(&tpg->tv_tpg_mutex);
65ea78986   Nicholas Bellinger   vhost/scsi: Conve...
1930
1931
  		kfree(tv_nexus);
  		return -ENOMEM;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1932
  	}
987183128   Asias He   vhost-scsi: Renam...
1933
  	tpg->tpg_nexus = tv_nexus;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1934

987183128   Asias He   vhost-scsi: Renam...
1935
  	mutex_unlock(&tpg->tv_tpg_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1936
1937
  	return 0;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1938
  static int vhost_scsi_drop_nexus(struct vhost_scsi_tpg *tpg)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1939
1940
  {
  	struct se_session *se_sess;
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1941
  	struct vhost_scsi_nexus *tv_nexus;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
  
  	mutex_lock(&tpg->tv_tpg_mutex);
  	tv_nexus = tpg->tpg_nexus;
  	if (!tv_nexus) {
  		mutex_unlock(&tpg->tv_tpg_mutex);
  		return -ENODEV;
  	}
  
  	se_sess = tv_nexus->tvn_se_sess;
  	if (!se_sess) {
  		mutex_unlock(&tpg->tv_tpg_mutex);
  		return -ENODEV;
  	}
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1955
  	if (tpg->tv_tpg_port_count != 0) {
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1956
  		mutex_unlock(&tpg->tv_tpg_mutex);
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1957
  		pr_err("Unable to remove TCM_vhost I_T Nexus with"
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1958
1959
  			" active TPG port count: %d
  ",
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1960
1961
  			tpg->tv_tpg_port_count);
  		return -EBUSY;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1962
  	}
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1963
  	if (tpg->tv_tpg_vhost_count != 0) {
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1964
  		mutex_unlock(&tpg->tv_tpg_mutex);
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1965
  		pr_err("Unable to remove TCM_vhost I_T Nexus with"
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1966
1967
  			" active TPG vhost count: %d
  ",
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1968
1969
  			tpg->tv_tpg_vhost_count);
  		return -EBUSY;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1970
  	}
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1971
  	pr_debug("TCM_vhost_ConfigFS: Removing I_T Nexus to emulated"
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1972
1973
  		" %s Initiator Port: %s
  ", vhost_scsi_dump_proto_id(tpg->tport),
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1974
  		tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
3aee26b4a   Nicholas Bellinger   vhost/scsi: Add p...
1975

65ea78986   Nicholas Bellinger   vhost/scsi: Conve...
1976
  	vhost_scsi_free_cmd_map_res(se_sess);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1977
  	/*
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
1978
  	 * Release the SCSI I_T Nexus to the emulated vhost Target Port
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1979
  	 */
25b88550b   Mike Christie   scsi: target: loo...
1980
  	target_remove_session(se_sess);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1981
1982
1983
1984
1985
1986
  	tpg->tpg_nexus = NULL;
  	mutex_unlock(&tpg->tv_tpg_mutex);
  
  	kfree(tv_nexus);
  	return 0;
  }
2eafd7293   Christoph Hellwig   target: use per-a...
1987
  static ssize_t vhost_scsi_tpg_nexus_show(struct config_item *item, char *page)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1988
  {
2eafd7293   Christoph Hellwig   target: use per-a...
1989
  	struct se_portal_group *se_tpg = to_tpg(item);
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
1990
1991
1992
  	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
  				struct vhost_scsi_tpg, se_tpg);
  	struct vhost_scsi_nexus *tv_nexus;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1993
  	ssize_t ret;
987183128   Asias He   vhost-scsi: Renam...
1994
1995
  	mutex_lock(&tpg->tv_tpg_mutex);
  	tv_nexus = tpg->tpg_nexus;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1996
  	if (!tv_nexus) {
987183128   Asias He   vhost-scsi: Renam...
1997
  		mutex_unlock(&tpg->tv_tpg_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
1998
1999
2000
2001
2002
  		return -ENODEV;
  	}
  	ret = snprintf(page, PAGE_SIZE, "%s
  ",
  			tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
987183128   Asias He   vhost-scsi: Renam...
2003
  	mutex_unlock(&tpg->tv_tpg_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2004
2005
2006
  
  	return ret;
  }
2eafd7293   Christoph Hellwig   target: use per-a...
2007
2008
  static ssize_t vhost_scsi_tpg_nexus_store(struct config_item *item,
  		const char *page, size_t count)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2009
  {
2eafd7293   Christoph Hellwig   target: use per-a...
2010
  	struct se_portal_group *se_tpg = to_tpg(item);
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2011
2012
2013
2014
  	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
  				struct vhost_scsi_tpg, se_tpg);
  	struct vhost_scsi_tport *tport_wwn = tpg->tport;
  	unsigned char i_port[VHOST_SCSI_NAMELEN], *ptr, *port_ptr;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2015
2016
2017
2018
2019
  	int ret;
  	/*
  	 * Shutdown the active I_T nexus if 'NULL' is passed..
  	 */
  	if (!strncmp(page, "NULL", 4)) {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2020
  		ret = vhost_scsi_drop_nexus(tpg);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2021
2022
2023
2024
  		return (!ret) ? count : ret;
  	}
  	/*
  	 * Otherwise make sure the passed virtual Initiator port WWN matches
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2025
2026
  	 * the fabric protocol_id set in vhost_scsi_make_tport(), and call
  	 * vhost_scsi_make_nexus().
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2027
  	 */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2028
  	if (strlen(page) >= VHOST_SCSI_NAMELEN) {
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2029
  		pr_err("Emulated NAA Sas Address: %s, exceeds"
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2030
2031
  				" max: %d
  ", page, VHOST_SCSI_NAMELEN);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2032
2033
  		return -EINVAL;
  	}
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2034
  	snprintf(&i_port[0], VHOST_SCSI_NAMELEN, "%s", page);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2035
2036
2037
2038
2039
2040
2041
  
  	ptr = strstr(i_port, "naa.");
  	if (ptr) {
  		if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_SAS) {
  			pr_err("Passed SAS Initiator Port %s does not"
  				" match target port protoid: %s
  ", i_port,
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2042
  				vhost_scsi_dump_proto_id(tport_wwn));
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
  			return -EINVAL;
  		}
  		port_ptr = &i_port[0];
  		goto check_newline;
  	}
  	ptr = strstr(i_port, "fc.");
  	if (ptr) {
  		if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_FCP) {
  			pr_err("Passed FCP Initiator Port %s does not"
  				" match target port protoid: %s
  ", i_port,
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2054
  				vhost_scsi_dump_proto_id(tport_wwn));
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
  			return -EINVAL;
  		}
  		port_ptr = &i_port[3]; /* Skip over "fc." */
  		goto check_newline;
  	}
  	ptr = strstr(i_port, "iqn.");
  	if (ptr) {
  		if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_ISCSI) {
  			pr_err("Passed iSCSI Initiator Port %s does not"
  				" match target port protoid: %s
  ", i_port,
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2066
  				vhost_scsi_dump_proto_id(tport_wwn));
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
  			return -EINVAL;
  		}
  		port_ptr = &i_port[0];
  		goto check_newline;
  	}
  	pr_err("Unable to locate prefix for emulated Initiator Port:"
  			" %s
  ", i_port);
  	return -EINVAL;
  	/*
  	 * Clear any trailing newline for the NAA WWN
  	 */
  check_newline:
  	if (i_port[strlen(i_port)-1] == '
  ')
  		i_port[strlen(i_port)-1] = '\0';
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2083
  	ret = vhost_scsi_make_nexus(tpg, port_ptr);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2084
2085
2086
2087
2088
  	if (ret < 0)
  		return ret;
  
  	return count;
  }
2eafd7293   Christoph Hellwig   target: use per-a...
2089
  CONFIGFS_ATTR(vhost_scsi_tpg_, nexus);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2090

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2091
  static struct configfs_attribute *vhost_scsi_tpg_attrs[] = {
2eafd7293   Christoph Hellwig   target: use per-a...
2092
  	&vhost_scsi_tpg_attr_nexus,
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2093
2094
  	NULL,
  };
683bd967d   Asias He   vhost-scsi: Make ...
2095
  static struct se_portal_group *
aa090eabc   Bart Van Assche   scsi: target: Rem...
2096
  vhost_scsi_make_tpg(struct se_wwn *wwn, const char *name)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2097
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2098
2099
  	struct vhost_scsi_tport *tport = container_of(wwn,
  			struct vhost_scsi_tport, tport_wwn);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2100

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2101
  	struct vhost_scsi_tpg *tpg;
59c816c1f   Dan Carpenter   vhost/scsi: poten...
2102
  	u16 tpgt;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2103
2104
2105
2106
  	int ret;
  
  	if (strstr(name, "tpgt_") != name)
  		return ERR_PTR(-EINVAL);
59c816c1f   Dan Carpenter   vhost/scsi: poten...
2107
  	if (kstrtou16(name + 5, 10, &tpgt) || tpgt >= VHOST_SCSI_MAX_TARGET)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2108
  		return ERR_PTR(-EINVAL);
473f0b15a   Markus Elfring   vhost/scsi: Impro...
2109
  	tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2110
  	if (!tpg) {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2111
  		pr_err("Unable to allocate struct vhost_scsi_tpg");
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2112
2113
2114
2115
2116
2117
  		return ERR_PTR(-ENOMEM);
  	}
  	mutex_init(&tpg->tv_tpg_mutex);
  	INIT_LIST_HEAD(&tpg->tv_tpg_list);
  	tpg->tport = tport;
  	tpg->tport_tpgt = tpgt;
bc0c94b14   Nicholas Bellinger   target: Drop unne...
2118
  	ret = core_tpg_register(wwn, &tpg->se_tpg, tport->tport_proto_id);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2119
2120
2121
2122
  	if (ret < 0) {
  		kfree(tpg);
  		return NULL;
  	}
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2123
2124
2125
  	mutex_lock(&vhost_scsi_mutex);
  	list_add_tail(&tpg->tv_tpg_list, &vhost_scsi_list);
  	mutex_unlock(&vhost_scsi_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2126
2127
2128
  
  	return &tpg->se_tpg;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2129
  static void vhost_scsi_drop_tpg(struct se_portal_group *se_tpg)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2130
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2131
2132
  	struct vhost_scsi_tpg *tpg = container_of(se_tpg,
  				struct vhost_scsi_tpg, se_tpg);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2133

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2134
  	mutex_lock(&vhost_scsi_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2135
  	list_del(&tpg->tv_tpg_list);
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2136
  	mutex_unlock(&vhost_scsi_mutex);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2137
  	/*
101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
2138
  	 * Release the virtual I_T Nexus for this vhost TPG
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2139
  	 */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2140
  	vhost_scsi_drop_nexus(tpg);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2141
2142
2143
2144
2145
2146
  	/*
  	 * Deregister the se_tpg from TCM..
  	 */
  	core_tpg_deregister(se_tpg);
  	kfree(tpg);
  }
683bd967d   Asias He   vhost-scsi: Make ...
2147
  static struct se_wwn *
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2148
  vhost_scsi_make_tport(struct target_fabric_configfs *tf,
683bd967d   Asias He   vhost-scsi: Make ...
2149
2150
  		     struct config_group *group,
  		     const char *name)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2151
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2152
  	struct vhost_scsi_tport *tport;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2153
2154
2155
  	char *ptr;
  	u64 wwpn = 0;
  	int off = 0;
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2156
  	/* if (vhost_scsi_parse_wwn(name, &wwpn, 1) < 0)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2157
  		return ERR_PTR(-EINVAL); */
473f0b15a   Markus Elfring   vhost/scsi: Impro...
2158
  	tport = kzalloc(sizeof(*tport), GFP_KERNEL);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2159
  	if (!tport) {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2160
  		pr_err("Unable to allocate struct vhost_scsi_tport");
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
  		return ERR_PTR(-ENOMEM);
  	}
  	tport->tport_wwpn = wwpn;
  	/*
  	 * Determine the emulated Protocol Identifier and Target Port Name
  	 * based on the incoming configfs directory name.
  	 */
  	ptr = strstr(name, "naa.");
  	if (ptr) {
  		tport->tport_proto_id = SCSI_PROTOCOL_SAS;
  		goto check_len;
  	}
  	ptr = strstr(name, "fc.");
  	if (ptr) {
  		tport->tport_proto_id = SCSI_PROTOCOL_FCP;
  		off = 3; /* Skip over "fc." */
  		goto check_len;
  	}
  	ptr = strstr(name, "iqn.");
  	if (ptr) {
  		tport->tport_proto_id = SCSI_PROTOCOL_ISCSI;
  		goto check_len;
  	}
  
  	pr_err("Unable to locate prefix for emulated Target Port:"
  			" %s
  ", name);
  	kfree(tport);
  	return ERR_PTR(-EINVAL);
  
  check_len:
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2192
  	if (strlen(name) >= VHOST_SCSI_NAMELEN) {
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2193
  		pr_err("Emulated %s Address: %s, exceeds"
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2194
2195
2196
  			" max: %d
  ", name, vhost_scsi_dump_proto_id(tport),
  			VHOST_SCSI_NAMELEN);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2197
2198
2199
  		kfree(tport);
  		return ERR_PTR(-EINVAL);
  	}
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2200
  	snprintf(&tport->tport_name[0], VHOST_SCSI_NAMELEN, "%s", &name[off]);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2201
2202
  
  	pr_debug("TCM_VHost_ConfigFS: Allocated emulated Target"
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2203
2204
  		" %s Address: %s
  ", vhost_scsi_dump_proto_id(tport), name);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2205
2206
2207
  
  	return &tport->tport_wwn;
  }
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2208
  static void vhost_scsi_drop_tport(struct se_wwn *wwn)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2209
  {
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2210
2211
  	struct vhost_scsi_tport *tport = container_of(wwn,
  				struct vhost_scsi_tport, tport_wwn);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2212
2213
  
  	pr_debug("TCM_VHost_ConfigFS: Deallocating emulated Target"
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2214
2215
  		" %s Address: %s
  ", vhost_scsi_dump_proto_id(tport),
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2216
2217
2218
2219
  		tport->tport_name);
  
  	kfree(tport);
  }
683bd967d   Asias He   vhost-scsi: Make ...
2220
  static ssize_t
2eafd7293   Christoph Hellwig   target: use per-a...
2221
  vhost_scsi_wwn_version_show(struct config_item *item, char *page)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2222
2223
  {
  	return sprintf(page, "TCM_VHOST fabric module %s on %s/%s"
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2224
2225
  		"on "UTS_RELEASE"
  ", VHOST_SCSI_VERSION, utsname()->sysname,
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2226
2227
  		utsname()->machine);
  }
2eafd7293   Christoph Hellwig   target: use per-a...
2228
  CONFIGFS_ATTR_RO(vhost_scsi_wwn_, version);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2229

1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2230
  static struct configfs_attribute *vhost_scsi_wwn_attrs[] = {
2eafd7293   Christoph Hellwig   target: use per-a...
2231
  	&vhost_scsi_wwn_attr_version,
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2232
2233
  	NULL,
  };
1d822a40b   Bhumika Goyal   vhost: scsi: cons...
2234
  static const struct target_core_fabric_ops vhost_scsi_ops = {
9ac8928e6   Christoph Hellwig   target: simplify ...
2235
2236
  	.module				= THIS_MODULE,
  	.name				= "vhost",
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2237
  	.get_fabric_name		= vhost_scsi_get_fabric_name,
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2238
2239
  	.tpg_get_wwn			= vhost_scsi_get_fabric_wwn,
  	.tpg_get_tag			= vhost_scsi_get_tpgt,
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2240
2241
2242
2243
  	.tpg_check_demo_mode		= vhost_scsi_check_true,
  	.tpg_check_demo_mode_cache	= vhost_scsi_check_true,
  	.tpg_check_demo_mode_write_protect = vhost_scsi_check_false,
  	.tpg_check_prod_mode_write_protect = vhost_scsi_check_false,
b1d75fe53   Nicholas Bellinger   vhost/scsi: Add f...
2244
  	.tpg_check_prot_fabric_only	= vhost_scsi_check_prot_fabric_only,
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2245
2246
  	.tpg_get_inst_index		= vhost_scsi_tpg_get_inst_index,
  	.release_cmd			= vhost_scsi_release_cmd,
084ed45b3   Nicholas Bellinger   vhost/scsi: Conve...
2247
  	.check_stop_free		= vhost_scsi_check_stop_free,
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2248
  	.sess_get_index			= vhost_scsi_sess_get_index,
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2249
  	.sess_get_initiator_sid		= NULL,
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2250
2251
2252
  	.write_pending			= vhost_scsi_write_pending,
  	.write_pending_status		= vhost_scsi_write_pending_status,
  	.set_default_node_attributes	= vhost_scsi_set_default_node_attrs,
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2253
2254
2255
2256
2257
  	.get_cmd_state			= vhost_scsi_get_cmd_state,
  	.queue_data_in			= vhost_scsi_queue_data_in,
  	.queue_status			= vhost_scsi_queue_status,
  	.queue_tm_rsp			= vhost_scsi_queue_tm_rsp,
  	.aborted_task			= vhost_scsi_aborted_task,
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2258
2259
2260
  	/*
  	 * Setup callers for generic logic in target_core_fabric_configfs.c
  	 */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2261
2262
2263
2264
2265
2266
  	.fabric_make_wwn		= vhost_scsi_make_tport,
  	.fabric_drop_wwn		= vhost_scsi_drop_tport,
  	.fabric_make_tpg		= vhost_scsi_make_tpg,
  	.fabric_drop_tpg		= vhost_scsi_drop_tpg,
  	.fabric_post_link		= vhost_scsi_port_link,
  	.fabric_pre_unlink		= vhost_scsi_port_unlink,
9ac8928e6   Christoph Hellwig   target: simplify ...
2267
2268
2269
2270
  
  	.tfc_wwn_attrs			= vhost_scsi_wwn_attrs,
  	.tfc_tpg_base_attrs		= vhost_scsi_tpg_attrs,
  	.tfc_tpg_attrib_attrs		= vhost_scsi_tpg_attrib_attrs,
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2271
  };
9ac8928e6   Christoph Hellwig   target: simplify ...
2272
  static int __init vhost_scsi_init(void)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2273
  {
9ac8928e6   Christoph Hellwig   target: simplify ...
2274
  	int ret = -ENOMEM;
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2275

9ac8928e6   Christoph Hellwig   target: simplify ...
2276
  	pr_debug("TCM_VHOST fabric module %s on %s/%s"
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2277
2278
  		" on "UTS_RELEASE"
  ", VHOST_SCSI_VERSION, utsname()->sysname,
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2279
  		utsname()->machine);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2280

101998f6f   Nicholas Bellinger   tcm_vhost: Post-m...
2281
2282
2283
2284
  	/*
  	 * Use our own dedicated workqueue for submitting I/O into
  	 * target core to avoid contention within system_wq.
  	 */
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2285
2286
  	vhost_scsi_workqueue = alloc_workqueue("vhost_scsi", 0, 0);
  	if (!vhost_scsi_workqueue)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2287
2288
2289
2290
2291
  		goto out;
  
  	ret = vhost_scsi_register();
  	if (ret < 0)
  		goto out_destroy_workqueue;
9ac8928e6   Christoph Hellwig   target: simplify ...
2292
  	ret = target_register_template(&vhost_scsi_ops);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2293
2294
2295
2296
2297
2298
2299
2300
  	if (ret < 0)
  		goto out_vhost_scsi_deregister;
  
  	return 0;
  
  out_vhost_scsi_deregister:
  	vhost_scsi_deregister();
  out_destroy_workqueue:
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2301
  	destroy_workqueue(vhost_scsi_workqueue);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2302
2303
2304
  out:
  	return ret;
  };
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2305
  static void vhost_scsi_exit(void)
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2306
  {
9ac8928e6   Christoph Hellwig   target: simplify ...
2307
  	target_unregister_template(&vhost_scsi_ops);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2308
  	vhost_scsi_deregister();
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2309
  	destroy_workqueue(vhost_scsi_workqueue);
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2310
  };
181c04a35   Michael S. Tsirkin   vhost_scsi: modul...
2311
2312
  MODULE_DESCRIPTION("VHOST_SCSI series fabric driver");
  MODULE_ALIAS("tcm_vhost");
057cbf49a   Nicholas Bellinger   tcm_vhost: Initia...
2313
  MODULE_LICENSE("GPL");
1a1ff8256   Nicholas Bellinger   vhost/scsi: Globa...
2314
2315
  module_init(vhost_scsi_init);
  module_exit(vhost_scsi_exit);