diff options
Diffstat (limited to 'drivers/target/target_core_configfs.c')
| -rw-r--r-- | drivers/target/target_core_configfs.c | 324 | 
1 files changed, 307 insertions, 17 deletions
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 82e81c542e4..bf55c5a04cf 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -177,16 +177,16 @@ static struct config_group *target_core_register_fabric(  	 * struct target_fabric_configfs *tf will contain a usage reference.  	 */  	pr_debug("Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n", -			&TF_CIT_TMPL(tf)->tfc_wwn_cit); +			&tf->tf_cit_tmpl.tfc_wwn_cit);  	tf->tf_group.default_groups = tf->tf_default_groups;  	tf->tf_group.default_groups[0] = &tf->tf_disc_group;  	tf->tf_group.default_groups[1] = NULL;  	config_group_init_type_name(&tf->tf_group, name, -			&TF_CIT_TMPL(tf)->tfc_wwn_cit); +			&tf->tf_cit_tmpl.tfc_wwn_cit);  	config_group_init_type_name(&tf->tf_disc_group, "discovery_auth", -			&TF_CIT_TMPL(tf)->tfc_discovery_cit); +			&tf->tf_cit_tmpl.tfc_discovery_cit);  	pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:"  			" %s\n", tf->tf_group.cg_item.ci_name); @@ -457,6 +457,10 @@ static int target_fabric_tf_ops_check(  		pr_err("Missing tfo->queue_tm_rsp()\n");  		return -EINVAL;  	} +	if (!tfo->aborted_task) { +		pr_err("Missing tfo->aborted_task()\n"); +		return -EINVAL; +	}  	/*  	 * We at least require tfo->fabric_make_wwn(), tfo->fabric_drop_wwn()  	 * tfo->fabric_make_tpg() and tfo->fabric_drop_tpg() in @@ -643,6 +647,15 @@ SE_DEV_ATTR(emulate_caw, S_IRUGO | S_IWUSR);  DEF_DEV_ATTRIB(emulate_3pc);  SE_DEV_ATTR(emulate_3pc, S_IRUGO | S_IWUSR); +DEF_DEV_ATTRIB(pi_prot_type); +SE_DEV_ATTR(pi_prot_type, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB_RO(hw_pi_prot_type); +SE_DEV_ATTR_RO(hw_pi_prot_type); + +DEF_DEV_ATTRIB(pi_prot_format); +SE_DEV_ATTR(pi_prot_format, S_IRUGO | S_IWUSR); +  DEF_DEV_ATTRIB(enforce_pr_isids);  SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR); @@ -702,6 +715,9 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {  	&target_core_dev_attrib_emulate_tpws.attr,  	&target_core_dev_attrib_emulate_caw.attr,  	&target_core_dev_attrib_emulate_3pc.attr, +	&target_core_dev_attrib_pi_prot_type.attr, +	&target_core_dev_attrib_hw_pi_prot_type.attr, +	&target_core_dev_attrib_pi_prot_format.attr,  	&target_core_dev_attrib_enforce_pr_isids.attr,  	&target_core_dev_attrib_is_nonrot.attr,  	&target_core_dev_attrib_emulate_rest_reord.attr, @@ -1741,6 +1757,176 @@ static struct target_core_configfs_attribute target_core_attr_dev_alua_lu_gp = {  	.store	= target_core_store_alua_lu_gp,  }; +static ssize_t target_core_show_dev_lba_map(void *p, char *page) +{ +	struct se_device *dev = p; +	struct t10_alua_lba_map *map; +	struct t10_alua_lba_map_member *mem; +	char *b = page; +	int bl = 0; +	char state; + +	spin_lock(&dev->t10_alua.lba_map_lock); +	if (!list_empty(&dev->t10_alua.lba_map_list)) +	    bl += sprintf(b + bl, "%u %u\n", +			  dev->t10_alua.lba_map_segment_size, +			  dev->t10_alua.lba_map_segment_multiplier); +	list_for_each_entry(map, &dev->t10_alua.lba_map_list, lba_map_list) { +		bl += sprintf(b + bl, "%llu %llu", +			      map->lba_map_first_lba, map->lba_map_last_lba); +		list_for_each_entry(mem, &map->lba_map_mem_list, +				    lba_map_mem_list) { +			switch (mem->lba_map_mem_alua_state) { +			case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: +				state = 'O'; +				break; +			case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: +				state = 'A'; +				break; +			case ALUA_ACCESS_STATE_STANDBY: +				state = 'S'; +				break; +			case ALUA_ACCESS_STATE_UNAVAILABLE: +				state = 'U'; +				break; +			default: +				state = '.'; +				break; +			} +			bl += sprintf(b + bl, " %d:%c", +				      mem->lba_map_mem_alua_pg_id, state); +		} +		bl += sprintf(b + bl, "\n"); +	} +	spin_unlock(&dev->t10_alua.lba_map_lock); +	return bl; +} + +static ssize_t target_core_store_dev_lba_map( +	void *p, +	const char *page, +	size_t count) +{ +	struct se_device *dev = p; +	struct t10_alua_lba_map *lba_map = NULL; +	struct list_head lba_list; +	char *map_entries, *ptr; +	char state; +	int pg_num = -1, pg; +	int ret = 0, num = 0, pg_id, alua_state; +	unsigned long start_lba = -1, end_lba = -1; +	unsigned long segment_size = -1, segment_mult = -1; + +	map_entries = kstrdup(page, GFP_KERNEL); +	if (!map_entries) +		return -ENOMEM; + +	INIT_LIST_HEAD(&lba_list); +	while ((ptr = strsep(&map_entries, "\n")) != NULL) { +		if (!*ptr) +			continue; + +		if (num == 0) { +			if (sscanf(ptr, "%lu %lu\n", +				   &segment_size, &segment_mult) != 2) { +				pr_err("Invalid line %d\n", num); +				ret = -EINVAL; +				break; +			} +			num++; +			continue; +		} +		if (sscanf(ptr, "%lu %lu", &start_lba, &end_lba) != 2) { +			pr_err("Invalid line %d\n", num); +			ret = -EINVAL; +			break; +		} +		ptr = strchr(ptr, ' '); +		if (!ptr) { +			pr_err("Invalid line %d, missing end lba\n", num); +			ret = -EINVAL; +			break; +		} +		ptr++; +		ptr = strchr(ptr, ' '); +		if (!ptr) { +			pr_err("Invalid line %d, missing state definitions\n", +			       num); +			ret = -EINVAL; +			break; +		} +		ptr++; +		lba_map = core_alua_allocate_lba_map(&lba_list, +						     start_lba, end_lba); +		if (IS_ERR(lba_map)) { +			ret = PTR_ERR(lba_map); +			break; +		} +		pg = 0; +		while (sscanf(ptr, "%d:%c", &pg_id, &state) == 2) { +			switch (state) { +			case 'O': +				alua_state = ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED; +				break; +			case 'A': +				alua_state = ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED; +				break; +			case 'S': +				alua_state = ALUA_ACCESS_STATE_STANDBY; +				break; +			case 'U': +				alua_state = ALUA_ACCESS_STATE_UNAVAILABLE; +				break; +			default: +				pr_err("Invalid ALUA state '%c'\n", state); +				ret = -EINVAL; +				goto out; +			} + +			ret = core_alua_allocate_lba_map_mem(lba_map, +							     pg_id, alua_state); +			if (ret) { +				pr_err("Invalid target descriptor %d:%c " +				       "at line %d\n", +				       pg_id, state, num); +				break; +			} +			pg++; +			ptr = strchr(ptr, ' '); +			if (ptr) +				ptr++; +			else +				break; +		} +		if (pg_num == -1) +		    pg_num = pg; +		else if (pg != pg_num) { +			pr_err("Only %d from %d port groups definitions " +			       "at line %d\n", pg, pg_num, num); +			ret = -EINVAL; +			break; +		} +		num++; +	} +out: +	if (ret) { +		core_alua_free_lba_map(&lba_list); +		count = ret; +	} else +		core_alua_set_lba_map(dev, &lba_list, +				      segment_size, segment_mult); +	kfree(map_entries); +	return count; +} + +static struct target_core_configfs_attribute target_core_attr_dev_lba_map = { +	.attr	= { .ca_owner = THIS_MODULE, +		    .ca_name = "lba_map", +		    .ca_mode = S_IRUGO | S_IWUSR }, +	.show	= target_core_show_dev_lba_map, +	.store	= target_core_store_dev_lba_map, +}; +  static struct configfs_attribute *lio_core_dev_attrs[] = {  	&target_core_attr_dev_info.attr,  	&target_core_attr_dev_control.attr, @@ -1748,6 +1934,7 @@ static struct configfs_attribute *lio_core_dev_attrs[] = {  	&target_core_attr_dev_udev_path.attr,  	&target_core_attr_dev_enable.attr,  	&target_core_attr_dev_alua_lu_gp.attr, +	&target_core_attr_dev_lba_map.attr,  	NULL,  }; @@ -2036,10 +2223,15 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(  	int new_state, ret;  	if (!tg_pt_gp->tg_pt_gp_valid_id) { -		pr_err("Unable to do implict ALUA on non valid" +		pr_err("Unable to do implicit ALUA on non valid"  			" tg_pt_gp ID: %hu\n", tg_pt_gp->tg_pt_gp_valid_id);  		return -EINVAL;  	} +	if (!(dev->dev_flags & DF_CONFIGURED)) { +		pr_err("Unable to set alua_access_state while device is" +		       " not configured\n"); +		return -ENODEV; +	}  	ret = kstrtoul(page, 0, &tmp);  	if (ret < 0) { @@ -2049,9 +2241,16 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(  	}  	new_state = (int)tmp; -	if (!(tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA)) { -		pr_err("Unable to process implict configfs ALUA" -			" transition while TPGS_IMPLICT_ALUA is disabled\n"); +	if (!(tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICIT_ALUA)) { +		pr_err("Unable to process implicit configfs ALUA" +			" transition while TPGS_IMPLICIT_ALUA is disabled\n"); +		return -EINVAL; +	} +	if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA && +	    new_state == ALUA_ACCESS_STATE_LBA_DEPENDENT) { +		/* LBA DEPENDENT is only allowed with implicit ALUA */ +		pr_err("Unable to process implicit configfs ALUA transition" +		       " while explicit ALUA management is enabled\n");  		return -EINVAL;  	} @@ -2097,8 +2296,8 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status(  	new_status = (int)tmp;  	if ((new_status != ALUA_STATUS_NONE) && -	    (new_status != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) && -	    (new_status != ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA)) { +	    (new_status != ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) && +	    (new_status != ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA)) {  		pr_err("Illegal ALUA access status: 0x%02x\n",  				new_status);  		return -EINVAL; @@ -2131,6 +2330,90 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_type(  SE_DEV_ALUA_TG_PT_ATTR(alua_access_type, S_IRUGO | S_IWUSR);  /* + * alua_supported_states + */ + +#define SE_DEV_ALUA_SUPPORT_STATE_SHOW(_name, _var, _bit)		\ +static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_support_##_name( \ +	struct t10_alua_tg_pt_gp *t, char *p)				\ +{									\ +	return sprintf(p, "%d\n", !!(t->_var & _bit));			\ +} + +#define SE_DEV_ALUA_SUPPORT_STATE_STORE(_name, _var, _bit)		\ +static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_support_##_name(\ +	struct t10_alua_tg_pt_gp *t, const char *p, size_t c)		\ +{									\ +	unsigned long tmp;						\ +	int ret;							\ +									\ +	if (!t->tg_pt_gp_valid_id) {					\ +		pr_err("Unable to do set ##_name ALUA state on non"	\ +		       " valid tg_pt_gp ID: %hu\n",			\ +		       t->tg_pt_gp_valid_id);				\ +		return -EINVAL;						\ +	}								\ +									\ +	ret = kstrtoul(p, 0, &tmp);					\ +	if (ret < 0) {							\ +		pr_err("Invalid value '%s', must be '0' or '1'\n", p);	\ +		return -EINVAL;						\ +	}								\ +	if (tmp > 1) {							\ +		pr_err("Invalid value '%ld', must be '0' or '1'\n", tmp); \ +		return -EINVAL;						\ +	}								\ +	if (!tmp)							\ +		t->_var |= _bit;					\ +	else								\ +		t->_var &= ~_bit;					\ +									\ +	return c;							\ +} + +SE_DEV_ALUA_SUPPORT_STATE_SHOW(transitioning, +			       tg_pt_gp_alua_supported_states, ALUA_T_SUP); +SE_DEV_ALUA_SUPPORT_STATE_STORE(transitioning, +				tg_pt_gp_alua_supported_states, ALUA_T_SUP); +SE_DEV_ALUA_TG_PT_ATTR(alua_support_transitioning, S_IRUGO | S_IWUSR); + +SE_DEV_ALUA_SUPPORT_STATE_SHOW(offline, +			       tg_pt_gp_alua_supported_states, ALUA_O_SUP); +SE_DEV_ALUA_SUPPORT_STATE_STORE(offline, +				tg_pt_gp_alua_supported_states, ALUA_O_SUP); +SE_DEV_ALUA_TG_PT_ATTR(alua_support_offline, S_IRUGO | S_IWUSR); + +SE_DEV_ALUA_SUPPORT_STATE_SHOW(lba_dependent, +			       tg_pt_gp_alua_supported_states, ALUA_LBD_SUP); +SE_DEV_ALUA_SUPPORT_STATE_STORE(lba_dependent, +				tg_pt_gp_alua_supported_states, ALUA_LBD_SUP); +SE_DEV_ALUA_TG_PT_ATTR(alua_support_lba_dependent, S_IRUGO); + +SE_DEV_ALUA_SUPPORT_STATE_SHOW(unavailable, +			       tg_pt_gp_alua_supported_states, ALUA_U_SUP); +SE_DEV_ALUA_SUPPORT_STATE_STORE(unavailable, +				tg_pt_gp_alua_supported_states, ALUA_U_SUP); +SE_DEV_ALUA_TG_PT_ATTR(alua_support_unavailable, S_IRUGO | S_IWUSR); + +SE_DEV_ALUA_SUPPORT_STATE_SHOW(standby, +			       tg_pt_gp_alua_supported_states, ALUA_S_SUP); +SE_DEV_ALUA_SUPPORT_STATE_STORE(standby, +				tg_pt_gp_alua_supported_states, ALUA_S_SUP); +SE_DEV_ALUA_TG_PT_ATTR(alua_support_standby, S_IRUGO | S_IWUSR); + +SE_DEV_ALUA_SUPPORT_STATE_SHOW(active_optimized, +			       tg_pt_gp_alua_supported_states, ALUA_AO_SUP); +SE_DEV_ALUA_SUPPORT_STATE_STORE(active_optimized, +				tg_pt_gp_alua_supported_states, ALUA_AO_SUP); +SE_DEV_ALUA_TG_PT_ATTR(alua_support_active_optimized, S_IRUGO | S_IWUSR); + +SE_DEV_ALUA_SUPPORT_STATE_SHOW(active_nonoptimized, +			       tg_pt_gp_alua_supported_states, ALUA_AN_SUP); +SE_DEV_ALUA_SUPPORT_STATE_STORE(active_nonoptimized, +				tg_pt_gp_alua_supported_states, ALUA_AN_SUP); +SE_DEV_ALUA_TG_PT_ATTR(alua_support_active_nonoptimized, S_IRUGO | S_IWUSR); + +/*   * alua_write_metadata   */  static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_write_metadata( @@ -2210,24 +2493,24 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_trans_delay_msecs(  SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR);  /* - * implict_trans_secs + * implicit_trans_secs   */ -static ssize_t target_core_alua_tg_pt_gp_show_attr_implict_trans_secs( +static ssize_t target_core_alua_tg_pt_gp_show_attr_implicit_trans_secs(  	struct t10_alua_tg_pt_gp *tg_pt_gp,  	char *page)  { -	return core_alua_show_implict_trans_secs(tg_pt_gp, page); +	return core_alua_show_implicit_trans_secs(tg_pt_gp, page);  } -static ssize_t target_core_alua_tg_pt_gp_store_attr_implict_trans_secs( +static ssize_t target_core_alua_tg_pt_gp_store_attr_implicit_trans_secs(  	struct t10_alua_tg_pt_gp *tg_pt_gp,  	const char *page,  	size_t count)  { -	return core_alua_store_implict_trans_secs(tg_pt_gp, page, count); +	return core_alua_store_implicit_trans_secs(tg_pt_gp, page, count);  } -SE_DEV_ALUA_TG_PT_ATTR(implict_trans_secs, S_IRUGO | S_IWUSR); +SE_DEV_ALUA_TG_PT_ATTR(implicit_trans_secs, S_IRUGO | S_IWUSR);  /*   * preferred @@ -2350,10 +2633,17 @@ static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = {  	&target_core_alua_tg_pt_gp_alua_access_state.attr,  	&target_core_alua_tg_pt_gp_alua_access_status.attr,  	&target_core_alua_tg_pt_gp_alua_access_type.attr, +	&target_core_alua_tg_pt_gp_alua_support_transitioning.attr, +	&target_core_alua_tg_pt_gp_alua_support_offline.attr, +	&target_core_alua_tg_pt_gp_alua_support_lba_dependent.attr, +	&target_core_alua_tg_pt_gp_alua_support_unavailable.attr, +	&target_core_alua_tg_pt_gp_alua_support_standby.attr, +	&target_core_alua_tg_pt_gp_alua_support_active_nonoptimized.attr, +	&target_core_alua_tg_pt_gp_alua_support_active_optimized.attr,  	&target_core_alua_tg_pt_gp_alua_write_metadata.attr,  	&target_core_alua_tg_pt_gp_nonop_delay_msecs.attr,  	&target_core_alua_tg_pt_gp_trans_delay_msecs.attr, -	&target_core_alua_tg_pt_gp_implict_trans_secs.attr, +	&target_core_alua_tg_pt_gp_implicit_trans_secs.attr,  	&target_core_alua_tg_pt_gp_preferred.attr,  	&target_core_alua_tg_pt_gp_tg_pt_gp_id.attr,  	&target_core_alua_tg_pt_gp_members.attr, @@ -2846,7 +3136,7 @@ static int __init target_core_init_configfs(void)  	 * and ALUA Logical Unit Group and Target Port Group infrastructure.  	 */  	target_cg = &subsys->su_group; -	target_cg->default_groups = kmalloc(sizeof(struct config_group) * 2, +	target_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,  				GFP_KERNEL);  	if (!target_cg->default_groups) {  		pr_err("Unable to allocate target_cg->default_groups\n");  | 
