[Open-FCoE] [RFC PATCH 05/16] libfc: use dummy rport and work for gpn_id and gnn_id

Robert Love robert.w.love at intel.com
Tue Sep 9 17:22:51 UTC 2008


This patch does three 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 around fc_rport's not
   fc_ns_port's.

2) Uses stack memory to allocate the temporary fc_ns_port
   for each discovered port. There's no need to dynamically
   allocate memory if it's just going to be freed in the
   same block.

Signed-off-by: Robert Love <robert.w.love at intel.com>
---

 drivers/scsi/libfc/fc_ns.c |  196 +++++++++++++++++++++++++-------------------
 include/scsi/libfc/libfc.h |   17 ++++
 2 files changed, 130 insertions(+), 83 deletions(-)

diff --git a/drivers/scsi/libfc/fc_ns.c b/drivers/scsi/libfc/fc_ns.c
index 1ad189f..97464db 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 fc_rport *);
 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 fc_rport *);
 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)
@@ -711,7 +725,9 @@ static int fc_ns_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len)
 	size_t plen;
 	size_t tlen;
 	int error = 0;
-	struct fc_ns_port *dp;
+	struct fc_ns_port dp;
+	struct fc_rport *rp;
+	struct fc_rport_libfc_priv *rpp;
 
 	/*
 	 * Handle partial name record left over from previous call.
@@ -750,17 +766,16 @@ static int fc_ns_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len)
 	 * After the first time through the loop, things return to "normal".
 	 */
 	while (plen >= sizeof(*np)) {
-		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;
+		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;
+		rp = fc_ns_create_dummy_rport(&dp);
+		rpp = rp->dd_data;
+
+		fc_ns_gnn_id_req(rp);
+
 		if (np->fp_flags & FC_NS_FID_LAST) {
 			fc_ns_disc_done(lp);
 			len = 0;
@@ -875,6 +890,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;
@@ -885,51 +902,50 @@ 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);
+
+	fc_ns_gpn_id_req(rp);
 	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
+ * @rp: A temporary fc_rport
  *
+ * 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 fc_rport *rp)
 {
+	struct fc_rport_libfc_priv *rpp = rp->dd_data;
+	struct fc_lport *lp = rpp->local_port;
 	struct fc_frame *fp;
 	struct req {
 		struct fc_ct_hdr ct;
 		struct fc_ns_fid fid;
 	} *cp;
-	int error = 0;
 
 	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);
 }
 
 /**
@@ -939,9 +955,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;
@@ -950,11 +968,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));
@@ -971,8 +989,8 @@ 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);
+		fc_ns_gnn_id_req(rp);
 		break;
 	case FC_FS_RJT:
 		fc_ns_restart(lp);
@@ -989,9 +1007,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:
@@ -1001,7 +1020,6 @@ static void fc_ns_gpn_id_error(struct fc_ns_port *dp, struct fc_frame *fp)
 	default:
 		break;
 	}
-	kfree(dp);
 }
 
 /*
@@ -1139,40 +1157,38 @@ EXPORT_SYMBOL(fc_ns_init);
 
 /**
  * fc_ns_gnn_id_req - Send Get Node Name by ID (GNN_ID) request
- * @lp: Fibre Channel host port instance
- * @dp: Temporary discovery port for holding IDs and world wide names
+ * @rp: Temporary fc_rport
  *
+ * 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 fc_rport *rp)
 {
+	struct fc_rport_libfc_priv *rpp = rp->dd_data;
+	struct fc_lport *lp = rpp->local_port;
 	struct fc_frame *fp;
 	struct req {
 		struct fc_ct_hdr ct;
 		struct fc_ns_fid fid;
 	} *cp;
-	int error = 0;
 
 	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);
 }
 
 /**
@@ -1182,22 +1198,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));
@@ -1205,6 +1226,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\n", fr_len(fp));
 		return;
 	}
+
 	cmd = ntohs(cp->ct.ct_cmd);
 	switch (cmd) {
 	case FC_FS_ACC:
@@ -1214,8 +1236,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);
@@ -1224,7 +1254,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);
 }
 
@@ -1233,9 +1263,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:
@@ -1245,6 +1276,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 f6b34c5..5936c78 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
@@ -144,6 +158,9 @@ struct fc_rport_libfc_priv {
 	struct delayed_work	retry_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;




More information about the devel mailing list