Blame view

drivers/target/target_core_file.c 16.3 KB
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  /*******************************************************************************
   * Filename:  target_core_file.c
   *
   * This file contains the Storage Engine <-> FILEIO transport specific functions
   *
   * Copyright (c) 2005 PyX Technologies, Inc.
   * Copyright (c) 2005-2006 SBE, Inc.  All Rights Reserved.
   * Copyright (c) 2007-2010 Rising Tide Systems
   * Copyright (c) 2008-2010 Linux-iSCSI.org
   *
   * Nicholas A. Bellinger <nab@kernel.org>
   *
   * 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.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   *
   ******************************************************************************/
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
28
29
30
31
32
33
  #include <linux/string.h>
  #include <linux/parser.h>
  #include <linux/timer.h>
  #include <linux/blkdev.h>
  #include <linux/slab.h>
  #include <linux/spinlock.h>
827509e38   Paul Gortmaker   drivers/target: A...
34
  #include <linux/module.h>
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
35
36
37
38
39
40
41
42
  #include <scsi/scsi.h>
  #include <scsi/scsi_host.h>
  
  #include <target/target_core_base.h>
  #include <target/target_core_device.h>
  #include <target/target_core_transport.h>
  
  #include "target_core_file.h"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
43
44
45
46
47
48
49
50
51
52
53
  static struct se_subsystem_api fileio_template;
  
  /*	fd_attach_hba(): (Part of se_subsystem_api_t template)
   *
   *
   */
  static int fd_attach_hba(struct se_hba *hba, u32 host_id)
  {
  	struct fd_host *fd_host;
  
  	fd_host = kzalloc(sizeof(struct fd_host), GFP_KERNEL);
6708bb27b   Andy Grover   target: Follow up...
54
55
56
  	if (!fd_host) {
  		pr_err("Unable to allocate memory for struct fd_host
  ");
e3d6f909e   Andy Grover   target: Core clea...
57
  		return -ENOMEM;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
58
59
60
  	}
  
  	fd_host->fd_host_id = host_id;
e3d6f909e   Andy Grover   target: Core clea...
61
  	hba->hba_ptr = fd_host;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
62

6708bb27b   Andy Grover   target: Follow up...
63
  	pr_debug("CORE_HBA[%d] - TCM FILEIO HBA Driver %s on Generic"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
64
65
66
  		" Target Core Stack %s
  ", hba->hba_id, FD_VERSION,
  		TARGET_CORE_MOD_VERSION);
6708bb27b   Andy Grover   target: Follow up...
67
  	pr_debug("CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic"
e3d6f909e   Andy Grover   target: Core clea...
68
69
70
  		" MaxSectors: %u
  ",
  		hba->hba_id, fd_host->fd_host_id, FD_MAX_SECTORS);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
71
72
73
74
75
76
77
  
  	return 0;
  }
  
  static void fd_detach_hba(struct se_hba *hba)
  {
  	struct fd_host *fd_host = hba->hba_ptr;
6708bb27b   Andy Grover   target: Follow up...
78
  	pr_debug("CORE_HBA[%d] - Detached FILEIO HBA: %u from Generic"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
79
80
81
82
83
84
85
86
87
88
89
90
91
  		" Target Core
  ", hba->hba_id, fd_host->fd_host_id);
  
  	kfree(fd_host);
  	hba->hba_ptr = NULL;
  }
  
  static void *fd_allocate_virtdevice(struct se_hba *hba, const char *name)
  {
  	struct fd_dev *fd_dev;
  	struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr;
  
  	fd_dev = kzalloc(sizeof(struct fd_dev), GFP_KERNEL);
6708bb27b   Andy Grover   target: Follow up...
92
93
94
  	if (!fd_dev) {
  		pr_err("Unable to allocate memory for struct fd_dev
  ");
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
95
96
97
98
  		return NULL;
  	}
  
  	fd_dev->fd_host = fd_host;
6708bb27b   Andy Grover   target: Follow up...
99
100
  	pr_debug("FILEIO: Allocated fd_dev for %p
  ", name);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  
  	return fd_dev;
  }
  
  /*	fd_create_virtdevice(): (Part of se_subsystem_api_t template)
   *
   *
   */
  static struct se_device *fd_create_virtdevice(
  	struct se_hba *hba,
  	struct se_subsystem_dev *se_dev,
  	void *p)
  {
  	char *dev_p = NULL;
  	struct se_device *dev;
  	struct se_dev_limits dev_limits;
  	struct queue_limits *limits;
  	struct fd_dev *fd_dev = (struct fd_dev *) p;
  	struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr;
  	mm_segment_t old_fs;
  	struct file *file;
  	struct inode *inode = NULL;
613640e4e   Nicholas Bellinger   [SCSI] target: Co...
123
  	int dev_flags = 0, flags, ret = -EINVAL;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
124
125
126
127
128
129
130
131
132
  
  	memset(&dev_limits, 0, sizeof(struct se_dev_limits));
  
  	old_fs = get_fs();
  	set_fs(get_ds());
  	dev_p = getname(fd_dev->fd_dev_name);
  	set_fs(old_fs);
  
  	if (IS_ERR(dev_p)) {
6708bb27b   Andy Grover   target: Follow up...
133
134
  		pr_err("getname(%s) failed: %lu
  ",
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
135
  			fd_dev->fd_dev_name, IS_ERR(dev_p));
613640e4e   Nicholas Bellinger   [SCSI] target: Co...
136
  		ret = PTR_ERR(dev_p);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
137
138
139
140
141
142
143
144
145
146
147
148
  		goto fail;
  	}
  #if 0
  	if (di->no_create_file)
  		flags = O_RDWR | O_LARGEFILE;
  	else
  		flags = O_RDWR | O_CREAT | O_LARGEFILE;
  #else
  	flags = O_RDWR | O_CREAT | O_LARGEFILE;
  #endif
  /*	flags |= O_DIRECT; */
  	/*
25985edce   Lucas De Marchi   Fix common misspe...
149
  	 * If fd_buffered_io=1 has not been set explicitly (the default),
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
150
151
152
153
154
155
  	 * use O_SYNC to force FILEIO writes to disk.
  	 */
  	if (!(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO))
  		flags |= O_SYNC;
  
  	file = filp_open(dev_p, flags, 0600);
613640e4e   Nicholas Bellinger   [SCSI] target: Co...
156
  	if (IS_ERR(file)) {
6708bb27b   Andy Grover   target: Follow up...
157
158
  		pr_err("filp_open(%s) failed
  ", dev_p);
613640e4e   Nicholas Bellinger   [SCSI] target: Co...
159
160
161
162
  		ret = PTR_ERR(file);
  		goto fail;
  	}
  	if (!file || !file->f_dentry) {
6708bb27b   Andy Grover   target: Follow up...
163
164
  		pr_err("filp_open(%s) failed
  ", dev_p);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
  		goto fail;
  	}
  	fd_dev->fd_file = file;
  	/*
  	 * If using a block backend with this struct file, we extract
  	 * fd_dev->fd_[block,dev]_size from struct block_device.
  	 *
  	 * Otherwise, we use the passed fd_size= from configfs
  	 */
  	inode = file->f_mapping->host;
  	if (S_ISBLK(inode->i_mode)) {
  		struct request_queue *q;
  		/*
  		 * Setup the local scope queue_limits from struct request_queue->limits
  		 * to pass into transport_add_device_to_core_hba() as struct se_dev_limits.
  		 */
  		q = bdev_get_queue(inode->i_bdev);
  		limits = &dev_limits.limits;
  		limits->logical_block_size = bdev_logical_block_size(inode->i_bdev);
  		limits->max_hw_sectors = queue_max_hw_sectors(q);
  		limits->max_sectors = queue_max_sectors(q);
  		/*
  		 * Determine the number of bytes from i_size_read() minus
  		 * one (1) logical sector from underlying struct block_device
  		 */
  		fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev);
  		fd_dev->fd_dev_size = (i_size_read(file->f_mapping->host) -
  				       fd_dev->fd_block_size);
6708bb27b   Andy Grover   target: Follow up...
193
  		pr_debug("FILEIO: Using size: %llu bytes from struct"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
194
195
196
197
198
199
200
  			" block_device blocks: %llu logical_block_size: %d
  ",
  			fd_dev->fd_dev_size,
  			div_u64(fd_dev->fd_dev_size, fd_dev->fd_block_size),
  			fd_dev->fd_block_size);
  	} else {
  		if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
6708bb27b   Andy Grover   target: Follow up...
201
  			pr_err("FILEIO: Missing fd_dev_size="
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  				" parameter, and no backing struct"
  				" block_device
  ");
  			goto fail;
  		}
  
  		limits = &dev_limits.limits;
  		limits->logical_block_size = FD_BLOCKSIZE;
  		limits->max_hw_sectors = FD_MAX_SECTORS;
  		limits->max_sectors = FD_MAX_SECTORS;
  		fd_dev->fd_block_size = FD_BLOCKSIZE;
  	}
  
  	dev_limits.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH;
  	dev_limits.queue_depth = FD_DEVICE_QUEUE_DEPTH;
  
  	dev = transport_add_device_to_core_hba(hba, &fileio_template,
5951146de   Andy Grover   target: More core...
219
  				se_dev, dev_flags, fd_dev,
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
220
  				&dev_limits, "FILEIO", FD_VERSION);
6708bb27b   Andy Grover   target: Follow up...
221
  	if (!dev)
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
222
223
224
225
  		goto fail;
  
  	fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
  	fd_dev->fd_queue_depth = dev->queue_depth;
6708bb27b   Andy Grover   target: Follow up...
226
  	pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s,"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
227
228
229
230
231
232
233
234
235
236
237
238
  		" %llu total bytes
  ", fd_host->fd_host_id, fd_dev->fd_dev_id,
  			fd_dev->fd_dev_name, fd_dev->fd_dev_size);
  
  	putname(dev_p);
  	return dev;
  fail:
  	if (fd_dev->fd_file) {
  		filp_close(fd_dev->fd_file, NULL);
  		fd_dev->fd_file = NULL;
  	}
  	putname(dev_p);
613640e4e   Nicholas Bellinger   [SCSI] target: Co...
239
  	return ERR_PTR(ret);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  }
  
  /*	fd_free_device(): (Part of se_subsystem_api_t template)
   *
   *
   */
  static void fd_free_device(void *p)
  {
  	struct fd_dev *fd_dev = (struct fd_dev *) p;
  
  	if (fd_dev->fd_file) {
  		filp_close(fd_dev->fd_file, NULL);
  		fd_dev->fd_file = NULL;
  	}
  
  	kfree(fd_dev);
  }
  
  static inline struct fd_request *FILE_REQ(struct se_task *task)
  {
  	return container_of(task, struct fd_request, fd_task);
  }
  
  
  static struct se_task *
6708bb27b   Andy Grover   target: Follow up...
265
  fd_alloc_task(unsigned char *cdb)
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
266
267
268
269
  {
  	struct fd_request *fd_req;
  
  	fd_req = kzalloc(sizeof(struct fd_request), GFP_KERNEL);
6708bb27b   Andy Grover   target: Follow up...
270
271
272
  	if (!fd_req) {
  		pr_err("Unable to allocate struct fd_request
  ");
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
273
274
  		return NULL;
  	}
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
275
276
277
278
279
280
  	return &fd_req->fd_task;
  }
  
  static int fd_do_readv(struct se_task *task)
  {
  	struct fd_request *req = FILE_REQ(task);
42bf829ee   Christoph Hellwig   target: Cleanup u...
281
282
  	struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev;
  	struct fd_dev *dev = se_dev->dev_ptr;
6708bb27b   Andy Grover   target: Follow up...
283
  	struct file *fd = dev->fd_file;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
284
285
286
  	struct scatterlist *sg = task->task_sg;
  	struct iovec *iov;
  	mm_segment_t old_fs;
e3d6f909e   Andy Grover   target: Core clea...
287
  	loff_t pos = (task->task_lba *
42bf829ee   Christoph Hellwig   target: Cleanup u...
288
  		      se_dev->se_sub_dev->se_dev_attrib.block_size);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
289
  	int ret = 0, i;
6708bb27b   Andy Grover   target: Follow up...
290
291
292
293
  	iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
  	if (!iov) {
  		pr_err("Unable to allocate fd_do_readv iov[]
  ");
e3d6f909e   Andy Grover   target: Core clea...
294
  		return -ENOMEM;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
295
  	}
9649fa1b8   Sebastian Andrzej Siewior   target/file: walk...
296
297
298
  	for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
  		iov[i].iov_len = sg->length;
  		iov[i].iov_base = sg_virt(sg);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
299
300
301
302
  	}
  
  	old_fs = get_fs();
  	set_fs(get_ds());
6708bb27b   Andy Grover   target: Follow up...
303
  	ret = vfs_readv(fd, &iov[0], task->task_sg_nents, &pos);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
304
305
306
307
308
309
310
311
312
313
  	set_fs(old_fs);
  
  	kfree(iov);
  	/*
  	 * Return zeros and GOOD status even if the READ did not return
  	 * the expected virt_size for struct file w/o a backing struct
  	 * block_device.
  	 */
  	if (S_ISBLK(fd->f_dentry->d_inode->i_mode)) {
  		if (ret < 0 || ret != task->task_size) {
6708bb27b   Andy Grover   target: Follow up...
314
  			pr_err("vfs_readv() returned %d,"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
315
316
317
  				" expecting %d for S_ISBLK
  ", ret,
  				(int)task->task_size);
e3d6f909e   Andy Grover   target: Core clea...
318
  			return (ret < 0 ? ret : -EINVAL);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
319
320
321
  		}
  	} else {
  		if (ret < 0) {
6708bb27b   Andy Grover   target: Follow up...
322
  			pr_err("vfs_readv() returned %d for non"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
323
324
  				" S_ISBLK
  ", ret);
e3d6f909e   Andy Grover   target: Core clea...
325
  			return ret;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
326
327
328
329
330
331
332
333
334
  		}
  	}
  
  	return 1;
  }
  
  static int fd_do_writev(struct se_task *task)
  {
  	struct fd_request *req = FILE_REQ(task);
42bf829ee   Christoph Hellwig   target: Cleanup u...
335
336
  	struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev;
  	struct fd_dev *dev = se_dev->dev_ptr;
6708bb27b   Andy Grover   target: Follow up...
337
  	struct file *fd = dev->fd_file;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
338
339
340
  	struct scatterlist *sg = task->task_sg;
  	struct iovec *iov;
  	mm_segment_t old_fs;
e3d6f909e   Andy Grover   target: Core clea...
341
  	loff_t pos = (task->task_lba *
42bf829ee   Christoph Hellwig   target: Cleanup u...
342
  		      se_dev->se_sub_dev->se_dev_attrib.block_size);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
343
  	int ret, i = 0;
6708bb27b   Andy Grover   target: Follow up...
344
345
346
347
  	iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
  	if (!iov) {
  		pr_err("Unable to allocate fd_do_writev iov[]
  ");
e3d6f909e   Andy Grover   target: Core clea...
348
  		return -ENOMEM;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
349
  	}
9649fa1b8   Sebastian Andrzej Siewior   target/file: walk...
350
351
352
  	for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
  		iov[i].iov_len = sg->length;
  		iov[i].iov_base = sg_virt(sg);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
353
354
355
356
  	}
  
  	old_fs = get_fs();
  	set_fs(get_ds());
6708bb27b   Andy Grover   target: Follow up...
357
  	ret = vfs_writev(fd, &iov[0], task->task_sg_nents, &pos);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
358
359
360
361
362
  	set_fs(old_fs);
  
  	kfree(iov);
  
  	if (ret < 0 || ret != task->task_size) {
6708bb27b   Andy Grover   target: Follow up...
363
364
  		pr_err("vfs_writev() returned %d
  ", ret);
e3d6f909e   Andy Grover   target: Core clea...
365
  		return (ret < 0 ? ret : -EINVAL);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
366
367
368
369
370
371
372
  	}
  
  	return 1;
  }
  
  static void fd_emulate_sync_cache(struct se_task *task)
  {
e3d6f909e   Andy Grover   target: Core clea...
373
  	struct se_cmd *cmd = task->task_se_cmd;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
374
375
  	struct se_device *dev = cmd->se_dev;
  	struct fd_dev *fd_dev = dev->dev_ptr;
a1d8b49ab   Andy Grover   target: Updates f...
376
  	int immed = (cmd->t_task_cdb[1] & 0x2);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
377
378
379
380
381
382
383
384
385
386
387
388
389
  	loff_t start, end;
  	int ret;
  
  	/*
  	 * If the Immediate bit is set, queue up the GOOD response
  	 * for this SYNCHRONIZE_CACHE op
  	 */
  	if (immed)
  		transport_complete_sync_cache(cmd, 1);
  
  	/*
  	 * Determine if we will be flushing the entire device.
  	 */
a1d8b49ab   Andy Grover   target: Updates f...
390
  	if (cmd->t_task_lba == 0 && cmd->data_length == 0) {
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
391
392
393
  		start = 0;
  		end = LLONG_MAX;
  	} else {
a1d8b49ab   Andy Grover   target: Updates f...
394
  		start = cmd->t_task_lba * dev->se_sub_dev->se_dev_attrib.block_size;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
395
396
397
398
399
400
401
402
  		if (cmd->data_length)
  			end = start + cmd->data_length;
  		else
  			end = LLONG_MAX;
  	}
  
  	ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1);
  	if (ret != 0)
6708bb27b   Andy Grover   target: Follow up...
403
404
  		pr_err("FILEIO: vfs_fsync_range() failed: %d
  ", ret);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
405
406
407
408
409
410
  
  	if (!immed)
  		transport_complete_sync_cache(cmd, ret == 0);
  }
  
  /*
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
411
412
413
414
415
416
417
   * WRITE Force Unit Access (FUA) emulation on a per struct se_task
   * LBA range basis..
   */
  static void fd_emulate_write_fua(struct se_cmd *cmd, struct se_task *task)
  {
  	struct se_device *dev = cmd->se_dev;
  	struct fd_dev *fd_dev = dev->dev_ptr;
e3d6f909e   Andy Grover   target: Core clea...
418
  	loff_t start = task->task_lba * dev->se_sub_dev->se_dev_attrib.block_size;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
419
420
  	loff_t end = start + task->task_size;
  	int ret;
6708bb27b   Andy Grover   target: Follow up...
421
422
  	pr_debug("FILEIO: FUA WRITE LBA: %llu, bytes: %u
  ",
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
423
424
425
426
  			task->task_lba, task->task_size);
  
  	ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1);
  	if (ret != 0)
6708bb27b   Andy Grover   target: Follow up...
427
428
  		pr_err("FILEIO: vfs_fsync_range() failed: %d
  ", ret);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
  }
  
  static int fd_do_task(struct se_task *task)
  {
  	struct se_cmd *cmd = task->task_se_cmd;
  	struct se_device *dev = cmd->se_dev;
  	int ret = 0;
  
  	/*
  	 * Call vectorized fileio functions to map struct scatterlist
  	 * physical memory addresses to struct iovec virtual memory.
  	 */
  	if (task->task_data_direction == DMA_FROM_DEVICE) {
  		ret = fd_do_readv(task);
  	} else {
  		ret = fd_do_writev(task);
  
  		if (ret > 0 &&
e3d6f909e   Andy Grover   target: Core clea...
447
448
  		    dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0 &&
  		    dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 &&
2d3a4b51d   Christoph Hellwig   target: remove th...
449
  		    (cmd->se_cmd_flags & SCF_FUA)) {
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
450
451
452
453
454
455
456
457
458
  			/*
  			 * We might need to be a bit smarter here
  			 * and return some sense data to let the initiator
  			 * know the FUA WRITE cache sync failed..?
  			 */
  			fd_emulate_write_fua(cmd, task);
  		}
  
  	}
03e98c9eb   Nicholas Bellinger   target: Address l...
459
460
  	if (ret < 0) {
  		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
461
  		return ret;
03e98c9eb   Nicholas Bellinger   target: Address l...
462
  	}
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
463
464
465
466
  	if (ret) {
  		task->task_scsi_status = GOOD;
  		transport_complete_task(task, 1);
  	}
03e98c9eb   Nicholas Bellinger   target: Address l...
467
  	return 0;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
  }
  
  /*	fd_free_task(): (Part of se_subsystem_api_t template)
   *
   *
   */
  static void fd_free_task(struct se_task *task)
  {
  	struct fd_request *req = FILE_REQ(task);
  
  	kfree(req);
  }
  
  enum {
  	Opt_fd_dev_name, Opt_fd_dev_size, Opt_fd_buffered_io, Opt_err
  };
  
  static match_table_t tokens = {
  	{Opt_fd_dev_name, "fd_dev_name=%s"},
  	{Opt_fd_dev_size, "fd_dev_size=%s"},
58c3e6477   Nicholas Bellinger   [SCSI] target: Fi...
488
  	{Opt_fd_buffered_io, "fd_buffered_io=%d"},
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
  	{Opt_err, NULL}
  };
  
  static ssize_t fd_set_configfs_dev_params(
  	struct se_hba *hba,
  	struct se_subsystem_dev *se_dev,
  	const char *page, ssize_t count)
  {
  	struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
  	char *orig, *ptr, *arg_p, *opts;
  	substring_t args[MAX_OPT_ARGS];
  	int ret = 0, arg, token;
  
  	opts = kstrdup(page, GFP_KERNEL);
  	if (!opts)
  		return -ENOMEM;
  
  	orig = opts;
  
  	while ((ptr = strsep(&opts, ",")) != NULL) {
  		if (!*ptr)
  			continue;
  
  		token = match_token(ptr, tokens, args);
  		switch (token) {
  		case Opt_fd_dev_name:
6d1802539   Jesper Juhl   [SCSI] target: Fi...
515
516
517
518
519
  			arg_p = match_strdup(&args[0]);
  			if (!arg_p) {
  				ret = -ENOMEM;
  				break;
  			}
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
520
  			snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME,
6d1802539   Jesper Juhl   [SCSI] target: Fi...
521
522
  					"%s", arg_p);
  			kfree(arg_p);
6708bb27b   Andy Grover   target: Follow up...
523
524
  			pr_debug("FILEIO: Referencing Path: %s
  ",
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
525
526
527
528
529
  					fd_dev->fd_dev_name);
  			fd_dev->fbd_flags |= FBDF_HAS_PATH;
  			break;
  		case Opt_fd_dev_size:
  			arg_p = match_strdup(&args[0]);
6d1802539   Jesper Juhl   [SCSI] target: Fi...
530
531
532
533
  			if (!arg_p) {
  				ret = -ENOMEM;
  				break;
  			}
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
534
  			ret = strict_strtoull(arg_p, 0, &fd_dev->fd_dev_size);
6d1802539   Jesper Juhl   [SCSI] target: Fi...
535
  			kfree(arg_p);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
536
  			if (ret < 0) {
6708bb27b   Andy Grover   target: Follow up...
537
  				pr_err("strict_strtoull() failed for"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
538
539
540
541
  						" fd_dev_size=
  ");
  				goto out;
  			}
6708bb27b   Andy Grover   target: Follow up...
542
  			pr_debug("FILEIO: Referencing Size: %llu"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
543
544
545
546
547
548
549
  					" bytes
  ", fd_dev->fd_dev_size);
  			fd_dev->fbd_flags |= FBDF_HAS_SIZE;
  			break;
  		case Opt_fd_buffered_io:
  			match_int(args, &arg);
  			if (arg != 1) {
6708bb27b   Andy Grover   target: Follow up...
550
551
  				pr_err("bogus fd_buffered_io=%d value
  ", arg);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
552
553
554
  				ret = -EINVAL;
  				goto out;
  			}
6708bb27b   Andy Grover   target: Follow up...
555
  			pr_debug("FILEIO: Using buffered I/O"
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
  				" operations for struct fd_dev
  ");
  
  			fd_dev->fbd_flags |= FDBD_USE_BUFFERED_IO;
  			break;
  		default:
  			break;
  		}
  	}
  
  out:
  	kfree(orig);
  	return (!ret) ? count : ret;
  }
  
  static ssize_t fd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev)
  {
  	struct fd_dev *fd_dev = (struct fd_dev *) se_dev->se_dev_su_ptr;
  
  	if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) {
6708bb27b   Andy Grover   target: Follow up...
576
577
  		pr_err("Missing fd_dev_name=
  ");
e3d6f909e   Andy Grover   target: Core clea...
578
  		return -EINVAL;
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
  	}
  
  	return 0;
  }
  
  static ssize_t fd_show_configfs_dev_params(
  	struct se_hba *hba,
  	struct se_subsystem_dev *se_dev,
  	char *b)
  {
  	struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
  	ssize_t bl = 0;
  
  	bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id);
  	bl += sprintf(b + bl, "        File: %s  Size: %llu  Mode: %s
  ",
  		fd_dev->fd_dev_name, fd_dev->fd_dev_size,
  		(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO) ?
  		"Buffered" : "Synchronous");
  	return bl;
  }
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
  /*	fd_get_device_rev(): (Part of se_subsystem_api_t template)
   *
   *
   */
  static u32 fd_get_device_rev(struct se_device *dev)
  {
  	return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
  }
  
  /*	fd_get_device_type(): (Part of se_subsystem_api_t template)
   *
   *
   */
  static u32 fd_get_device_type(struct se_device *dev)
  {
  	return TYPE_DISK;
  }
  
  static sector_t fd_get_blocks(struct se_device *dev)
  {
  	struct fd_dev *fd_dev = dev->dev_ptr;
  	unsigned long long blocks_long = div_u64(fd_dev->fd_dev_size,
e3d6f909e   Andy Grover   target: Core clea...
622
  			dev->se_sub_dev->se_dev_attrib.block_size);
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
623
624
625
626
627
628
629
630
  
  	return blocks_long;
  }
  
  static struct se_subsystem_api fileio_template = {
  	.name			= "fileio",
  	.owner			= THIS_MODULE,
  	.transport_type		= TRANSPORT_PLUGIN_VHBA_PDEV,
f55918fa3   Christoph Hellwig   target: clean up ...
631
632
  	.write_cache_emulated	= 1,
  	.fua_write_emulated	= 1,
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
633
634
635
636
637
  	.attach_hba		= fd_attach_hba,
  	.detach_hba		= fd_detach_hba,
  	.allocate_virtdevice	= fd_allocate_virtdevice,
  	.create_virtdevice	= fd_create_virtdevice,
  	.free_device		= fd_free_device,
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
638
639
640
641
642
643
644
  	.alloc_task		= fd_alloc_task,
  	.do_task		= fd_do_task,
  	.do_sync_cache		= fd_emulate_sync_cache,
  	.free_task		= fd_free_task,
  	.check_configfs_dev_params = fd_check_configfs_dev_params,
  	.set_configfs_dev_params = fd_set_configfs_dev_params,
  	.show_configfs_dev_params = fd_show_configfs_dev_params,
c66ac9db8   Nicholas Bellinger   [SCSI] target: Ad...
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
  	.get_device_rev		= fd_get_device_rev,
  	.get_device_type	= fd_get_device_type,
  	.get_blocks		= fd_get_blocks,
  };
  
  static int __init fileio_module_init(void)
  {
  	return transport_subsystem_register(&fileio_template);
  }
  
  static void fileio_module_exit(void)
  {
  	transport_subsystem_release(&fileio_template);
  }
  
  MODULE_DESCRIPTION("TCM FILEIO subsystem plugin");
  MODULE_AUTHOR("nab@Linux-iSCSI.org");
  MODULE_LICENSE("GPL");
  
  module_init(fileio_module_init);
  module_exit(fileio_module_exit);