diff options
Diffstat (limited to 'drivers/target/target_core_file.c')
| -rw-r--r-- | drivers/target/target_core_file.c | 228 | 
1 files changed, 222 insertions, 6 deletions
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index b662f89deda..7d6cddaec52 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -66,9 +66,8 @@ static int fd_attach_hba(struct se_hba *hba, u32 host_id)  	pr_debug("CORE_HBA[%d] - TCM FILEIO HBA Driver %s on Generic"  		" Target Core Stack %s\n", hba->hba_id, FD_VERSION,  		TARGET_CORE_MOD_VERSION); -	pr_debug("CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic" -		" MaxSectors: %u\n", -		hba->hba_id, fd_host->fd_host_id, FD_MAX_SECTORS); +	pr_debug("CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic\n", +		hba->hba_id, fd_host->fd_host_id);  	return 0;  } @@ -220,7 +219,8 @@ static int fd_configure_device(struct se_device *dev)  	}  	dev->dev_attrib.hw_block_size = fd_dev->fd_block_size; -	dev->dev_attrib.hw_max_sectors = FD_MAX_SECTORS; +	dev->dev_attrib.max_bytes_per_io = FD_MAX_BYTES; +	dev->dev_attrib.hw_max_sectors = FD_MAX_BYTES / fd_dev->fd_block_size;  	dev->dev_attrib.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH;  	if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) { @@ -257,6 +257,72 @@ static void fd_free_device(struct se_device *dev)  	kfree(fd_dev);  } +static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot, +			 int is_write) +{ +	struct se_device *se_dev = cmd->se_dev; +	struct fd_dev *dev = FD_DEV(se_dev); +	struct file *prot_fd = dev->fd_prot_file; +	struct scatterlist *sg; +	loff_t pos = (cmd->t_task_lba * se_dev->prot_length); +	unsigned char *buf; +	u32 prot_size, len, size; +	int rc, ret = 1, i; + +	prot_size = (cmd->data_length / se_dev->dev_attrib.block_size) * +		     se_dev->prot_length; + +	if (!is_write) { +		fd_prot->prot_buf = vzalloc(prot_size); +		if (!fd_prot->prot_buf) { +			pr_err("Unable to allocate fd_prot->prot_buf\n"); +			return -ENOMEM; +		} +		buf = fd_prot->prot_buf; + +		fd_prot->prot_sg_nents = cmd->t_prot_nents; +		fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist) * +					   fd_prot->prot_sg_nents, GFP_KERNEL); +		if (!fd_prot->prot_sg) { +			pr_err("Unable to allocate fd_prot->prot_sg\n"); +			vfree(fd_prot->prot_buf); +			return -ENOMEM; +		} +		size = prot_size; + +		for_each_sg(fd_prot->prot_sg, sg, fd_prot->prot_sg_nents, i) { + +			len = min_t(u32, PAGE_SIZE, size); +			sg_set_buf(sg, buf, len); +			size -= len; +			buf += len; +		} +	} + +	if (is_write) { +		rc = kernel_write(prot_fd, fd_prot->prot_buf, prot_size, pos); +		if (rc < 0 || prot_size != rc) { +			pr_err("kernel_write() for fd_do_prot_rw failed:" +			       " %d\n", rc); +			ret = -EINVAL; +		} +	} else { +		rc = kernel_read(prot_fd, pos, fd_prot->prot_buf, prot_size); +		if (rc < 0) { +			pr_err("kernel_read() for fd_do_prot_rw failed:" +			       " %d\n", rc); +			ret = -EINVAL; +		} +	} + +	if (is_write || ret < 0) { +		kfree(fd_prot->prot_sg); +		vfree(fd_prot->prot_buf); +	} + +	return ret; +} +  static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl,  		u32 sgl_nents, int is_write)  { @@ -551,6 +617,8 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,  	      enum dma_data_direction data_direction)  {  	struct se_device *dev = cmd->se_dev; +	struct fd_prot fd_prot; +	sense_reason_t rc;  	int ret = 0;  	/* @@ -558,11 +626,51 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,  	 * physical memory addresses to struct iovec virtual memory.  	 */  	if (data_direction == DMA_FROM_DEVICE) { +		memset(&fd_prot, 0, sizeof(struct fd_prot)); + +		if (cmd->prot_type) { +			ret = fd_do_prot_rw(cmd, &fd_prot, false); +			if (ret < 0) +				return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +		} +  		ret = fd_do_rw(cmd, sgl, sgl_nents, 0); + +		if (ret > 0 && cmd->prot_type) { +			u32 sectors = cmd->data_length / dev->dev_attrib.block_size; + +			rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, +						 0, fd_prot.prot_sg, 0); +			if (rc) { +				kfree(fd_prot.prot_sg); +				vfree(fd_prot.prot_buf); +				return rc; +			} +			kfree(fd_prot.prot_sg); +			vfree(fd_prot.prot_buf); +		}  	} else { +		memset(&fd_prot, 0, sizeof(struct fd_prot)); + +		if (cmd->prot_type) { +			u32 sectors = cmd->data_length / dev->dev_attrib.block_size; + +			ret = fd_do_prot_rw(cmd, &fd_prot, false); +			if (ret < 0) +				return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + +			rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, +						  0, fd_prot.prot_sg, 0); +			if (rc) { +				kfree(fd_prot.prot_sg); +				vfree(fd_prot.prot_buf); +				return rc; +			} +		} +  		ret = fd_do_rw(cmd, sgl, sgl_nents, 1);  		/* -		 * Perform implict vfs_fsync_range() for fd_do_writev() ops +		 * Perform implicit vfs_fsync_range() for fd_do_writev() ops  		 * for SCSI WRITEs with Forced Unit Access (FUA) set.  		 * Allow this to happen independent of WCE=0 setting.  		 */ @@ -576,10 +684,19 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,  			vfs_fsync_range(fd_dev->fd_file, start, end, 1);  		} + +		if (ret > 0 && cmd->prot_type) { +			ret = fd_do_prot_rw(cmd, &fd_prot, true); +			if (ret < 0) +				return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +		}  	} -	if (ret < 0) +	if (ret < 0) { +		kfree(fd_prot.prot_sg); +		vfree(fd_prot.prot_buf);  		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +	}  	if (ret)  		target_complete_cmd(cmd, SAM_STAT_GOOD); @@ -700,6 +817,102 @@ static sector_t fd_get_blocks(struct se_device *dev)  		       dev->dev_attrib.block_size);  } +static int fd_init_prot(struct se_device *dev) +{ +	struct fd_dev *fd_dev = FD_DEV(dev); +	struct file *prot_file, *file = fd_dev->fd_file; +	struct inode *inode; +	int ret, flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC; +	char buf[FD_MAX_DEV_PROT_NAME]; + +	if (!file) { +		pr_err("Unable to locate fd_dev->fd_file\n"); +		return -ENODEV; +	} + +	inode = file->f_mapping->host; +	if (S_ISBLK(inode->i_mode)) { +		pr_err("FILEIO Protection emulation only supported on" +		       " !S_ISBLK\n"); +		return -ENOSYS; +	} + +	if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) +		flags &= ~O_DSYNC; + +	snprintf(buf, FD_MAX_DEV_PROT_NAME, "%s.protection", +		 fd_dev->fd_dev_name); + +	prot_file = filp_open(buf, flags, 0600); +	if (IS_ERR(prot_file)) { +		pr_err("filp_open(%s) failed\n", buf); +		ret = PTR_ERR(prot_file); +		return ret; +	} +	fd_dev->fd_prot_file = prot_file; + +	return 0; +} + +static int fd_format_prot(struct se_device *dev) +{ +	struct fd_dev *fd_dev = FD_DEV(dev); +	struct file *prot_fd = fd_dev->fd_prot_file; +	sector_t prot_length, prot; +	unsigned char *buf; +	loff_t pos = 0; +	int unit_size = FDBD_FORMAT_UNIT_SIZE * dev->dev_attrib.block_size; +	int rc, ret = 0, size, len; + +	if (!dev->dev_attrib.pi_prot_type) { +		pr_err("Unable to format_prot while pi_prot_type == 0\n"); +		return -ENODEV; +	} +	if (!prot_fd) { +		pr_err("Unable to locate fd_dev->fd_prot_file\n"); +		return -ENODEV; +	} + +	buf = vzalloc(unit_size); +	if (!buf) { +		pr_err("Unable to allocate FILEIO prot buf\n"); +		return -ENOMEM; +	} +	prot_length = (dev->transport->get_blocks(dev) + 1) * dev->prot_length; +	size = prot_length; + +	pr_debug("Using FILEIO prot_length: %llu\n", +		 (unsigned long long)prot_length); + +	memset(buf, 0xff, unit_size); +	for (prot = 0; prot < prot_length; prot += unit_size) { +		len = min(unit_size, size); +		rc = kernel_write(prot_fd, buf, len, pos); +		if (rc != len) { +			pr_err("vfs_write to prot file failed: %d\n", rc); +			ret = -ENODEV; +			goto out; +		} +		pos += len; +		size -= len; +	} + +out: +	vfree(buf); +	return ret; +} + +static void fd_free_prot(struct se_device *dev) +{ +	struct fd_dev *fd_dev = FD_DEV(dev); + +	if (!fd_dev->fd_prot_file) +		return; + +	filp_close(fd_dev->fd_prot_file, NULL); +	fd_dev->fd_prot_file = NULL; +} +  static struct sbc_ops fd_sbc_ops = {  	.execute_rw		= fd_execute_rw,  	.execute_sync_cache	= fd_execute_sync_cache, @@ -730,6 +943,9 @@ static struct se_subsystem_api fileio_template = {  	.show_configfs_dev_params = fd_show_configfs_dev_params,  	.get_device_type	= sbc_get_device_type,  	.get_blocks		= fd_get_blocks, +	.init_prot		= fd_init_prot, +	.format_prot		= fd_format_prot, +	.free_prot		= fd_free_prot,  };  static int __init fileio_module_init(void)  | 
