drivers/target/iscsi/iscsi_target_util.c

Source file repositories/reference/linux-study-clean/drivers/target/iscsi/iscsi_target_util.c

File Facts

System
Linux kernel
Corpus path
drivers/target/iscsi/iscsi_target_util.c
Extension
.c
Size
34701 bytes
Lines
1375
Domain
Driver Families
Bucket
drivers/target
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!r2t->sent_r2t) {
			spin_unlock_bh(&cmd->r2t_lock);
			return r2t;
		}
	}
	spin_unlock_bh(&cmd->r2t_lock);

	pr_err("Unable to locate next R2T to send for ITT:"
			" 0x%08x.\n", cmd->init_task_tag);
	return NULL;
}

void iscsit_free_r2t(struct iscsi_r2t *r2t, struct iscsit_cmd *cmd)
{
	lockdep_assert_held(&cmd->r2t_lock);

	list_del(&r2t->r2t_list);
	kmem_cache_free(lio_r2t_cache, r2t);
}

void iscsit_free_r2ts_from_list(struct iscsit_cmd *cmd)
{
	struct iscsi_r2t *r2t, *r2t_tmp;

	spin_lock_bh(&cmd->r2t_lock);
	list_for_each_entry_safe(r2t, r2t_tmp, &cmd->cmd_r2t_list, r2t_list)
		iscsit_free_r2t(r2t, cmd);
	spin_unlock_bh(&cmd->r2t_lock);
}

static int iscsit_wait_for_tag(struct se_session *se_sess, int state, int *cpup)
{
	int tag = -1;
	DEFINE_SBQ_WAIT(wait);
	struct sbq_wait_state *ws;
	struct sbitmap_queue *sbq;

	if (state == TASK_RUNNING)
		return tag;

	sbq = &se_sess->sess_tag_pool;
	ws = &sbq->ws[0];
	for (;;) {
		sbitmap_prepare_to_wait(sbq, ws, &wait, state);
		if (signal_pending_state(state, current))
			break;
		tag = sbitmap_queue_get(sbq, cpup);
		if (tag >= 0)
			break;
		schedule();
	}

	sbitmap_finish_wait(sbq, ws, &wait);
	return tag;
}

/*
 * May be called from software interrupt (timer) context for allocating
 * iSCSI NopINs.
 */
struct iscsit_cmd *iscsit_allocate_cmd(struct iscsit_conn *conn, int state)
{
	struct iscsit_cmd *cmd;
	struct se_session *se_sess = conn->sess->se_sess;
	int size, tag, cpu;

	tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
	if (tag < 0)
		tag = iscsit_wait_for_tag(se_sess, state, &cpu);
	if (tag < 0)
		return NULL;

	size = sizeof(struct iscsit_cmd) + conn->conn_transport->priv_size;
	cmd = (struct iscsit_cmd *)(se_sess->sess_cmd_map + (tag * size));
	memset(cmd, 0, size);

	cmd->se_cmd.map_tag = tag;
	cmd->se_cmd.map_cpu = cpu;
	cmd->conn = conn;
	cmd->data_direction = DMA_NONE;
	INIT_LIST_HEAD(&cmd->i_conn_node);
	INIT_LIST_HEAD(&cmd->datain_list);
	INIT_LIST_HEAD(&cmd->cmd_r2t_list);
	spin_lock_init(&cmd->datain_lock);
	spin_lock_init(&cmd->dataout_timeout_lock);
	spin_lock_init(&cmd->istate_lock);
	spin_lock_init(&cmd->error_lock);
	spin_lock_init(&cmd->r2t_lock);
	timer_setup(&cmd->dataout_timer, iscsit_handle_dataout_timeout, 0);

Annotation

Implementation Notes