Ejemplo n.º 1
0
int iscsit_get_lun_for_tmr(
	struct iscsi_cmd *cmd,
	u64 lun)
{
	u32 unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);

	return transport_lookup_tmr_lun(&cmd->se_cmd, unpacked_lun);
}
Ejemplo n.º 2
0
static void ft_send_work(struct work_struct *work)
{
	struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
	struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
	struct fcp_cmnd *fcp;
	int data_dir = 0;
	int task_attr;

	fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
	if (!fcp)
		goto err;

	if (fcp->fc_flags & FCP_CFL_LEN_MASK)
		goto err;		

	if (fcp->fc_tm_flags) {
		ft_send_tm(cmd);
		return;
	}

	switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) {
	case 0:
		data_dir = DMA_NONE;
		break;
	case FCP_CFL_RDDATA:
		data_dir = DMA_FROM_DEVICE;
		break;
	case FCP_CFL_WRDATA:
		data_dir = DMA_TO_DEVICE;
		break;
	case FCP_CFL_WRDATA | FCP_CFL_RDDATA:
		goto err;	
	}
	switch (fcp->fc_pri_ta & FCP_PTA_MASK) {
	case FCP_PTA_HEADQ:
		task_attr = MSG_HEAD_TAG;
		break;
	case FCP_PTA_ORDERED:
		task_attr = MSG_ORDERED_TAG;
		break;
	case FCP_PTA_ACA:
		task_attr = MSG_ACA_TAG;
		break;
	case FCP_PTA_SIMPLE: 
	default:
		task_attr = MSG_SIMPLE_TAG;
	}

	fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd);
	target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb,
			&cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
			ntohl(fcp->fc_dl), task_attr, data_dir, 0);
	pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl);
	return;

err:
	ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
}
Ejemplo n.º 3
0
static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
					    struct device_attribute *attr,
					    const char *buf, size_t count)
{
	struct zfcp_port *port = dev_get_drvdata(dev);
	struct zfcp_unit *unit;
	u64 fcp_lun;
	LIST_HEAD(unit_remove_lh);
	struct scsi_device *sdev;

	mutex_lock(&zfcp_data.config_mutex);
	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) {
		mutex_unlock(&zfcp_data.config_mutex);
		return -EBUSY;
	}

	if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) {
		mutex_unlock(&zfcp_data.config_mutex);
		return -EINVAL;
	}

	read_lock_irq(&zfcp_data.config_lock);
	unit = zfcp_get_unit_by_lun(port, fcp_lun);
	read_unlock_irq(&zfcp_data.config_lock);
	if (!unit) {
		mutex_unlock(&zfcp_data.config_mutex);
		return -ENXIO;
	}
	zfcp_unit_get(unit);
	mutex_unlock(&zfcp_data.config_mutex);

	sdev = scsi_device_lookup(port->adapter->scsi_host, 0,
				  port->starget_id,
				  scsilun_to_int((struct scsi_lun *)&fcp_lun));
	if (sdev) {
		scsi_remove_device(sdev);
		scsi_device_put(sdev);
	}

	mutex_lock(&zfcp_data.config_mutex);
	zfcp_unit_put(unit);
	if (atomic_read(&unit->refcount)) {
		mutex_unlock(&zfcp_data.config_mutex);
		return -ENXIO;
	}

	write_lock_irq(&zfcp_data.config_lock);
	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
	list_move(&unit->list, &unit_remove_lh);
	write_unlock_irq(&zfcp_data.config_lock);
	mutex_unlock(&zfcp_data.config_mutex);

	zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL);
	zfcp_erp_wait(unit->port->adapter);
	zfcp_unit_dequeue(unit);

	return (ssize_t)count;
}
Ejemplo n.º 4
0
int iscsit_get_lun_for_cmd(
	struct iscsi_cmd *cmd,
	unsigned char *cdb,
	u64 lun)
{
	u32 unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);

	return transport_lookup_cmd_lun(&cmd->se_cmd, unpacked_lun);
}
Ejemplo n.º 5
0
static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
					    struct device_attribute *attr,
					    const char *buf, size_t count)
{
	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
	struct zfcp_unit *unit;
	u64 fcp_lun;
	int retval = -EINVAL;
	struct scsi_device *sdev;

	if (!(port && get_device(&port->dev)))
		return -EBUSY;

	if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
		goto out;

	unit = zfcp_get_unit_by_lun(port, fcp_lun);
	if (!unit)
		goto out;
	else
		retval = 0;

	sdev = scsi_device_lookup(port->adapter->scsi_host, 0,
				  port->starget_id,
				  scsilun_to_int((struct scsi_lun *)&fcp_lun));
	if (sdev) {
		scsi_remove_device(sdev);
		scsi_device_put(sdev);
	}

	write_lock_irq(&port->unit_list_lock);
	list_del(&unit->list);
	write_unlock_irq(&port->unit_list_lock);

	put_device(&unit->dev);

	zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL);
	zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs);
