This patch does two things:
1) Creates dummy fc_rport and fc_rport_libfc_priv objects
to use durring gpn_id and gnn_id instead of fc_ns_port
objects. This will be used in a later patch that will
move gpn_id and gnn_id into the RP state machine. The
RP state machine passes aroudn fc_rport's not
fc_ns_port's.
2) Starts gpn_id and gnn_id from a work thread. This will
also help with a later patch that will start the
rport_login() from this work thread.
Signed-off-by: Robert Love <[EMAIL PROTECTED]>
---
drivers/scsi/libfc/fc_ns.c | 201 ++++++++++++++++++++++++++++----------------
include/scsi/libfc/libfc.h | 18 ++++
2 files changed, 147 insertions(+), 72 deletions(-)
diff --git a/drivers/scsi/libfc/fc_ns.c b/drivers/scsi/libfc/fc_ns.c
index 3d50b21..8145e1c 100644
--- a/drivers/scsi/libfc/fc_ns.c
+++ b/drivers/scsi/libfc/fc_ns.c
@@ -44,25 +44,13 @@ static void fc_ns_disc_done(struct fc_lport *);
static void fcdt_ns_error(struct fc_lport *, struct fc_frame *);
static void fc_ns_timeout(struct work_struct *);
-/**
- * struct fc_ns_port - temporary discovery port to hold rport identifiers
- * @lp: Fibre Channel host port instance
- * @peers: node for list management during discovery and RSCN processing
- * @ids: identifiers structure to pass to fc_remote_port_add()
- */
-struct fc_ns_port {
- struct fc_lport *lp;
- struct list_head peers;
- struct fc_rport_identifiers ids;
-};
-
-static int fc_ns_gpn_id_req(struct fc_lport *, struct fc_ns_port *);
+static void fc_ns_gpn_id_req(struct work_struct *);
static void fc_ns_gpn_id_resp(struct fc_seq *, struct fc_frame *, void *);
-static void fc_ns_gpn_id_error(struct fc_ns_port *rp, struct fc_frame *fp);
+static void fc_ns_gpn_id_error(struct fc_rport *, struct fc_frame *);
-static int fc_ns_gnn_id_req(struct fc_lport *, struct fc_ns_port *);
+static void fc_ns_gnn_id_req(struct work_struct *);
static void fc_ns_gnn_id_resp(struct fc_seq *, struct fc_frame *, void *);
-static void fc_ns_gnn_id_error(struct fc_ns_port *, struct fc_frame *);
+static void fc_ns_gnn_id_error(struct fc_rport *, struct fc_frame *);
static void fc_ns_enter_reg_pn(struct fc_lport *lp);
static void fc_ns_error(struct fc_lport *lp, struct fc_frame *fp);
static void fc_ns_resp(struct fc_seq *sp, struct fc_frame *fp,
@@ -71,6 +59,32 @@ static void fc_ns_retry(struct fc_lport *lp);
static void fc_ns_single(struct fc_lport *, struct fc_ns_port *);
static int fc_ns_restart(struct fc_lport *);
+struct fc_rport *fc_ns_create_dummy_rport(struct fc_ns_port *dp)
+{
+ struct fc_rport *rp;
+ struct fc_rport_libfc_priv *rpp;
+ rp = kzalloc(sizeof(*rp) + sizeof(*rpp), GFP_KERNEL);
+ rpp = ((void *)rp + sizeof(struct fc_rport));
+
+ rp->dd_data = rpp;
+ rp->port_id = dp->ids.port_id;
+ rp->port_name = dp->ids.port_name;
+ rp->node_name = dp->ids.node_name;
+ rp->roles = dp->ids.roles;
+
+ spin_lock_init(&rpp->rp_lock);
+ rpp->local_port = dp->lp;
+ rpp->rp_state = RPORT_ST_INIT;
+ rpp->flags = FC_RP_FLAGS_REC_SUPPORTED;
+ INIT_DELAYED_WORK(&rpp->retry_work, fc_ns_timeout);
+
+ return rp;
+}
+
+void fc_ns_destroy_dummy_rport(struct fc_rport *rp)
+{
+ kfree(rp);
+}
/**
* fc_ns_rscn_req - Handle Registered State Change Notification (RSCN)
@@ -712,6 +726,8 @@ static int fc_ns_gpn_ft_parse(struct fc_lport *lp, void
*buf, size_t len)
size_t tlen;
int error = 0;
struct fc_ns_port *dp;
+ struct fc_rport *rp;
+ struct fc_rport_libfc_priv *rpp;
/*
* Handle partial name record left over from previous call.
@@ -753,14 +769,20 @@ static int fc_ns_gpn_ft_parse(struct fc_lport *lp, void
*buf, size_t len)
dp = kzalloc(sizeof(*dp), GFP_KERNEL);
if (!dp)
break;
+
dp->lp = lp;
dp->ids.port_id = ntoh24(np->fp_fid);
dp->ids.port_name = ntohll(np->fp_wwpn);
dp->ids.node_name = -1;
dp->ids.roles = FC_RPORT_ROLE_UNKNOWN;
- error = fc_ns_gnn_id_req(lp, dp);
- if (error)
- break;
+
+ rp = fc_ns_create_dummy_rport(dp);
+ rpp = rp->dd_data;
+ kfree(dp);
+
+ INIT_WORK(&rpp->login_work, fc_ns_gnn_id_req);
+ schedule_work(&rpp->login_work);
+
if (np->fp_flags & FC_NS_FID_LAST) {
fc_ns_disc_done(lp);
len = 0;
@@ -874,6 +896,8 @@ static void fc_ns_gpn_ft_resp(struct fc_seq *sp, struct
fc_frame *fp,
static void fc_ns_single(struct fc_lport *lp, struct fc_ns_port *dp)
{
struct fc_rport *rport;
+ struct fc_rport *rp;
+ struct fc_rport_libfc_priv *rpp;
if (dp->ids.port_id == lp->fid)
goto out;
@@ -884,51 +908,59 @@ static void fc_ns_single(struct fc_lport *lp, struct
fc_ns_port *dp)
put_device(&rport->dev); /* hold from lookup */
}
- if (fc_ns_gpn_id_req(lp, dp) != 0)
- goto error;
+ rp = fc_ns_create_dummy_rport(dp);
+ rpp = rp->dd_data;
+ kfree(dp);
+
+ INIT_WORK(&rpp->login_work, fc_ns_gpn_id_req);
+ schedule_work(&rpp->login_work);
return;
-error:
- fc_ns_restart(lp);
out:
kfree(dp);
}
/**
* fc_ns_gpn_id_req - Send Get Port Name by ID (GPN_ID) request
- * @lp: Fibre Channel host port instance
- * @dp: Temporary discovery port for holding IDs and world wide names
+ * @work: The work member of the fc_ns_port structure
*
+ * XXX - this the following statement still valid?
* The remote port is held by the caller for us.
*/
-static int fc_ns_gpn_id_req(struct fc_lport *lp, struct fc_ns_port *dp)
+static void fc_ns_gpn_id_req(struct work_struct *work)
{
+ struct fc_rport_libfc_priv *rpp;
+ struct fc_rport *rp;
+ struct fc_lport *lp;
struct fc_frame *fp;
struct req {
struct fc_ct_hdr ct;
struct fc_ns_fid fid;
} *cp;
- int error = 0;
+
+ rpp = container_of(work,
+ struct fc_rport_libfc_priv,
+ login_work);
+ rp = (((void *)rpp) - sizeof(struct fc_rport));
+
+ lp = rpp->local_port;
fp = fc_frame_alloc(lp, sizeof(*cp));
- if (fp == NULL)
- return -ENOMEM;
+ if (!fp)
+ return;
cp = fc_frame_payload_get(fp, sizeof(*cp));
fc_fill_dns_hdr(lp, &cp->ct, FC_NS_GPN_ID, sizeof(cp->fid));
- hton24(cp->fid.fp_fid, dp->ids.port_id);
+ hton24(cp->fid.fp_fid, rp->port_id);
WARN_ON(!fc_lport_test_ready(lp));
fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT);
- if (!lp->tt.exch_seq_send(lp, fp,
- fc_ns_gpn_id_resp,
- dp, lp->e_d_tov,
- lp->fid,
- lp->dns_rp->port_id,
- FC_FC_SEQ_INIT | FC_FC_END_SEQ))
- error = -ENOMEM;
-
- return error;
+ lp->tt.exch_seq_send(lp, fp,
+ fc_ns_gpn_id_resp,
+ rp, lp->e_d_tov,
+ lp->fid,
+ lp->dns_rp->port_id,
+ FC_FC_SEQ_INIT | FC_FC_END_SEQ);
}
/**
@@ -938,9 +970,11 @@ static int fc_ns_gpn_id_req(struct fc_lport *lp, struct
fc_ns_port *dp)
* @dp_arg: Temporary discovery port for holding IDs and world wide names
*/
static void fc_ns_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
- void *dp_arg)
+ void *rp_arg)
{
- struct fc_ns_port *dp = dp_arg;
+ struct fc_rport *rp = rp_arg;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+
struct fc_lport *lp;
struct resp {
struct fc_ct_hdr ct;
@@ -949,11 +983,11 @@ static void fc_ns_gpn_id_resp(struct fc_seq *sp, struct
fc_frame *fp,
unsigned int cmd;
if (IS_ERR(fp)) {
- fc_ns_gpn_id_error(dp, fp);
+ fc_ns_gpn_id_error(rp, fp);
return;
}
- lp = dp->lp;
+ lp = rpp->local_port;
WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */
cp = fc_frame_payload_get(fp, sizeof(cp->ct));
@@ -970,8 +1004,10 @@ static void fc_ns_gpn_id_resp(struct fc_seq *sp, struct
fc_frame *fp,
fr_len(fp));
break;
}
- dp->ids.port_name = ntohll(cp->wwn);
- fc_ns_gnn_id_req(lp, dp);
+ rp->port_name = ntohll(cp->wwn);
+
+ INIT_WORK(&rpp->login_work, fc_ns_gnn_id_req);
+ schedule_work(&rpp->login_work);
break;
case FC_FS_RJT:
fc_ns_restart(lp);
@@ -988,9 +1024,10 @@ static void fc_ns_gpn_id_resp(struct fc_seq *sp, struct
fc_frame *fp,
* @dp: Temporary discovery port for holding IDs and world wide names
* @fp: response frame
*/
-static void fc_ns_gpn_id_error(struct fc_ns_port *dp, struct fc_frame *fp)
+static void fc_ns_gpn_id_error(struct fc_rport *rp, struct fc_frame *fp)
{
- struct fc_lport *lp = dp->lp;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ struct fc_lport *lp = rpp->local_port;
switch (PTR_ERR(fp)) {
case -FC_EX_TIMEOUT:
@@ -1000,7 +1037,6 @@ static void fc_ns_gpn_id_error(struct fc_ns_port *dp,
struct fc_frame *fp)
default:
break;
}
- kfree(dp);
}
/*
@@ -1141,37 +1177,44 @@ EXPORT_SYMBOL(fc_ns_init);
* @lp: Fibre Channel host port instance
* @dp: Temporary discovery port for holding IDs and world wide names
*
+ * XXX- Is the following statement still true?
* The remote port is held by the caller for us.
*/
-static int fc_ns_gnn_id_req(struct fc_lport *lp, struct fc_ns_port *dp)
+static void fc_ns_gnn_id_req(struct work_struct *work)
{
+ struct fc_rport_libfc_priv *rpp;
+ struct fc_rport *rp;
+ struct fc_lport *lp;
struct fc_frame *fp;
struct req {
struct fc_ct_hdr ct;
struct fc_ns_fid fid;
} *cp;
- int error = 0;
+
+ rpp = container_of(work,
+ struct fc_rport_libfc_priv,
+ login_work);
+
+ rp = (((void *)rpp) - sizeof(struct fc_rport));
+ lp = rpp->local_port;
fp = fc_frame_alloc(lp, sizeof(*cp));
- if (fp == NULL)
- return -ENOMEM;
+ if (!fp)
+ return;
cp = fc_frame_payload_get(fp, sizeof(*cp));
fc_fill_dns_hdr(lp, &cp->ct, FC_NS_GNN_ID, sizeof(cp->fid));
- hton24(cp->fid.fp_fid, dp->ids.port_id);
+ hton24(cp->fid.fp_fid, rp->port_id);
WARN_ON(!fc_lport_test_ready(lp));
fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT);
- if (!lp->tt.exch_seq_send(lp, fp,
- fc_ns_gnn_id_resp,
- dp, lp->e_d_tov,
- lp->fid,
- lp->dns_rp->port_id,
- FC_FC_SEQ_INIT | FC_FC_END_SEQ))
- error = -ENOMEM;
-
- return error;
+ lp->tt.exch_seq_send(lp, fp,
+ fc_ns_gnn_id_resp,
+ rp, lp->e_d_tov,
+ lp->fid,
+ lp->dns_rp->port_id,
+ FC_FC_SEQ_INIT | FC_FC_END_SEQ);
}
/**
@@ -1181,22 +1224,27 @@ static int fc_ns_gnn_id_req(struct fc_lport *lp, struct
fc_ns_port *dp)
* @dp_arg: Temporary discovery port for holding IDs and world wide names
*/
static void fc_ns_gnn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
- void *dp_arg)
+ void *rp_arg)
{
- struct fc_ns_port *dp = dp_arg;
+ struct fc_rport *rp = rp_arg;
+ struct fc_rport_libfc_priv *rpp;
struct fc_lport *lp;
+ struct fc_rport_identifiers ids;
+
struct resp {
struct fc_ct_hdr ct;
__be64 wwn;
} *cp;
unsigned int cmd;
+ rpp = rp->dd_data;
+
if (IS_ERR(fp)) {
- fc_ns_gnn_id_error(dp, fp);
+ fc_ns_gnn_id_error(rp, fp);
return;
}
- lp = dp->lp;
+ lp = rpp->local_port;
WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */
cp = fc_frame_payload_get(fp, sizeof(cp->ct));
@@ -1204,6 +1252,7 @@ static void fc_ns_gnn_id_resp(struct fc_seq *sp, struct
fc_frame *fp,
FC_DBG("GNN_ID response too short. len %d", fr_len(fp));
return;
}
+
cmd = ntohs(cp->ct.ct_cmd);
switch (cmd) {
case FC_FS_ACC:
@@ -1213,8 +1262,16 @@ static void fc_ns_gnn_id_resp(struct fc_seq *sp, struct
fc_frame *fp,
fr_len(fp));
break;
}
- dp->ids.node_name = ntohll(cp->wwn);
- fc_ns_new_target(lp, NULL, &dp->ids);
+ rp->node_name = ntohll(cp->wwn);
+
+ ids.port_id = rp->port_id;
+ ids.port_name = rp->port_name;
+ ids.node_name = rp->node_name;
+ ids.roles = rp->roles;
+
+ fc_ns_destroy_dummy_rport(rp);
+
+ fc_ns_new_target(lp, NULL, &ids);
break;
case FC_FS_RJT:
fc_ns_restart(lp);
@@ -1223,7 +1280,7 @@ static void fc_ns_gnn_id_resp(struct fc_seq *sp, struct
fc_frame *fp,
FC_DBG("GNN_ID unexpected CT response cmd %x\n", cmd);
break;
}
- kfree(dp);
+
fc_frame_free(fp);
}
@@ -1232,9 +1289,10 @@ static void fc_ns_gnn_id_resp(struct fc_seq *sp, struct
fc_frame *fp,
* @dp: Temporary discovery port for holding IDs and world wide names
* @fp: response frame
*/
-static void fc_ns_gnn_id_error(struct fc_ns_port *dp, struct fc_frame *fp)
+static void fc_ns_gnn_id_error(struct fc_rport *rp, struct fc_frame *fp)
{
- struct fc_lport *lp = dp->lp;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ struct fc_lport *lp = rpp->local_port;
switch (PTR_ERR(fp)) {
case -FC_EX_TIMEOUT:
@@ -1244,6 +1302,5 @@ static void fc_ns_gnn_id_error(struct fc_ns_port *dp,
struct fc_frame *fp)
default:
break;
}
- kfree(dp);
}
diff --git a/include/scsi/libfc/libfc.h b/include/scsi/libfc/libfc.h
index 07b98c6..1966a38 100644
--- a/include/scsi/libfc/libfc.h
+++ b/include/scsi/libfc/libfc.h
@@ -119,6 +119,20 @@ enum fc_rport_state {
};
/**
+ * struct fc_ns_port - temporary discovery port to hold rport identifiers
+ * @lp: Fibre Channel host port instance
+ * @peers: node for list management during discovery and RSCN processing
+ * @ids: identifiers structure to pass to fc_remote_port_add()
+ * @rport_work: work struct for starting the rport state machine
+ */
+struct fc_ns_port {
+ struct fc_lport *lp;
+ struct list_head peers;
+ struct fc_rport_identifiers ids;
+ struct work_struct rport_work;
+};
+
+/**
* struct fc_rport_libfc_priv - libfc internal information about a remote port
* @local_port: Fibre Channel host port instance
* @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges
@@ -142,8 +156,12 @@ struct fc_rport_libfc_priv {
unsigned int r_a_tov;
spinlock_t rp_lock;
struct delayed_work retry_work;
+ struct work_struct login_work;
};
+struct fc_rport *fc_ns_create_dummy_rport(struct fc_ns_port *);
+void fc_ns_destroy_dummy_rport(struct fc_rport *);
+
static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64
wwnn)
{
rport->node_name = wwnn;
_______________________________________________
devel mailing list
[email protected]
http://www.open-fcoe.org/mailman/listinfo/devel