diff options
Diffstat (limited to 'drivers/target/target_core_device.c')
| -rw-r--r-- | drivers/target/target_core_device.c | 167 | 
1 files changed, 138 insertions, 29 deletions
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index d90dbb0f1a6..98da9016715 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -92,6 +92,9 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun)  		se_cmd->pr_res_key = deve->pr_res_key;  		se_cmd->orig_fe_lun = unpacked_lun;  		se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; + +		percpu_ref_get(&se_lun->lun_ref); +		se_cmd->lun_ref_active = true;  	}  	spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); @@ -119,24 +122,20 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun)  		se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0;  		se_cmd->orig_fe_lun = 0;  		se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; + +		percpu_ref_get(&se_lun->lun_ref); +		se_cmd->lun_ref_active = true;  	}  	/* Directly associate cmd with se_dev */  	se_cmd->se_dev = se_lun->lun_se_dev; -	/* TODO: get rid of this and use atomics for stats */  	dev = se_lun->lun_se_dev; -	spin_lock_irqsave(&dev->stats_lock, flags); -	dev->num_cmds++; +	atomic_long_inc(&dev->num_cmds);  	if (se_cmd->data_direction == DMA_TO_DEVICE) -		dev->write_bytes += se_cmd->data_length; +		atomic_long_add(se_cmd->data_length, &dev->write_bytes);  	else if (se_cmd->data_direction == DMA_FROM_DEVICE) -		dev->read_bytes += se_cmd->data_length; -	spin_unlock_irqrestore(&dev->stats_lock, flags); - -	spin_lock_irqsave(&se_lun->lun_cmd_lock, flags); -	list_add_tail(&se_cmd->se_lun_node, &se_lun->lun_cmd_list); -	spin_unlock_irqrestore(&se_lun->lun_cmd_lock, flags); +		atomic_long_add(se_cmd->data_length, &dev->read_bytes);  	return 0;  } @@ -226,7 +225,7 @@ struct se_dev_entry *core_get_se_deve_from_rtpi(  			continue;  		atomic_inc(&deve->pr_ref_count); -		smp_mb__after_atomic_inc(); +		smp_mb__after_atomic();  		spin_unlock_irq(&nacl->device_list_lock);  		return deve; @@ -314,14 +313,14 @@ int core_enable_device_list_for_node(  	deve = nacl->device_list[mapped_lun];  	/* -	 * Check if the call is handling demo mode -> explict LUN ACL +	 * Check if the call is handling demo mode -> explicit LUN ACL  	 * transition.  This transition must be for the same struct se_lun  	 * + mapped_lun that was setup in demo mode..  	 */  	if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {  		if (deve->se_lun_acl != NULL) {  			pr_err("struct se_dev_entry->se_lun_acl" -			       " already set for demo mode -> explict" +			       " already set for demo mode -> explicit"  			       " LUN ACL transition\n");  			spin_unlock_irq(&nacl->device_list_lock);  			return -EINVAL; @@ -329,7 +328,7 @@ int core_enable_device_list_for_node(  		if (deve->se_lun != lun) {  			pr_err("struct se_dev_entry->se_lun does"  			       " match passed struct se_lun for demo mode" -			       " -> explict LUN ACL transition\n"); +			       " -> explicit LUN ACL transition\n");  			spin_unlock_irq(&nacl->device_list_lock);  			return -EINVAL;  		} @@ -617,6 +616,7 @@ void core_dev_unexport(  	dev->export_count--;  	spin_unlock(&hba->device_lock); +	lun->lun_sep = NULL;  	lun->lun_se_dev = NULL;  } @@ -799,10 +799,10 @@ 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; +	if (flag && +	    dev->transport->get_write_cache) { +		pr_err("emulate_write_cache not supported for this device\n"); +		return -EINVAL;  	}  	dev->dev_attrib.emulate_write_cache = flag; @@ -919,6 +919,94 @@ int se_dev_set_emulate_3pc(struct se_device *dev, int flag)  	return 0;  } +int se_dev_set_pi_prot_type(struct se_device *dev, int flag) +{ +	int rc, old_prot = dev->dev_attrib.pi_prot_type; + +	if (flag != 0 && flag != 1 && flag != 2 && flag != 3) { +		pr_err("Illegal value %d for pi_prot_type\n", flag); +		return -EINVAL; +	} +	if (flag == 2) { +		pr_err("DIF TYPE2 protection currently not supported\n"); +		return -ENOSYS; +	} +	if (dev->dev_attrib.hw_pi_prot_type) { +		pr_warn("DIF protection enabled on underlying hardware," +			" ignoring\n"); +		return 0; +	} +	if (!dev->transport->init_prot || !dev->transport->free_prot) { +		/* 0 is only allowed value for non-supporting backends */ +		if (flag == 0) +			return 0; + +		pr_err("DIF protection not supported by backend: %s\n", +		       dev->transport->name); +		return -ENOSYS; +	} +	if (!(dev->dev_flags & DF_CONFIGURED)) { +		pr_err("DIF protection requires device to be configured\n"); +		return -ENODEV; +	} +	if (dev->export_count) { +		pr_err("dev[%p]: Unable to change SE Device PROT type while" +		       " export_count is %d\n", dev, dev->export_count); +		return -EINVAL; +	} + +	dev->dev_attrib.pi_prot_type = flag; + +	if (flag && !old_prot) { +		rc = dev->transport->init_prot(dev); +		if (rc) { +			dev->dev_attrib.pi_prot_type = old_prot; +			return rc; +		} + +	} else if (!flag && old_prot) { +		dev->transport->free_prot(dev); +	} +	pr_debug("dev[%p]: SE Device Protection Type: %d\n", dev, flag); + +	return 0; +} + +int se_dev_set_pi_prot_format(struct se_device *dev, int flag) +{ +	int rc; + +	if (!flag) +		return 0; + +	if (flag != 1) { +		pr_err("Illegal value %d for pi_prot_format\n", flag); +		return -EINVAL; +	} +	if (!dev->transport->format_prot) { +		pr_err("DIF protection format not supported by backend %s\n", +		       dev->transport->name); +		return -ENOSYS; +	} +	if (!(dev->dev_flags & DF_CONFIGURED)) { +		pr_err("DIF protection format requires device to be configured\n"); +		return -ENODEV; +	} +	if (dev->export_count) { +		pr_err("dev[%p]: Unable to format SE Device PROT type while" +		       " export_count is %d\n", dev, dev->export_count); +		return -EINVAL; +	} + +	rc = dev->transport->format_prot(dev); +	if (rc) +		return rc; + +	pr_debug("dev[%p]: SE Device Protection Format complete\n", dev); + +	return 0; +} +  int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag)  {  	if ((flag != 0) && (flag != 1)) { @@ -1107,29 +1195,34 @@ int se_dev_set_block_size(struct se_device *dev, u32 block_size)  	dev->dev_attrib.block_size = block_size;  	pr_debug("dev[%p]: SE Device block_size changed to %u\n",  			dev, block_size); + +	if (dev->dev_attrib.max_bytes_per_io) +		dev->dev_attrib.hw_max_sectors = +			dev->dev_attrib.max_bytes_per_io / block_size; +  	return 0;  }  struct se_lun *core_dev_add_lun(  	struct se_portal_group *tpg,  	struct se_device *dev, -	u32 lun) +	u32 unpacked_lun)  { -	struct se_lun *lun_p; +	struct se_lun *lun;  	int rc; -	lun_p = core_tpg_pre_addlun(tpg, lun); -	if (IS_ERR(lun_p)) -		return lun_p; +	lun = core_tpg_alloc_lun(tpg, unpacked_lun); +	if (IS_ERR(lun)) +		return lun; -	rc = core_tpg_post_addlun(tpg, lun_p, +	rc = core_tpg_add_lun(tpg, lun,  				TRANSPORT_LUNFLAGS_READ_WRITE, dev);  	if (rc < 0)  		return ERR_PTR(rc);  	pr_debug("%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from"  		" CORE HBA: %u\n", tpg->se_tpg_tfo->get_fabric_name(), -		tpg->se_tpg_tfo->tpg_get_tag(tpg), lun_p->unpacked_lun, +		tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun,  		tpg->se_tpg_tfo->get_fabric_name(), dev->se_hba->hba_id);  	/*  	 * Update LUN maps for dynamically added initiators when @@ -1150,7 +1243,7 @@ struct se_lun *core_dev_add_lun(  		spin_unlock_irq(&tpg->acl_node_lock);  	} -	return lun_p; +	return lun;  }  /*      core_dev_del_lun(): @@ -1304,7 +1397,7 @@ int core_dev_add_initiator_node_lun_acl(  	spin_lock(&lun->lun_acl_lock);  	list_add_tail(&lacl->lacl_list, &lun->lun_acl_list);  	atomic_inc(&lun->lun_acl_count); -	smp_mb__after_atomic_inc(); +	smp_mb__after_atomic();  	spin_unlock(&lun->lun_acl_lock);  	pr_debug("%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for " @@ -1338,7 +1431,7 @@ int core_dev_del_initiator_node_lun_acl(  	spin_lock(&lun->lun_acl_lock);  	list_del(&lacl->lacl_list);  	atomic_dec(&lun->lun_acl_count); -	smp_mb__after_atomic_dec(); +	smp_mb__after_atomic();  	spin_unlock(&lun->lun_acl_lock);  	core_disable_device_list_for_node(lun, NULL, lacl->mapped_lun, @@ -1407,6 +1500,7 @@ static void scsi_dump_inquiry(struct se_device *dev)  struct se_device *target_alloc_device(struct se_hba *hba, const char *name)  {  	struct se_device *dev; +	struct se_lun *xcopy_lun;  	dev = hba->transport->alloc_device(hba, name);  	if (!dev) @@ -1415,6 +1509,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)  	dev->dev_link_magic = SE_DEV_LINK_MAGIC;  	dev->se_hba = hba;  	dev->transport = hba->transport; +	dev->prot_length = sizeof(struct se_dif_v1_tuple);  	INIT_LIST_HEAD(&dev->dev_list);  	INIT_LIST_HEAD(&dev->dev_sep_list); @@ -1423,7 +1518,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)  	INIT_LIST_HEAD(&dev->state_list);  	INIT_LIST_HEAD(&dev->qf_cmd_list);  	INIT_LIST_HEAD(&dev->g_dev_node); -	spin_lock_init(&dev->stats_lock);  	spin_lock_init(&dev->execute_task_lock);  	spin_lock_init(&dev->delayed_cmd_lock);  	spin_lock_init(&dev->dev_reservation_lock); @@ -1440,6 +1534,8 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)  	spin_lock_init(&dev->t10_pr.aptpl_reg_lock);  	INIT_LIST_HEAD(&dev->t10_alua.tg_pt_gps_list);  	spin_lock_init(&dev->t10_alua.tg_pt_gps_lock); +	INIT_LIST_HEAD(&dev->t10_alua.lba_map_list); +	spin_lock_init(&dev->t10_alua.lba_map_lock);  	dev->t10_wwn.t10_dev = dev;  	dev->t10_alua.t10_dev = dev; @@ -1456,6 +1552,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)  	dev->dev_attrib.emulate_tpws = DA_EMULATE_TPWS;  	dev->dev_attrib.emulate_caw = DA_EMULATE_CAW;  	dev->dev_attrib.emulate_3pc = DA_EMULATE_3PC; +	dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE0_PROT;  	dev->dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS;  	dev->dev_attrib.is_nonrot = DA_IS_NONROT;  	dev->dev_attrib.emulate_rest_reord = DA_EMULATE_REST_REORD; @@ -1469,6 +1566,14 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)  	dev->dev_attrib.fabric_max_sectors = DA_FABRIC_MAX_SECTORS;  	dev->dev_attrib.optimal_sectors = DA_FABRIC_MAX_SECTORS; +	xcopy_lun = &dev->xcopy_lun; +	xcopy_lun->lun_se_dev = dev; +	init_completion(&xcopy_lun->lun_shutdown_comp); +	INIT_LIST_HEAD(&xcopy_lun->lun_acl_list); +	spin_lock_init(&xcopy_lun->lun_acl_lock); +	spin_lock_init(&xcopy_lun->lun_sep_lock); +	init_completion(&xcopy_lun->lun_ref_comp); +  	return dev;  } @@ -1576,9 +1681,13 @@ void target_free_device(struct se_device *dev)  	}  	core_alua_free_lu_gp_mem(dev); +	core_alua_set_lba_map(dev, NULL, 0, 0);  	core_scsi3_free_all_registrations(dev);  	se_release_vpd_for_dev(dev); +	if (dev->transport->free_prot) +		dev->transport->free_prot(dev); +  	dev->transport->free_device(dev);  }  | 