out:
	put_device(&port->dev);
	return retval ? retval : (ssize_t) count;
}
Ejemplo n.º 6
0
/*
 * Handle Task Management Request.
 */
static void ft_send_tm(struct ft_cmd *cmd)
{
	struct fcp_cmnd *fcp;
	int rc;
	u8 tm_func;

	fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));

	switch (fcp->fc_tm_flags) {
	case FCP_TMF_LUN_RESET:
		tm_func = TMR_LUN_RESET;
		break;
	case FCP_TMF_TGT_RESET:
		tm_func = TMR_TARGET_WARM_RESET;
		break;
	case FCP_TMF_CLR_TASK_SET:
		tm_func = TMR_CLEAR_TASK_SET;
		break;
	case FCP_TMF_ABT_TASK_SET:
		tm_func = TMR_ABORT_TASK_SET;
		break;
	case FCP_TMF_CLR_ACA:
		tm_func = TMR_CLEAR_ACA;
		break;
	default:
		/*
		 * FCP4r01 indicates having a combination of
		 * tm_flags set is invalid.
		 */
		pr_debug("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
		ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
		return;
	}

	/* FIXME: Add referenced task tag for ABORT_TASK */
	rc = target_submit_tmr(&cmd->se_cmd, cmd->sess->se_sess,
		&cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
		cmd, tm_func, GFP_KERNEL, 0, 0);
	if (rc < 0)
		ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
}
Ejemplo n.º 7
0
/*
 * Send new command to target.
 */
static void ft_send_work(struct work_struct *work)
{
	struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
	struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
	struct fcp_cmnd *fcp;
	int data_dir = 0;
	int task_attr;

	fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
	if (!fcp)
		goto err;

	if (fcp->fc_flags & FCP_CFL_LEN_MASK)
		goto err;		/* not handling longer CDBs yet */

	/*
	 * Check for FCP task management flags
	 */
	if (fcp->fc_tm_flags) {
		ft_send_tm(cmd);
		return;
	}

	switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) {
	case 0:
		data_dir = DMA_NONE;
		break;
	case FCP_CFL_RDDATA:
		data_dir = DMA_FROM_DEVICE;
		break;
	case FCP_CFL_WRDATA:
		data_dir = DMA_TO_DEVICE;
		break;
	case FCP_CFL_WRDATA | FCP_CFL_RDDATA:
		goto err;	/* TBD not supported by tcm_fc yet */
	}
	/*
	 * Locate the SAM Task Attr from fc_pri_ta
	 */
	switch (fcp->fc_pri_ta & FCP_PTA_MASK) {
	case FCP_PTA_HEADQ:
		task_attr = MSG_HEAD_TAG;
		break;
	case FCP_PTA_ORDERED:
		task_attr = MSG_ORDERED_TAG;
		break;
	case FCP_PTA_ACA:
		task_attr = MSG_ACA_TAG;
		break;
	case FCP_PTA_SIMPLE: /* Fallthrough */
	default:
		task_attr = MSG_SIMPLE_TAG;
	}

	fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd);
	/*
	 * Use a single se_cmd->cmd_kref as we expect to release se_cmd
	 * directly from ft_check_stop_free callback in response path.
	 */
	if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb,
			      &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
			      ntohl(fcp->fc_dl), task_attr, data_dir, 0))
		goto err;

	pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl);
	return;

err:
	ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
}
Ejemplo n.º 8
0
/*
 * Send new command to target.
 */
