Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull scsi target updates from Nicholas Bellinger: "The highlights in this series include: - Improve sg_table lookup scalability in RAMDISK_MCP (martin) - Add device attribute to expose config name for INQUIRY model (tregaron) - Convert tcm_vhost to use lock-less list for cmd completion (asias) - Add tcm_vhost support for multiple target's per endpoint (asias) - Add tcm_vhost support for multiple queues per vhost (asias) - Add missing mapped_lun bounds checking during make_mappedlun setup in generic fabric configfs code (jan engelhardt + nab) - Enforce individual iscsi-target network portal export once per TargetName endpoint (grover + nab) - Add WRITE_SAME w/ UNMAP=0 emulation to FILEIO backend (nab) Things have been mostly quiet this round, with majority of the work being done on the iser-target WIP driver + associated iscsi-target refactoring patches currently in flight for v3.10 code. At this point there is one patch series left outstanding from Asias to add support for UNMAP + WRITE_SAME w/ UNMAP=1 to FILEIO awaiting feedback from hch & Co, that will likely be included in a post v3.9-rc1 PULL request if there are no objections. Also, there is a regression bug recently reported off-list that seems to be effecting v3.5 and v3.6 kernels with MSFT iSCSI initiators that is still being tracked down. No word if this effects >= v3.7 just yet, but if so there will likely another PULL request coming your way.." * 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (26 commits) target: Rename spc_get_write_same_sectors -> sbc_get_write_same_sectors target/file: Add WRITE_SAME w/ UNMAP=0 emulation support iscsi-target: Enforce individual network portal export once per TargetName iscsi-target: Refactor iscsit_get_np sockaddr matching into iscsit_check_np_match target: Add missing mapped_lun bounds checking during make_mappedlun setup target: Fix lookup of dynamic NodeACLs during cached demo-mode operation target: Fix parameter list length checking in MODE SELECT target: Fix error checking for UNMAP commands target: Fix sense data for out-of-bounds IO operations target_core_rd: break out unterminated loop during copy tcm_vhost: Multi-queue support tcm_vhost: Multi-target support target: Add device attribute to expose config_item_name for INQUIRY model target: don't truncate the fail intr address target: don't always say "ipv6" as address type target/iblock: Use backend REQ_FLUSH hint for WriteCacheEnabled status iscsi-target: make some temporary buffers larger tcm_vhost: Optimize gup in vhost_scsi_map_to_sgl tcm_vhost: Use iov_num_pages to calculate sgl_count tcm_vhost: Introduce iov_num_pages ...
This commit is contained in:
@@ -264,16 +264,50 @@ int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct iscsi_np *iscsit_get_np(
|
||||
bool iscsit_check_np_match(
|
||||
struct __kernel_sockaddr_storage *sockaddr,
|
||||
struct iscsi_np *np,
|
||||
int network_transport)
|
||||
{
|
||||
struct sockaddr_in *sock_in, *sock_in_e;
|
||||
struct sockaddr_in6 *sock_in6, *sock_in6_e;
|
||||
struct iscsi_np *np;
|
||||
int ip_match = 0;
|
||||
bool ip_match = false;
|
||||
u16 port;
|
||||
|
||||
if (sockaddr->ss_family == AF_INET6) {
|
||||
sock_in6 = (struct sockaddr_in6 *)sockaddr;
|
||||
sock_in6_e = (struct sockaddr_in6 *)&np->np_sockaddr;
|
||||
|
||||
if (!memcmp(&sock_in6->sin6_addr.in6_u,
|
||||
&sock_in6_e->sin6_addr.in6_u,
|
||||
sizeof(struct in6_addr)))
|
||||
ip_match = true;
|
||||
|
||||
port = ntohs(sock_in6->sin6_port);
|
||||
} else {
|
||||
sock_in = (struct sockaddr_in *)sockaddr;
|
||||
sock_in_e = (struct sockaddr_in *)&np->np_sockaddr;
|
||||
|
||||
if (sock_in->sin_addr.s_addr == sock_in_e->sin_addr.s_addr)
|
||||
ip_match = true;
|
||||
|
||||
port = ntohs(sock_in->sin_port);
|
||||
}
|
||||
|
||||
if ((ip_match == true) && (np->np_port == port) &&
|
||||
(np->np_network_transport == network_transport))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct iscsi_np *iscsit_get_np(
|
||||
struct __kernel_sockaddr_storage *sockaddr,
|
||||
int network_transport)
|
||||
{
|
||||
struct iscsi_np *np;
|
||||
bool match;
|
||||
|
||||
spin_lock_bh(&np_lock);
|
||||
list_for_each_entry(np, &g_np_list, np_list) {
|
||||
spin_lock(&np->np_thread_lock);
|
||||
@@ -282,29 +316,8 @@ static struct iscsi_np *iscsit_get_np(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sockaddr->ss_family == AF_INET6) {
|
||||
sock_in6 = (struct sockaddr_in6 *)sockaddr;
|
||||
sock_in6_e = (struct sockaddr_in6 *)&np->np_sockaddr;
|
||||
|
||||
if (!memcmp(&sock_in6->sin6_addr.in6_u,
|
||||
&sock_in6_e->sin6_addr.in6_u,
|
||||
sizeof(struct in6_addr)))
|
||||
ip_match = 1;
|
||||
|
||||
port = ntohs(sock_in6->sin6_port);
|
||||
} else {
|
||||
sock_in = (struct sockaddr_in *)sockaddr;
|
||||
sock_in_e = (struct sockaddr_in *)&np->np_sockaddr;
|
||||
|
||||
if (sock_in->sin_addr.s_addr ==
|
||||
sock_in_e->sin_addr.s_addr)
|
||||
ip_match = 1;
|
||||
|
||||
port = ntohs(sock_in->sin_port);
|
||||
}
|
||||
|
||||
if ((ip_match == 1) && (np->np_port == port) &&
|
||||
(np->np_network_transport == network_transport)) {
|
||||
match = iscsit_check_np_match(sockaddr, np, network_transport);
|
||||
if (match == true) {
|
||||
/*
|
||||
* Increment the np_exports reference count now to
|
||||
* prevent iscsit_del_np() below from being called
|
||||
|
@@ -8,6 +8,8 @@ extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *);
|
||||
extern void iscsit_del_tiqn(struct iscsi_tiqn *);
|
||||
extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *);
|
||||
extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *);
|
||||
extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *,
|
||||
struct iscsi_np *, int);
|
||||
extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *,
|
||||
char *, int);
|
||||
extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
|
||||
|
@@ -1095,11 +1095,11 @@ static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value,
|
||||
SET_PSTATE_REPLY_OPTIONAL(param);
|
||||
}
|
||||
} else if (IS_TYPE_NUMBER(param)) {
|
||||
char *tmpptr, buf[10];
|
||||
char *tmpptr, buf[11];
|
||||
u32 acceptor_value = simple_strtoul(param->value, &tmpptr, 0);
|
||||
u32 proposer_value = simple_strtoul(value, &tmpptr, 0);
|
||||
|
||||
memset(buf, 0, 10);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (!strcmp(param->name, MAXCONNECTIONS) ||
|
||||
!strcmp(param->name, MAXBURSTLENGTH) ||
|
||||
@@ -1503,8 +1503,8 @@ static int iscsi_enforce_integrity_rules(
|
||||
FirstBurstLength = simple_strtoul(param->value,
|
||||
&tmpptr, 0);
|
||||
if (FirstBurstLength > MaxBurstLength) {
|
||||
char tmpbuf[10];
|
||||
memset(tmpbuf, 0, 10);
|
||||
char tmpbuf[11];
|
||||
memset(tmpbuf, 0, sizeof(tmpbuf));
|
||||
sprintf(tmpbuf, "%u", MaxBurstLength);
|
||||
if (iscsi_update_param_value(param, tmpbuf))
|
||||
return -1;
|
||||
|
@@ -410,14 +410,16 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr_type(
|
||||
struct iscsi_tiqn *tiqn = container_of(igrps,
|
||||
struct iscsi_tiqn, tiqn_stat_grps);
|
||||
struct iscsi_login_stats *lstat = &tiqn->login_stats;
|
||||
unsigned char buf[8];
|
||||
int ret;
|
||||
|
||||
spin_lock(&lstat->lock);
|
||||
snprintf(buf, 8, "%s", (lstat->last_intr_fail_ip_addr != NULL) ?
|
||||
"ipv6" : "ipv4");
|
||||
if (lstat->last_intr_fail_ip_family == AF_INET6)
|
||||
ret = snprintf(page, PAGE_SIZE, "ipv6\n");
|
||||
else
|
||||
ret = snprintf(page, PAGE_SIZE, "ipv4\n");
|
||||
spin_unlock(&lstat->lock);
|
||||
|
||||
return snprintf(page, PAGE_SIZE, "%s\n", buf);
|
||||
return ret;
|
||||
}
|
||||
ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr_type);
|
||||
|
||||
@@ -427,16 +429,19 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr(
|
||||
struct iscsi_tiqn *tiqn = container_of(igrps,
|
||||
struct iscsi_tiqn, tiqn_stat_grps);
|
||||
struct iscsi_login_stats *lstat = &tiqn->login_stats;
|
||||
unsigned char buf[32];
|
||||
int ret;
|
||||
|
||||
spin_lock(&lstat->lock);
|
||||
if (lstat->last_intr_fail_ip_family == AF_INET6)
|
||||
snprintf(buf, 32, "[%s]", lstat->last_intr_fail_ip_addr);
|
||||
else
|
||||
snprintf(buf, 32, "%s", lstat->last_intr_fail_ip_addr);
|
||||
if (lstat->last_intr_fail_ip_family == AF_INET6) {
|
||||
ret = snprintf(page, PAGE_SIZE, "[%s]\n",
|
||||
lstat->last_intr_fail_ip_addr);
|
||||
} else {
|
||||
ret = snprintf(page, PAGE_SIZE, "%s\n",
|
||||
lstat->last_intr_fail_ip_addr);
|
||||
}
|
||||
spin_unlock(&lstat->lock);
|
||||
|
||||
return snprintf(page, PAGE_SIZE, "%s\n", buf);
|
||||
return ret;
|
||||
}
|
||||
ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr);
|
||||
|
||||
|
@@ -422,6 +422,35 @@ struct iscsi_tpg_np *iscsit_tpg_locate_child_np(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool iscsit_tpg_check_network_portal(
|
||||
struct iscsi_tiqn *tiqn,
|
||||
struct __kernel_sockaddr_storage *sockaddr,
|
||||
int network_transport)
|
||||
{
|
||||
struct iscsi_portal_group *tpg;
|
||||
struct iscsi_tpg_np *tpg_np;
|
||||
struct iscsi_np *np;
|
||||
bool match = false;
|
||||
|
||||
spin_lock(&tiqn->tiqn_tpg_lock);
|
||||
list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) {
|
||||
|
||||
spin_lock(&tpg->tpg_np_lock);
|
||||
list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) {
|
||||
np = tpg_np->tpg_np;
|
||||
|
||||
match = iscsit_check_np_match(sockaddr, np,
|
||||
network_transport);
|
||||
if (match == true)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&tpg->tpg_np_lock);
|
||||
}
|
||||
spin_unlock(&tiqn->tiqn_tpg_lock);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
|
||||
struct iscsi_portal_group *tpg,
|
||||
struct __kernel_sockaddr_storage *sockaddr,
|
||||
@@ -432,6 +461,16 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
|
||||
struct iscsi_np *np;
|
||||
struct iscsi_tpg_np *tpg_np;
|
||||
|
||||
if (!tpg_np_parent) {
|
||||
if (iscsit_tpg_check_network_portal(tpg->tpg_tiqn, sockaddr,
|
||||
network_transport) == true) {
|
||||
pr_err("Network Portal: %s already exists on a"
|
||||
" different TPG on %s\n", ip_str,
|
||||
tpg->tpg_tiqn->tiqn);
|
||||
return ERR_PTR(-EEXIST);
|
||||
}
|
||||
}
|
||||
|
||||
tpg_np = kzalloc(sizeof(struct iscsi_tpg_np), GFP_KERNEL);
|
||||
if (!tpg_np) {
|
||||
pr_err("Unable to allocate memory for"
|
||||
|
@@ -609,6 +609,9 @@ static struct target_core_dev_attrib_attribute \
|
||||
__CONFIGFS_EATTR_RO(_name, \
|
||||
target_core_dev_show_attr_##_name);
|
||||
|
||||
DEF_DEV_ATTRIB(emulate_model_alias);
|
||||
SE_DEV_ATTR(emulate_model_alias, S_IRUGO | S_IWUSR);
|
||||
|
||||
DEF_DEV_ATTRIB(emulate_dpo);
|
||||
SE_DEV_ATTR(emulate_dpo, S_IRUGO | S_IWUSR);
|
||||
|
||||
@@ -681,6 +684,7 @@ SE_DEV_ATTR(max_write_same_len, S_IRUGO | S_IWUSR);
|
||||
CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group);
|
||||
|
||||
static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
|
||||
&target_core_dev_attrib_emulate_model_alias.attr,
|
||||
&target_core_dev_attrib_emulate_dpo.attr,
|
||||
&target_core_dev_attrib_emulate_fua_write.attr,
|
||||
&target_core_dev_attrib_emulate_fua_read.attr,
|
||||
|
@@ -713,6 +713,44 @@ int se_dev_set_max_write_same_len(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dev_set_t10_wwn_model_alias(struct se_device *dev)
|
||||
{
|
||||
const char *configname;
|
||||
|
||||
configname = config_item_name(&dev->dev_group.cg_item);
|
||||
if (strlen(configname) >= 16) {
|
||||
pr_warn("dev[%p]: Backstore name '%s' is too long for "
|
||||
"INQUIRY_MODEL, truncating to 16 bytes\n", dev,
|
||||
configname);
|
||||
}
|
||||
snprintf(&dev->t10_wwn.model[0], 16, "%s", configname);
|
||||
}
|
||||
|
||||
int se_dev_set_emulate_model_alias(struct se_device *dev, int flag)
|
||||
{
|
||||
if (dev->export_count) {
|
||||
pr_err("dev[%p]: Unable to change model alias"
|
||||
" while export_count is %d\n",
|
||||
dev, dev->export_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (flag != 0 && flag != 1) {
|
||||
pr_err("Illegal value %d\n", flag);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
dev_set_t10_wwn_model_alias(dev);
|
||||
} else {
|
||||
strncpy(&dev->t10_wwn.model[0],
|
||||
dev->transport->inquiry_prod, 16);
|
||||
}
|
||||
dev->dev_attrib.emulate_model_alias = flag;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int se_dev_set_emulate_dpo(struct se_device *dev, int flag)
|
||||
{
|
||||
if (flag != 0 && flag != 1) {
|
||||
@@ -772,6 +810,12 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
|
||||
pr_err("emulate_write_cache not supported for pSCSI\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (dev->transport->get_write_cache) {
|
||||
pr_warn("emulate_write_cache cannot be changed when underlying"
|
||||
" HW reports WriteCacheEnabled, ignoring request\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->dev_attrib.emulate_write_cache = flag;
|
||||
pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n",
|
||||
dev, dev->dev_attrib.emulate_write_cache);
|
||||
@@ -1182,24 +1226,18 @@ static struct se_lun *core_dev_get_lun(struct se_portal_group *tpg, u32 unpacked
|
||||
|
||||
struct se_lun_acl *core_dev_init_initiator_node_lun_acl(
|
||||
struct se_portal_group *tpg,
|
||||
struct se_node_acl *nacl,
|
||||
u32 mapped_lun,
|
||||
char *initiatorname,
|
||||
int *ret)
|
||||
{
|
||||
struct se_lun_acl *lacl;
|
||||
struct se_node_acl *nacl;
|
||||
|
||||
if (strlen(initiatorname) >= TRANSPORT_IQN_LEN) {
|
||||
if (strlen(nacl->initiatorname) >= TRANSPORT_IQN_LEN) {
|
||||
pr_err("%s InitiatorName exceeds maximum size.\n",
|
||||
tpg->se_tpg_tfo->get_fabric_name());
|
||||
*ret = -EOVERFLOW;
|
||||
return NULL;
|
||||
}
|
||||
nacl = core_tpg_get_initiator_node_acl(tpg, initiatorname);
|
||||
if (!nacl) {
|
||||
*ret = -EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
lacl = kzalloc(sizeof(struct se_lun_acl), GFP_KERNEL);
|
||||
if (!lacl) {
|
||||
pr_err("Unable to allocate memory for struct se_lun_acl.\n");
|
||||
@@ -1210,7 +1248,8 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl(
|
||||
INIT_LIST_HEAD(&lacl->lacl_list);
|
||||
lacl->mapped_lun = mapped_lun;
|
||||
lacl->se_lun_nacl = nacl;
|
||||
snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
|
||||
snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s",
|
||||
nacl->initiatorname);
|
||||
|
||||
return lacl;
|
||||
}
|
||||
@@ -1390,6 +1429,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
|
||||
dev->t10_alua.t10_dev = dev;
|
||||
|
||||
dev->dev_attrib.da_dev = dev;
|
||||
dev->dev_attrib.emulate_model_alias = DA_EMULATE_MODEL_ALIAS;
|
||||
dev->dev_attrib.emulate_dpo = DA_EMULATE_DPO;
|
||||
dev->dev_attrib.emulate_fua_write = DA_EMULATE_FUA_WRITE;
|
||||
dev->dev_attrib.emulate_fua_read = DA_EMULATE_FUA_READ;
|
||||
|
@@ -354,9 +354,17 @@ static struct config_group *target_fabric_make_mappedlun(
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (mapped_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) {
|
||||
pr_err("Mapped LUN: %lu exceeds TRANSPORT_MAX_LUNS_PER_TPG"
|
||||
"-1: %u for Target Portal Group: %u\n", mapped_lun,
|
||||
TRANSPORT_MAX_LUNS_PER_TPG-1,
|
||||
se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg));
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun,
|
||||
config_item_name(acl_ci), &ret);
|
||||
lacl = core_dev_init_initiator_node_lun_acl(se_tpg, se_nacl,
|
||||
mapped_lun, &ret);
|
||||
if (!lacl) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
@@ -190,6 +190,11 @@ static int fd_configure_device(struct se_device *dev)
|
||||
|
||||
fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
|
||||
fd_dev->fd_queue_depth = dev->queue_depth;
|
||||
/*
|
||||
* Limit WRITE_SAME w/ UNMAP=0 emulation to 8k Number of LBAs (NoLB)
|
||||
* based upon struct iovec limit for vfs_writev()
|
||||
*/
|
||||
dev->dev_attrib.max_write_same_len = 0x1000;
|
||||
|
||||
pr_debug("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,
|
||||
@@ -328,6 +333,114 @@ fd_execute_sync_cache(struct se_cmd *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
fd_setup_write_same_buf(struct se_cmd *cmd, struct scatterlist *sg,
|
||||
unsigned int len)
|
||||
{
|
||||
struct se_device *se_dev = cmd->se_dev;
|
||||
unsigned int block_size = se_dev->dev_attrib.block_size;
|
||||
unsigned int i = 0, end;
|
||||
unsigned char *buf, *p, *kmap_buf;
|
||||
|
||||
buf = kzalloc(min_t(unsigned int, len, PAGE_SIZE), GFP_KERNEL);
|
||||
if (!buf) {
|
||||
pr_err("Unable to allocate fd_execute_write_same buf\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kmap_buf = kmap(sg_page(sg)) + sg->offset;
|
||||
if (!kmap_buf) {
|
||||
pr_err("kmap() failed in fd_setup_write_same\n");
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Fill local *buf to contain multiple WRITE_SAME blocks up to
|
||||
* min(len, PAGE_SIZE)
|
||||
*/
|
||||
p = buf;
|
||||
end = min_t(unsigned int, len, PAGE_SIZE);
|
||||
|
||||
while (i < end) {
|
||||
memcpy(p, kmap_buf, block_size);
|
||||
|
||||
i += block_size;
|
||||
p += block_size;
|
||||
}
|
||||
kunmap(sg_page(sg));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static sense_reason_t
|
||||
fd_execute_write_same(struct se_cmd *cmd)
|
||||
{
|
||||
struct se_device *se_dev = cmd->se_dev;
|
||||
struct fd_dev *fd_dev = FD_DEV(se_dev);
|
||||
struct file *f = fd_dev->fd_file;
|
||||
struct scatterlist *sg;
|
||||
struct iovec *iov;
|
||||
mm_segment_t old_fs;
|
||||
sector_t nolb = sbc_get_write_same_sectors(cmd);
|
||||
loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size;
|
||||
unsigned int len, len_tmp, iov_num;
|
||||
int i, rc;
|
||||
unsigned char *buf;
|
||||
|
||||
if (!nolb) {
|
||||
target_complete_cmd(cmd, SAM_STAT_GOOD);
|
||||
return 0;
|
||||
}
|
||||
sg = &cmd->t_data_sg[0];
|
||||
|
||||
if (cmd->t_data_nents > 1 ||
|
||||
sg->length != cmd->se_dev->dev_attrib.block_size) {
|
||||
pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u"
|
||||
" block_size: %u\n", cmd->t_data_nents, sg->length,
|
||||
cmd->se_dev->dev_attrib.block_size);
|
||||
return TCM_INVALID_CDB_FIELD;
|
||||
}
|
||||
|
||||
len = len_tmp = nolb * se_dev->dev_attrib.block_size;
|
||||
iov_num = DIV_ROUND_UP(len, PAGE_SIZE);
|
||||
|
||||
buf = fd_setup_write_same_buf(cmd, sg, len);
|
||||
if (!buf)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
|
||||
iov = vzalloc(sizeof(struct iovec) * iov_num);
|
||||
if (!iov) {
|
||||
pr_err("Unable to allocate fd_execute_write_same iovecs\n");
|
||||
kfree(buf);
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
}
|
||||
/*
|
||||
* Map the single fabric received scatterlist block now populated
|
||||
* in *buf into each iovec for I/O submission.
|
||||
*/
|
||||
for (i = 0; i < iov_num; i++) {
|
||||
iov[i].iov_base = buf;
|
||||
iov[i].iov_len = min_t(unsigned int, len_tmp, PAGE_SIZE);
|
||||
len_tmp -= iov[i].iov_len;
|
||||
}
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
rc = vfs_writev(f, &iov[0], iov_num, &pos);
|
||||
set_fs(old_fs);
|
||||
|
||||
vfree(iov);
|
||||
kfree(buf);
|
||||
|
||||
if (rc < 0 || rc != len) {
|
||||
pr_err("vfs_writev() returned %d for write same\n", rc);
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
}
|
||||
|
||||
target_complete_cmd(cmd, SAM_STAT_GOOD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static sense_reason_t
|
||||
fd_execute_rw(struct se_cmd *cmd)
|
||||
{
|
||||
@@ -486,6 +599,7 @@ static sector_t fd_get_blocks(struct se_device *dev)
|
||||
static struct sbc_ops fd_sbc_ops = {
|
||||
.execute_rw = fd_execute_rw,
|
||||
.execute_sync_cache = fd_execute_sync_cache,
|
||||
.execute_write_same = fd_execute_write_same,
|
||||
};
|
||||
|
||||
static sense_reason_t
|
||||
|
@@ -154,6 +154,7 @@ static int iblock_configure_device(struct se_device *dev)
|
||||
|
||||
if (blk_queue_nonrot(q))
|
||||
dev->dev_attrib.is_nonrot = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_bioset:
|
||||
@@ -390,10 +391,19 @@ iblock_execute_unmap(struct se_cmd *cmd)
|
||||
sense_reason_t ret = 0;
|
||||
int dl, bd_dl, err;
|
||||
|
||||
/* We never set ANC_SUP */
|
||||
if (cmd->t_task_cdb[1])
|
||||
return TCM_INVALID_CDB_FIELD;
|
||||
|
||||
if (cmd->data_length == 0) {
|
||||
target_complete_cmd(cmd, SAM_STAT_GOOD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmd->data_length < 8) {
|
||||
pr_warn("UNMAP parameter list length %u too small\n",
|
||||
cmd->data_length);
|
||||
return TCM_INVALID_PARAMETER_LIST;
|
||||
return TCM_PARAMETER_LIST_LENGTH_ERROR;
|
||||
}
|
||||
|
||||
buf = transport_kmap_data_sg(cmd);
|
||||
@@ -463,7 +473,7 @@ iblock_execute_write_same_unmap(struct se_cmd *cmd)
|
||||
int rc;
|
||||
|
||||
rc = blkdev_issue_discard(ib_dev->ibd_bd, cmd->t_task_lba,
|
||||
spc_get_write_same_sectors(cmd), GFP_KERNEL, 0);
|
||||
sbc_get_write_same_sectors(cmd), GFP_KERNEL, 0);
|
||||
if (rc < 0) {
|
||||
pr_warn("blkdev_issue_discard() failed: %d\n", rc);
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
@@ -481,7 +491,7 @@ iblock_execute_write_same(struct se_cmd *cmd)
|
||||
struct bio *bio;
|
||||
struct bio_list list;
|
||||
sector_t block_lba = cmd->t_task_lba;
|
||||
sector_t sectors = spc_get_write_same_sectors(cmd);
|
||||
sector_t sectors = sbc_get_write_same_sectors(cmd);
|
||||
|
||||
sg = &cmd->t_data_sg[0];
|
||||
|
||||
@@ -654,20 +664,24 @@ iblock_execute_rw(struct se_cmd *cmd)
|
||||
u32 sg_num = sgl_nents;
|
||||
sector_t block_lba;
|
||||
unsigned bio_cnt;
|
||||
int rw;
|
||||
int rw = 0;
|
||||
int i;
|
||||
|
||||
if (data_direction == DMA_TO_DEVICE) {
|
||||
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
|
||||
struct request_queue *q = bdev_get_queue(ib_dev->ibd_bd);
|
||||
/*
|
||||
* Force data to disk if we pretend to not have a volatile
|
||||
* write cache, or the initiator set the Force Unit Access bit.
|
||||
* Force writethrough using WRITE_FUA if a volatile write cache
|
||||
* is not enabled, or if initiator set the Force Unit Access bit.
|
||||
*/
|
||||
if (dev->dev_attrib.emulate_write_cache == 0 ||
|
||||
(dev->dev_attrib.emulate_fua_write > 0 &&
|
||||
(cmd->se_cmd_flags & SCF_FUA)))
|
||||
rw = WRITE_FUA;
|
||||
else
|
||||
if (q->flush_flags & REQ_FUA) {
|
||||
if (cmd->se_cmd_flags & SCF_FUA)
|
||||
rw = WRITE_FUA;
|
||||
else if (!(q->flush_flags & REQ_FLUSH))
|
||||
rw = WRITE_FUA;
|
||||
} else {
|
||||
rw = WRITE;
|
||||
}
|
||||
} else {
|
||||
rw = READ;
|
||||
}
|
||||
@@ -774,6 +788,15 @@ iblock_parse_cdb(struct se_cmd *cmd)
|
||||
return sbc_parse_cdb(cmd, &iblock_sbc_ops);
|
||||
}
|
||||
|
||||
bool iblock_get_write_cache(struct se_device *dev)
|
||||
{
|
||||
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
|
||||
struct block_device *bd = ib_dev->ibd_bd;
|
||||
struct request_queue *q = bdev_get_queue(bd);
|
||||
|
||||
return q->flush_flags & REQ_FLUSH;
|
||||
}
|
||||
|
||||
static struct se_subsystem_api iblock_template = {
|
||||
.name = "iblock",
|
||||
.inquiry_prod = "IBLOCK",
|
||||
@@ -790,6 +813,7 @@ static struct se_subsystem_api iblock_template = {
|
||||
.show_configfs_dev_params = iblock_show_configfs_dev_params,
|
||||
.get_device_type = sbc_get_device_type,
|
||||
.get_blocks = iblock_get_blocks,
|
||||
.get_write_cache = iblock_get_write_cache,
|
||||
};
|
||||
|
||||
static int __init iblock_module_init(void)
|
||||
|
@@ -25,6 +25,7 @@ int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);
|
||||
int se_dev_set_unmap_granularity(struct se_device *, u32);
|
||||
int se_dev_set_unmap_granularity_alignment(struct se_device *, u32);
|
||||
int se_dev_set_max_write_same_len(struct se_device *, u32);
|
||||
int se_dev_set_emulate_model_alias(struct se_device *, int);
|
||||
int se_dev_set_emulate_dpo(struct se_device *, int);
|
||||
int se_dev_set_emulate_fua_write(struct se_device *, int);
|
||||
int se_dev_set_emulate_fua_read(struct se_device *, int);
|
||||
@@ -45,7 +46,7 @@ struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_device *, u3
|
||||
int core_dev_del_lun(struct se_portal_group *, u32);
|
||||
struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32);
|
||||
struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *,
|
||||
u32, char *, int *);
|
||||
struct se_node_acl *, u32, int *);
|
||||
int core_dev_add_initiator_node_lun_acl(struct se_portal_group *,
|
||||
struct se_lun_acl *, u32, u32);
|
||||
int core_dev_del_initiator_node_lun_acl(struct se_portal_group *,
|
||||
|
@@ -256,10 +256,12 @@ static void rd_free_device(struct se_device *dev)
|
||||
|
||||
static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
|
||||
{
|
||||
u32 i;
|
||||
struct rd_dev_sg_table *sg_table;
|
||||
u32 i, sg_per_table = (RD_MAX_ALLOCATION_SIZE /
|
||||
sizeof(struct scatterlist));
|
||||
|
||||
for (i = 0; i < rd_dev->sg_table_count; i++) {
|
||||
i = page / sg_per_table;
|
||||
if (i < rd_dev->sg_table_count) {
|
||||
sg_table = &rd_dev->sg_table_array[i];
|
||||
if ((sg_table->page_start_offset <= page) &&
|
||||
(sg_table->page_end_offset >= page))
|
||||
@@ -314,7 +316,19 @@ rd_execute_rw(struct se_cmd *cmd)
|
||||
void *rd_addr;
|
||||
|
||||
sg_miter_next(&m);
|
||||
if (!(u32)m.length) {
|
||||
pr_debug("RD[%u]: invalid sgl %p len %zu\n",
|
||||
dev->rd_dev_id, m.addr, m.length);
|
||||
sg_miter_stop(&m);
|
||||
return TCM_INCORRECT_AMOUNT_OF_DATA;
|
||||
}
|
||||
len = min((u32)m.length, src_len);
|
||||
if (len > rd_size) {
|
||||
pr_debug("RD[%u]: size underrun page %d offset %d "
|
||||
"size %d\n", dev->rd_dev_id,
|
||||
rd_page, rd_offset, rd_size);
|
||||
len = rd_size;
|
||||
}
|
||||
m.consumed = len;
|
||||
|
||||
rd_addr = sg_virt(rd_sg) + rd_offset;
|
||||
|
@@ -105,7 +105,7 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sector_t spc_get_write_same_sectors(struct se_cmd *cmd)
|
||||
sector_t sbc_get_write_same_sectors(struct se_cmd *cmd)
|
||||
{
|
||||
u32 num_blocks;
|
||||
|
||||
@@ -126,7 +126,7 @@ sector_t spc_get_write_same_sectors(struct se_cmd *cmd)
|
||||
return cmd->se_dev->transport->get_blocks(cmd->se_dev) -
|
||||
cmd->t_task_lba + 1;
|
||||
}
|
||||
EXPORT_SYMBOL(spc_get_write_same_sectors);
|
||||
EXPORT_SYMBOL(sbc_get_write_same_sectors);
|
||||
|
||||
static sense_reason_t
|
||||
sbc_emulate_noop(struct se_cmd *cmd)
|
||||
@@ -233,7 +233,7 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
|
||||
static sense_reason_t
|
||||
sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops)
|
||||
{
|
||||
unsigned int sectors = spc_get_write_same_sectors(cmd);
|
||||
unsigned int sectors = sbc_get_write_same_sectors(cmd);
|
||||
|
||||
if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
|
||||
pr_err("WRITE_SAME PBDATA and LBDATA"
|
||||
@@ -486,7 +486,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
|
||||
*/
|
||||
if (cmd->t_task_lba || sectors) {
|
||||
if (sbc_check_valid_sectors(cmd) < 0)
|
||||
return TCM_INVALID_CDB_FIELD;
|
||||
return TCM_ADDRESS_OUT_OF_RANGE;
|
||||
}
|
||||
cmd->execute_cmd = ops->execute_sync_cache;
|
||||
break;
|
||||
|
@@ -66,8 +66,8 @@ static void spc_fill_alua_data(struct se_port *port, unsigned char *buf)
|
||||
spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
|
||||
}
|
||||
|
||||
static sense_reason_t
|
||||
spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf)
|
||||
sense_reason_t
|
||||
spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
|
||||
{
|
||||
struct se_lun *lun = cmd->se_lun;
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
@@ -104,6 +104,7 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(spc_emulate_inquiry_std);
|
||||
|
||||
/* unit serial number */
|
||||
static sense_reason_t
|
||||
@@ -160,7 +161,7 @@ static void spc_parse_naa_6h_vendor_specific(struct se_device *dev,
|
||||
* Device identification VPD, for a complete list of
|
||||
* DESIGNATOR TYPEs see spc4r17 Table 459.
|
||||
*/
|
||||
static sense_reason_t
|
||||
sense_reason_t
|
||||
spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
@@ -404,17 +405,33 @@ check_scsi_name:
|
||||
buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(spc_emulate_evpd_83);
|
||||
|
||||
static bool
|
||||
spc_check_dev_wce(struct se_device *dev)
|
||||
{
|
||||
bool wce = false;
|
||||
|
||||
if (dev->transport->get_write_cache)
|
||||
wce = dev->transport->get_write_cache(dev);
|
||||
else if (dev->dev_attrib.emulate_write_cache > 0)
|
||||
wce = true;
|
||||
|
||||
return wce;
|
||||
}
|
||||
|
||||
/* Extended INQUIRY Data VPD Page */
|
||||
static sense_reason_t
|
||||
spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
|
||||
{
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
|
||||
buf[3] = 0x3c;
|
||||
/* Set HEADSUP, ORDSUP, SIMPSUP */
|
||||
buf[5] = 0x07;
|
||||
|
||||
/* If WriteCache emulation is enabled, set V_SUP */
|
||||
if (cmd->se_dev->dev_attrib.emulate_write_cache > 0)
|
||||
if (spc_check_dev_wce(dev))
|
||||
buf[6] = 0x01;
|
||||
return 0;
|
||||
}
|
||||
@@ -764,7 +781,7 @@ static int spc_modesense_caching(struct se_device *dev, u8 pc, u8 *p)
|
||||
if (pc == 1)
|
||||
goto out;
|
||||
|
||||
if (dev->dev_attrib.emulate_write_cache > 0)
|
||||
if (spc_check_dev_wce(dev))
|
||||
p[2] = 0x04; /* Write Cache Enable */
|
||||
p[12] = 0x20; /* Disabled Read Ahead */
|
||||
|
||||
@@ -876,7 +893,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
|
||||
(cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
|
||||
spc_modesense_write_protect(&buf[length], type);
|
||||
|
||||
if ((dev->dev_attrib.emulate_write_cache > 0) &&
|
||||
if ((spc_check_dev_wce(dev)) &&
|
||||
(dev->dev_attrib.emulate_fua_write > 0))
|
||||
spc_modesense_dpofua(&buf[length], type);
|
||||
|
||||
@@ -983,6 +1000,14 @@ static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd)
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (!cmd->data_length) {
|
||||
target_complete_cmd(cmd, GOOD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmd->data_length < off + 2)
|
||||
return TCM_PARAMETER_LIST_LENGTH_ERROR;
|
||||
|
||||
buf = transport_kmap_data_sg(cmd);
|
||||
if (!buf)
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
@@ -1007,6 +1032,11 @@ static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd)
|
||||
goto out;
|
||||
|
||||
check_contents:
|
||||
if (cmd->data_length < off + length) {
|
||||
ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memcmp(buf + off, tbuf, length))
|
||||
ret = TCM_INVALID_PARAMETER_LIST;
|
||||
|
||||
|
@@ -331,18 +331,6 @@ static void core_tmr_drain_state_list(
|
||||
|
||||
fe_count = atomic_read(&cmd->t_fe_count);
|
||||
|
||||
if (!(cmd->transport_state & CMD_T_ACTIVE)) {
|
||||
pr_debug("LUN_RESET: got CMD_T_ACTIVE for"
|
||||
" cdb: %p, t_fe_count: %d dev: %p\n", cmd,
|
||||
fe_count, dev);
|
||||
cmd->transport_state |= CMD_T_ABORTED;
|
||||
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
||||
|
||||
core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
|
||||
continue;
|
||||
}
|
||||
pr_debug("LUN_RESET: Got !CMD_T_ACTIVE for cdb: %p,"
|
||||
" t_fe_count: %d dev: %p\n", cmd, fe_count, dev);
|
||||
cmd->transport_state |= CMD_T_ABORTED;
|
||||
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
||||
|
||||
|
@@ -111,16 +111,10 @@ struct se_node_acl *core_tpg_get_initiator_node_acl(
|
||||
struct se_node_acl *acl;
|
||||
|
||||
spin_lock_irq(&tpg->acl_node_lock);
|
||||
list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
|
||||
if (!strcmp(acl->initiatorname, initiatorname) &&
|
||||
!acl->dynamic_node_acl) {
|
||||
spin_unlock_irq(&tpg->acl_node_lock);
|
||||
return acl;
|
||||
}
|
||||
}
|
||||
acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
|
||||
spin_unlock_irq(&tpg->acl_node_lock);
|
||||
|
||||
return NULL;
|
||||
return acl;
|
||||
}
|
||||
|
||||
/* core_tpg_add_node_to_devs():
|
||||
|
@@ -907,15 +907,18 @@ int transport_dump_vpd_ident(
|
||||
|
||||
switch (vpd->device_identifier_code_set) {
|
||||
case 0x01: /* Binary */
|
||||
sprintf(buf, "T10 VPD Binary Device Identifier: %s\n",
|
||||
snprintf(buf, sizeof(buf),
|
||||
"T10 VPD Binary Device Identifier: %s\n",
|
||||
&vpd->device_identifier[0]);
|
||||
break;
|
||||
case 0x02: /* ASCII */
|
||||
sprintf(buf, "T10 VPD ASCII Device Identifier: %s\n",
|
||||
snprintf(buf, sizeof(buf),
|
||||
"T10 VPD ASCII Device Identifier: %s\n",
|
||||
&vpd->device_identifier[0]);
|
||||
break;
|
||||
case 0x03: /* UTF-8 */
|
||||
sprintf(buf, "T10 VPD UTF-8 Device Identifier: %s\n",
|
||||
snprintf(buf, sizeof(buf),
|
||||
"T10 VPD UTF-8 Device Identifier: %s\n",
|
||||
&vpd->device_identifier[0]);
|
||||
break;
|
||||
default:
|
||||
@@ -1514,6 +1517,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
|
||||
case TCM_UNSUPPORTED_SCSI_OPCODE:
|
||||
case TCM_INVALID_CDB_FIELD:
|
||||
case TCM_INVALID_PARAMETER_LIST:
|
||||
case TCM_PARAMETER_LIST_LENGTH_ERROR:
|
||||
case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE:
|
||||
case TCM_UNKNOWN_MODE_PAGE:
|
||||
case TCM_WRITE_PROTECTED:
|
||||
@@ -2674,6 +2678,15 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
|
||||
/* INVALID FIELD IN PARAMETER LIST */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x26;
|
||||
break;
|
||||
case TCM_PARAMETER_LIST_LENGTH_ERROR:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ILLEGAL REQUEST */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||||
/* PARAMETER LIST LENGTH ERROR */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x1a;
|
||||
break;
|
||||
case TCM_UNEXPECTED_UNSOLICITED_DATA:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
|
Reference in New Issue
Block a user