drivers/target/tcm_fc/tfc_sess.c

Source file repositories/reference/linux-study-clean/drivers/target/tcm_fc/tfc_sess.c

File Facts

System
Linux kernel
Corpus path
drivers/target/tcm_fc/tfc_sess.c
Extension
.c
Size
11574 bytes
Lines
504
Domain
Driver Families
Bucket
drivers/target
Inferred role
Driver Families: implementation source
Status
source 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 (sess->port_id == port_id) {
			kref_get(&sess->kref);
			rcu_read_unlock();
			TFC_SESS_DBG(lport, "port_id %x found %p\n",
				     port_id, sess);
			return sess;
		}
	}
out:
	rcu_read_unlock();
	TFC_SESS_DBG(lport, "port_id %x not found, %s\n",
		     port_id, reason);
	return NULL;
}

static int ft_sess_alloc_cb(struct se_portal_group *se_tpg,
			    struct se_session *se_sess, void *p)
{
	struct ft_sess *sess = p;
	struct ft_tport *tport = sess->tport;
	struct hlist_head *head = &tport->hash[ft_sess_hash(sess->port_id)];

	TFC_SESS_DBG(tport->lport, "port_id %x sess %p\n", sess->port_id, sess);
	hlist_add_head_rcu(&sess->hash, head);
	tport->sess_count++;

	return 0;
}

/*
 * Allocate session and enter it in the hash for the local port.
 * Caller holds ft_lport_lock.
 */
static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
				      struct fc_rport_priv *rdata)
{
	struct se_portal_group *se_tpg = &tport->tpg->se_tpg;
	struct ft_sess *sess;
	struct hlist_head *head;
	unsigned char initiatorname[TRANSPORT_IQN_LEN];

	ft_format_wwn(&initiatorname[0], TRANSPORT_IQN_LEN, rdata->ids.port_name);

	head = &tport->hash[ft_sess_hash(port_id)];
	hlist_for_each_entry_rcu(sess, head, hash)
		if (sess->port_id == port_id)
			return sess;

	sess = kzalloc_obj(*sess);
	if (!sess)
		return ERR_PTR(-ENOMEM);

	kref_init(&sess->kref); /* ref for table entry */
	sess->tport = tport;
	sess->port_id = port_id;

	sess->se_sess = target_setup_session(se_tpg, TCM_FC_DEFAULT_TAGS,
					     sizeof(struct ft_cmd),
					     TARGET_PROT_NORMAL, &initiatorname[0],
					     sess, ft_sess_alloc_cb);
	if (IS_ERR(sess->se_sess)) {
		int rc = PTR_ERR(sess->se_sess);
		kfree(sess);
		sess = ERR_PTR(rc);
	}
	return sess;
}

/*
 * Unhash the session.
 * Caller holds ft_lport_lock.
 */
static void ft_sess_unhash(struct ft_sess *sess)
{
	struct ft_tport *tport = sess->tport;

	hlist_del_rcu(&sess->hash);
	BUG_ON(!tport->sess_count);
	tport->sess_count--;
	sess->port_id = -1;
	sess->params = 0;
}

/*
 * Delete session from hash.
 * Caller holds ft_lport_lock.
 */
static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id)
{
	struct hlist_head *head;

Annotation

Implementation Notes