static void ft_send_cmd(struct ft_cmd *cmd)
{
	struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
	struct se_cmd *se_cmd;
	struct fcp_cmnd *fcp;
	int data_dir;
	u32 data_len;
	int task_attr;
	int ret;

	fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
	if (!fcp)
		goto err;

	if (fcp->fc_flags & FCP_CFL_LEN_MASK)
		goto err;		/* not handling longer CDBs yet */

	if (fcp->fc_tm_flags) {
		task_attr = FCP_PTA_SIMPLE;
		data_dir = DMA_NONE;
		data_len = 0;
	} else {
		switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) {
		case 0:
			data_dir = DMA_NONE;
			break;
		case FCP_CFL_RDDATA:
			data_dir = DMA_FROM_DEVICE;
			break;
		case FCP_CFL_WRDATA:
			data_dir = DMA_TO_DEVICE;
			break;
		case FCP_CFL_WRDATA | FCP_CFL_RDDATA:
			goto err;	/* TBD not supported by tcm_fc yet */
		}
		/*
		 * Locate the SAM Task Attr from fc_pri_ta
		 */
		switch (fcp->fc_pri_ta & FCP_PTA_MASK) {
		case FCP_PTA_HEADQ:
			task_attr = MSG_HEAD_TAG;
			break;
		case FCP_PTA_ORDERED:
			task_attr = MSG_ORDERED_TAG;
			break;
		case FCP_PTA_ACA:
			task_attr = MSG_ACA_TAG;
			break;
		case FCP_PTA_SIMPLE: /* Fallthrough */
		default:
			task_attr = MSG_SIMPLE_TAG;
		}


		task_attr = fcp->fc_pri_ta & FCP_PTA_MASK;
		data_len = ntohl(fcp->fc_dl);
		cmd->cdb = fcp->fc_cdb;
	}

	se_cmd = &cmd->se_cmd;
	/*
	 * Initialize struct se_cmd descriptor from target_core_mod
	 * infrastructure
	 */
	transport_init_se_cmd(se_cmd, &ft_configfs->tf_ops, cmd->sess->se_sess,
			      data_len, data_dir, task_attr,
			      &cmd->ft_sense_buffer[0]);
	/*
	 * Check for FCP task management flags
	 */
	if (fcp->fc_tm_flags) {
		ft_send_tm(cmd);
		return;
	}

	fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd);

	cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun);
	ret = transport_get_lun_for_cmd(&cmd->se_cmd, NULL, cmd->lun);
	if (ret < 0) {
		ft_dump_cmd(cmd, __func__);
		transport_send_check_condition_and_sense(&cmd->se_cmd,
			cmd->se_cmd.scsi_sense_reason, 0);
		return;
	}

	ret = transport_generic_allocate_tasks(se_cmd, cmd->cdb);

	FT_IO_DBG("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret);
	ft_dump_cmd(cmd, __func__);

	if (ret == -1) {
		transport_send_check_condition_and_sense(se_cmd,
				TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
		transport_generic_free_cmd(se_cmd, 0, 1, 0);
		return;
	}
	if (ret == -2) {
		if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
			ft_queue_status(se_cmd);
		else
			transport_send_check_condition_and_sense(se_cmd,
					se_cmd->scsi_sense_reason, 0);
		transport_generic_free_cmd(se_cmd, 0, 1, 0);
		return;
	}
	transport_generic_handle_cdb(se_cmd);
	return;

err:
	ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID);
	return;
}
Ejemplo n.º 9
0
/*
 * Handle Task Management Request.
 */
