* [RFC PATCH 4/19] Target_Core_Mod FILEIO <-> Linux/VFS subsystem
@ 2009-09-12 1:55 Nicholas A. Bellinger
0 siblings, 0 replies; 4+ messages in thread
From: Nicholas A. Bellinger @ 2009-09-12 1:55 UTC (permalink / raw)
To: LKML, linux-scsi
Cc: Andrew Morton, Greg KH, Douglas Gilbert, James Bottomley,
Hannes Reinecke, FUJITA Tomonori, Mike Christie, Joel Becker,
Martin K. Petersen, Christoph Hellwig, Linus Torvalds,
Alan Stern, Boaz Harrosh, Florian Haas, Philipp Reisner
[RFC PATCH 4/19] Target_Core_Mod FILEIO <-> Linux/VFS subsystem
This patch adds the buffered FILEIO subsystem plugin for accessing struct file
from upstream Linux/VFS code.
It also includes AIO kernel code and O_DIRECT (needs seperate kernel patch for non buffered kernel file I/O),
that are currently disabled.
Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org>
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
new file mode 100644
index 0000000..4ac2916
--- /dev/null
+++ b/drivers/target/target_core_file.c
@@ -0,0 +1,1227 @@
+/*******************************************************************************
+ * 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-2009 Rising Tide Software, Inc.
+ * Copyright (c) 2008-2009 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.
+ *
+ ******************************************************************************/
+
+
+#define TARGET_CORE_FILE_C
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#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/target_core_file.h>
+
+#undef TARGET_CORE_FILE_C
+
+/* fd_attach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_attach_hba(se_hba_t *hba, u32 host_id)
+{
+ fd_host_t *fd_host;
+
+ fd_host = kzalloc(sizeof(fd_host_t), GFP_KERNEL);
+ if (!(fd_host)) {
+ printk(KERN_ERR "Unable to allocate memory for fd_host_t\n");
+ return -1;
+ }
+
+ fd_host->fd_host_id = host_id;
+
+ atomic_set(&hba->left_queue_depth, FD_HBA_QUEUE_DEPTH);
+ atomic_set(&hba->max_queue_depth, FD_HBA_QUEUE_DEPTH);
+ hba->hba_ptr = (void *) fd_host;
+ hba->transport = &fileio_template;
+
+ printk(KERN_INFO "CORE_HBA[%d] - %s FILEIO HBA Driver %s on Generic"
+ " Target Core Stack %s\n", hba->hba_id,
+ PYX_ISCSI_VENDOR, FD_VERSION, TARGET_CORE_MOD_VERSION);
+ printk(KERN_INFO "CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic"
+ " Target Core with TCQ Depth: %d MaxSectors: %u\n",
+ hba->hba_id, fd_host->fd_host_id,
+ atomic_read(&hba->max_queue_depth), FD_MAX_SECTORS);
+
+ return 0;
+}
+
+/* fd_detach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_detach_hba(se_hba_t *hba)
+{
+ fd_host_t *fd_host;
+
+ if (!hba->hba_ptr) {
+ printk(KERN_ERR "hba->hba_ptr is NULL!\n");
+ return -1;
+ }
+ fd_host = (fd_host_t *) hba->hba_ptr;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached FILEIO HBA: %u from Generic"
+ " Target Core\n", hba->hba_id, fd_host->fd_host_id);
+
+ kfree(fd_host);
+ hba->hba_ptr = NULL;
+
+ return 0;
+}
+
+int fd_claim_phydevice(se_hba_t *hba, se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *)dev->dev_ptr;
+ struct block_device *bd;
+
+ if (fd_dev->fd_bd)
+ return 0;
+
+ if (dev->dev_flags & DF_READ_ONLY) {
+ printk(KERN_INFO "FILEIO: Using previously claimed %p Major"
+ ":Minor - %d:%d\n", fd_dev->fd_bd, fd_dev->fd_major,
+ fd_dev->fd_minor);
+ } else {
+ printk(KERN_INFO "FILEIO: Claiming %p Major:Minor - %d:%d\n",
+ fd_dev, fd_dev->fd_major, fd_dev->fd_minor);
+
+ bd = linux_blockdevice_claim(fd_dev->fd_major,
+ fd_dev->fd_minor, (void *)fd_dev);
+ if (!(bd))
+ return -1;
+
+ fd_dev->fd_bd = bd;
+ fd_dev->fd_bd->bd_contains = bd;
+ }
+
+ return 0;
+}
+
+int fd_release_phydevice(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *)dev->dev_ptr;
+
+ if (!fd_dev->fd_bd)
+ return 0;
+
+ if (dev->dev_flags & DF_READ_ONLY) {
+ printk(KERN_INFO "FILEIO: Calling blkdev_put() for Major:Minor"
+ " - %d:%d\n", fd_dev->fd_major, fd_dev->fd_minor);
+ blkdev_put((struct block_device *)fd_dev->fd_bd, FMODE_READ);
+ } else {
+ printk(KERN_INFO "FILEIO: Releasing Major:Minor - %d:%d\n",
+ fd_dev->fd_major, fd_dev->fd_minor);
+ linux_blockdevice_release(fd_dev->fd_major, fd_dev->fd_minor,
+ (struct block_device *)fd_dev->fd_bd);
+ }
+ fd_dev->fd_bd = NULL;
+
+ return 0;
+}
+
+void *fd_allocate_virtdevice(se_hba_t *hba, const char *name)
+{
+ fd_dev_t *fd_dev;
+ fd_host_t *fd_host = (fd_host_t *) hba->hba_ptr;
+
+ fd_dev = kzalloc(sizeof(fd_dev_t), GFP_KERNEL);
+ if (!(fd_dev)) {
+ printk(KERN_ERR "Unable to allocate memory for fd_dev_t\n");
+ return NULL;
+ }
+
+ fd_dev->fd_host = fd_host;
+
+ printk(KERN_INFO "FILEIO: Allocated fd_dev for %p\n", name);
+
+ return fd_dev;
+}
+
+/* fd_create_virtdevice(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+se_device_t *fd_create_virtdevice(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ void *p)
+{
+ char *dev_p = NULL;
+ se_device_t *dev;
+ fd_dev_t *fd_dev = (fd_dev_t *) p;
+ fd_host_t *fd_host = (fd_host_t *) hba->hba_ptr;
+ mm_segment_t old_fs;
+ struct block_device *bd = NULL;
+ struct file *file;
+ struct inode *inode = NULL;
+ struct request_queue *q;
+ unsigned long long blocks_long;
+ int dev_flags = 0, flags;
+
+ 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)) {
+ printk(KERN_ERR "getname(%s) failed: %lu\n",
+ fd_dev->fd_dev_name, IS_ERR(dev_p));
+ 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; */
+
+ file = filp_open(dev_p, flags, 0600);
+
+ if (IS_ERR(file) || !file || !file->f_dentry) {
+ printk(KERN_ERR "filp_open(%s) failed\n", dev_p);
+ goto fail;
+ }
+ fd_dev->fd_file = file;
+ /*
+ * If we are claiming a blockend for this struct file, we extract
+ * fd_dev->fd_size from struct block_device.
+ *
+ * Otherwise, we use the passed fd_size= from configfs
+ */
+ inode = igrab(file->f_mapping->host);
+ if (!(inode)) {
+ printk(KERN_ERR "FILEIO: Unable to locate struct inode from"
+ " struct file\n");
+ goto fail;
+ }
+ /*
+ * If struct file is referencing a underlying struct block_device,
+ * claim it now.
+ */
+ if (S_ISBLK(inode->i_mode)) {
+ fd_dev->fd_bd = I_BDEV(file->f_mapping->host);
+ if (!(fd_dev->fd_bd)) {
+ printk(KERN_ERR "FILEIO: Unable to locate struct"
+ " block_device\n");
+ goto fail;
+ }
+ fd_dev->fd_major = fd_dev->fd_bd->bd_disk->major;
+ fd_dev->fd_minor = fd_dev->fd_bd->bd_disk->first_minor;
+
+ printk(KERN_INFO "FILEIO: Claiming %p Major:Minor - %d:%d\n",
+ fd_dev, fd_dev->fd_major, fd_dev->fd_minor);
+
+ bd = linux_blockdevice_claim(fd_dev->fd_bd->bd_disk->major,
+ fd_dev->fd_bd->bd_disk->first_minor,
+ fd_dev);
+ if (!(bd)) {
+ printk(KERN_ERR "FILEIO: Unable to claim"
+ " struct block_device\n");
+ goto fail;
+ }
+
+ dev_flags |= DF_CLAIMED_BLOCKDEV;
+ if (dev_flags & DF_CLAIMED_BLOCKDEV)
+ fd_dev->fd_bd->bd_contains = bd;
+ /*
+ * Determine the number of bytes for this FILEIO device from
+ * struct block_device's block count and block_size.
+ */
+ blocks_long = (get_capacity(bd->bd_disk) - 1);
+ q = bdev_get_queue(bd);
+ fd_dev->fd_dev_size = ((unsigned long long)blocks_long *
+ bdev_logical_block_size(bd));
+ printk(KERN_INFO "FILEIO: Using size: %llu bytes from struct"
+ " block_device blocks: %llu logical_block_size: %d\n",
+ fd_dev->fd_dev_size, blocks_long,
+ bdev_logical_block_size(bd));
+ } else {
+ if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
+ printk(KERN_ERR "FILEIO: Missing fd_dev_size="
+ " parameter, and no backing struct"
+ " block_device\n");
+ goto fail;
+ }
+ }
+ /*
+ * Pass dev_flags for linux_blockdevice_claim_bd or
+ * linux_blockdevice_claim() from the usage above.
+ *
+ * Note that transport_add_device_to_core_hba() will call
+ * linux_blockdevice_release() internally on failure to
+ * call bd_release() on the referenced struct block_device.
+ */
+ dev = transport_add_device_to_core_hba(hba, &fileio_template,
+ se_dev, dev_flags, (void *)fd_dev);
+ if (!(dev))
+ goto fail;
+
+ fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
+ fd_dev->fd_queue_depth = dev->queue_depth;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Added LIO FILEIO Device ID: %u at %s,"
+ " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+
+ iput(inode);
+ putname(dev_p);
+ return dev;
+fail:
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+ fd_dev->fd_bd = NULL;
+ fd_dev->fd_major = 0;
+ fd_dev->fd_minor = 0;
+ if (inode)
+ iput(inode);
+ putname(dev_p);
+ return NULL;
+}
+
+/* fd_activate_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_activate_device(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+ fd_host_t *fd_host = fd_dev->fd_host;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Activating Device with TCQ: %d at"
+ " FILEIO Device ID: %d\n", fd_host->fd_host_id,
+ fd_dev->fd_queue_depth, fd_dev->fd_dev_id);
+
+ return 0;
+}
+
+/* fd_deactivate_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_deactivate_device(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+ fd_host_t *fd_host = fd_dev->fd_host;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Deactivating Device with TCQ: %d at"
+ " FILEIO Device ID: %d\n", fd_host->fd_host_id,
+ fd_dev->fd_queue_depth, fd_dev->fd_dev_id);
+
+ return;
+}
+
+/* fd_free_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_free_device(void *p)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) p;
+
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+
+ kfree(fd_dev);
+}
+
+/* fd_transport_complete(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_transport_complete(se_task_t *task)
+{
+ return 0;
+}
+
+/* fd_allocate_request(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void *fd_allocate_request(
+ se_task_t *task,
+ se_device_t *dev)
+{
+ fd_request_t *fd_req;
+
+ fd_req = kzalloc(sizeof(fd_request_t), GFP_KERNEL);
+ if (!(fd_req)) {
+ printk(KERN_ERR "Unable to allocate fd_request_t\n");
+ return NULL;
+ }
+
+ fd_req->fd_dev = (fd_dev_t *) dev->dev_ptr;
+
+ return (void *)fd_req;
+}
+
+/* fd_emulate_inquiry():
+ *
+ *
+ */
+int fd_emulate_inquiry(se_task_t *task)
+{
+ unsigned char prod[64], se_location[128];
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_dev_t *fdev = (fd_dev_t *) task->se_dev->dev_ptr;
+ se_hba_t *hba = task->se_dev->se_hba;
+
+ memset(prod, 0, 64);
+ memset(se_location, 0, 128);
+
+ sprintf(prod, "FILEIO");
+ sprintf(se_location, "%u_%u", hba->hba_id, fdev->fd_dev_id);
+
+ return transport_generic_emulate_inquiry(cmd, TYPE_DISK, prod,
+ FD_VERSION, se_location);
+}
+
+/* fd_emulate_read_cap():
+ *
+ *
+ */
+static int fd_emulate_read_cap(se_task_t *task)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) task->se_dev->dev_ptr;
+ u32 blocks = (fd_dev->fd_dev_size /
+ DEV_ATTRIB(task->se_dev)->block_size);
+
+ if ((fd_dev->fd_dev_size / DEV_ATTRIB(task->se_dev)->block_size)
+ >= 0x00000000ffffffff)
+ blocks = 0xffffffff;
+
+ return transport_generic_emulate_readcapacity(TASK_CMD(task), blocks);
+}
+
+static int fd_emulate_read_cap16(se_task_t *task)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) task->se_dev->dev_ptr;
+ unsigned long long blocks_long = ((fd_dev->fd_dev_size /
+ DEV_ATTRIB(task->se_dev)->block_size) - 1);
+
+ return transport_generic_emulate_readcapacity_16(TASK_CMD(task),
+ blocks_long);
+}
+
+/* fd_emulate_scsi_cdb():
+ *
+ *
+ */
+static int fd_emulate_scsi_cdb(se_task_t *task)
+{
+ int ret;
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_request_t *fd_req = (fd_request_t *) task->transport_req;
+
+ switch (fd_req->fd_scsi_cdb[0]) {
+ case INQUIRY:
+ if (fd_emulate_inquiry(task) < 0)
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ break;
+ case READ_CAPACITY:
+ ret = fd_emulate_read_cap(task);
+ if (ret < 0)
+ return ret;
+ break;
+ case MODE_SENSE:
+ ret = transport_generic_emulate_modesense(TASK_CMD(task),
+ fd_req->fd_scsi_cdb, fd_req->fd_buf, 0,
+ TYPE_DISK);
+ if (ret < 0)
+ return ret;
+ break;
+ case MODE_SENSE_10:
+ ret = transport_generic_emulate_modesense(TASK_CMD(task),
+ fd_req->fd_scsi_cdb, fd_req->fd_buf, 1,
+ TYPE_DISK);
+ if (ret < 0)
+ return ret;
+ break;
+ case SERVICE_ACTION_IN:
+ if ((T_TASK(cmd)->t_task_cdb[1] & 0x1f) !=
+ SAI_READ_CAPACITY_16) {
+ printk(KERN_ERR "Unsupported SA: 0x%02x\n",
+ T_TASK(cmd)->t_task_cdb[1] & 0x1f);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = fd_emulate_read_cap16(task);
+ if (ret < 0)
+ return ret;
+ break;
+ case REQUEST_SENSE:
+ ret = transport_generic_emulate_request_sense(cmd,
+ T_TASK(cmd)->t_task_cdb);
+ if (ret < 0)
+ return ret;
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case ERASE:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case SPACE:
+ case START_STOP:
+ case SYNCHRONIZE_CACHE:
+ case TEST_UNIT_READY:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ case RESERVE:
+ case RESERVE_10:
+ case RELEASE:
+ case RELEASE_10:
+ break;
+ default:
+ printk(KERN_ERR "Unsupported SCSI Opcode: 0x%02x for FILEIO\n",
+ fd_req->fd_scsi_cdb[0]);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+static inline int fd_iovec_alloc(fd_request_t *req)
+{
+ req->fd_iovs = kzalloc(sizeof(struct iovec) * req->fd_sg_count,
+ GFP_KERNEL);
+ if (!(req->fd_iovs)) {
+ printk(KERN_ERR "Unable to allocate req->fd_iovs\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline int fd_seek(
+ struct file *fd,
+ unsigned long long lba,
+ u32 block_size)
+{
+ mm_segment_t old_fs;
+ unsigned long long offset;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+#if 0
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba, block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba * block_size));
+#endif
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fd_do_readv(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec iov[req->fd_sg_count];
+
+ memset(iov, 0, sizeof(struct iovec) + req->fd_sg_count);
+
+ if (fd_seek(fd, req->fd_lba, DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_readv(fd, &iov[0], req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk(KERN_ERR "vfs_readv() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+
+#if 0
+
+static void fd_aio_intr(struct kiocb *kcb)
+{
+ se_task_t *task = (se_task_t *)kcb->private;
+
+ printk(KERN_INFO "Got AIO_READ Response: task: %p\n", task);
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+}
+
+static ssize_t fd_aio_retry(struct kiocb *kcb)
+{
+ printk(KERN_WARNING "fd_aio_retry() called for %p\n", kcb);
+ return 0;
+}
+
+static int fd_do_aio_read(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i, length = 0;
+ u32 block_size = DEV_ATTRIB(task->se_dev)->block_size;
+ unsigned long long offset, lba = req->fd_lba;;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ struct kiocb *iocb;
+
+ if (fd_iovec_alloc(req) < 0)
+ return -1;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba, block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba * block_size));
+
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+ printk(KERN_INFO "req->fd_lba: %llu\n", req->fd_lba);
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov = &req->fd_iovs[i];
+ printk(KERN_INFO "sg->length: %d sg->page: %p\n",
+ sg[i].length, sg[i].page);
+ length += sg[i].length;
+ iov->iov_len = sg[i].length;
+ iov->iov_base = sg_virt(&sg[i]);
+ printk(KERN_INFO "iov_iov_len: %d iov_iov_base: %p\n",
+ iov->iov_len, iov->iov_base);
+ }
+
+ init_sync_kiocb(&req->fd_iocb, fd);
+ req->fd_iocb.ki_opcode = IOCB_CMD_PREAD;
+ req->fd_iocb.ki_nbytes = length;
+ req->fd_iocb.private = (void *) task;
+ req->fd_iocb.ki_dtor = &fd_aio_intr;
+ req->fd_iocb.ki_retry = &fd_aio_retry;
+
+ printk(KERN_INFO "Launching AIO_READ: %p iovecs: %p total length:"
+ " %u\n", &req->fd_iocb, &req->fd_iovs[0], length);
+ printk(KERN_INFO "fd->f_pos: %d\n", fd->f_pos);
+ printk(KERN_INFO "req->fd_iocb.ki_pos: %d\n", req->fd_iocb.ki_pos);
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = __generic_file_aio_read(&req->fd_iocb, &req->fd_iovs[0],
+ req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ printk(KERN_INFO"__generic_file_aio_read() returned %d\n", ret);
+
+ if (ret <= 0)
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ if (ret != length)
+ printk(KERN_ERR "ret [%d] != LENGTH [%d]\n", ret, length);
+
+ return 1;
+}
+
+void fd_sendfile_free_DMA(se_cmd_t *cmd)
+{
+ printk(KERN_INFO "Release reference to pages now..\n");
+}
+
+static int fd_sendactor(
+ read_descriptor_t *desc,
+ struct page *page,
+ unsigned long offset,
+ unsigned long size)
+{
+ unsigned long count = desc->count;
+ se_task_t *task = desc->arg.data;
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+ struct scatterlist *sg = task->task_sg;
+
+ printk(KERN_INFO "page: %p offset: %lu size: %lu\n", page,
+ offset, size);
+
+ __free_page(sg[req->fd_cur_offset].page);
+
+ printk(KERN_INFO "page_address(page): %p\n", page_address(page));
+ sg[req->fd_cur_offset].page = page;
+ sg[req->fd_cur_offset].offset = offset;
+ sg[req->fd_cur_offset].length = size;
+
+ printk(KERN_INFO "sg[%d:%p].page %p length: %d\n", req->fd_cur_offset,
+ &sg[req->fd_cur_offset], sg[req->fd_cur_offset].page,
+ sg[req->fd_cur_offset].length);
+
+ req->fd_cur_size += size;
+ printk(KERN_INFO "fd_cur_size: %u\n", req->fd_cur_size);
+
+ req->fd_cur_offset++;
+
+ desc->count--;
+ desc->written += size;
+ return size;
+}
+
+static int fd_do_sendfile(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ struct file *fd = req->fd_dev->fd_file;
+
+ if (fd_seek(fd, req->fd_lba, DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ TASK_CMD(task)->transport_free_DMA = &fd_sendfile_free_DMA;
+
+ ret = fd->f_op->sendfile(fd, &fd->f_pos, req->fd_sg_count,
+ fd_sendactor, (void *)task);
+
+ if (ret < 0) {
+ printk(KERN_ERR "fd->f_op->sendfile() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+#endif
+
+static int fd_do_writev(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ mm_segment_t old_fs;
+ struct iovec iov[req->fd_sg_count];
+
+ memset(iov, 0, sizeof(struct iovec) + req->fd_sg_count);
+
+ if (fd_seek(fd, req->fd_lba, DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_writev(fd, &iov[0], req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk(KERN_ERR "vfs_writev() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+
+#if 0
+
+static int fd_do_aio_write(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i, length = 0;
+ u32 block_size = DEV_ATTRIB(task->se_dev)->block_size;
+ unsigned long long offset, lba = req->fd_lba;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ struct kiocb *iocb;
+
+ if (fd_iovec_alloc(req) < 0)
+ return -1;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba, block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba * block_size));
+
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov = &req->fd_iovs[i];
+ printk(KERN_INFO "sg->length: %d sg->page: %p\n",
+ sg[i].length, sg[i].page);
+
+ length += sg[i].length;
+ iov->iov_len = sg[i].length;
+ iov->iov_base = sg_virt(&sg[i]);
+ printk(KERN_INFO "iov_iov_len: %d iov_iov_base: %p\n",
+ iov->iov_len, iov->iov_base);
+ }
+
+ init_sync_kiocb(&req->fd_iocb, fd);
+ req->fd_iocb.ki_opcode = IOCB_CMD_PWRITE;
+ req->fd_iocb.ki_nbytes = length;
+ req->fd_iocb.private = (void *) task;
+ req->fd_iocb.ki_dtor = &fd_aio_intr;
+ req->fd_iocb.ki_retry = &fd_aio_retry;
+
+ printk(KERN_INFO "Launching AIO_WRITE: %p iovecs: %p total length:"
+ " %u\n", &req->fd_iocb, &req->fd_iovs[0], length);
+ printk(KERN_INFO "fd->f_pos: %d\n", fd->f_pos);
+ printk(KERN_INFO "req->fd_iocb.ki_pos: %d\n", req->fd_iocb.ki_pos);
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = generic_file_aio_write_nolock(&req->fd_iocb, &req->fd_iovs[0],
+ req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "generic_file_aio_write_nolock() returned %d\n", ret);
+
+ if (ret <= 0)
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ if (ret != length)
+ printk(KERN_ERR "ret [%d] != WRITE LENGTH [%d]\n", ret, length);
+
+ return 1;
+}
+#endif
+
+int fd_do_task(se_task_t *task)
+{
+ int ret = 0;
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ if (!(TASK_CMD(task)->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))
+ return fd_emulate_scsi_cdb(task);
+
+ req->fd_lba = task->task_lba;
+ req->fd_size = task->task_size;
+
+ if (req->fd_data_direction == FD_DATA_READ) {
+ /* ret = fd_do_aio_read(req, task); */
+ /* ret = fd_do_sendfile(req, task); */
+ ret = fd_do_readv(req, task);
+ } else {
+ /* ret = fd_do_aio_write(req, task); */
+ ret = fd_do_writev(req, task);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* fd_free_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_free_task(se_task_t *task)
+{
+ fd_request_t *req;
+
+ req = (fd_request_t *) task->transport_req;
+ kfree(req->fd_iovs);
+
+ kfree(req);
+}
+
+ssize_t fd_set_configfs_dev_params(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ const char *page, ssize_t count)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+ char *buf, *cur, *ptr, *ptr2;
+ int params = 0;
+
+ buf = kzalloc(count, GFP_KERNEL);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " temporary buffer\n");
+ return 0;
+ }
+ memcpy(buf, page, count);
+ cur = buf;
+
+ while (cur) {
+ ptr = strstr(cur, "=");
+ if (!(ptr))
+ goto out;
+
+ *ptr = '\0';
+ ptr++;
+
+ ptr2 = strstr(cur, "fd_dev_name");
+ if (ptr2) {
+ transport_check_dev_params_delim(ptr, &cur);
+ ptr = strstrip(ptr);
+ snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME,
+ "%s", ptr);
+ printk(KERN_INFO "FILEIO: Referencing Path: %s\n",
+ fd_dev->fd_dev_name);
+ fd_dev->fbd_flags |= FBDF_HAS_PATH;
+ params++;
+ continue;
+ }
+ ptr2 = strstr(cur, "fd_dev_size");
+ if (ptr2) {
+ transport_check_dev_params_delim(ptr, &cur);
+ if (strict_strtoull(ptr, 0, &fd_dev->fd_dev_size) < 0) {
+ printk(KERN_ERR "strict_strtoull() failed for"
+ " fd_dev_size=\n");
+ continue;
+ }
+ printk(KERN_INFO "FILEIO: Referencing Size: %llu"
+ " bytes\n", fd_dev->fd_dev_size);
+ fd_dev->fbd_flags |= FBDF_HAS_SIZE;
+ params++;
+ continue;
+ } else
+ cur = NULL;
+ }
+
+out:
+ kfree(buf);
+ return (params) ? count : -EINVAL;
+}
+
+ssize_t fd_check_configfs_dev_params(se_hba_t *hba, se_subsystem_dev_t *se_dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+
+ if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) {
+ printk(KERN_ERR "Missing fd_dev_name=\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+ssize_t fd_show_configfs_dev_params(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ char *page)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+ int bl = 0;
+
+ __fd_get_dev_info(fd_dev, page, &bl);
+ return (ssize_t)bl;
+}
+
+void fd_get_plugin_info(void *p, char *b, int *bl)
+{
+ *bl += sprintf(b + *bl, "%s FILEIO Plugin %s\n",
+ PYX_ISCSI_VENDOR, FD_VERSION);
+}
+
+void fd_get_hba_info(se_hba_t *hba, char *b, int *bl)
+{
+ fd_host_t *fd_host = (fd_host_t *)hba->hba_ptr;
+
+ *bl += sprintf(b + *bl, "SE Host ID: %u FD Host ID: %u\n",
+ hba->hba_id, fd_host->fd_host_id);
+ *bl += sprintf(b + *bl, " LIO FILEIO HBA\n");
+}
+
+void fd_get_dev_info(se_device_t *dev, char *b, int *bl)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+
+ __fd_get_dev_info(fd_dev, b, bl);
+}
+
+void __fd_get_dev_info(fd_dev_t *fd_dev, char *b, int *bl)
+{
+ *bl += sprintf(b + *bl, "LIO FILEIO ID: %u", fd_dev->fd_dev_id);
+ *bl += sprintf(b + *bl, " File: %s Size: %llu ",
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+
+ if (fd_dev->fd_bd) {
+ struct block_device *bd = fd_dev->fd_bd;
+
+ *bl += sprintf(b + *bl, "%s\n",
+ (!bd->bd_contains) ? "" :
+ (bd->bd_holder == (fd_dev_t *)fd_dev) ?
+ "CLAIMED: FILEIO" : "CLAIMED: OS");
+ } else
+ *bl += sprintf(b + *bl, "\n");
+}
+
+/* fd_map_task_non_SG():
+ *
+ *
+ */
+void fd_map_task_non_SG(se_task_t *task)
+{
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_bufflen = task->task_size;
+ req->fd_buf = (void *) T_TASK(cmd)->t_task_buf;
+ req->fd_sg_count = 0;
+}
+
+/* fd_map_task_SG():
+ *
+ *
+ */
+void fd_map_task_SG(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_bufflen = task->task_size;
+ req->fd_buf = NULL;
+ req->fd_sg_count = task->task_sg_num;
+}
+
+/* fd_CDB_inquiry():
+ *
+ *
+ */
+int fd_CDB_inquiry(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_none():
+ *
+ *
+ */
+int fd_CDB_none(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_NONE;
+ req->fd_bufflen = 0;
+ req->fd_sg_count = 0;
+ req->fd_buf = NULL;
+
+ return 0;
+}
+
+/* fd_CDB_read_non_SG():
+ *
+ *
+ */
+int fd_CDB_read_non_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_read_SG):
+ *
+ *
+ */
+int fd_CDB_read_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_SG(task);
+
+ return req->fd_sg_count;
+}
+
+/* fd_CDB_write_non_SG():
+ *
+ *
+ */
+int fd_CDB_write_non_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_WRITE;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_write_SG():
+ *
+ *
+ */
+int fd_CDB_write_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_WRITE;
+ fd_map_task_SG(task);
+
+ return req->fd_sg_count;
+}
+
+/* fd_check_lba():
+ *
+ *
+ */
+int fd_check_lba(unsigned long long lba, se_device_t *dev)
+{
+ return 0;
+}
+
+/* fd_check_for_SG(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_check_for_SG(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ return req->fd_sg_count;
+}
+
+/* fd_get_cdb(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+unsigned char *fd_get_cdb(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ return req->fd_scsi_cdb;
+}
+
+/* fd_get_blocksize(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_blocksize(se_device_t *dev)
+{
+ return FD_BLOCKSIZE;
+}
+
+/* fd_get_device_rev(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_device_rev(se_device_t *dev)
+{
+ return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
+}
+
+/* fd_get_device_type(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_device_type(se_device_t *dev)
+{
+ return TYPE_DISK;
+}
+
+/* fd_get_dma_length(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_dma_length(u32 task_size, se_device_t *dev)
+{
+ return PAGE_SIZE;
+}
+
+/* fd_get_max_sectors(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_max_sectors(se_device_t *dev)
+{
+ return FD_MAX_SECTORS;
+}
+
+/* fd_get_queue_depth(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_queue_depth(se_device_t *dev)
+{
+ return FD_DEVICE_QUEUE_DEPTH;
+}
+
+u32 fd_get_max_queue_depth(se_device_t *dev)
+{
+ return FD_MAX_DEVICE_QUEUE_DEPTH;
+}
diff --git a/include/target/target_core_file.h b/include/target/target_core_file.h
new file mode 100644
index 0000000..1f299e3
--- /dev/null
+++ b/include/target/target_core_file.h
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Filename: target_core_file.h
+ *
+ * This file contains the Storage Engine <-> FILEIO transport specific
+ * definitions and prototypes.
+ *
+ * Copyright (c) 2005 PyX Technologies, Inc.
+ * Copyright (c) 2006 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2009 Rising Tide Software, Inc.
+ * Copyright (c) 2008-2009 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.
+ *
+ ******************************************************************************/
+
+
+#ifndef TARGET_CORE_FILE_H
+#define TARGET_CORE_FILE_H
+
+#define FD_VERSION "3.1"
+
+#define FD_MAX_DEV_NAME 256
+/* Maximum queuedepth for the FILEIO HBA */
+#define FD_HBA_QUEUE_DEPTH 256
+#define FD_DEVICE_QUEUE_DEPTH 32
+#define FD_MAX_DEVICE_QUEUE_DEPTH 128
+#define FD_BLOCKSIZE 512
+#define FD_MAX_SECTORS 1024
+
+#define FD_DATA_READ 1
+#define FD_DATA_WRITE 2
+#define FD_DATA_NONE 3
+
+extern se_global_t *se_global;
+extern struct block_device *__linux_blockdevice_claim(int, int, void *, int *);
+extern struct block_device *linux_blockdevice_claim(int, int, void *);
+extern int linux_blockdevice_release(int, int, struct block_device *);
+extern int linux_blockdevice_check(int, int);
+
+#ifndef FD_INCLUDE_STRUCTS
+extern int fd_CDB_inquiry(se_task_t *, u32);
+extern int fd_CDB_none(se_task_t *, u32);
+extern int fd_CDB_read_non_SG(se_task_t *, u32);
+extern int fd_CDB_read_SG(se_task_t *, u32);
+extern int fd_CDB_write_non_SG(se_task_t *, u32);
+extern int fd_CDB_write_SG(se_task_t *, u32);
+
+extern int fd_attach_hba(se_hba_t *, u32);
+extern int fd_detach_hba(se_hba_t *);
+extern int fd_claim_phydevice(se_hba_t *, se_device_t *);
+extern int fd_release_phydevice(se_device_t *);
+extern void *fd_allocate_virtdevice(se_hba_t *, const char *);
+extern se_device_t *fd_create_virtdevice(se_hba_t *, se_subsystem_dev_t *,
+ void *);
+extern int fd_activate_device(se_device_t *);
+extern void fd_deactivate_device(se_device_t *);
+extern void fd_free_device(void *);
+extern int fd_transport_complete(se_task_t *);
+extern void *fd_allocate_request(se_task_t *, se_device_t *);
+extern int fd_do_task(se_task_t *);
+extern void fd_free_task(se_task_t *);
+extern ssize_t fd_set_configfs_dev_params(se_hba_t *, se_subsystem_dev_t *,
+ const char *, ssize_t);
+extern ssize_t fd_check_configfs_dev_params(se_hba_t *, se_subsystem_dev_t *);
+extern ssize_t fd_show_configfs_dev_params(se_hba_t *, se_subsystem_dev_t *,
+ char *);
+extern void fd_get_plugin_info(void *, char *, int *);
+extern void fd_get_hba_info(se_hba_t *, char *, int *);
+extern void fd_get_dev_info(se_device_t *, char *, int *);
+extern int fd_check_lba(unsigned long long, se_device_t *);
+extern int fd_check_for_SG(se_task_t *);
+extern unsigned char *fd_get_cdb(se_task_t *);
+extern u32 fd_get_blocksize(se_device_t *);
+extern u32 fd_get_device_rev(se_device_t *);
+extern u32 fd_get_device_type(se_device_t *);
+extern u32 fd_get_dma_length(u32, se_device_t *);
+extern u32 fd_get_max_sectors(se_device_t *);
+extern u32 fd_get_queue_depth(se_device_t *);
+extern u32 fd_get_max_queue_depth(se_device_t *);
+#endif /* ! FD_INCLUDE_STRUCTS */
+
+#define RRF_EMULATE_CDB 0x01
+#define RRF_GOT_LBA 0x02
+
+typedef struct fd_request_s {
+ /* SCSI CDB from iSCSI Command PDU */
+ unsigned char fd_scsi_cdb[SCSI_CDB_SIZE];
+ /* Data Direction */
+ u8 fd_data_direction;
+ /* Total length of request */
+ u32 fd_bufflen;
+ /* RD request flags */
+ u32 fd_req_flags;
+ /* Offset from start of page */
+ u32 fd_offset;
+ u32 fd_cur_size;
+ u32 fd_cur_offset;
+ /* Scatterlist count */
+ u32 fd_sg_count;
+ /* Logical Block Address */
+ unsigned long long fd_lba;
+ u64 fd_size;
+ struct kiocb fd_iocb;
+ struct iovec *fd_iovs;
+ /* Data buffer containing scatterlists(s) or contingous
+ memory segments */
+ void *fd_buf;
+ /* FILEIO device */
+ struct fd_dev_s *fd_dev;
+} ____cacheline_aligned fd_request_t;
+
+typedef struct fd_dev_sg_table_s {
+ u32 page_start_offset;
+ u32 page_end_offset;
+ u32 fd_sg_count;
+ struct scatterlist *sg_table;
+} ____cacheline_aligned fd_dev_sg_table_t;
+
+#define FBDF_HAS_PATH 0x01
+#define FBDF_HAS_SIZE 0x02
+
+typedef struct fd_dev_s {
+ u32 fbd_flags;
+ unsigned char fd_dev_name[FD_MAX_DEV_NAME];
+ int fd_claim_bd;
+ int fd_major;
+ int fd_minor;
+ /* Unique Ramdisk Device ID in Ramdisk HBA */
+ u32 fd_dev_id;
+ /* Number of SG tables in sg_table_array */
+ u32 fd_table_count;
+ u32 fd_queue_depth;
+ unsigned long long fd_dev_size;
+ struct file *fd_file;
+ struct block_device *fd_bd;
+ /* FILEIO HBA device is connected to */
+ struct fd_host_s *fd_host;
+ /* Next FILEIO Device entry in list */
+ struct fd_dev_s *next;
+} ____cacheline_aligned fd_dev_t;
+
+extern void __fd_get_dev_info(struct fd_dev_s *, char *, int *);
+
+typedef struct fd_host_s {
+ u32 fd_host_dev_id_count;
+ /* Unique FILEIO Host ID */
+ u32 fd_host_id;
+} ____cacheline_aligned fd_host_t;
+
+#ifndef FD_INCLUDE_STRUCTS
+/*
+ * We use the generic command sequencer, so we must setup
+ * se_subsystem_spc_t.
+ */
+se_subsystem_spc_t fileio_template_spc = {
+ .inquiry = fd_CDB_inquiry,
+ .none = fd_CDB_none,
+ .read_non_SG = fd_CDB_read_non_SG,
+ .read_SG = fd_CDB_read_SG,
+ .write_non_SG = fd_CDB_write_non_SG,
+ .write_SG = fd_CDB_write_SG,
+};
+
+/*#warning FIXME v2.8: transport_type for FILEIO will need to change
+ with DIRECT_IO to blockdevs */
+
+se_subsystem_api_t fileio_template = {
+ .name = "fileio",
+ .type = FILEIO,
+ .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
+ .attach_hba = fd_attach_hba,
+ .detach_hba = fd_detach_hba,
+ .claim_phydevice = fd_claim_phydevice,
+ .release_phydevice = fd_release_phydevice,
+ .allocate_virtdevice = fd_allocate_virtdevice,
+ .create_virtdevice = fd_create_virtdevice,
+ .activate_device = fd_activate_device,
+ .deactivate_device = fd_deactivate_device,
+ .free_device = fd_free_device,
+ .transport_complete = fd_transport_complete,
+ .allocate_request = fd_allocate_request,
+ .do_task = fd_do_task,
+ .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,
+ .get_plugin_info = fd_get_plugin_info,
+ .get_hba_info = fd_get_hba_info,
+ .get_dev_info = fd_get_dev_info,
+ .check_lba = fd_check_lba,
+ .check_for_SG = fd_check_for_SG,
+ .get_cdb = fd_get_cdb,
+ .get_blocksize = fd_get_blocksize,
+ .get_device_rev = fd_get_device_rev,
+ .get_device_type = fd_get_device_type,
+ .get_dma_length = fd_get_dma_length,
+ .get_max_sectors = fd_get_max_sectors,
+ .get_queue_depth = fd_get_queue_depth,
+ .get_max_queue_depth = fd_get_max_queue_depth,
+ .write_pending = NULL,
+ .spc = &fileio_template_spc,
+};
+
+#endif /* ! FD_INCLUDE_STRUCTS */
+
+#endif /* TARGET_CORE_FILE_H */
^ permalink raw reply [flat|nested] 4+ messages in thread* [RFC PATCH 4/19] Target_Core_Mod FILEIO <-> Linux/VFS subsystem
@ 2009-09-18 22:08 Nicholas A. Bellinger
0 siblings, 0 replies; 4+ messages in thread
From: Nicholas A. Bellinger @ 2009-09-18 22:08 UTC (permalink / raw)
To: LKML, linux-scsi
Cc: Andrew Morton, Greg KH, Douglas Gilbert, James Bottomley,
Hannes Reinecke, FUJITA Tomonori, Mike Christie, Joel Becker,
Martin K. Petersen, Christoph Hellwig, Linus Torvalds,
Alan Stern, Boaz Harrosh, Florian Haas, Philipp Reisner,
Lars Ellenberg, Daniel Walker
[RFC PATCH 4/19] Target_Core_Mod FILEIO <-> Linux/VFS subsystem
This patch adds the buffered FILEIO subsystem plugin for accessing struct file
from upstream Linux/VFS code.
It also includes AIO kernel code and O_DIRECT (needs seperate kernel patch for non buffered kernel file I/O),
that are currently disabled.
Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org>
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
new file mode 100644
index 0000000..767dcc7
--- /dev/null
+++ b/drivers/target/target_core_file.c
@@ -0,0 +1,1228 @@
+/*******************************************************************************
+ * 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-2009 Rising Tide Software, Inc.
+ * Copyright (c) 2008-2009 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.
+ *
+ ******************************************************************************/
+
+
+#define TARGET_CORE_FILE_C
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#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/target_core_file.h>
+
+#undef TARGET_CORE_FILE_C
+
+/* fd_attach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_attach_hba(se_hba_t *hba, u32 host_id)
+{
+ fd_host_t *fd_host;
+
+ fd_host = kzalloc(sizeof(fd_host_t), GFP_KERNEL);
+ if (!(fd_host)) {
+ printk(KERN_ERR "Unable to allocate memory for fd_host_t\n");
+ return -1;
+ }
+
+ fd_host->fd_host_id = host_id;
+
+ atomic_set(&hba->left_queue_depth, FD_HBA_QUEUE_DEPTH);
+ atomic_set(&hba->max_queue_depth, FD_HBA_QUEUE_DEPTH);
+ hba->hba_ptr = (void *) fd_host;
+ hba->transport = &fileio_template;
+
+ printk(KERN_INFO "CORE_HBA[%d] - TCM FILEIO HBA Driver %s on Generic"
+ " Target Core Stack %s\n", hba->hba_id, FD_VERSION,
+ TARGET_CORE_MOD_VERSION);
+ printk(KERN_INFO "CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic"
+ " Target Core with TCQ Depth: %d MaxSectors: %u\n",
+ hba->hba_id, fd_host->fd_host_id,
+ atomic_read(&hba->max_queue_depth), FD_MAX_SECTORS);
+
+ return 0;
+}
+
+/* fd_detach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_detach_hba(se_hba_t *hba)
+{
+ fd_host_t *fd_host;
+
+ if (!hba->hba_ptr) {
+ printk(KERN_ERR "hba->hba_ptr is NULL!\n");
+ return -1;
+ }
+ fd_host = (fd_host_t *) hba->hba_ptr;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached FILEIO HBA: %u from Generic"
+ " Target Core\n", hba->hba_id, fd_host->fd_host_id);
+
+ kfree(fd_host);
+ hba->hba_ptr = NULL;
+
+ return 0;
+}
+
+int fd_claim_phydevice(se_hba_t *hba, se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *)dev->dev_ptr;
+ struct block_device *bd;
+
+ if (fd_dev->fd_bd)
+ return 0;
+
+ if (dev->dev_flags & DF_READ_ONLY) {
+ printk(KERN_INFO "FILEIO: Using previously claimed %p Major"
+ ":Minor - %d:%d\n", fd_dev->fd_bd, fd_dev->fd_major,
+ fd_dev->fd_minor);
+ } else {
+ printk(KERN_INFO "FILEIO: Claiming %p Major:Minor - %d:%d\n",
+ fd_dev, fd_dev->fd_major, fd_dev->fd_minor);
+
+ bd = linux_blockdevice_claim(fd_dev->fd_major,
+ fd_dev->fd_minor, (void *)fd_dev);
+ if (!(bd))
+ return -1;
+
+ fd_dev->fd_bd = bd;
+ fd_dev->fd_bd->bd_contains = bd;
+ }
+
+ return 0;
+}
+
+int fd_release_phydevice(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *)dev->dev_ptr;
+
+ if (!fd_dev->fd_bd)
+ return 0;
+
+ if (dev->dev_flags & DF_READ_ONLY) {
+ printk(KERN_INFO "FILEIO: Calling blkdev_put() for Major:Minor"
+ " - %d:%d\n", fd_dev->fd_major, fd_dev->fd_minor);
+ blkdev_put((struct block_device *)fd_dev->fd_bd, FMODE_READ);
+ } else {
+ printk(KERN_INFO "FILEIO: Releasing Major:Minor - %d:%d\n",
+ fd_dev->fd_major, fd_dev->fd_minor);
+ linux_blockdevice_release(fd_dev->fd_major, fd_dev->fd_minor,
+ (struct block_device *)fd_dev->fd_bd);
+ }
+ fd_dev->fd_bd = NULL;
+
+ return 0;
+}
+
+void *fd_allocate_virtdevice(se_hba_t *hba, const char *name)
+{
+ fd_dev_t *fd_dev;
+ fd_host_t *fd_host = (fd_host_t *) hba->hba_ptr;
+
+ fd_dev = kzalloc(sizeof(fd_dev_t), GFP_KERNEL);
+ if (!(fd_dev)) {
+ printk(KERN_ERR "Unable to allocate memory for fd_dev_t\n");
+ return NULL;
+ }
+
+ fd_dev->fd_host = fd_host;
+
+ printk(KERN_INFO "FILEIO: Allocated fd_dev for %p\n", name);
+
+ return fd_dev;
+}
+
+/* fd_create_virtdevice(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+se_device_t *fd_create_virtdevice(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ void *p)
+{
+ char *dev_p = NULL;
+ se_device_t *dev;
+ fd_dev_t *fd_dev = (fd_dev_t *) p;
+ fd_host_t *fd_host = (fd_host_t *) hba->hba_ptr;
+ mm_segment_t old_fs;
+ struct block_device *bd = NULL;
+ struct file *file;
+ struct inode *inode = NULL;
+ struct request_queue *q;
+ unsigned long long blocks_long;
+ int dev_flags = 0, flags;
+
+ 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)) {
+ printk(KERN_ERR "getname(%s) failed: %lu\n",
+ fd_dev->fd_dev_name, IS_ERR(dev_p));
+ 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; */
+
+ file = filp_open(dev_p, flags, 0600);
+
+ if (IS_ERR(file) || !file || !file->f_dentry) {
+ printk(KERN_ERR "filp_open(%s) failed\n", dev_p);
+ goto fail;
+ }
+ fd_dev->fd_file = file;
+ /*
+ * If we are claiming a blockend for this struct file, we extract
+ * fd_dev->fd_size from struct block_device.
+ *
+ * Otherwise, we use the passed fd_size= from configfs
+ */
+ inode = igrab(file->f_mapping->host);
+ if (!(inode)) {
+ printk(KERN_ERR "FILEIO: Unable to locate struct inode from"
+ " struct file\n");
+ goto fail;
+ }
+ /*
+ * If struct file is referencing a underlying struct block_device,
+ * claim it now.
+ */
+ if (S_ISBLK(inode->i_mode)) {
+ fd_dev->fd_bd = I_BDEV(file->f_mapping->host);
+ if (!(fd_dev->fd_bd)) {
+ printk(KERN_ERR "FILEIO: Unable to locate struct"
+ " block_device\n");
+ goto fail;
+ }
+ fd_dev->fd_major = fd_dev->fd_bd->bd_disk->major;
+ fd_dev->fd_minor = fd_dev->fd_bd->bd_disk->first_minor;
+
+ printk(KERN_INFO "FILEIO: Claiming %p Major:Minor - %d:%d\n",
+ fd_dev, fd_dev->fd_major, fd_dev->fd_minor);
+
+ bd = linux_blockdevice_claim(fd_dev->fd_bd->bd_disk->major,
+ fd_dev->fd_bd->bd_disk->first_minor,
+ fd_dev);
+ if (!(bd)) {
+ printk(KERN_ERR "FILEIO: Unable to claim"
+ " struct block_device\n");
+ goto fail;
+ }
+
+ dev_flags |= DF_CLAIMED_BLOCKDEV;
+ if (dev_flags & DF_CLAIMED_BLOCKDEV)
+ fd_dev->fd_bd->bd_contains = bd;
+ /*
+ * Determine the number of bytes for this FILEIO device from
+ * struct block_device's block count and block_size.
+ */
+ blocks_long = (get_capacity(bd->bd_disk) - 1);
+ q = bdev_get_queue(bd);
+ fd_dev->fd_dev_size = ((unsigned long long)blocks_long *
+ bdev_logical_block_size(bd));
+ printk(KERN_INFO "FILEIO: Using size: %llu bytes from struct"
+ " block_device blocks: %llu logical_block_size: %d\n",
+ fd_dev->fd_dev_size, blocks_long,
+ bdev_logical_block_size(bd));
+ } else {
+ if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
+ printk(KERN_ERR "FILEIO: Missing fd_dev_size="
+ " parameter, and no backing struct"
+ " block_device\n");
+ goto fail;
+ }
+ }
+ /*
+ * Pass dev_flags for linux_blockdevice_claim_bd or
+ * linux_blockdevice_claim() from the usage above.
+ *
+ * Note that transport_add_device_to_core_hba() will call
+ * linux_blockdevice_release() internally on failure to
+ * call bd_release() on the referenced struct block_device.
+ */
+ dev = transport_add_device_to_core_hba(hba, &fileio_template,
+ se_dev, dev_flags, (void *)fd_dev);
+ if (!(dev))
+ goto fail;
+
+ fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
+ fd_dev->fd_queue_depth = dev->queue_depth;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s,"
+ " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+
+ iput(inode);
+ putname(dev_p);
+ return dev;
+fail:
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+ fd_dev->fd_bd = NULL;
+ fd_dev->fd_major = 0;
+ fd_dev->fd_minor = 0;
+ if (inode)
+ iput(inode);
+ putname(dev_p);
+ return NULL;
+}
+
+/* fd_activate_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_activate_device(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+ fd_host_t *fd_host = fd_dev->fd_host;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Activating Device with TCQ: %d at"
+ " FILEIO Device ID: %d\n", fd_host->fd_host_id,
+ fd_dev->fd_queue_depth, fd_dev->fd_dev_id);
+
+ return 0;
+}
+
+/* fd_deactivate_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_deactivate_device(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+ fd_host_t *fd_host = fd_dev->fd_host;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Deactivating Device with TCQ: %d at"
+ " FILEIO Device ID: %d\n", fd_host->fd_host_id,
+ fd_dev->fd_queue_depth, fd_dev->fd_dev_id);
+
+ return;
+}
+
+/* fd_free_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_free_device(void *p)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) p;
+
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+
+ kfree(fd_dev);
+}
+
+/* fd_transport_complete(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_transport_complete(se_task_t *task)
+{
+ return 0;
+}
+
+/* fd_allocate_request(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void *fd_allocate_request(
+ se_task_t *task,
+ se_device_t *dev)
+{
+ fd_request_t *fd_req;
+
+ fd_req = kzalloc(sizeof(fd_request_t), GFP_KERNEL);
+ if (!(fd_req)) {
+ printk(KERN_ERR "Unable to allocate fd_request_t\n");
+ return NULL;
+ }
+
+ fd_req->fd_dev = (fd_dev_t *) dev->dev_ptr;
+
+ return (void *)fd_req;
+}
+
+/* fd_emulate_inquiry():
+ *
+ *
+ */
+int fd_emulate_inquiry(se_task_t *task)
+{
+ unsigned char prod[64], se_location[128];
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_dev_t *fdev = (fd_dev_t *) task->se_dev->dev_ptr;
+ se_hba_t *hba = task->se_dev->se_hba;
+
+ memset(prod, 0, 64);
+ memset(se_location, 0, 128);
+
+ sprintf(prod, "FILEIO");
+ sprintf(se_location, "%u_%u", hba->hba_id, fdev->fd_dev_id);
+
+ return transport_generic_emulate_inquiry(cmd, TYPE_DISK, prod,
+ FD_VERSION, se_location);
+}
+
+/* fd_emulate_read_cap():
+ *
+ *
+ */
+static int fd_emulate_read_cap(se_task_t *task)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) task->se_dev->dev_ptr;
+ unsigned long long blocks_long = div_u64(fd_dev->fd_dev_size,
+ DEV_ATTRIB(task->se_dev)->block_size);
+ u32 blocks;
+
+ if (blocks_long >= 0x00000000ffffffff)
+ blocks = 0xffffffff;
+ else
+ blocks = (u32)blocks_long;
+
+ return transport_generic_emulate_readcapacity(TASK_CMD(task), blocks);
+}
+
+static int fd_emulate_read_cap16(se_task_t *task)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) task->se_dev->dev_ptr;
+ unsigned long long blocks_long = div_u64(fd_dev->fd_dev_size,
+ DEV_ATTRIB(task->se_dev)->block_size);
+
+ return transport_generic_emulate_readcapacity_16(TASK_CMD(task),
+ blocks_long);
+}
+
+/* fd_emulate_scsi_cdb():
+ *
+ *
+ */
+static int fd_emulate_scsi_cdb(se_task_t *task)
+{
+ int ret;
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_request_t *fd_req = (fd_request_t *) task->transport_req;
+
+ switch (fd_req->fd_scsi_cdb[0]) {
+ case INQUIRY:
+ if (fd_emulate_inquiry(task) < 0)
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ break;
+ case READ_CAPACITY:
+ ret = fd_emulate_read_cap(task);
+ if (ret < 0)
+ return ret;
+ break;
+ case MODE_SENSE:
+ ret = transport_generic_emulate_modesense(TASK_CMD(task),
+ fd_req->fd_scsi_cdb, fd_req->fd_buf, 0,
+ TYPE_DISK);
+ if (ret < 0)
+ return ret;
+ break;
+ case MODE_SENSE_10:
+ ret = transport_generic_emulate_modesense(TASK_CMD(task),
+ fd_req->fd_scsi_cdb, fd_req->fd_buf, 1,
+ TYPE_DISK);
+ if (ret < 0)
+ return ret;
+ break;
+ case SERVICE_ACTION_IN:
+ if ((T_TASK(cmd)->t_task_cdb[1] & 0x1f) !=
+ SAI_READ_CAPACITY_16) {
+ printk(KERN_ERR "Unsupported SA: 0x%02x\n",
+ T_TASK(cmd)->t_task_cdb[1] & 0x1f);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = fd_emulate_read_cap16(task);
+ if (ret < 0)
+ return ret;
+ break;
+ case REQUEST_SENSE:
+ ret = transport_generic_emulate_request_sense(cmd,
+ T_TASK(cmd)->t_task_cdb);
+ if (ret < 0)
+ return ret;
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case ERASE:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case SPACE:
+ case START_STOP:
+ case SYNCHRONIZE_CACHE:
+ case TEST_UNIT_READY:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ case RESERVE:
+ case RESERVE_10:
+ case RELEASE:
+ case RELEASE_10:
+ break;
+ default:
+ printk(KERN_ERR "Unsupported SCSI Opcode: 0x%02x for FILEIO\n",
+ fd_req->fd_scsi_cdb[0]);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+static inline int fd_iovec_alloc(fd_request_t *req)
+{
+ req->fd_iovs = kzalloc(sizeof(struct iovec) * req->fd_sg_count,
+ GFP_KERNEL);
+ if (!(req->fd_iovs)) {
+ printk(KERN_ERR "Unable to allocate req->fd_iovs\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline int fd_seek(
+ struct file *fd,
+ unsigned long long lba,
+ u32 block_size)
+{
+ mm_segment_t old_fs;
+ unsigned long long offset;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+#if 0
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba, block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba * block_size));
+#endif
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fd_do_readv(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec iov[req->fd_sg_count];
+
+ memset(iov, 0, sizeof(struct iovec) + req->fd_sg_count);
+
+ if (fd_seek(fd, req->fd_lba, DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_readv(fd, &iov[0], req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk(KERN_ERR "vfs_readv() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+
+#if 0
+
+static void fd_aio_intr(struct kiocb *kcb)
+{
+ se_task_t *task = (se_task_t *)kcb->private;
+
+ printk(KERN_INFO "Got AIO_READ Response: task: %p\n", task);
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+}
+
+static ssize_t fd_aio_retry(struct kiocb *kcb)
+{
+ printk(KERN_WARNING "fd_aio_retry() called for %p\n", kcb);
+ return 0;
+}
+
+static int fd_do_aio_read(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i, length = 0;
+ u32 block_size = DEV_ATTRIB(task->se_dev)->block_size;
+ unsigned long long offset, lba = req->fd_lba;;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ struct kiocb *iocb;
+
+ if (fd_iovec_alloc(req) < 0)
+ return -1;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba, block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba * block_size));
+
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+ printk(KERN_INFO "req->fd_lba: %llu\n", req->fd_lba);
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov = &req->fd_iovs[i];
+ printk(KERN_INFO "sg->length: %d sg->page: %p\n",
+ sg[i].length, sg[i].page);
+ length += sg[i].length;
+ iov->iov_len = sg[i].length;
+ iov->iov_base = sg_virt(&sg[i]);
+ printk(KERN_INFO "iov_iov_len: %d iov_iov_base: %p\n",
+ iov->iov_len, iov->iov_base);
+ }
+
+ init_sync_kiocb(&req->fd_iocb, fd);
+ req->fd_iocb.ki_opcode = IOCB_CMD_PREAD;
+ req->fd_iocb.ki_nbytes = length;
+ req->fd_iocb.private = (void *) task;
+ req->fd_iocb.ki_dtor = &fd_aio_intr;
+ req->fd_iocb.ki_retry = &fd_aio_retry;
+
+ printk(KERN_INFO "Launching AIO_READ: %p iovecs: %p total length:"
+ " %u\n", &req->fd_iocb, &req->fd_iovs[0], length);
+ printk(KERN_INFO "fd->f_pos: %d\n", fd->f_pos);
+ printk(KERN_INFO "req->fd_iocb.ki_pos: %d\n", req->fd_iocb.ki_pos);
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = __generic_file_aio_read(&req->fd_iocb, &req->fd_iovs[0],
+ req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ printk(KERN_INFO"__generic_file_aio_read() returned %d\n", ret);
+
+ if (ret <= 0)
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ if (ret != length)
+ printk(KERN_ERR "ret [%d] != LENGTH [%d]\n", ret, length);
+
+ return 1;
+}
+
+void fd_sendfile_free_DMA(se_cmd_t *cmd)
+{
+ printk(KERN_INFO "Release reference to pages now..\n");
+}
+
+static int fd_sendactor(
+ read_descriptor_t *desc,
+ struct page *page,
+ unsigned long offset,
+ unsigned long size)
+{
+ unsigned long count = desc->count;
+ se_task_t *task = desc->arg.data;
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+ struct scatterlist *sg = task->task_sg;
+
+ printk(KERN_INFO "page: %p offset: %lu size: %lu\n", page,
+ offset, size);
+
+ __free_page(sg[req->fd_cur_offset].page);
+
+ printk(KERN_INFO "page_address(page): %p\n", page_address(page));
+ sg[req->fd_cur_offset].page = page;
+ sg[req->fd_cur_offset].offset = offset;
+ sg[req->fd_cur_offset].length = size;
+
+ printk(KERN_INFO "sg[%d:%p].page %p length: %d\n", req->fd_cur_offset,
+ &sg[req->fd_cur_offset], sg[req->fd_cur_offset].page,
+ sg[req->fd_cur_offset].length);
+
+ req->fd_cur_size += size;
+ printk(KERN_INFO "fd_cur_size: %u\n", req->fd_cur_size);
+
+ req->fd_cur_offset++;
+
+ desc->count--;
+ desc->written += size;
+ return size;
+}
+
+static int fd_do_sendfile(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ struct file *fd = req->fd_dev->fd_file;
+
+ if (fd_seek(fd, req->fd_lba, DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ TASK_CMD(task)->transport_free_DMA = &fd_sendfile_free_DMA;
+
+ ret = fd->f_op->sendfile(fd, &fd->f_pos, req->fd_sg_count,
+ fd_sendactor, (void *)task);
+
+ if (ret < 0) {
+ printk(KERN_ERR "fd->f_op->sendfile() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+#endif
+
+static int fd_do_writev(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ mm_segment_t old_fs;
+ struct iovec iov[req->fd_sg_count];
+
+ memset(iov, 0, sizeof(struct iovec) + req->fd_sg_count);
+
+ if (fd_seek(fd, req->fd_lba, DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_writev(fd, &iov[0], req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk(KERN_ERR "vfs_writev() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+
+#if 0
+
+static int fd_do_aio_write(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i, length = 0;
+ u32 block_size = DEV_ATTRIB(task->se_dev)->block_size;
+ unsigned long long offset, lba = req->fd_lba;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ struct kiocb *iocb;
+
+ if (fd_iovec_alloc(req) < 0)
+ return -1;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba, block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba * block_size));
+
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov = &req->fd_iovs[i];
+ printk(KERN_INFO "sg->length: %d sg->page: %p\n",
+ sg[i].length, sg[i].page);
+
+ length += sg[i].length;
+ iov->iov_len = sg[i].length;
+ iov->iov_base = sg_virt(&sg[i]);
+ printk(KERN_INFO "iov_iov_len: %d iov_iov_base: %p\n",
+ iov->iov_len, iov->iov_base);
+ }
+
+ init_sync_kiocb(&req->fd_iocb, fd);
+ req->fd_iocb.ki_opcode = IOCB_CMD_PWRITE;
+ req->fd_iocb.ki_nbytes = length;
+ req->fd_iocb.private = (void *) task;
+ req->fd_iocb.ki_dtor = &fd_aio_intr;
+ req->fd_iocb.ki_retry = &fd_aio_retry;
+
+ printk(KERN_INFO "Launching AIO_WRITE: %p iovecs: %p total length:"
+ " %u\n", &req->fd_iocb, &req->fd_iovs[0], length);
+ printk(KERN_INFO "fd->f_pos: %d\n", fd->f_pos);
+ printk(KERN_INFO "req->fd_iocb.ki_pos: %d\n", req->fd_iocb.ki_pos);
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = generic_file_aio_write_nolock(&req->fd_iocb, &req->fd_iovs[0],
+ req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "generic_file_aio_write_nolock() returned %d\n", ret);
+
+ if (ret <= 0)
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ if (ret != length)
+ printk(KERN_ERR "ret [%d] != WRITE LENGTH [%d]\n", ret, length);
+
+ return 1;
+}
+#endif
+
+int fd_do_task(se_task_t *task)
+{
+ int ret = 0;
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ if (!(TASK_CMD(task)->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))
+ return fd_emulate_scsi_cdb(task);
+
+ req->fd_lba = task->task_lba;
+ req->fd_size = task->task_size;
+
+ if (req->fd_data_direction == FD_DATA_READ) {
+ /* ret = fd_do_aio_read(req, task); */
+ /* ret = fd_do_sendfile(req, task); */
+ ret = fd_do_readv(req, task);
+ } else {
+ /* ret = fd_do_aio_write(req, task); */
+ ret = fd_do_writev(req, task);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* fd_free_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_free_task(se_task_t *task)
+{
+ fd_request_t *req;
+
+ req = (fd_request_t *) task->transport_req;
+ kfree(req->fd_iovs);
+
+ kfree(req);
+}
+
+ssize_t fd_set_configfs_dev_params(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ const char *page, ssize_t count)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+ char *buf, *cur, *ptr, *ptr2;
+ int params = 0;
+
+ buf = kzalloc(count, GFP_KERNEL);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " temporary buffer\n");
+ return 0;
+ }
+ memcpy(buf, page, count);
+ cur = buf;
+
+ while (cur) {
+ ptr = strstr(cur, "=");
+ if (!(ptr))
+ goto out;
+
+ *ptr = '\0';
+ ptr++;
+
+ ptr2 = strstr(cur, "fd_dev_name");
+ if (ptr2) {
+ transport_check_dev_params_delim(ptr, &cur);
+ ptr = strstrip(ptr);
+ snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME,
+ "%s", ptr);
+ printk(KERN_INFO "FILEIO: Referencing Path: %s\n",
+ fd_dev->fd_dev_name);
+ fd_dev->fbd_flags |= FBDF_HAS_PATH;
+ params++;
+ continue;
+ }
+ ptr2 = strstr(cur, "fd_dev_size");
+ if (ptr2) {
+ transport_check_dev_params_delim(ptr, &cur);
+ if (strict_strtoull(ptr, 0, &fd_dev->fd_dev_size) < 0) {
+ printk(KERN_ERR "strict_strtoull() failed for"
+ " fd_dev_size=\n");
+ continue;
+ }
+ printk(KERN_INFO "FILEIO: Referencing Size: %llu"
+ " bytes\n", fd_dev->fd_dev_size);
+ fd_dev->fbd_flags |= FBDF_HAS_SIZE;
+ params++;
+ continue;
+ } else
+ cur = NULL;
+ }
+
+out:
+ kfree(buf);
+ return (params) ? count : -EINVAL;
+}
+
+ssize_t fd_check_configfs_dev_params(se_hba_t *hba, se_subsystem_dev_t *se_dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+
+ if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) {
+ printk(KERN_ERR "Missing fd_dev_name=\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+ssize_t fd_show_configfs_dev_params(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ char *page)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+ int bl = 0;
+
+ __fd_get_dev_info(fd_dev, page, &bl);
+ return (ssize_t)bl;
+}
+
+void fd_get_plugin_info(void *p, char *b, int *bl)
+{
+ *bl += sprintf(b + *bl, "TCM FILEIO Plugin %s\n", FD_VERSION);
+}
+
+void fd_get_hba_info(se_hba_t *hba, char *b, int *bl)
+{
+ fd_host_t *fd_host = (fd_host_t *)hba->hba_ptr;
+
+ *bl += sprintf(b + *bl, "SE Host ID: %u FD Host ID: %u\n",
+ hba->hba_id, fd_host->fd_host_id);
+ *bl += sprintf(b + *bl, " TCM FILEIO HBA\n");
+}
+
+void fd_get_dev_info(se_device_t *dev, char *b, int *bl)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+
+ __fd_get_dev_info(fd_dev, b, bl);
+}
+
+void __fd_get_dev_info(fd_dev_t *fd_dev, char *b, int *bl)
+{
+ *bl += sprintf(b + *bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id);
+ *bl += sprintf(b + *bl, " File: %s Size: %llu ",
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+
+ if (fd_dev->fd_bd) {
+ struct block_device *bd = fd_dev->fd_bd;
+
+ *bl += sprintf(b + *bl, "%s\n",
+ (!bd->bd_contains) ? "" :
+ (bd->bd_holder == (fd_dev_t *)fd_dev) ?
+ "CLAIMED: FILEIO" : "CLAIMED: OS");
+ } else
+ *bl += sprintf(b + *bl, "\n");
+}
+
+/* fd_map_task_non_SG():
+ *
+ *
+ */
+void fd_map_task_non_SG(se_task_t *task)
+{
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_bufflen = task->task_size;
+ req->fd_buf = (void *) T_TASK(cmd)->t_task_buf;
+ req->fd_sg_count = 0;
+}
+
+/* fd_map_task_SG():
+ *
+ *
+ */
+void fd_map_task_SG(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_bufflen = task->task_size;
+ req->fd_buf = NULL;
+ req->fd_sg_count = task->task_sg_num;
+}
+
+/* fd_CDB_inquiry():
+ *
+ *
+ */
+int fd_CDB_inquiry(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_none():
+ *
+ *
+ */
+int fd_CDB_none(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_NONE;
+ req->fd_bufflen = 0;
+ req->fd_sg_count = 0;
+ req->fd_buf = NULL;
+
+ return 0;
+}
+
+/* fd_CDB_read_non_SG():
+ *
+ *
+ */
+int fd_CDB_read_non_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_read_SG):
+ *
+ *
+ */
+int fd_CDB_read_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_SG(task);
+
+ return req->fd_sg_count;
+}
+
+/* fd_CDB_write_non_SG():
+ *
+ *
+ */
+int fd_CDB_write_non_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_WRITE;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_write_SG():
+ *
+ *
+ */
+int fd_CDB_write_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_WRITE;
+ fd_map_task_SG(task);
+
+ return req->fd_sg_count;
+}
+
+/* fd_check_lba():
+ *
+ *
+ */
+int fd_check_lba(unsigned long long lba, se_device_t *dev)
+{
+ return 0;
+}
+
+/* fd_check_for_SG(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_check_for_SG(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ return req->fd_sg_count;
+}
+
+/* fd_get_cdb(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+unsigned char *fd_get_cdb(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ return req->fd_scsi_cdb;
+}
+
+/* fd_get_blocksize(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_blocksize(se_device_t *dev)
+{
+ return FD_BLOCKSIZE;
+}
+
+/* fd_get_device_rev(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_device_rev(se_device_t *dev)
+{
+ return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
+}
+
+/* fd_get_device_type(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_device_type(se_device_t *dev)
+{
+ return TYPE_DISK;
+}
+
+/* fd_get_dma_length(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_dma_length(u32 task_size, se_device_t *dev)
+{
+ return PAGE_SIZE;
+}
+
+/* fd_get_max_sectors(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_max_sectors(se_device_t *dev)
+{
+ return FD_MAX_SECTORS;
+}
+
+/* fd_get_queue_depth(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_queue_depth(se_device_t *dev)
+{
+ return FD_DEVICE_QUEUE_DEPTH;
+}
+
+u32 fd_get_max_queue_depth(se_device_t *dev)
+{
+ return FD_MAX_DEVICE_QUEUE_DEPTH;
+}
diff --git a/include/target/target_core_file.h b/include/target/target_core_file.h
new file mode 100644
index 0000000..1f299e3
--- /dev/null
+++ b/include/target/target_core_file.h
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Filename: target_core_file.h
+ *
+ * This file contains the Storage Engine <-> FILEIO transport specific
+ * definitions and prototypes.
+ *
+ * Copyright (c) 2005 PyX Technologies, Inc.
+ * Copyright (c) 2006 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2009 Rising Tide Software, Inc.
+ * Copyright (c) 2008-2009 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.
+ *
+ ******************************************************************************/
+
+
+#ifndef TARGET_CORE_FILE_H
+#define TARGET_CORE_FILE_H
+
+#define FD_VERSION "3.1"
+
+#define FD_MAX_DEV_NAME 256
+/* Maximum queuedepth for the FILEIO HBA */
+#define FD_HBA_QUEUE_DEPTH 256
+#define FD_DEVICE_QUEUE_DEPTH 32
+#define FD_MAX_DEVICE_QUEUE_DEPTH 128
+#define FD_BLOCKSIZE 512
+#define FD_MAX_SECTORS 1024
+
+#define FD_DATA_READ 1
+#define FD_DATA_WRITE 2
+#define FD_DATA_NONE 3
+
+extern se_global_t *se_global;
+extern struct block_device *__linux_blockdevice_claim(int, int, void *, int *);
+extern struct block_device *linux_blockdevice_claim(int, int, void *);
+extern int linux_blockdevice_release(int, int, struct block_device *);
+extern int linux_blockdevice_check(int, int);
+
+#ifndef FD_INCLUDE_STRUCTS
+extern int fd_CDB_inquiry(se_task_t *, u32);
+extern int fd_CDB_none(se_task_t *, u32);
+extern int fd_CDB_read_non_SG(se_task_t *, u32);
+extern int fd_CDB_read_SG(se_task_t *, u32);
+extern int fd_CDB_write_non_SG(se_task_t *, u32);
+extern int fd_CDB_write_SG(se_task_t *, u32);
+
+extern int fd_attach_hba(se_hba_t *, u32);
+extern int fd_detach_hba(se_hba_t *);
+extern int fd_claim_phydevice(se_hba_t *, se_device_t *);
+extern int fd_release_phydevice(se_device_t *);
+extern void *fd_allocate_virtdevice(se_hba_t *, const char *);
+extern se_device_t *fd_create_virtdevice(se_hba_t *, se_subsystem_dev_t *,
+ void *);
+extern int fd_activate_device(se_device_t *);
+extern void fd_deactivate_device(se_device_t *);
+extern void fd_free_device(void *);
+extern int fd_transport_complete(se_task_t *);
+extern void *fd_allocate_request(se_task_t *, se_device_t *);
+extern int fd_do_task(se_task_t *);
+extern void fd_free_task(se_task_t *);
+extern ssize_t fd_set_configfs_dev_params(se_hba_t *, se_subsystem_dev_t *,
+ const char *, ssize_t);
+extern ssize_t fd_check_configfs_dev_params(se_hba_t *, se_subsystem_dev_t *);
+extern ssize_t fd_show_configfs_dev_params(se_hba_t *, se_subsystem_dev_t *,
+ char *);
+extern void fd_get_plugin_info(void *, char *, int *);
+extern void fd_get_hba_info(se_hba_t *, char *, int *);
+extern void fd_get_dev_info(se_device_t *, char *, int *);
+extern int fd_check_lba(unsigned long long, se_device_t *);
+extern int fd_check_for_SG(se_task_t *);
+extern unsigned char *fd_get_cdb(se_task_t *);
+extern u32 fd_get_blocksize(se_device_t *);
+extern u32 fd_get_device_rev(se_device_t *);
+extern u32 fd_get_device_type(se_device_t *);
+extern u32 fd_get_dma_length(u32, se_device_t *);
+extern u32 fd_get_max_sectors(se_device_t *);
+extern u32 fd_get_queue_depth(se_device_t *);
+extern u32 fd_get_max_queue_depth(se_device_t *);
+#endif /* ! FD_INCLUDE_STRUCTS */
+
+#define RRF_EMULATE_CDB 0x01
+#define RRF_GOT_LBA 0x02
+
+typedef struct fd_request_s {
+ /* SCSI CDB from iSCSI Command PDU */
+ unsigned char fd_scsi_cdb[SCSI_CDB_SIZE];
+ /* Data Direction */
+ u8 fd_data_direction;
+ /* Total length of request */
+ u32 fd_bufflen;
+ /* RD request flags */
+ u32 fd_req_flags;
+ /* Offset from start of page */
+ u32 fd_offset;
+ u32 fd_cur_size;
+ u32 fd_cur_offset;
+ /* Scatterlist count */
+ u32 fd_sg_count;
+ /* Logical Block Address */
+ unsigned long long fd_lba;
+ u64 fd_size;
+ struct kiocb fd_iocb;
+ struct iovec *fd_iovs;
+ /* Data buffer containing scatterlists(s) or contingous
+ memory segments */
+ void *fd_buf;
+ /* FILEIO device */
+ struct fd_dev_s *fd_dev;
+} ____cacheline_aligned fd_request_t;
+
+typedef struct fd_dev_sg_table_s {
+ u32 page_start_offset;
+ u32 page_end_offset;
+ u32 fd_sg_count;
+ struct scatterlist *sg_table;
+} ____cacheline_aligned fd_dev_sg_table_t;
+
+#define FBDF_HAS_PATH 0x01
+#define FBDF_HAS_SIZE 0x02
+
+typedef struct fd_dev_s {
+ u32 fbd_flags;
+ unsigned char fd_dev_name[FD_MAX_DEV_NAME];
+ int fd_claim_bd;
+ int fd_major;
+ int fd_minor;
+ /* Unique Ramdisk Device ID in Ramdisk HBA */
+ u32 fd_dev_id;
+ /* Number of SG tables in sg_table_array */
+ u32 fd_table_count;
+ u32 fd_queue_depth;
+ unsigned long long fd_dev_size;
+ struct file *fd_file;
+ struct block_device *fd_bd;
+ /* FILEIO HBA device is connected to */
+ struct fd_host_s *fd_host;
+ /* Next FILEIO Device entry in list */
+ struct fd_dev_s *next;
+} ____cacheline_aligned fd_dev_t;
+
+extern void __fd_get_dev_info(struct fd_dev_s *, char *, int *);
+
+typedef struct fd_host_s {
+ u32 fd_host_dev_id_count;
+ /* Unique FILEIO Host ID */
+ u32 fd_host_id;
+} ____cacheline_aligned fd_host_t;
+
+#ifndef FD_INCLUDE_STRUCTS
+/*
+ * We use the generic command sequencer, so we must setup
+ * se_subsystem_spc_t.
+ */
+se_subsystem_spc_t fileio_template_spc = {
+ .inquiry = fd_CDB_inquiry,
+ .none = fd_CDB_none,
+ .read_non_SG = fd_CDB_read_non_SG,
+ .read_SG = fd_CDB_read_SG,
+ .write_non_SG = fd_CDB_write_non_SG,
+ .write_SG = fd_CDB_write_SG,
+};
+
+/*#warning FIXME v2.8: transport_type for FILEIO will need to change
+ with DIRECT_IO to blockdevs */
+
+se_subsystem_api_t fileio_template = {
+ .name = "fileio",
+ .type = FILEIO,
+ .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
+ .attach_hba = fd_attach_hba,
+ .detach_hba = fd_detach_hba,
+ .claim_phydevice = fd_claim_phydevice,
+ .release_phydevice = fd_release_phydevice,
+ .allocate_virtdevice = fd_allocate_virtdevice,
+ .create_virtdevice = fd_create_virtdevice,
+ .activate_device = fd_activate_device,
+ .deactivate_device = fd_deactivate_device,
+ .free_device = fd_free_device,
+ .transport_complete = fd_transport_complete,
+ .allocate_request = fd_allocate_request,
+ .do_task = fd_do_task,
+ .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,
+ .get_plugin_info = fd_get_plugin_info,
+ .get_hba_info = fd_get_hba_info,
+ .get_dev_info = fd_get_dev_info,
+ .check_lba = fd_check_lba,
+ .check_for_SG = fd_check_for_SG,
+ .get_cdb = fd_get_cdb,
+ .get_blocksize = fd_get_blocksize,
+ .get_device_rev = fd_get_device_rev,
+ .get_device_type = fd_get_device_type,
+ .get_dma_length = fd_get_dma_length,
+ .get_max_sectors = fd_get_max_sectors,
+ .get_queue_depth = fd_get_queue_depth,
+ .get_max_queue_depth = fd_get_max_queue_depth,
+ .write_pending = NULL,
+ .spc = &fileio_template_spc,
+};
+
+#endif /* ! FD_INCLUDE_STRUCTS */
+
+#endif /* TARGET_CORE_FILE_H */
^ permalink raw reply [flat|nested] 4+ messages in thread* [RFC PATCH 4/19] Target_Core_Mod FILEIO <-> Linux/VFS subsystem
@ 2009-04-05 4:13 Nicholas A. Bellinger
0 siblings, 0 replies; 4+ messages in thread
From: Nicholas A. Bellinger @ 2009-04-05 4:13 UTC (permalink / raw)
To: LKML, linux-scsi, Linux-fsdevel
This patch adds the buffered FILEIO subsystem plugin for accessing struct file
from upstream Linux/VFS code.
Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org>
diff --git a/drivers/target/target_core_file.c
b/drivers/target/target_core_file.c
new file mode 100644
index 0000000..c631bf5
--- /dev/null
+++ b/drivers/target/target_core_file.c
@@ -0,0 +1,1213 @@
+/*******************************************************************************
+ * 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-2009 Rising Tide Software, Inc.
+ * Copyright (c) 2008-2009 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.
+ *
+
******************************************************************************/
+
+
+#define TARGET_CORE_FILE_C
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#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/target_core_file.h>
+
+#undef TARGET_CORE_FILE_C
+
+/* fd_attach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_attach_hba(se_hba_t *hba, u32 host_id)
+{
+ fd_host_t *fd_host;
+
+ fd_host = kzalloc(sizeof(fd_host_t), GFP_KERNEL);
+ if (!(fd_host)) {
+ printk(KERN_ERR "Unable to allocate memory for fd_host_t
\n");
+ return -1;
+ }
+
+ fd_host->fd_host_id = host_id;
+
+ atomic_set(&hba->left_queue_depth, FD_HBA_QUEUE_DEPTH);
+ atomic_set(&hba->max_queue_depth, FD_HBA_QUEUE_DEPTH);
+ hba->hba_ptr = (void *) fd_host;
+ hba->transport = &fileio_template;
+
+ printk(KERN_INFO "CORE_HBA[%d] - %s FILEIO HBA Driver %s on
Generic"
+ " Target Core Stack %s\n", hba->hba_id,
+ PYX_ISCSI_VENDOR, FD_VERSION, TARGET_CORE_MOD_VERSION);
+ printk(KERN_INFO "CORE_HBA[%d] - Attached FILEIO HBA: %u to
Generic"
+ " Target Core with TCQ Depth: %d MaxSectors: %u\n",
+ hba->hba_id, fd_host->fd_host_id,
+ atomic_read(&hba->max_queue_depth), FD_MAX_SECTORS);
+
+ return 0;
+}
+
+/* fd_detach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_detach_hba(se_hba_t *hba)
+{
+ fd_host_t *fd_host;
+
+ if (!hba->hba_ptr) {
+ printk(KERN_ERR "hba->hba_ptr is NULL!\n");
+ return -1;
+ }
+ fd_host = (fd_host_t *) hba->hba_ptr;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached FILEIO HBA: %u from
Generic"
+ " Target Core\n", hba->hba_id, fd_host->fd_host_id);
+
+ kfree(fd_host);
+ hba->hba_ptr = NULL;
+
+ return 0;
+}
+
+int fd_claim_phydevice(se_hba_t *hba, se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *)dev->dev_ptr;
+ struct block_device *bd;
+
+ if (fd_dev->fd_bd)
+ return 0;
+
+ if (dev->dev_flags & DF_READ_ONLY) {
+ printk(KERN_INFO "FILEIO: Using previously claimed %p
Major"
+ ":Minor - %d:%d\n", fd_dev->fd_bd,
fd_dev->fd_major,
+ fd_dev->fd_minor);
+ } else {
+ printk(KERN_INFO "FILEIO: Claiming %p Major:Minor - %d:%
d\n",
+ fd_dev, fd_dev->fd_major, fd_dev->fd_minor);
+
+ bd = linux_blockdevice_claim(fd_dev->fd_major,
+ fd_dev->fd_minor, (void *)fd_dev);
+ if (!(bd))
+ return -1;
+
+ fd_dev->fd_bd = bd;
+ fd_dev->fd_bd->bd_contains = bd;
+ }
+
+ return 0;
+}
+
+int fd_release_phydevice(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *)dev->dev_ptr;
+
+ if (!fd_dev->fd_bd)
+ return 0;
+
+ if (dev->dev_flags & DF_READ_ONLY) {
+ printk(KERN_INFO "FILEIO: Calling blkdev_put() for
Major:Minor"
+ " - %d:%d\n", fd_dev->fd_major,
fd_dev->fd_minor);
+ blkdev_put((struct block_device *)fd_dev->fd_bd,
FMODE_READ);
+ } else {
+ printk(KERN_INFO "FILEIO: Releasing Major:Minor - %d:%d
\n",
+ fd_dev->fd_major, fd_dev->fd_minor);
+ linux_blockdevice_release(fd_dev->fd_major,
fd_dev->fd_minor,
+ (struct block_device *)fd_dev->fd_bd);
+ }
+ fd_dev->fd_bd = NULL;
+
+ return 0;
+}
+
+void *fd_allocate_virtdevice(se_hba_t *hba, const char *name)
+{
+ fd_dev_t *fd_dev;
+ fd_host_t *fd_host = (fd_host_t *) hba->hba_ptr;
+
+ fd_dev = kzalloc(sizeof(fd_dev_t), GFP_KERNEL);
+ if (!(fd_dev)) {
+ printk(KERN_ERR "Unable to allocate memory for fd_dev_t
\n");
+ return NULL;
+ }
+
+ fd_dev->fd_host = fd_host;
+
+ printk(KERN_INFO "FILEIO: Allocated fd_dev for %p\n", name);
+
+ return fd_dev;
+}
+
+/* fd_create_virtdevice(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+se_device_t *fd_create_virtdevice(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ void *p)
+{
+ char *dev_p = NULL;
+ se_device_t *dev;
+ fd_dev_t *fd_dev = (fd_dev_t *) p;
+ fd_host_t *fd_host = (fd_host_t *) hba->hba_ptr;
+ mm_segment_t old_fs;
+ struct block_device *bd = NULL;
+ struct file *file;
+ struct inode *inode = NULL;
+ struct request_queue *q;
+ unsigned long long blocks_long;
+ int dev_flags = 0, flags;
+
+ 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)) {
+ printk(KERN_ERR "getname(%s) failed: %lu\n",
+ fd_dev->fd_dev_name, IS_ERR(dev_p));
+ 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; */
+
+ file = filp_open(dev_p, flags, 0600);
+
+ if (IS_ERR(file) || !file || !file->f_dentry) {
+ printk(KERN_ERR "filp_open(%s) failed\n", dev_p);
+ goto fail;
+ }
+ fd_dev->fd_file = file;
+ /*
+ * If we are claiming a blockend for this struct file, we
extract
+ * fd_dev->fd_size from struct block_device.
+ *
+ * Otherwise, we use the passed fd_size= from configfs
+ */
+ inode = igrab(file->f_mapping->host);
+ if (!(inode)) {
+ printk(KERN_ERR "FILEIO: Unable to locate struct inode
from"
+ " struct file\n");
+ goto fail;
+ }
+ /*
+ * If struct file is referencing a underlying struct
block_device,
+ * claim it now.
+ */
+ if (S_ISBLK(inode->i_mode)) {
+ fd_dev->fd_bd = I_BDEV(file->f_mapping->host);
+ if (!(fd_dev->fd_bd)) {
+ printk(KERN_ERR "FILEIO: Unable to locate
struct"
+ " block_device\n");
+ goto fail;
+ }
+ fd_dev->fd_major = fd_dev->fd_bd->bd_disk->major;
+ fd_dev->fd_minor = fd_dev->fd_bd->bd_disk->first_minor;
+
+ printk(KERN_INFO "FILEIO: Claiming %p Major:Minor - %d:%
d\n",
+ fd_dev, fd_dev->fd_major, fd_dev->fd_minor);
+
+ bd = linux_blockdevice_claim_bd(fd_dev->fd_bd, fd_dev);
+ if (!(bd))
+ goto fail;
+
+ dev_flags |= DF_CLAIMED_BLOCKDEV;
+ if (dev_flags & DF_CLAIMED_BLOCKDEV)
+ fd_dev->fd_bd->bd_contains = bd;
+ /*
+ * Determine the number of bytes for this FILEIO device
from
+ * struct block_device's block count and block_size.
+ */
+ blocks_long = (get_capacity(bd->bd_disk) - 1);
+ q = bdev_get_queue(bd);
+ fd_dev->fd_dev_size = ((unsigned long long)blocks_long *
+ q->hardsect_size);
+ printk(KERN_INFO "FILEIO: Using size: %llu bytes from
struct"
+ " block_device blocks: %llu hardsect_size: %d
\n",
+ fd_dev->fd_dev_size, blocks_long,
+ q->hardsect_size);
+ } else {
+ if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
+ printk(KERN_ERR "FILEIO: Missing fd_dev_size="
+ " parameter, and no backing struct"
+ " block_device\n");
+ goto fail;
+ }
+ }
+ dev = transport_add_device_to_core_hba(hba, &fileio_template,
+ se_dev, dev_flags, (void *)fd_dev);
+ if (!(dev))
+ goto fail;
+
+ fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
+ fd_dev->fd_queue_depth = dev->queue_depth;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Added LIO FILEIO Device ID: %u
at %s,"
+ " %llu total bytes\n", fd_host->fd_host_id,
fd_dev->fd_dev_id,
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+
+ iput(inode);
+ putname(dev_p);
+ return dev;
+fail:
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+ fd_dev->fd_bd = NULL;
+ if (inode)
+ iput(inode);
+ putname(dev_p);
+ kfree(fd_dev);
+ return NULL;
+}
+
+/* fd_activate_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_activate_device(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+ fd_host_t *fd_host = fd_dev->fd_host;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Activating Device with TCQ: %d
at"
+ " FILEIO Device ID: %d\n", fd_host->fd_host_id,
+ fd_dev->fd_queue_depth, fd_dev->fd_dev_id);
+
+ return 0;
+}
+
+/* fd_deactivate_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_deactivate_device(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+ fd_host_t *fd_host = fd_dev->fd_host;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Deactivating Device with TCQ:
%d at"
+ " FILEIO Device ID: %d\n", fd_host->fd_host_id,
+ fd_dev->fd_queue_depth, fd_dev->fd_dev_id);
+
+ return;
+}
+
+/* fd_free_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_free_device(void *p)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) p;
+
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+
+ kfree(fd_dev);
+}
+
+/* fd_transport_complete(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_transport_complete(se_task_t *task)
+{
+ return 0;
+}
+
+/* fd_allocate_request(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void *fd_allocate_request(
+ se_task_t *task,
+ se_device_t *dev)
+{
+ fd_request_t *fd_req;
+
+ fd_req = kzalloc(sizeof(fd_request_t), GFP_KERNEL);
+ if (!(fd_req)) {
+ printk(KERN_ERR "Unable to allocate fd_request_t\n");
+ return NULL;
+ }
+
+ fd_req->fd_dev = (fd_dev_t *) dev->dev_ptr;
+
+ return (void *)fd_req;
+}
+
+/* fd_emulate_inquiry():
+ *
+ *
+ */
+int fd_emulate_inquiry(se_task_t *task)
+{
+ unsigned char prod[64], se_location[128];
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_dev_t *fdev = (fd_dev_t *) task->se_dev->dev_ptr;
+ se_hba_t *hba = task->se_dev->se_hba;
+
+ memset(prod, 0, 64);
+ memset(se_location, 0, 128);
+
+ sprintf(prod, "FILEIO");
+ sprintf(se_location, "%u_%u", hba->hba_id, fdev->fd_dev_id);
+
+ return transport_generic_emulate_inquiry(cmd, TYPE_DISK, prod,
+ FD_VERSION, se_location);
+}
+
+/* fd_emulate_read_cap():
+ *
+ *
+ */
+static int fd_emulate_read_cap(se_task_t *task)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) task->se_dev->dev_ptr;
+ u32 blocks = (fd_dev->fd_dev_size /
+ DEV_ATTRIB(task->se_dev)->block_size);
+
+ if ((fd_dev->fd_dev_size / DEV_ATTRIB(task->se_dev)->block_size)
+ >= 0x00000000ffffffff)
+ blocks = 0xffffffff;
+
+ return transport_generic_emulate_readcapacity(TASK_CMD(task),
blocks);
+}
+
+static int fd_emulate_read_cap16(se_task_t *task)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) task->se_dev->dev_ptr;
+ unsigned long long blocks_long = ((fd_dev->fd_dev_size /
+ DEV_ATTRIB(task->se_dev)->block_size)
- 1);
+
+ return transport_generic_emulate_readcapacity_16(TASK_CMD(task),
+ blocks_long);
+}
+
+/* fd_emulate_scsi_cdb():
+ *
+ *
+ */
+static int fd_emulate_scsi_cdb(se_task_t *task)
+{
+ int ret;
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_request_t *fd_req = (fd_request_t *) task->transport_req;
+
+ switch (fd_req->fd_scsi_cdb[0]) {
+ case INQUIRY:
+ if (fd_emulate_inquiry(task) < 0)
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ break;
+ case READ_CAPACITY:
+ ret = fd_emulate_read_cap(task);
+ if (ret < 0)
+ return ret;
+ break;
+ case MODE_SENSE:
+ ret =
transport_generic_emulate_modesense(TASK_CMD(task),
+ fd_req->fd_scsi_cdb, fd_req->fd_buf, 0,
+ TYPE_DISK);
+ if (ret < 0)
+ return ret;
+ break;
+ case MODE_SENSE_10:
+ ret =
transport_generic_emulate_modesense(TASK_CMD(task),
+ fd_req->fd_scsi_cdb, fd_req->fd_buf, 1,
+ TYPE_DISK);
+ if (ret < 0)
+ return ret;
+ break;
+ case SERVICE_ACTION_IN:
+ if ((T_TASK(cmd)->t_task_cdb[1] & 0x1f) !=
+ SAI_READ_CAPACITY_16) {
+ printk(KERN_ERR "Unsupported SA: 0x%02x\n",
+ T_TASK(cmd)->t_task_cdb[1] & 0x1f);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = fd_emulate_read_cap16(task);
+ if (ret < 0)
+ return ret;
+ break;
+ case REQUEST_SENSE:
+ ret = transport_generic_emulate_request_sense(cmd,
+ T_TASK(cmd)->t_task_cdb);
+ if (ret < 0)
+ return ret;
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case ERASE:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case SPACE:
+ case START_STOP:
+ case SYNCHRONIZE_CACHE:
+ case TEST_UNIT_READY:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ case RESERVE:
+ case RESERVE_10:
+ case RELEASE:
+ case RELEASE_10:
+ break;
+ default:
+ printk(KERN_ERR "Unsupported SCSI Opcode: 0x%02x for
FILEIO\n",
+ fd_req->fd_scsi_cdb[0]);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+static inline int fd_iovec_alloc(fd_request_t *req)
+{
+ req->fd_iovs = kzalloc(sizeof(struct iovec) * req->fd_sg_count,
+ GFP_KERNEL);
+ if (!(req->fd_iovs)) {
+ printk(KERN_ERR "Unable to allocate req->fd_iovs\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline int fd_seek(
+ struct file *fd,
+ unsigned long long lba,
+ u32 block_size)
+{
+ mm_segment_t old_fs;
+ unsigned long long offset;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+#if 0
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba,
block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba *
block_size));
+#endif
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fd_do_readv(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec iov[req->fd_sg_count];
+
+ memset(iov, 0, sizeof(struct iovec) + req->fd_sg_count);
+
+ if (fd_seek(fd, req->fd_lba,
DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_readv(fd, &iov[0], req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk(KERN_ERR "vfs_readv() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+
+#if 0
+
+static void fd_aio_intr(struct kiocb *kcb)
+{
+ se_task_t *task = (se_task_t *)kcb->private;
+
+ printk(KERN_INFO "Got AIO_READ Response: task: %p\n", task);
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+}
+
+static ssize_t fd_aio_retry(struct kiocb *kcb)
+{
+ printk(KERN_WARNING "fd_aio_retry() called for %p\n", kcb);
+ return 0;
+}
+
+static int fd_do_aio_read(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i, length = 0;
+ u32 block_size = DEV_ATTRIB(task->se_dev)->block_size;
+ unsigned long long offset, lba = req->fd_lba;;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ struct kiocb *iocb;
+
+ if (fd_iovec_alloc(req) < 0)
+ return -1;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba,
block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba *
block_size));
+
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+ printk(KERN_INFO "req->fd_lba: %llu\n", req->fd_lba);
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov = &req->fd_iovs[i];
+ printk(KERN_INFO "sg->length: %d sg->page: %p\n",
+ sg[i].length, sg[i].page);
+ length += sg[i].length;
+ iov->iov_len = sg[i].length;
+ iov->iov_base = sg_virt(&sg[i]);
+ printk(KERN_INFO "iov_iov_len: %d iov_iov_base: %p\n",
+ iov->iov_len, iov->iov_base);
+ }
+
+ init_sync_kiocb(&req->fd_iocb, fd);
+ req->fd_iocb.ki_opcode = IOCB_CMD_PREAD;
+ req->fd_iocb.ki_nbytes = length;
+ req->fd_iocb.private = (void *) task;
+ req->fd_iocb.ki_dtor = &fd_aio_intr;
+ req->fd_iocb.ki_retry = &fd_aio_retry;
+
+ printk(KERN_INFO "Launching AIO_READ: %p iovecs: %p total
length:"
+ " %u\n", &req->fd_iocb, &req->fd_iovs[0], length);
+ printk(KERN_INFO "fd->f_pos: %d\n", fd->f_pos);
+ printk(KERN_INFO "req->fd_iocb.ki_pos: %d\n",
req->fd_iocb.ki_pos);
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = __generic_file_aio_read(&req->fd_iocb, &req->fd_iovs[0],
+ req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ printk(KERN_INFO"__generic_file_aio_read() returned %d\n", ret);
+
+ if (ret <= 0)
+ return PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+ if (ret != length)
+ printk(KERN_ERR "ret [%d] != LENGTH [%d]\n", ret,
length);
+
+ return 1;
+}
+
+void fd_sendfile_free_DMA(se_cmd_t *cmd)
+{
+ printk(KERN_INFO "Release reference to pages now..\n");
+}
+
+static int fd_sendactor(
+ read_descriptor_t *desc,
+ struct page *page,
+ unsigned long offset,
+ unsigned long size)
+{
+ unsigned long count = desc->count;
+ se_task_t *task = desc->arg.data;
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+ struct scatterlist *sg = task->task_sg;
+
+ printk(KERN_INFO "page: %p offset: %lu size: %lu\n", page,
+ offset, size);
+
+ __free_page(sg[req->fd_cur_offset].page);
+
+ printk(KERN_INFO "page_address(page): %p\n",
page_address(page));
+ sg[req->fd_cur_offset].page = page;
+ sg[req->fd_cur_offset].offset = offset;
+ sg[req->fd_cur_offset].length = size;
+
+ printk(KERN_INFO "sg[%d:%p].page %p length: %d\n",
req->fd_cur_offset,
+ &sg[req->fd_cur_offset], sg[req->fd_cur_offset].page,
+ sg[req->fd_cur_offset].length);
+
+ req->fd_cur_size += size;
+ printk(KERN_INFO "fd_cur_size: %u\n", req->fd_cur_size);
+
+ req->fd_cur_offset++;
+
+ desc->count--;
+ desc->written += size;
+ return size;
+}
+
+static int fd_do_sendfile(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ struct file *fd = req->fd_dev->fd_file;
+
+ if (fd_seek(fd, req->fd_lba,
DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ TASK_CMD(task)->transport_free_DMA = &fd_sendfile_free_DMA;
+
+ ret = fd->f_op->sendfile(fd, &fd->f_pos, req->fd_sg_count,
+ fd_sendactor, (void *)task);
+
+ if (ret < 0) {
+ printk(KERN_ERR "fd->f_op->sendfile() returned %d\n",
ret);
+ return -1;
+ }
+
+ return 1;
+}
+#endif
+
+static int fd_do_writev(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ mm_segment_t old_fs;
+ struct iovec iov[req->fd_sg_count];
+
+ memset(iov, 0, sizeof(struct iovec) + req->fd_sg_count);
+
+ if (fd_seek(fd, req->fd_lba,
DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_writev(fd, &iov[0], req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk(KERN_ERR "vfs_writev() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+
+#if 0
+
+static int fd_do_aio_write(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i, length = 0;
+ u32 block_size = DEV_ATTRIB(task->se_dev)->block_size;
+ unsigned long long offset, lba = req->fd_lba;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ struct kiocb *iocb;
+
+ if (fd_iovec_alloc(req) < 0)
+ return -1;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba,
block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba *
block_size));
+
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov = &req->fd_iovs[i];
+ printk(KERN_INFO "sg->length: %d sg->page: %p\n",
+ sg[i].length, sg[i].page);
+
+ length += sg[i].length;
+ iov->iov_len = sg[i].length;
+ iov->iov_base = sg_virt(&sg[i]);
+ printk(KERN_INFO "iov_iov_len: %d iov_iov_base: %p\n",
+ iov->iov_len, iov->iov_base);
+ }
+
+ init_sync_kiocb(&req->fd_iocb, fd);
+ req->fd_iocb.ki_opcode = IOCB_CMD_PWRITE;
+ req->fd_iocb.ki_nbytes = length;
+ req->fd_iocb.private = (void *) task;
+ req->fd_iocb.ki_dtor = &fd_aio_intr;
+ req->fd_iocb.ki_retry = &fd_aio_retry;
+
+ printk(KERN_INFO "Launching AIO_WRITE: %p iovecs: %p total
length:"
+ " %u\n", &req->fd_iocb, &req->fd_iovs[0], length);
+ printk(KERN_INFO "fd->f_pos: %d\n", fd->f_pos);
+ printk(KERN_INFO "req->fd_iocb.ki_pos: %d\n",
req->fd_iocb.ki_pos);
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = generic_file_aio_write_nolock(&req->fd_iocb,
&req->fd_iovs[0],
+ req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "generic_file_aio_write_nolock() returned %d
\n", ret);
+
+ if (ret <= 0)
+ return PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+ if (ret != length)
+ printk(KERN_ERR "ret [%d] != WRITE LENGTH [%d]\n", ret,
length);
+
+ return 1;
+}
+#endif
+
+int fd_do_task(se_task_t *task)
+{
+ int ret = 0;
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ if (!(TASK_CMD(task)->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))
+ return fd_emulate_scsi_cdb(task);
+
+ req->fd_lba = task->task_lba;
+ req->fd_size = task->task_size;
+
+ if (req->fd_data_direction == FD_DATA_READ) {
+/* ret = fd_do_aio_read(req, task); */
+/* ret = fd_do_sendfile(req, task); */
+ ret = fd_do_readv(req, task);
+ } else {
+/* ret = fd_do_aio_write(req, task); */
+ ret = fd_do_writev(req, task);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* fd_free_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_free_task(se_task_t *task)
+{
+ fd_request_t *req;
+
+ req = (fd_request_t *) task->transport_req;
+ kfree(req->fd_iovs);
+
+ kfree(req);
+}
+
+ssize_t fd_set_configfs_dev_params(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ const char *page, ssize_t count)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+ char *buf, *cur, *ptr, *ptr2;
+ int params = 0;
+
+ buf = kzalloc(count, GFP_KERNEL);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " temporary buffer\n");
+ return 0;
+ }
+ memcpy(buf, page, count);
+ cur = buf;
+
+ while (cur) {
+ ptr = strstr(cur, "=");
+ if (!(ptr))
+ goto out;
+
+ *ptr = '\0';
+ ptr++;
+
+ ptr2 = strstr(cur, "fd_dev_name");
+ if (ptr2) {
+ transport_check_dev_params_delim(ptr, &cur);
+ ptr = strstrip(ptr);
+ snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME,
+ "%s", ptr);
+ printk(KERN_INFO "FILEIO: Referencing Path: %s
\n",
+ fd_dev->fd_dev_name);
+ fd_dev->fbd_flags |= FBDF_HAS_PATH;
+ params++;
+ continue;
+ }
+ ptr2 = strstr(cur, "fd_dev_size");
+ if (ptr2) {
+ transport_check_dev_params_delim(ptr, &cur);
+ if (strict_strtoull(ptr, 0,
&fd_dev->fd_dev_size) < 0) {
+ printk(KERN_ERR "strict_strtoull()
failed for"
+ " fd_dev_size=\n");
+ continue;
+ }
+ printk(KERN_INFO "FILEIO: Referencing Size: %
llu"
+ " bytes\n",
fd_dev->fd_dev_size);
+ fd_dev->fbd_flags |= FBDF_HAS_SIZE;
+ params++;
+ continue;
+ } else
+ cur = NULL;
+ }
+
+out:
+ kfree(buf);
+ return (params) ? count : -EINVAL;
+}
+
+ssize_t fd_check_configfs_dev_params(se_hba_t *hba, se_subsystem_dev_t
*se_dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+
+ if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) {
+ printk(KERN_ERR "Missing fd_dev_name=\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+ssize_t fd_show_configfs_dev_params(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ char *page)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+ int bl = 0;
+
+ __fd_get_dev_info(fd_dev, page, &bl);
+ return (ssize_t)bl;
+}
+
+void fd_get_plugin_info(void *p, char *b, int *bl)
+{
+ *bl += sprintf(b + *bl, "%s FILEIO Plugin %s\n",
+ PYX_ISCSI_VENDOR, FD_VERSION);
+}
+
+void fd_get_hba_info(se_hba_t *hba, char *b, int *bl)
+{
+ fd_host_t *fd_host = (fd_host_t *)hba->hba_ptr;
+
+ *bl += sprintf(b + *bl, "SE Host ID: %u FD Host ID: %u\n",
+ hba->hba_id, fd_host->fd_host_id);
+ *bl += sprintf(b + *bl, " LIO FILEIO HBA\n");
+}
+
+void fd_get_dev_info(se_device_t *dev, char *b, int *bl)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+
+ __fd_get_dev_info(fd_dev, b, bl);
+}
+
+void __fd_get_dev_info(fd_dev_t *fd_dev, char *b, int *bl)
+{
+ *bl += sprintf(b + *bl, "LIO FILEIO ID: %u", fd_dev->fd_dev_id);
+ *bl += sprintf(b + *bl, " File: %s Size: %llu ",
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+
+ if (fd_dev->fd_bd) {
+ struct block_device *bd = fd_dev->fd_bd;
+
+ *bl += sprintf(b + *bl, "%s\n",
+ (!bd->bd_contains) ? "" :
+ (bd->bd_holder == (fd_dev_t *)fd_dev) ?
+ "CLAIMED: FILEIO" : "CLAIMED:
OS");
+ } else
+ *bl += sprintf(b + *bl, "\n");
+}
+
+/* fd_map_task_non_SG():
+ *
+ *
+ */
+void fd_map_task_non_SG(se_task_t *task)
+{
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_bufflen = task->task_size;
+ req->fd_buf = (void *) T_TASK(cmd)->t_task_buf;
+ req->fd_sg_count = 0;
+}
+
+/* fd_map_task_SG():
+ *
+ *
+ */
+void fd_map_task_SG(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_bufflen = task->task_size;
+ req->fd_buf = NULL;
+ req->fd_sg_count = task->task_sg_num;
+}
+
+/* fd_CDB_inquiry():
+ *
+ *
+ */
+int fd_CDB_inquiry(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_none():
+ *
+ *
+ */
+int fd_CDB_none(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_NONE;
+ req->fd_bufflen = 0;
+ req->fd_sg_count = 0;
+ req->fd_buf = NULL;
+
+ return 0;
+}
+
+/* fd_CDB_read_non_SG():
+ *
+ *
+ */
+int fd_CDB_read_non_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_read_SG):
+ *
+ *
+ */
+int fd_CDB_read_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_SG(task);
+
+ return req->fd_sg_count;
+}
+
+/* fd_CDB_write_non_SG():
+ *
+ *
+ */
+int fd_CDB_write_non_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_WRITE;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_write_SG():
+ *
+ *
+ */
+int fd_CDB_write_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_WRITE;
+ fd_map_task_SG(task);
+
+ return req->fd_sg_count;
+}
+
+/* fd_check_lba():
+ *
+ *
+ */
+int fd_check_lba(unsigned long long lba, se_device_t *dev)
+{
+ return 0;
+}
+
+/* fd_check_for_SG(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_check_for_SG(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ return req->fd_sg_count;
+}
+
+/* fd_get_cdb(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+unsigned char *fd_get_cdb(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ return req->fd_scsi_cdb;
+}
+
+/* fd_get_blocksize(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_blocksize(se_device_t *dev)
+{
+ return FD_BLOCKSIZE;
+}
+
+/* fd_get_device_rev(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_device_rev(se_device_t *dev)
+{
+ return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
+}
+
+/* fd_get_device_type(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_device_type(se_device_t *dev)
+{
+ return TYPE_DISK;
+}
+
+/* fd_get_dma_length(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_dma_length(u32 task_size, se_device_t *dev)
+{
+ return PAGE_SIZE;
+}
+
+/* fd_get_max_sectors(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_max_sectors(se_device_t *dev)
+{
+ return FD_MAX_SECTORS;
+}
+
+/* fd_get_queue_depth(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_queue_depth(se_device_t *dev)
+{
+ return FD_DEVICE_QUEUE_DEPTH;
+}
+
+u32 fd_get_max_queue_depth(se_device_t *dev)
+{
+ return FD_MAX_DEVICE_QUEUE_DEPTH;
+}
diff --git a/include/target/target_core_file.h
b/include/target/target_core_file.h
new file mode 100644
index 0000000..0780ddb
--- /dev/null
+++ b/include/target/target_core_file.h
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Filename: target_core_file.h
+ *
+ * This file contains the Storage Engine <-> FILEIO transport specific
+ * definitions and prototypes.
+ *
+ * Copyright (c) 2005 PyX Technologies, Inc.
+ * Copyright (c) 2006 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2009 Rising Tide Software, Inc.
+ * Copyright (c) 2008-2009 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.
+ *
+
******************************************************************************/
+
+
+#ifndef TARGET_CORE_FILE_H
+#define TARGET_CORE_FILE_H
+
+#define FD_VERSION "3.0"
+
+#define FD_MAX_DEV_NAME 256
+/* Maximum queuedepth for the FILEIO HBA */
+#define FD_HBA_QUEUE_DEPTH 256
+#define FD_DEVICE_QUEUE_DEPTH 32
+#define FD_MAX_DEVICE_QUEUE_DEPTH 128
+#define FD_BLOCKSIZE 512
+#define FD_MAX_SECTORS 1024
+
+#define FD_DATA_READ 1
+#define FD_DATA_WRITE 2
+#define FD_DATA_NONE 3
+
+extern se_global_t *se_global;
+extern struct block_device *__linux_blockdevice_claim(int, int, void *,
int *);
+extern struct block_device *linux_blockdevice_claim(int, int, void *);
+extern int linux_blockdevice_release(int, int, struct block_device *);
+extern int linux_blockdevice_check(int, int);
+
+#ifndef FD_INCLUDE_STRUCTS
+extern int fd_CDB_inquiry(se_task_t *, u32);
+extern int fd_CDB_none(se_task_t *, u32);
+extern int fd_CDB_read_non_SG(se_task_t *, u32);
+extern int fd_CDB_read_SG(se_task_t *, u32);
+extern int fd_CDB_write_non_SG(se_task_t *, u32);
+extern int fd_CDB_write_SG(se_task_t *, u32);
+
+extern int fd_attach_hba(se_hba_t *, u32);
+extern int fd_detach_hba(se_hba_t *);
+extern int fd_claim_phydevice(se_hba_t *, se_device_t *);
+extern int fd_release_phydevice(se_device_t *);
+extern void *fd_allocate_virtdevice(se_hba_t *, const char *);
+extern se_device_t *fd_create_virtdevice(se_hba_t *, se_subsystem_dev_t
*,
+ void *);
+extern int fd_activate_device(se_device_t *);
+extern void fd_deactivate_device(se_device_t *);
+extern void fd_free_device(void *);
+extern int fd_transport_complete(se_task_t *);
+extern void *fd_allocate_request(se_task_t *, se_device_t *);
+extern int fd_do_task(se_task_t *);
+extern void fd_free_task(se_task_t *);
+extern ssize_t fd_set_configfs_dev_params(se_hba_t *,
se_subsystem_dev_t *,
+ const char *, ssize_t);
+extern ssize_t fd_check_configfs_dev_params(se_hba_t *,
se_subsystem_dev_t *);
+extern ssize_t fd_show_configfs_dev_params(se_hba_t *,
se_subsystem_dev_t *,
+ char *);
+extern void fd_get_plugin_info(void *, char *, int *);
+extern void fd_get_hba_info(se_hba_t *, char *, int *);
+extern void fd_get_dev_info(se_device_t *, char *, int *);
+extern int fd_check_lba(unsigned long long, se_device_t *);
+extern int fd_check_for_SG(se_task_t *);
+extern unsigned char *fd_get_cdb(se_task_t *);
+extern u32 fd_get_blocksize(se_device_t *);
+extern u32 fd_get_device_rev(se_device_t *);
+extern u32 fd_get_device_type(se_device_t *);
+extern u32 fd_get_dma_length(u32, se_device_t *);
+extern u32 fd_get_max_sectors(se_device_t *);
+extern u32 fd_get_queue_depth(se_device_t *);
+extern u32 fd_get_max_queue_depth(se_device_t *);
+#endif /* ! FD_INCLUDE_STRUCTS */
+
+#define RRF_EMULATE_CDB 0x01
+#define RRF_GOT_LBA 0x02
+
+typedef struct fd_request_s {
+ /* SCSI CDB from iSCSI Command PDU */
+ unsigned char fd_scsi_cdb[SCSI_CDB_SIZE];
+ /* Data Direction */
+ u8 fd_data_direction;
+ /* Total length of request */
+ u32 fd_bufflen;
+ /* RD request flags */
+ u32 fd_req_flags;
+ /* Offset from start of page */
+ u32 fd_offset;
+ u32 fd_cur_size;
+ u32 fd_cur_offset;
+ /* Scatterlist count */
+ u32 fd_sg_count;
+ /* Logical Block Address */
+ unsigned long long fd_lba;
+ u64 fd_size;
+ struct kiocb fd_iocb;
+ struct iovec *fd_iovs;
+ /* Data buffer containing scatterlists(s) or contingous
+ memory segments */
+ void *fd_buf;
+ /* FILEIO device */
+ struct fd_dev_s *fd_dev;
+} ____cacheline_aligned fd_request_t;
+
+typedef struct fd_dev_sg_table_s {
+ u32 page_start_offset;
+ u32 page_end_offset;
+ u32 fd_sg_count;
+ struct scatterlist *sg_table;
+} ____cacheline_aligned fd_dev_sg_table_t;
+
+#define FBDF_HAS_PATH 0x01
+#define FBDF_HAS_SIZE 0x02
+
+typedef struct fd_dev_s {
+ u32 fbd_flags;
+ unsigned char fd_dev_name[FD_MAX_DEV_NAME];
+ int fd_claim_bd;
+ int fd_major;
+ int fd_minor;
+ /* Unique Ramdisk Device ID in Ramdisk HBA */
+ u32 fd_dev_id;
+ /* Number of SG tables in sg_table_array */
+ u32 fd_table_count;
+ u32 fd_queue_depth;
+ unsigned long long fd_dev_size;
+ struct file *fd_file;
+ struct block_device *fd_bd;
+ /* FILEIO HBA device is connected to */
+ struct fd_host_s *fd_host;
+ /* Next FILEIO Device entry in list */
+ struct fd_dev_s *next;
+} ____cacheline_aligned fd_dev_t;
+
+extern void __fd_get_dev_info(struct fd_dev_s *, char *, int *);
+
+typedef struct fd_host_s {
+ u32 fd_host_dev_id_count;
+ /* Unique FILEIO Host ID */
+ u32 fd_host_id;
+} ____cacheline_aligned fd_host_t;
+
+#ifndef FD_INCLUDE_STRUCTS
+/*
+ * We use the generic command sequencer, so we must setup
+ * se_subsystem_spc_t.
+ */
+se_subsystem_spc_t fileio_template_spc = {
+ .inquiry = fd_CDB_inquiry,
+ .none = fd_CDB_none,
+ .read_non_SG = fd_CDB_read_non_SG,
+ .read_SG = fd_CDB_read_SG,
+ .write_non_SG = fd_CDB_write_non_SG,
+ .write_SG = fd_CDB_write_SG,
+};
+
+/*#warning FIXME v2.8: transport_type for FILEIO will need to change
+ with DIRECT_IO to blockdevs */
+
+se_subsystem_api_t fileio_template = {
+ .name = "fileio",
+ .type = FILEIO,
+ .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
+ .attach_hba = fd_attach_hba,
+ .detach_hba = fd_detach_hba,
+ .claim_phydevice = fd_claim_phydevice,
+ .release_phydevice = fd_release_phydevice,
+ .allocate_virtdevice = fd_allocate_virtdevice,
+ .create_virtdevice = fd_create_virtdevice,
+ .activate_device = fd_activate_device,
+ .deactivate_device = fd_deactivate_device,
+ .free_device = fd_free_device,
+ .transport_complete = fd_transport_complete,
+ .allocate_request = fd_allocate_request,
+ .do_task = fd_do_task,
+ .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,
+ .get_plugin_info = fd_get_plugin_info,
+ .get_hba_info = fd_get_hba_info,
+ .get_dev_info = fd_get_dev_info,
+ .check_lba = fd_check_lba,
+ .check_for_SG = fd_check_for_SG,
+ .get_cdb = fd_get_cdb,
+ .get_blocksize = fd_get_blocksize,
+ .get_device_rev = fd_get_device_rev,
+ .get_device_type = fd_get_device_type,
+ .get_dma_length = fd_get_dma_length,
+ .get_max_sectors = fd_get_max_sectors,
+ .get_queue_depth = fd_get_queue_depth,
+ .get_max_queue_depth = fd_get_max_queue_depth,
+ .write_pending = NULL,
+ .spc = &fileio_template_spc,
+};
+
+#endif /* ! FD_INCLUDE_STRUCTS */
+
+#endif /* TARGET_CORE_FILE_H */
^ permalink raw reply [flat|nested] 4+ messages in thread* [RFC PATCH 4/19] Target_Core_Mod FILEIO <-> Linux/VFS subsystem
@ 2009-04-05 4:01 Nicholas A. Bellinger
0 siblings, 0 replies; 4+ messages in thread
From: Nicholas A. Bellinger @ 2009-04-05 4:01 UTC (permalink / raw)
To: LKML, linux-scsi
Cc: James Bottomley, Andrew Morton, Hannes Reinecke, FUJITA Tomonori,
Mike Christie, Joel Becker, Martin K. Petersen, Ming Zhang,
Philipp Reisner, Linus Torvalds
This patch adds the buffered FILEIO subsystem plugin for accessing struct file
from upstream Linux/VFS code.
Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org>
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
new file mode 100644
index 0000000..c631bf5
--- /dev/null
+++ b/drivers/target/target_core_file.c
@@ -0,0 +1,1213 @@
+/*******************************************************************************
+ * 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-2009 Rising Tide Software, Inc.
+ * Copyright (c) 2008-2009 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.
+ *
+ ******************************************************************************/
+
+
+#define TARGET_CORE_FILE_C
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#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/target_core_file.h>
+
+#undef TARGET_CORE_FILE_C
+
+/* fd_attach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_attach_hba(se_hba_t *hba, u32 host_id)
+{
+ fd_host_t *fd_host;
+
+ fd_host = kzalloc(sizeof(fd_host_t), GFP_KERNEL);
+ if (!(fd_host)) {
+ printk(KERN_ERR "Unable to allocate memory for fd_host_t\n");
+ return -1;
+ }
+
+ fd_host->fd_host_id = host_id;
+
+ atomic_set(&hba->left_queue_depth, FD_HBA_QUEUE_DEPTH);
+ atomic_set(&hba->max_queue_depth, FD_HBA_QUEUE_DEPTH);
+ hba->hba_ptr = (void *) fd_host;
+ hba->transport = &fileio_template;
+
+ printk(KERN_INFO "CORE_HBA[%d] - %s FILEIO HBA Driver %s on Generic"
+ " Target Core Stack %s\n", hba->hba_id,
+ PYX_ISCSI_VENDOR, FD_VERSION, TARGET_CORE_MOD_VERSION);
+ printk(KERN_INFO "CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic"
+ " Target Core with TCQ Depth: %d MaxSectors: %u\n",
+ hba->hba_id, fd_host->fd_host_id,
+ atomic_read(&hba->max_queue_depth), FD_MAX_SECTORS);
+
+ return 0;
+}
+
+/* fd_detach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_detach_hba(se_hba_t *hba)
+{
+ fd_host_t *fd_host;
+
+ if (!hba->hba_ptr) {
+ printk(KERN_ERR "hba->hba_ptr is NULL!\n");
+ return -1;
+ }
+ fd_host = (fd_host_t *) hba->hba_ptr;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached FILEIO HBA: %u from Generic"
+ " Target Core\n", hba->hba_id, fd_host->fd_host_id);
+
+ kfree(fd_host);
+ hba->hba_ptr = NULL;
+
+ return 0;
+}
+
+int fd_claim_phydevice(se_hba_t *hba, se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *)dev->dev_ptr;
+ struct block_device *bd;
+
+ if (fd_dev->fd_bd)
+ return 0;
+
+ if (dev->dev_flags & DF_READ_ONLY) {
+ printk(KERN_INFO "FILEIO: Using previously claimed %p Major"
+ ":Minor - %d:%d\n", fd_dev->fd_bd, fd_dev->fd_major,
+ fd_dev->fd_minor);
+ } else {
+ printk(KERN_INFO "FILEIO: Claiming %p Major:Minor - %d:%d\n",
+ fd_dev, fd_dev->fd_major, fd_dev->fd_minor);
+
+ bd = linux_blockdevice_claim(fd_dev->fd_major,
+ fd_dev->fd_minor, (void *)fd_dev);
+ if (!(bd))
+ return -1;
+
+ fd_dev->fd_bd = bd;
+ fd_dev->fd_bd->bd_contains = bd;
+ }
+
+ return 0;
+}
+
+int fd_release_phydevice(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *)dev->dev_ptr;
+
+ if (!fd_dev->fd_bd)
+ return 0;
+
+ if (dev->dev_flags & DF_READ_ONLY) {
+ printk(KERN_INFO "FILEIO: Calling blkdev_put() for Major:Minor"
+ " - %d:%d\n", fd_dev->fd_major, fd_dev->fd_minor);
+ blkdev_put((struct block_device *)fd_dev->fd_bd, FMODE_READ);
+ } else {
+ printk(KERN_INFO "FILEIO: Releasing Major:Minor - %d:%d\n",
+ fd_dev->fd_major, fd_dev->fd_minor);
+ linux_blockdevice_release(fd_dev->fd_major, fd_dev->fd_minor,
+ (struct block_device *)fd_dev->fd_bd);
+ }
+ fd_dev->fd_bd = NULL;
+
+ return 0;
+}
+
+void *fd_allocate_virtdevice(se_hba_t *hba, const char *name)
+{
+ fd_dev_t *fd_dev;
+ fd_host_t *fd_host = (fd_host_t *) hba->hba_ptr;
+
+ fd_dev = kzalloc(sizeof(fd_dev_t), GFP_KERNEL);
+ if (!(fd_dev)) {
+ printk(KERN_ERR "Unable to allocate memory for fd_dev_t\n");
+ return NULL;
+ }
+
+ fd_dev->fd_host = fd_host;
+
+ printk(KERN_INFO "FILEIO: Allocated fd_dev for %p\n", name);
+
+ return fd_dev;
+}
+
+/* fd_create_virtdevice(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+se_device_t *fd_create_virtdevice(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ void *p)
+{
+ char *dev_p = NULL;
+ se_device_t *dev;
+ fd_dev_t *fd_dev = (fd_dev_t *) p;
+ fd_host_t *fd_host = (fd_host_t *) hba->hba_ptr;
+ mm_segment_t old_fs;
+ struct block_device *bd = NULL;
+ struct file *file;
+ struct inode *inode = NULL;
+ struct request_queue *q;
+ unsigned long long blocks_long;
+ int dev_flags = 0, flags;
+
+ 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)) {
+ printk(KERN_ERR "getname(%s) failed: %lu\n",
+ fd_dev->fd_dev_name, IS_ERR(dev_p));
+ 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; */
+
+ file = filp_open(dev_p, flags, 0600);
+
+ if (IS_ERR(file) || !file || !file->f_dentry) {
+ printk(KERN_ERR "filp_open(%s) failed\n", dev_p);
+ goto fail;
+ }
+ fd_dev->fd_file = file;
+ /*
+ * If we are claiming a blockend for this struct file, we extract
+ * fd_dev->fd_size from struct block_device.
+ *
+ * Otherwise, we use the passed fd_size= from configfs
+ */
+ inode = igrab(file->f_mapping->host);
+ if (!(inode)) {
+ printk(KERN_ERR "FILEIO: Unable to locate struct inode from"
+ " struct file\n");
+ goto fail;
+ }
+ /*
+ * If struct file is referencing a underlying struct block_device,
+ * claim it now.
+ */
+ if (S_ISBLK(inode->i_mode)) {
+ fd_dev->fd_bd = I_BDEV(file->f_mapping->host);
+ if (!(fd_dev->fd_bd)) {
+ printk(KERN_ERR "FILEIO: Unable to locate struct"
+ " block_device\n");
+ goto fail;
+ }
+ fd_dev->fd_major = fd_dev->fd_bd->bd_disk->major;
+ fd_dev->fd_minor = fd_dev->fd_bd->bd_disk->first_minor;
+
+ printk(KERN_INFO "FILEIO: Claiming %p Major:Minor - %d:%d\n",
+ fd_dev, fd_dev->fd_major, fd_dev->fd_minor);
+
+ bd = linux_blockdevice_claim_bd(fd_dev->fd_bd, fd_dev);
+ if (!(bd))
+ goto fail;
+
+ dev_flags |= DF_CLAIMED_BLOCKDEV;
+ if (dev_flags & DF_CLAIMED_BLOCKDEV)
+ fd_dev->fd_bd->bd_contains = bd;
+ /*
+ * Determine the number of bytes for this FILEIO device from
+ * struct block_device's block count and block_size.
+ */
+ blocks_long = (get_capacity(bd->bd_disk) - 1);
+ q = bdev_get_queue(bd);
+ fd_dev->fd_dev_size = ((unsigned long long)blocks_long *
+ q->hardsect_size);
+ printk(KERN_INFO "FILEIO: Using size: %llu bytes from struct"
+ " block_device blocks: %llu hardsect_size: %d\n",
+ fd_dev->fd_dev_size, blocks_long,
+ q->hardsect_size);
+ } else {
+ if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
+ printk(KERN_ERR "FILEIO: Missing fd_dev_size="
+ " parameter, and no backing struct"
+ " block_device\n");
+ goto fail;
+ }
+ }
+ dev = transport_add_device_to_core_hba(hba, &fileio_template,
+ se_dev, dev_flags, (void *)fd_dev);
+ if (!(dev))
+ goto fail;
+
+ fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
+ fd_dev->fd_queue_depth = dev->queue_depth;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Added LIO FILEIO Device ID: %u at %s,"
+ " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+
+ iput(inode);
+ putname(dev_p);
+ return dev;
+fail:
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+ fd_dev->fd_bd = NULL;
+ if (inode)
+ iput(inode);
+ putname(dev_p);
+ kfree(fd_dev);
+ return NULL;
+}
+
+/* fd_activate_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_activate_device(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+ fd_host_t *fd_host = fd_dev->fd_host;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Activating Device with TCQ: %d at"
+ " FILEIO Device ID: %d\n", fd_host->fd_host_id,
+ fd_dev->fd_queue_depth, fd_dev->fd_dev_id);
+
+ return 0;
+}
+
+/* fd_deactivate_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_deactivate_device(se_device_t *dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+ fd_host_t *fd_host = fd_dev->fd_host;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Deactivating Device with TCQ: %d at"
+ " FILEIO Device ID: %d\n", fd_host->fd_host_id,
+ fd_dev->fd_queue_depth, fd_dev->fd_dev_id);
+
+ return;
+}
+
+/* fd_free_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_free_device(void *p)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) p;
+
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+
+ kfree(fd_dev);
+}
+
+/* fd_transport_complete(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_transport_complete(se_task_t *task)
+{
+ return 0;
+}
+
+/* fd_allocate_request(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void *fd_allocate_request(
+ se_task_t *task,
+ se_device_t *dev)
+{
+ fd_request_t *fd_req;
+
+ fd_req = kzalloc(sizeof(fd_request_t), GFP_KERNEL);
+ if (!(fd_req)) {
+ printk(KERN_ERR "Unable to allocate fd_request_t\n");
+ return NULL;
+ }
+
+ fd_req->fd_dev = (fd_dev_t *) dev->dev_ptr;
+
+ return (void *)fd_req;
+}
+
+/* fd_emulate_inquiry():
+ *
+ *
+ */
+int fd_emulate_inquiry(se_task_t *task)
+{
+ unsigned char prod[64], se_location[128];
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_dev_t *fdev = (fd_dev_t *) task->se_dev->dev_ptr;
+ se_hba_t *hba = task->se_dev->se_hba;
+
+ memset(prod, 0, 64);
+ memset(se_location, 0, 128);
+
+ sprintf(prod, "FILEIO");
+ sprintf(se_location, "%u_%u", hba->hba_id, fdev->fd_dev_id);
+
+ return transport_generic_emulate_inquiry(cmd, TYPE_DISK, prod,
+ FD_VERSION, se_location);
+}
+
+/* fd_emulate_read_cap():
+ *
+ *
+ */
+static int fd_emulate_read_cap(se_task_t *task)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) task->se_dev->dev_ptr;
+ u32 blocks = (fd_dev->fd_dev_size /
+ DEV_ATTRIB(task->se_dev)->block_size);
+
+ if ((fd_dev->fd_dev_size / DEV_ATTRIB(task->se_dev)->block_size)
+ >= 0x00000000ffffffff)
+ blocks = 0xffffffff;
+
+ return transport_generic_emulate_readcapacity(TASK_CMD(task), blocks);
+}
+
+static int fd_emulate_read_cap16(se_task_t *task)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) task->se_dev->dev_ptr;
+ unsigned long long blocks_long = ((fd_dev->fd_dev_size /
+ DEV_ATTRIB(task->se_dev)->block_size) - 1);
+
+ return transport_generic_emulate_readcapacity_16(TASK_CMD(task),
+ blocks_long);
+}
+
+/* fd_emulate_scsi_cdb():
+ *
+ *
+ */
+static int fd_emulate_scsi_cdb(se_task_t *task)
+{
+ int ret;
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_request_t *fd_req = (fd_request_t *) task->transport_req;
+
+ switch (fd_req->fd_scsi_cdb[0]) {
+ case INQUIRY:
+ if (fd_emulate_inquiry(task) < 0)
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ break;
+ case READ_CAPACITY:
+ ret = fd_emulate_read_cap(task);
+ if (ret < 0)
+ return ret;
+ break;
+ case MODE_SENSE:
+ ret = transport_generic_emulate_modesense(TASK_CMD(task),
+ fd_req->fd_scsi_cdb, fd_req->fd_buf, 0,
+ TYPE_DISK);
+ if (ret < 0)
+ return ret;
+ break;
+ case MODE_SENSE_10:
+ ret = transport_generic_emulate_modesense(TASK_CMD(task),
+ fd_req->fd_scsi_cdb, fd_req->fd_buf, 1,
+ TYPE_DISK);
+ if (ret < 0)
+ return ret;
+ break;
+ case SERVICE_ACTION_IN:
+ if ((T_TASK(cmd)->t_task_cdb[1] & 0x1f) !=
+ SAI_READ_CAPACITY_16) {
+ printk(KERN_ERR "Unsupported SA: 0x%02x\n",
+ T_TASK(cmd)->t_task_cdb[1] & 0x1f);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = fd_emulate_read_cap16(task);
+ if (ret < 0)
+ return ret;
+ break;
+ case REQUEST_SENSE:
+ ret = transport_generic_emulate_request_sense(cmd,
+ T_TASK(cmd)->t_task_cdb);
+ if (ret < 0)
+ return ret;
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case ERASE:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case SPACE:
+ case START_STOP:
+ case SYNCHRONIZE_CACHE:
+ case TEST_UNIT_READY:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ case RESERVE:
+ case RESERVE_10:
+ case RELEASE:
+ case RELEASE_10:
+ break;
+ default:
+ printk(KERN_ERR "Unsupported SCSI Opcode: 0x%02x for FILEIO\n",
+ fd_req->fd_scsi_cdb[0]);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+static inline int fd_iovec_alloc(fd_request_t *req)
+{
+ req->fd_iovs = kzalloc(sizeof(struct iovec) * req->fd_sg_count,
+ GFP_KERNEL);
+ if (!(req->fd_iovs)) {
+ printk(KERN_ERR "Unable to allocate req->fd_iovs\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline int fd_seek(
+ struct file *fd,
+ unsigned long long lba,
+ u32 block_size)
+{
+ mm_segment_t old_fs;
+ unsigned long long offset;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+#if 0
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba, block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba * block_size));
+#endif
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fd_do_readv(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec iov[req->fd_sg_count];
+
+ memset(iov, 0, sizeof(struct iovec) + req->fd_sg_count);
+
+ if (fd_seek(fd, req->fd_lba, DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_readv(fd, &iov[0], req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk(KERN_ERR "vfs_readv() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+
+#if 0
+
+static void fd_aio_intr(struct kiocb *kcb)
+{
+ se_task_t *task = (se_task_t *)kcb->private;
+
+ printk(KERN_INFO "Got AIO_READ Response: task: %p\n", task);
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+}
+
+static ssize_t fd_aio_retry(struct kiocb *kcb)
+{
+ printk(KERN_WARNING "fd_aio_retry() called for %p\n", kcb);
+ return 0;
+}
+
+static int fd_do_aio_read(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i, length = 0;
+ u32 block_size = DEV_ATTRIB(task->se_dev)->block_size;
+ unsigned long long offset, lba = req->fd_lba;;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ struct kiocb *iocb;
+
+ if (fd_iovec_alloc(req) < 0)
+ return -1;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba, block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba * block_size));
+
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+ printk(KERN_INFO "req->fd_lba: %llu\n", req->fd_lba);
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov = &req->fd_iovs[i];
+ printk(KERN_INFO "sg->length: %d sg->page: %p\n",
+ sg[i].length, sg[i].page);
+ length += sg[i].length;
+ iov->iov_len = sg[i].length;
+ iov->iov_base = sg_virt(&sg[i]);
+ printk(KERN_INFO "iov_iov_len: %d iov_iov_base: %p\n",
+ iov->iov_len, iov->iov_base);
+ }
+
+ init_sync_kiocb(&req->fd_iocb, fd);
+ req->fd_iocb.ki_opcode = IOCB_CMD_PREAD;
+ req->fd_iocb.ki_nbytes = length;
+ req->fd_iocb.private = (void *) task;
+ req->fd_iocb.ki_dtor = &fd_aio_intr;
+ req->fd_iocb.ki_retry = &fd_aio_retry;
+
+ printk(KERN_INFO "Launching AIO_READ: %p iovecs: %p total length:"
+ " %u\n", &req->fd_iocb, &req->fd_iovs[0], length);
+ printk(KERN_INFO "fd->f_pos: %d\n", fd->f_pos);
+ printk(KERN_INFO "req->fd_iocb.ki_pos: %d\n", req->fd_iocb.ki_pos);
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = __generic_file_aio_read(&req->fd_iocb, &req->fd_iovs[0],
+ req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ printk(KERN_INFO"__generic_file_aio_read() returned %d\n", ret);
+
+ if (ret <= 0)
+ return PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+ if (ret != length)
+ printk(KERN_ERR "ret [%d] != LENGTH [%d]\n", ret, length);
+
+ return 1;
+}
+
+void fd_sendfile_free_DMA(se_cmd_t *cmd)
+{
+ printk(KERN_INFO "Release reference to pages now..\n");
+}
+
+static int fd_sendactor(
+ read_descriptor_t *desc,
+ struct page *page,
+ unsigned long offset,
+ unsigned long size)
+{
+ unsigned long count = desc->count;
+ se_task_t *task = desc->arg.data;
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+ struct scatterlist *sg = task->task_sg;
+
+ printk(KERN_INFO "page: %p offset: %lu size: %lu\n", page,
+ offset, size);
+
+ __free_page(sg[req->fd_cur_offset].page);
+
+ printk(KERN_INFO "page_address(page): %p\n", page_address(page));
+ sg[req->fd_cur_offset].page = page;
+ sg[req->fd_cur_offset].offset = offset;
+ sg[req->fd_cur_offset].length = size;
+
+ printk(KERN_INFO "sg[%d:%p].page %p length: %d\n", req->fd_cur_offset,
+ &sg[req->fd_cur_offset], sg[req->fd_cur_offset].page,
+ sg[req->fd_cur_offset].length);
+
+ req->fd_cur_size += size;
+ printk(KERN_INFO "fd_cur_size: %u\n", req->fd_cur_size);
+
+ req->fd_cur_offset++;
+
+ desc->count--;
+ desc->written += size;
+ return size;
+}
+
+static int fd_do_sendfile(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ struct file *fd = req->fd_dev->fd_file;
+
+ if (fd_seek(fd, req->fd_lba, DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ TASK_CMD(task)->transport_free_DMA = &fd_sendfile_free_DMA;
+
+ ret = fd->f_op->sendfile(fd, &fd->f_pos, req->fd_sg_count,
+ fd_sendactor, (void *)task);
+
+ if (ret < 0) {
+ printk(KERN_ERR "fd->f_op->sendfile() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+#endif
+
+static int fd_do_writev(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ mm_segment_t old_fs;
+ struct iovec iov[req->fd_sg_count];
+
+ memset(iov, 0, sizeof(struct iovec) + req->fd_sg_count);
+
+ if (fd_seek(fd, req->fd_lba, DEV_ATTRIB(task->se_dev)->block_size) < 0)
+ return -1;
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_writev(fd, &iov[0], req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk(KERN_ERR "vfs_writev() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+
+#if 0
+
+static int fd_do_aio_write(fd_request_t *req, se_task_t *task)
+{
+ int ret = 0;
+ u32 i, length = 0;
+ u32 block_size = DEV_ATTRIB(task->se_dev)->block_size;
+ unsigned long long offset, lba = req->fd_lba;
+ mm_segment_t old_fs;
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ struct kiocb *iocb;
+
+ if (fd_iovec_alloc(req) < 0)
+ return -1;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if (fd->f_op->llseek)
+ offset = fd->f_op->llseek(fd, lba * block_size, 0);
+ else
+ offset = default_llseek(fd, lba * block_size, 0);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "lba: %llu : block_size: %d\n", lba, block_size);
+ printk(KERN_INFO "offset from llseek: %llu\n", offset);
+ printk(KERN_INFO "(lba * block_size): %llu\n", (lba * block_size));
+
+ if (offset != (lba * block_size)) {
+ printk(KERN_ERR "offset: %llu not equal to LBA: %llu\n",
+ offset, (lba * block_size));
+ return -1;
+ }
+
+ for (i = 0; i < req->fd_sg_count; i++) {
+ iov = &req->fd_iovs[i];
+ printk(KERN_INFO "sg->length: %d sg->page: %p\n",
+ sg[i].length, sg[i].page);
+
+ length += sg[i].length;
+ iov->iov_len = sg[i].length;
+ iov->iov_base = sg_virt(&sg[i]);
+ printk(KERN_INFO "iov_iov_len: %d iov_iov_base: %p\n",
+ iov->iov_len, iov->iov_base);
+ }
+
+ init_sync_kiocb(&req->fd_iocb, fd);
+ req->fd_iocb.ki_opcode = IOCB_CMD_PWRITE;
+ req->fd_iocb.ki_nbytes = length;
+ req->fd_iocb.private = (void *) task;
+ req->fd_iocb.ki_dtor = &fd_aio_intr;
+ req->fd_iocb.ki_retry = &fd_aio_retry;
+
+ printk(KERN_INFO "Launching AIO_WRITE: %p iovecs: %p total length:"
+ " %u\n", &req->fd_iocb, &req->fd_iovs[0], length);
+ printk(KERN_INFO "fd->f_pos: %d\n", fd->f_pos);
+ printk(KERN_INFO "req->fd_iocb.ki_pos: %d\n", req->fd_iocb.ki_pos);
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = generic_file_aio_write_nolock(&req->fd_iocb, &req->fd_iovs[0],
+ req->fd_sg_count, &fd->f_pos);
+ set_fs(old_fs);
+
+ printk(KERN_INFO "generic_file_aio_write_nolock() returned %d\n", ret);
+
+ if (ret <= 0)
+ return PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+ if (ret != length)
+ printk(KERN_ERR "ret [%d] != WRITE LENGTH [%d]\n", ret, length);
+
+ return 1;
+}
+#endif
+
+int fd_do_task(se_task_t *task)
+{
+ int ret = 0;
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ if (!(TASK_CMD(task)->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))
+ return fd_emulate_scsi_cdb(task);
+
+ req->fd_lba = task->task_lba;
+ req->fd_size = task->task_size;
+
+ if (req->fd_data_direction == FD_DATA_READ) {
+/* ret = fd_do_aio_read(req, task); */
+/* ret = fd_do_sendfile(req, task); */
+ ret = fd_do_readv(req, task);
+ } else {
+/* ret = fd_do_aio_write(req, task); */
+ ret = fd_do_writev(req, task);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* fd_free_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+void fd_free_task(se_task_t *task)
+{
+ fd_request_t *req;
+
+ req = (fd_request_t *) task->transport_req;
+ kfree(req->fd_iovs);
+
+ kfree(req);
+}
+
+ssize_t fd_set_configfs_dev_params(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ const char *page, ssize_t count)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+ char *buf, *cur, *ptr, *ptr2;
+ int params = 0;
+
+ buf = kzalloc(count, GFP_KERNEL);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " temporary buffer\n");
+ return 0;
+ }
+ memcpy(buf, page, count);
+ cur = buf;
+
+ while (cur) {
+ ptr = strstr(cur, "=");
+ if (!(ptr))
+ goto out;
+
+ *ptr = '\0';
+ ptr++;
+
+ ptr2 = strstr(cur, "fd_dev_name");
+ if (ptr2) {
+ transport_check_dev_params_delim(ptr, &cur);
+ ptr = strstrip(ptr);
+ snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME,
+ "%s", ptr);
+ printk(KERN_INFO "FILEIO: Referencing Path: %s\n",
+ fd_dev->fd_dev_name);
+ fd_dev->fbd_flags |= FBDF_HAS_PATH;
+ params++;
+ continue;
+ }
+ ptr2 = strstr(cur, "fd_dev_size");
+ if (ptr2) {
+ transport_check_dev_params_delim(ptr, &cur);
+ if (strict_strtoull(ptr, 0, &fd_dev->fd_dev_size) < 0) {
+ printk(KERN_ERR "strict_strtoull() failed for"
+ " fd_dev_size=\n");
+ continue;
+ }
+ printk(KERN_INFO "FILEIO: Referencing Size: %llu"
+ " bytes\n", fd_dev->fd_dev_size);
+ fd_dev->fbd_flags |= FBDF_HAS_SIZE;
+ params++;
+ continue;
+ } else
+ cur = NULL;
+ }
+
+out:
+ kfree(buf);
+ return (params) ? count : -EINVAL;
+}
+
+ssize_t fd_check_configfs_dev_params(se_hba_t *hba, se_subsystem_dev_t *se_dev)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+
+ if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) {
+ printk(KERN_ERR "Missing fd_dev_name=\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+ssize_t fd_show_configfs_dev_params(
+ se_hba_t *hba,
+ se_subsystem_dev_t *se_dev,
+ char *page)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) se_dev->se_dev_su_ptr;
+ int bl = 0;
+
+ __fd_get_dev_info(fd_dev, page, &bl);
+ return (ssize_t)bl;
+}
+
+void fd_get_plugin_info(void *p, char *b, int *bl)
+{
+ *bl += sprintf(b + *bl, "%s FILEIO Plugin %s\n",
+ PYX_ISCSI_VENDOR, FD_VERSION);
+}
+
+void fd_get_hba_info(se_hba_t *hba, char *b, int *bl)
+{
+ fd_host_t *fd_host = (fd_host_t *)hba->hba_ptr;
+
+ *bl += sprintf(b + *bl, "SE Host ID: %u FD Host ID: %u\n",
+ hba->hba_id, fd_host->fd_host_id);
+ *bl += sprintf(b + *bl, " LIO FILEIO HBA\n");
+}
+
+void fd_get_dev_info(se_device_t *dev, char *b, int *bl)
+{
+ fd_dev_t *fd_dev = (fd_dev_t *) dev->dev_ptr;
+
+ __fd_get_dev_info(fd_dev, b, bl);
+}
+
+void __fd_get_dev_info(fd_dev_t *fd_dev, char *b, int *bl)
+{
+ *bl += sprintf(b + *bl, "LIO FILEIO ID: %u", fd_dev->fd_dev_id);
+ *bl += sprintf(b + *bl, " File: %s Size: %llu ",
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+
+ if (fd_dev->fd_bd) {
+ struct block_device *bd = fd_dev->fd_bd;
+
+ *bl += sprintf(b + *bl, "%s\n",
+ (!bd->bd_contains) ? "" :
+ (bd->bd_holder == (fd_dev_t *)fd_dev) ?
+ "CLAIMED: FILEIO" : "CLAIMED: OS");
+ } else
+ *bl += sprintf(b + *bl, "\n");
+}
+
+/* fd_map_task_non_SG():
+ *
+ *
+ */
+void fd_map_task_non_SG(se_task_t *task)
+{
+ se_cmd_t *cmd = TASK_CMD(task);
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_bufflen = task->task_size;
+ req->fd_buf = (void *) T_TASK(cmd)->t_task_buf;
+ req->fd_sg_count = 0;
+}
+
+/* fd_map_task_SG():
+ *
+ *
+ */
+void fd_map_task_SG(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_bufflen = task->task_size;
+ req->fd_buf = NULL;
+ req->fd_sg_count = task->task_sg_num;
+}
+
+/* fd_CDB_inquiry():
+ *
+ *
+ */
+int fd_CDB_inquiry(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_none():
+ *
+ *
+ */
+int fd_CDB_none(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_NONE;
+ req->fd_bufflen = 0;
+ req->fd_sg_count = 0;
+ req->fd_buf = NULL;
+
+ return 0;
+}
+
+/* fd_CDB_read_non_SG():
+ *
+ *
+ */
+int fd_CDB_read_non_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_read_SG):
+ *
+ *
+ */
+int fd_CDB_read_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_READ;
+ fd_map_task_SG(task);
+
+ return req->fd_sg_count;
+}
+
+/* fd_CDB_write_non_SG():
+ *
+ *
+ */
+int fd_CDB_write_non_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_WRITE;
+ fd_map_task_non_SG(task);
+
+ return 0;
+}
+
+/* fd_CDB_write_SG():
+ *
+ *
+ */
+int fd_CDB_write_SG(se_task_t *task, u32 size)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ req->fd_data_direction = FD_DATA_WRITE;
+ fd_map_task_SG(task);
+
+ return req->fd_sg_count;
+}
+
+/* fd_check_lba():
+ *
+ *
+ */
+int fd_check_lba(unsigned long long lba, se_device_t *dev)
+{
+ return 0;
+}
+
+/* fd_check_for_SG(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+int fd_check_for_SG(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ return req->fd_sg_count;
+}
+
+/* fd_get_cdb(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+unsigned char *fd_get_cdb(se_task_t *task)
+{
+ fd_request_t *req = (fd_request_t *) task->transport_req;
+
+ return req->fd_scsi_cdb;
+}
+
+/* fd_get_blocksize(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_blocksize(se_device_t *dev)
+{
+ return FD_BLOCKSIZE;
+}
+
+/* fd_get_device_rev(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_device_rev(se_device_t *dev)
+{
+ return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
+}
+
+/* fd_get_device_type(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_device_type(se_device_t *dev)
+{
+ return TYPE_DISK;
+}
+
+/* fd_get_dma_length(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_dma_length(u32 task_size, se_device_t *dev)
+{
+ return PAGE_SIZE;
+}
+
+/* fd_get_max_sectors(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_max_sectors(se_device_t *dev)
+{
+ return FD_MAX_SECTORS;
+}
+
+/* fd_get_queue_depth(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+u32 fd_get_queue_depth(se_device_t *dev)
+{
+ return FD_DEVICE_QUEUE_DEPTH;
+}
+
+u32 fd_get_max_queue_depth(se_device_t *dev)
+{
+ return FD_MAX_DEVICE_QUEUE_DEPTH;
+}
diff --git a/include/target/target_core_file.h b/include/target/target_core_file.h
new file mode 100644
index 0000000..0780ddb
--- /dev/null
+++ b/include/target/target_core_file.h
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Filename: target_core_file.h
+ *
+ * This file contains the Storage Engine <-> FILEIO transport specific
+ * definitions and prototypes.
+ *
+ * Copyright (c) 2005 PyX Technologies, Inc.
+ * Copyright (c) 2006 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2009 Rising Tide Software, Inc.
+ * Copyright (c) 2008-2009 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.
+ *
+ ******************************************************************************/
+
+
+#ifndef TARGET_CORE_FILE_H
+#define TARGET_CORE_FILE_H
+
+#define FD_VERSION "3.0"
+
+#define FD_MAX_DEV_NAME 256
+/* Maximum queuedepth for the FILEIO HBA */
+#define FD_HBA_QUEUE_DEPTH 256
+#define FD_DEVICE_QUEUE_DEPTH 32
+#define FD_MAX_DEVICE_QUEUE_DEPTH 128
+#define FD_BLOCKSIZE 512
+#define FD_MAX_SECTORS 1024
+
+#define FD_DATA_READ 1
+#define FD_DATA_WRITE 2
+#define FD_DATA_NONE 3
+
+extern se_global_t *se_global;
+extern struct block_device *__linux_blockdevice_claim(int, int, void *, int *);
+extern struct block_device *linux_blockdevice_claim(int, int, void *);
+extern int linux_blockdevice_release(int, int, struct block_device *);
+extern int linux_blockdevice_check(int, int);
+
+#ifndef FD_INCLUDE_STRUCTS
+extern int fd_CDB_inquiry(se_task_t *, u32);
+extern int fd_CDB_none(se_task_t *, u32);
+extern int fd_CDB_read_non_SG(se_task_t *, u32);
+extern int fd_CDB_read_SG(se_task_t *, u32);
+extern int fd_CDB_write_non_SG(se_task_t *, u32);
+extern int fd_CDB_write_SG(se_task_t *, u32);
+
+extern int fd_attach_hba(se_hba_t *, u32);
+extern int fd_detach_hba(se_hba_t *);
+extern int fd_claim_phydevice(se_hba_t *, se_device_t *);
+extern int fd_release_phydevice(se_device_t *);
+extern void *fd_allocate_virtdevice(se_hba_t *, const char *);
+extern se_device_t *fd_create_virtdevice(se_hba_t *, se_subsystem_dev_t *,
+ void *);
+extern int fd_activate_device(se_device_t *);
+extern void fd_deactivate_device(se_device_t *);
+extern void fd_free_device(void *);
+extern int fd_transport_complete(se_task_t *);
+extern void *fd_allocate_request(se_task_t *, se_device_t *);
+extern int fd_do_task(se_task_t *);
+extern void fd_free_task(se_task_t *);
+extern ssize_t fd_set_configfs_dev_params(se_hba_t *, se_subsystem_dev_t *,
+ const char *, ssize_t);
+extern ssize_t fd_check_configfs_dev_params(se_hba_t *, se_subsystem_dev_t *);
+extern ssize_t fd_show_configfs_dev_params(se_hba_t *, se_subsystem_dev_t *,
+ char *);
+extern void fd_get_plugin_info(void *, char *, int *);
+extern void fd_get_hba_info(se_hba_t *, char *, int *);
+extern void fd_get_dev_info(se_device_t *, char *, int *);
+extern int fd_check_lba(unsigned long long, se_device_t *);
+extern int fd_check_for_SG(se_task_t *);
+extern unsigned char *fd_get_cdb(se_task_t *);
+extern u32 fd_get_blocksize(se_device_t *);
+extern u32 fd_get_device_rev(se_device_t *);
+extern u32 fd_get_device_type(se_device_t *);
+extern u32 fd_get_dma_length(u32, se_device_t *);
+extern u32 fd_get_max_sectors(se_device_t *);
+extern u32 fd_get_queue_depth(se_device_t *);
+extern u32 fd_get_max_queue_depth(se_device_t *);
+#endif /* ! FD_INCLUDE_STRUCTS */
+
+#define RRF_EMULATE_CDB 0x01
+#define RRF_GOT_LBA 0x02
+
+typedef struct fd_request_s {
+ /* SCSI CDB from iSCSI Command PDU */
+ unsigned char fd_scsi_cdb[SCSI_CDB_SIZE];
+ /* Data Direction */
+ u8 fd_data_direction;
+ /* Total length of request */
+ u32 fd_bufflen;
+ /* RD request flags */
+ u32 fd_req_flags;
+ /* Offset from start of page */
+ u32 fd_offset;
+ u32 fd_cur_size;
+ u32 fd_cur_offset;
+ /* Scatterlist count */
+ u32 fd_sg_count;
+ /* Logical Block Address */
+ unsigned long long fd_lba;
+ u64 fd_size;
+ struct kiocb fd_iocb;
+ struct iovec *fd_iovs;
+ /* Data buffer containing scatterlists(s) or contingous
+ memory segments */
+ void *fd_buf;
+ /* FILEIO device */
+ struct fd_dev_s *fd_dev;
+} ____cacheline_aligned fd_request_t;
+
+typedef struct fd_dev_sg_table_s {
+ u32 page_start_offset;
+ u32 page_end_offset;
+ u32 fd_sg_count;
+ struct scatterlist *sg_table;
+} ____cacheline_aligned fd_dev_sg_table_t;
+
+#define FBDF_HAS_PATH 0x01
+#define FBDF_HAS_SIZE 0x02
+
+typedef struct fd_dev_s {
+ u32 fbd_flags;
+ unsigned char fd_dev_name[FD_MAX_DEV_NAME];
+ int fd_claim_bd;
+ int fd_major;
+ int fd_minor;
+ /* Unique Ramdisk Device ID in Ramdisk HBA */
+ u32 fd_dev_id;
+ /* Number of SG tables in sg_table_array */
+ u32 fd_table_count;
+ u32 fd_queue_depth;
+ unsigned long long fd_dev_size;
+ struct file *fd_file;
+ struct block_device *fd_bd;
+ /* FILEIO HBA device is connected to */
+ struct fd_host_s *fd_host;
+ /* Next FILEIO Device entry in list */
+ struct fd_dev_s *next;
+} ____cacheline_aligned fd_dev_t;
+
+extern void __fd_get_dev_info(struct fd_dev_s *, char *, int *);
+
+typedef struct fd_host_s {
+ u32 fd_host_dev_id_count;
+ /* Unique FILEIO Host ID */
+ u32 fd_host_id;
+} ____cacheline_aligned fd_host_t;
+
+#ifndef FD_INCLUDE_STRUCTS
+/*
+ * We use the generic command sequencer, so we must setup
+ * se_subsystem_spc_t.
+ */
+se_subsystem_spc_t fileio_template_spc = {
+ .inquiry = fd_CDB_inquiry,
+ .none = fd_CDB_none,
+ .read_non_SG = fd_CDB_read_non_SG,
+ .read_SG = fd_CDB_read_SG,
+ .write_non_SG = fd_CDB_write_non_SG,
+ .write_SG = fd_CDB_write_SG,
+};
+
+/*#warning FIXME v2.8: transport_type for FILEIO will need to change
+ with DIRECT_IO to blockdevs */
+
+se_subsystem_api_t fileio_template = {
+ .name = "fileio",
+ .type = FILEIO,
+ .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
+ .attach_hba = fd_attach_hba,
+ .detach_hba = fd_detach_hba,
+ .claim_phydevice = fd_claim_phydevice,
+ .release_phydevice = fd_release_phydevice,
+ .allocate_virtdevice = fd_allocate_virtdevice,
+ .create_virtdevice = fd_create_virtdevice,
+ .activate_device = fd_activate_device,
+ .deactivate_device = fd_deactivate_device,
+ .free_device = fd_free_device,
+ .transport_complete = fd_transport_complete,
+ .allocate_request = fd_allocate_request,
+ .do_task = fd_do_task,
+ .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,
+ .get_plugin_info = fd_get_plugin_info,
+ .get_hba_info = fd_get_hba_info,
+ .get_dev_info = fd_get_dev_info,
+ .check_lba = fd_check_lba,
+ .check_for_SG = fd_check_for_SG,
+ .get_cdb = fd_get_cdb,
+ .get_blocksize = fd_get_blocksize,
+ .get_device_rev = fd_get_device_rev,
+ .get_device_type = fd_get_device_type,
+ .get_dma_length = fd_get_dma_length,
+ .get_max_sectors = fd_get_max_sectors,
+ .get_queue_depth = fd_get_queue_depth,
+ .get_max_queue_depth = fd_get_max_queue_depth,
+ .write_pending = NULL,
+ .spc = &fileio_template_spc,
+};
+
+#endif /* ! FD_INCLUDE_STRUCTS */
+
+#endif /* TARGET_CORE_FILE_H */
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2009-09-18 22:11 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-09-12 1:55 [RFC PATCH 4/19] Target_Core_Mod FILEIO <-> Linux/VFS subsystem Nicholas A. Bellinger
-- strict thread matches above, loose matches on Subject: below --
2009-09-18 22:08 Nicholas A. Bellinger
2009-04-05 4:13 Nicholas A. Bellinger
2009-04-05 4:01 Nicholas A. Bellinger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®