static void ft_send_tm(struct ft_cmd *cmd)
{
	struct se_tmr_req *tmr;
	struct fcp_cmnd *fcp;
	struct ft_sess *sess;
	u8 tm_func;

	fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));

	switch (fcp->fc_tm_flags) {
	case FCP_TMF_LUN_RESET:
		tm_func = TMR_LUN_RESET;
		break;
	case FCP_TMF_TGT_RESET:
		tm_func = TMR_TARGET_WARM_RESET;
		break;
	case FCP_TMF_CLR_TASK_SET:
		tm_func = TMR_CLEAR_TASK_SET;
		break;
	case FCP_TMF_ABT_TASK_SET:
		tm_func = TMR_ABORT_TASK_SET;
		break;
	case FCP_TMF_CLR_ACA:
		tm_func = TMR_CLEAR_ACA;
		break;
	default:
		/*
		 * FCP4r01 indicates having a combination of
		 * tm_flags set is invalid.
		 */
		FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
		ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID);
		return;
	}

	FT_TM_DBG("alloc tm cmd fn %d\n", tm_func);
	tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func);
	if (!tmr) {
		FT_TM_DBG("alloc failed\n");
		ft_send_resp_code(cmd, FCP_TMF_FAILED);
		return;
	}
	cmd->se_cmd.se_tmr_req = tmr;

	switch (fcp->fc_tm_flags) {
	case FCP_TMF_LUN_RESET:
		cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun);
		if (transport_get_lun_for_tmr(&cmd->se_cmd, cmd->lun) < 0) {
			/*
			 * Make sure to clean up newly allocated TMR request
			 * since "unable to  handle TMR request because failed
			 * to get to LUN"
			 */
			FT_TM_DBG("Failed to get LUN for TMR func %d, "
				  "se_cmd %p, unpacked_lun %d\n",
				  tm_func, &cmd->se_cmd, cmd->lun);
			ft_dump_cmd(cmd, __func__);
			sess = cmd->sess;
			transport_send_check_condition_and_sense(&cmd->se_cmd,
				cmd->se_cmd.scsi_sense_reason, 0);
			transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0);
			ft_sess_put(sess);
			return;
		}
		break;
	case FCP_TMF_TGT_RESET:
	case FCP_TMF_CLR_TASK_SET:
	case FCP_TMF_ABT_TASK_SET:
	case FCP_TMF_CLR_ACA:
		break;
	default:
		return;
	}
	transport_generic_handle_tmr(&cmd->se_cmd);
}
Ejemplo n.º 10
0
/**
 * zfcp_unit_enqueue - enqueue unit to unit list of a port.
 * @port: pointer to port where unit is added
 * @fcp_lun: FCP LUN of unit to be enqueued
 * Returns: pointer to enqueued unit on success, ERR_PTR on error
 * Locks: config_sema must be held to serialize changes to the unit list
 *
 * Sets up some unit internal structures and creates sysfs entry.
 */
struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
{
	struct zfcp_unit *unit;

	unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
	if (!unit)
		return ERR_PTR(-ENOMEM);

	atomic_set(&unit->refcount, 0);
	init_waitqueue_head(&unit->remove_wq);

	unit->port = port;
	unit->fcp_lun = fcp_lun;

	snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", fcp_lun);
	unit->sysfs_device.parent = &port->sysfs_device;
	unit->sysfs_device.release = zfcp_sysfs_unit_release;
	dev_set_drvdata(&unit->sysfs_device, unit);

	/* mark unit unusable as long as sysfs registration is not complete */
	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);

	spin_lock_init(&unit->latencies.lock);
	unit->latencies.write.channel.min = 0xFFFFFFFF;
	unit->latencies.write.fabric.min = 0xFFFFFFFF;
	unit->latencies.read.channel.min = 0xFFFFFFFF;
	unit->latencies.read.fabric.min = 0xFFFFFFFF;
	unit->latencies.cmd.channel.min = 0xFFFFFFFF;
	unit->latencies.cmd.fabric.min = 0xFFFFFFFF;

	read_lock_irq(&zfcp_data.config_lock);
	if (zfcp_get_unit_by_lun(port, fcp_lun)) {
		read_unlock_irq(&zfcp_data.config_lock);
		goto err_out_free;
	}
	read_unlock_irq(&zfcp_data.config_lock);

	if (device_register(&unit->sysfs_device))
		goto err_out_free;

	if (sysfs_create_group(&unit->sysfs_device.kobj,
			       &zfcp_sysfs_unit_attrs)) {
		device_unregister(&unit->sysfs_device);
		return ERR_PTR(-EIO);
	}

	zfcp_unit_get(unit);
	unit->scsi_lun = scsilun_to_int((struct scsi_lun *)&unit->fcp_lun);

	write_lock_irq(&zfcp_data.config_lock);
	list_add_tail(&unit->list, &port->unit_list_head);
	atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
	atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status);

	write_unlock_irq(&zfcp_data.config_lock);

	port->units++;
	zfcp_port_get(port);

	return unit;

err_out_free:
	kfree(unit);
	return ERR_PTR(-EINVAL);
}