[Open-FCoE] [PATCH 26/28] libfc: re-work lport locking using mutexes

Robert Love robert.w.love at intel.com
Tue Sep 30 18:27:06 UTC 2008


This patch attempts to organize functions into the following
groups to determine when we need to hold the lport lock. This
patch also changes the locking from spin locks to mutexes, just
like the rport code. This patch also adds locking comments and
attempts to complete function comments for some functions.

Action Functions (called without LP lock, locks, calls an _enter_ and unlocks)
 fc_lport_rport_event
 fc_fabric_login
 fc_linkup
 fc_linkdown
 fc_pause
 fc_unpause
 fc_fabric_logoff
 fc_lport_destroy
 fc_lport_timeout
        - needs to be called from a work thread

 fc_lport_recv
        - Calls one of the request handlers with the lock held
        - should it just call fc_lport_recv_req or call rport_recv?

Request Handlers (called without lock, will lock process and unlock)
 fc_lport_rlir_req
 fc_lport_echo_req
 fc_lport_rnid_req
 fc_lport_recv_logo_req
 fc_lport_recv_flogi_req

Response Handlers (called without lock, lock, call an _enter_ function and unlock)
 fc_lport_rpn_id_resp
 fc_lport_rft_id_resp
 fc_lport_scr_resp
 fc_lport_logo_resp
 fc_lport_flogi_resp

Enter Functions (called with lock held)
 fc_lport_enter_reset
 fc_lport_enter_flogi
 fc_lport_enter_scr
 fc_lport_enter_rft_id
 fc_lport_enter_rpn_id
 fc_lport_enter_dns
 fc_lport_enter_ready
 fc_lport_enter_logo

Helper Functions (need lock held)
 fc_lport_flogi_fill (mfs, wwnn, wwpn, tovs)
 fc_lport_set_fid
 fc_lport_add_fc4_type
 fc_set_mfs
 fc_lport_error
 - should start a work thread for fc_lport_timeout or call fc_lport_reject
 - rename fc_lport_enter_reject to fc_lport_reject

Helper Functions (don't need lock held)
 fc_frame_drop
 fc_lport_state
 fc_lport_ptp_setup
 fc_lport_ptp_clear
 fc_lport_dns_acc
 fc_lport_config
 fc_lport_init

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

 drivers/scsi/fcoe/fcoeinit.c  |    4 
 drivers/scsi/libfc/fc_lport.c |  741 ++++++++++++++++++++++++++++-------------
 drivers/scsi/libfc/fc_ns.c    |   10 -
 include/scsi/libfc/libfc.h    |   33 --
 4 files changed, 517 insertions(+), 271 deletions(-)

diff --git a/drivers/scsi/fcoe/fcoeinit.c b/drivers/scsi/fcoe/fcoeinit.c
index 4baa9f5..7d52ed5 100644
--- a/drivers/scsi/fcoe/fcoeinit.c
+++ b/drivers/scsi/fcoe/fcoeinit.c
@@ -53,8 +53,8 @@ struct scsi_transport_template *fcoe_transport_template;
 
 static int fcoe_reset(struct Scsi_Host *shost)
 {
-	struct fc_lport *lp = shost_priv(shost);
-	fc_lport_enter_reset(lp);
+	struct fc_lport *lport = shost_priv(shost);
+	fc_lport_reset(lport);
 	return 0;
 }
 
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index 0f65577..a43c48b 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -38,10 +38,11 @@ static int fc_lport_debug;
 
 static void fc_lport_error(struct fc_lport *, struct fc_frame *);
 
+static void fc_lport_enter_reset(struct fc_lport *);
 static void fc_lport_enter_flogi(struct fc_lport *);
 static void fc_lport_enter_dns(struct fc_lport *);
-static void fc_lport_enter_reg_pn(struct fc_lport *);
-static void fc_lport_enter_reg_ft(struct fc_lport *);
+static void fc_lport_enter_rpn_id(struct fc_lport *);
+static void fc_lport_enter_rft_id(struct fc_lport *);
 static void fc_lport_enter_scr(struct fc_lport *);
 static void fc_lport_enter_ready(struct fc_lport *);
 static void fc_lport_enter_logo(struct fc_lport *);
@@ -50,8 +51,8 @@ static const char *fc_lport_state_names[] = {
 	[LPORT_ST_NONE] =     "none",
 	[LPORT_ST_FLOGI] =    "FLOGI",
 	[LPORT_ST_DNS] =      "dNS",
-	[LPORT_ST_REG_PN] =   "REG_PN",
-	[LPORT_ST_REG_FT] =   "REG_FT",
+	[LPORT_ST_RPN_ID] =   "RPN_ID",
+	[LPORT_ST_RFT_ID] =   "RFT_ID",
 	[LPORT_ST_SCR] =      "SCR",
 	[LPORT_ST_READY] =    "Ready",
 	[LPORT_ST_LOGO] =     "LOGO",
@@ -64,33 +65,45 @@ static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp)
 	return 0;
 }
 
+/**
+ * fc_lport_rport_event - Event handler for rport events
+ * @lport: The lport which is receiving the event
+ * @port_id: The FID of the rport which the event has occured on
+ * @event: The event that occured
+ *
+ * Locking Note: The rport lock should not be held when calling
+ *               this function.
+ */
 static void fc_lport_rport_event(struct fc_lport *lport, u32 port_id,
 				 enum fc_lport_event event)
 {
 	struct fc_rport *rport = lport->tt.rport_lookup(lport, port_id);
-	fc_lport_lock(lport);
+
 	if (port_id == FC_FID_DIR_SERV) {
+		mutex_lock(&lport->lp_mutex);
 		switch (event) {
 		case LPORT_EV_RPORT_CREATED:
 			if (rport) {
 				lport->dns_rp = rport;
-				fc_lport_enter_dns(lport);
+				fc_lport_enter_rpn_id(lport);
 			}
 			break;
 		case LPORT_EV_RPORT_LOGO:
 		case LPORT_EV_RPORT_FAILED:
 			lport->dns_rp = NULL;
-			fc_lport_lock(lport);
-			fc_lport_enter_reset(lport);
-			fc_lport_unlock(lport);
+			fc_lport_enter_dns(lport);
 			break;
 		case LPORT_EV_RPORT_NONE:
 			break;
 		}
 	}
-	fc_lport_unlock(lport);
+	mutex_unlock(&lport->lp_mutex);
 }
 
+/**
+ * fc_lport_state - Return a string which represents the lport's state
+ * @lport: The lport whose state is to converted to a string
+ */
 static const char *fc_lport_state(struct fc_lport *lport)
 {
 	const char *cp;
@@ -101,6 +114,13 @@ static const char *fc_lport_state(struct fc_lport *lport)
 	return cp;
 }
 
+/**
+ * fc_lport_ptp_setup - Create an rport for point-to-point mode
+ * @lport: The lport to attach the ptp rport to
+ * @fid: The FID of the ptp rport
+ * @remote_wwpn: The WWPN of the ptp rport
+ * @remote_wwnn: The WWNN of the ptp rport
+ */
 static void fc_lport_ptp_setup(struct fc_lport *lport,
 			       u32 remote_fid, u64 remote_wwpn,
 			       u64 remote_wwnn)
@@ -116,11 +136,11 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
 	 * if we have to create a rport the fc class can sleep so we must
 	 * drop the lock here
 	 */
-	fc_lport_unlock(lport);
 	rport = lport->tt.rport_lookup(lport, ids.port_id);
+
 	if (!rport)
 		rport = lport->tt.rport_create(lport, &ids);
-	fc_lport_lock(lport);
+
 	if (rport) {
 		if (lport->ptp_rp)
 			fc_remote_port_delete(lport->ptp_rp);
@@ -129,6 +149,10 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
 	}
 }
 
+/**
+ * fc_lport_ptp_clear - Delete the ptp rport
+ * @lport: The lport whose ptp rport should be removed
+ */
 static void fc_lport_ptp_clear(struct fc_lport *lport)
 {
 	if (lport->ptp_rp) {
@@ -137,8 +161,9 @@ static void fc_lport_ptp_clear(struct fc_lport *lport)
 	}
 }
 
-/*
- * Routines to support struct fc_function_template
+/**
+ * fc_get_host_port_state - supports fc_function_template
+ * @shost: The host whose port state should be returned
  */
 void fc_get_host_port_state(struct Scsi_Host *shost)
 {
@@ -201,26 +226,6 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost)
 EXPORT_SYMBOL(fc_get_host_stats);
 
 /*
- * Test for dNS accept in response payload.
- */
-static int fc_lport_dns_acc(struct fc_frame *fp)
-{
-	struct fc_frame_header *fh;
-	struct fc_ct_hdr *ct;
-	int rc = 0;
-
-	fh = fc_frame_header_get(fp);
-	ct = fc_frame_payload_get(fp, sizeof(*ct));
-	if (fh && ct && fh->fh_type == FC_TYPE_CT &&
-	    ct->ct_fs_type == FC_FST_DIR &&
-	    ct->ct_fs_subtype == FC_NS_SUBTYPE &&
-	    ntohs(ct->ct_cmd) == FC_FS_ACC) {
-		rc = 1;
-	}
-	return rc;
-}
-
-/*
  * Fill in FLOGI command for request.
  */
 static void
@@ -264,21 +269,37 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type)
 	*mp = htonl(ntohl(*mp) | 1UL << (type % FC_NS_BPW));
 }
 
-/*
- * Handle received RLIR - registered link incident report.
+/**
+ * fc_lport_recv_rlir_req - Handle received Registered Link Incident Report.
+ * @lport: Fibre Channel local port recieving the RLIR
+ * @sp: current sequence in the RLIR exchange
+ * @fp: RLIR request frame
+ *
+ * Locking Note: The lport lock is exected to be held before calling
+ * this function.
  */
-static void fc_lport_rlir_req(struct fc_seq *sp, struct fc_frame *fp,
-			      struct fc_lport *lport)
+static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp,
+				   struct fc_lport *lport)
 {
+	if (fc_lport_debug)
+		FC_DBG("Received RLIR request while in state %s\n",
+		       fc_lport_state(lport));
+
 	lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
 	fc_frame_free(fp);
 }
 
-/*
- * Handle received ECHO.
+/**
+ * fc_lport_recv_echo_req - Handle received ECHO request
+ * @lport: Fibre Channel local port recieving the ECHO
+ * @sp: current sequence in the ECHO exchange
+ * @fp: ECHO request frame
+ *
+ * Locking Note: The lport lock is exected to be held before calling
+ * this function.
  */
-static void fc_lport_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
-			      struct fc_lport *lport)
+static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
+				   struct fc_lport *lport)
 {
 	struct fc_frame *fp;
 	unsigned int len;
@@ -286,11 +307,16 @@ static void fc_lport_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
 	void *dp;
 	u32 f_ctl;
 
+	if (fc_lport_debug)
+		FC_DBG("Received RLIR request while in state %s\n",
+		       fc_lport_state(lport));
+
 	len = fr_len(in_fp) - sizeof(struct fc_frame_header);
 	pp = fc_frame_payload_get(in_fp, len);
 
 	if (len < sizeof(__be32))
 		len = sizeof(__be32);
+
 	fp = fc_frame_alloc(lport, len);
 	if (fp) {
 		dp = fc_frame_payload_get(fp, len);
@@ -304,11 +330,17 @@ static void fc_lport_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
 	fc_frame_free(in_fp);
 }
 
-/*
- * Handle received RNID.
+/**
+ * fc_lport_recv_echo_req - Handle received Request Node ID data request
+ * @lport: Fibre Channel local port recieving the RNID
+ * @sp: current sequence in the RNID exchange
+ * @fp: RNID request frame
+ *
+ * Locking Note: The lport lock is exected to be held before calling
+ * this function.
  */
-static void fc_lport_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
-			      struct fc_lport *lport)
+static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
+				   struct fc_lport *lport)
 {
 	struct fc_frame *fp;
 	struct fc_els_rnid *req;
@@ -322,6 +354,10 @@ static void fc_lport_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
 	size_t len;
 	u32 f_ctl;
 
+	if (fc_lport_debug)
+		FC_DBG("Received RNID request while in state %s\n",
+		       fc_lport_state(lport));
+
 	req = fc_frame_payload_get(in_fp, sizeof(*req));
 	if (!req) {
 		rjt_data.fp = NULL;
@@ -359,90 +395,124 @@ static void fc_lport_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
 	fc_frame_free(in_fp);
 }
 
-/*
- * Handle received fabric logout request.
+/**
+ * fc_lport_recv_logo_req - Handle received fabric LOGO request
+ * @lport: Fibre Channel local port recieving the LOGO
+ * @sp: current sequence in the LOGO exchange
+ * @fp: LOGO request frame
+ *
+ * Locking Note: The lport lock is exected to be held before calling
+ * this function.
  */
 static void fc_lport_recv_logo_req(struct fc_seq *sp, struct fc_frame *fp,
-				   struct fc_lport *lp)
+				   struct fc_lport *lport)
 {
-	lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
-	fc_lport_enter_reset(lp);
+	lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
+	fc_lport_enter_reset(lport);
 	fc_frame_free(fp);
 }
 
-/*
- * Receive request frame
+/**
+ * fc_fabric_login - Start the lport state machine
+ * @lport: The lport that should log into the fabric
+ *
+ * Locking Note: This function should not be called
+ *               with the lport lock held.
  */
-
 int fc_fabric_login(struct fc_lport *lport)
 {
 	int rc = -1;
 
+	mutex_lock(&lport->lp_mutex);
 	if (lport->state == LPORT_ST_NONE) {
-		fc_lport_lock(lport);
 		fc_lport_enter_reset(lport);
-		fc_lport_unlock(lport);
 		rc = 0;
 	}
+	mutex_unlock(&lport->lp_mutex);
+
 	return rc;
 }
 EXPORT_SYMBOL(fc_fabric_login);
 
 /**
- * fc_linkup -	link up notification
- * @lport:      Pointer to fc_lport
- **/
+ * fc_linkup - Handler for transport linkup events
+ * @lport: The lport whose link is up
+ */
 void fc_linkup(struct fc_lport *lport)
 {
+	mutex_lock(&lport->lp_mutex);
 	if ((lport->link_status & FC_LINK_UP) != FC_LINK_UP) {
 		lport->link_status |= FC_LINK_UP;
-		fc_lport_lock(lport);
+
 		if (lport->state == LPORT_ST_RESET)
 			fc_lport_enter_flogi(lport);
-		fc_lport_unlock(lport);
 	}
+	mutex_unlock(&lport->lp_mutex);
 }
 EXPORT_SYMBOL(fc_linkup);
 
 /**
- * fc_linkdown -  link down notification
- * @dev:      Pointer to fc_lport .
- **/
+ * fc_linkdown - Handler for transport linkdown events
+ * @lport: The lport whose link is down
+ */
 void fc_linkdown(struct fc_lport *lport)
 {
+	mutex_lock(&lport->lp_mutex);
+
 	if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP) {
 		lport->link_status &= ~(FC_LINK_UP);
 		fc_lport_enter_reset(lport);
 		lport->tt.scsi_cleanup(lport);
 	}
+
+	mutex_unlock(&lport->lp_mutex);
 }
 EXPORT_SYMBOL(fc_linkdown);
 
+/**
+ * fc_pause - Pause the flow of frames
+ * @lport: The lport to be paused
+ */
 void fc_pause(struct fc_lport *lport)
 {
+	mutex_lock(&lport->lp_mutex);
 	lport->link_status |= FC_PAUSE;
+	mutex_unlock(&lport->lp_mutex);
 }
 EXPORT_SYMBOL(fc_pause);
 
+/**
+ * fc_unpause - Unpause the flow of frames
+ * @lport: The lport to be unpaused
+ */
 void fc_unpause(struct fc_lport *lport)
 {
+	mutex_lock(&lport->lp_mutex);
 	lport->link_status &= ~(FC_PAUSE);
+	mutex_unlock(&lport->lp_mutex);
 }
 EXPORT_SYMBOL(fc_unpause);
 
+/**
+ * fc_fabric_logoff - Logout of the fabric
+ * @lport:	      fc_lport pointer to logoff the fabric
+ *
+ * Return value:
+ *	0 for success, -1 for failure
+ **/
 int fc_fabric_logoff(struct fc_lport *lport)
 {
-	fc_lport_lock(lport);
+	mutex_lock(&lport->lp_mutex);
 	fc_lport_enter_logo(lport);
-	fc_lport_unlock(lport);
 	lport->tt.scsi_cleanup(lport);
+	mutex_unlock(&lport->lp_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(fc_fabric_logoff);
 
 /**
  * fc_lport_destroy - unregister a fc_lport
- * @lport:	   fc_lport pointer to unregister
+ * @lport:	      fc_lport pointer to unregister
  *
  * Return value:
  *	None
@@ -454,18 +524,12 @@ EXPORT_SYMBOL(fc_fabric_logoff);
  **/
 int fc_lport_destroy(struct fc_lport *lport)
 {
-	fc_lport_lock(lport);
-	fc_lport_state_enter(lport, LPORT_ST_LOGO);
-	fc_lport_unlock(lport);
-
+	mutex_lock(&lport->lp_mutex);
 	cancel_delayed_work_sync(&lport->ns_disc_work);
-
 	lport->tt.scsi_abort_io(lport);
-
 	lport->tt.frame_send = fc_frame_drop;
-
 	lport->tt.exch_mgr_reset(lport->emp, 0, 0);
-
+	mutex_unlock(&lport->lp_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(fc_lport_destroy);
@@ -475,6 +539,8 @@ int fc_set_mfs(struct fc_lport *lport, u32 mfs)
 	unsigned int old_mfs;
 	int rc = -1;
 
+	mutex_lock(&lport->lp_mutex);
+
 	old_mfs = lport->mfs;
 
 	if (mfs >= FC_MIN_MAX_FRAME) {
@@ -491,10 +557,20 @@ int fc_set_mfs(struct fc_lport *lport, u32 mfs)
 		lport->ns_disc_done = 0;
 		fc_lport_enter_reset(lport);
 	}
+
+	mutex_unlock(&lport->lp_mutex);
+
 	return rc;
 }
 EXPORT_SYMBOL(fc_set_mfs);
 
+/**
+ * fc_rport_enter_ready - Enter the ready state and start discovery
+ * @lport: Fibre Channel local port that is ready
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
+ */
 static void fc_lport_enter_ready(struct fc_lport *lport)
 {
 	if (fc_lport_debug)
@@ -502,12 +578,22 @@ static void fc_lport_enter_ready(struct fc_lport *lport)
 		       lport->fid, fc_lport_state(lport));
 
 	fc_lport_state_enter(lport, LPORT_ST_READY);
+
+	lport->tt.disc_start(lport);
 }
 
-/*
+/**
+ * fc_lport_recv_flogi_req - Receive a FLOGI request
+ * @sp_in: The sequence the FLOGI is on
+ * @rx_fp: The frame the FLOGI is in
+ * @lport: The lport that recieved the request
+ *
  * A received FLOGI request indicates a point-to-point connection.
  * Accept it with the common service parameters indicating our N port.
  * Set up to do a PLOGI if we have the higher-number WWPN.
+ *
+ * Locking Note: The lport lock is exected to be held before calling
+ * this function.
  */
 static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
 				    struct fc_frame *rx_fp,
@@ -523,6 +609,10 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
 	u32 local_fid;
 	u32 f_ctl;
 
+	if (fc_lport_debug)
+		FC_DBG("Received FLOGI request while in state %s\n",
+		       fc_lport_state(lport));
+
 	fh = fc_frame_header_get(rx_fp);
 	remote_fid = ntoh24(fh->fh_s_id);
 	flp = fc_frame_payload_get(rx_fp, sizeof(*flp));
@@ -535,7 +625,6 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
 		goto out;
 	}
 	FC_DBG("FLOGI from port WWPN %llx\n", remote_wwpn);
-	fc_lport_lock(lport);
 
 	/*
 	 * XXX what is the right thing to do for FIDs?
@@ -573,7 +662,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
 	}
 	fc_lport_ptp_setup(lport, remote_fid, remote_wwpn,
 			   get_unaligned_be64(&flp->fl_wwnn));
-	fc_lport_unlock(lport);
+
 	if (lport->tt.disc_start(lport))
 		FC_DBG("target discovery start error\n");
 out:
@@ -581,8 +670,20 @@ out:
 	fc_frame_free(rx_fp);
 }
 
-static void fc_lport_recv(struct fc_lport *lport, struct fc_seq *sp,
-			  struct fc_frame *fp)
+/**
+ * fc_lport_recv_req - The generic lport request handler
+ * @lport: The lport that received the request
+ * @sp: The sequence the request is on
+ * @fp: The frame the request is in
+ *
+ * This function will see if the lport handles the request or
+ * if an rport should handle the request.
+ *
+ * Locking Note: This function should not be called with the lport
+ *               lock held becuase it will grab the lock.
+ */
+static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
+			      struct fc_frame *fp)
 {
 	struct fc_frame_header *fh = fc_frame_header_get(fp);
 	void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *);
@@ -591,6 +692,8 @@ static void fc_lport_recv(struct fc_lport *lport, struct fc_seq *sp,
 	u32 d_id;
 	struct fc_seq_els_data rjt_data;
 
+	mutex_lock(&lport->lp_mutex);
+
 	/*
 	 * Handle special ELS cases like FLOGI, LOGO, and
 	 * RSCN here.  These don't require a session.
@@ -614,13 +717,13 @@ static void fc_lport_recv(struct fc_lport *lport, struct fc_seq *sp,
 			recv = lport->tt.disc_recv_req;
 			break;
 		case ELS_ECHO:
-			recv = fc_lport_echo_req;
+			recv = fc_lport_recv_echo_req;
 			break;
 		case ELS_RLIR:
-			recv = fc_lport_rlir_req;
+			recv = fc_lport_recv_rlir_req;
 			break;
 		case ELS_RNID:
-			recv = fc_lport_rnid_req;
+			recv = fc_lport_recv_rnid_req;
 			break;
 		}
 
@@ -652,23 +755,39 @@ static void fc_lport_recv(struct fc_lport *lport, struct fc_seq *sp,
 		FC_DBG("dropping invalid frame (eof %x)\n", fr_eof(fp));
 		fc_frame_free(fp);
 	}
+	mutex_unlock(&lport->lp_mutex);
+}
 
-	/*
-	 *  The common exch_done for all request may not be good
-	 *  if any request requires longer hold on exhange. XXX
-	 */
-	lport->tt.exch_done(sp);
+/**
+ * fc_lport_reset - Reset an lport
+ * @lport: The lport which should be reset
+ *
+ * Locking Note: This functions should not be called with the
+ *               lport lock held.
+ */
+int fc_lport_reset(struct fc_lport *lport)
+{
+	mutex_lock(&lport->lp_mutex);
+	fc_lport_enter_reset(lport);
+	mutex_unlock(&lport->lp_mutex);
+	return 0;
 }
+EXPORT_SYMBOL(fc_lport_reset);
 
-/*
- * Put the local port back into the initial state.  Reset all sessions.
- * This is called after a SCSI reset or the driver is unloading
- * or the program is exiting.
+/**
+ * fc_rport_enter_reset - Reset the local port
+ * @lport: Fibre Channel local port to be reset
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
  */
-int fc_lport_enter_reset(struct fc_lport *lport)
+static void fc_lport_enter_reset(struct fc_lport *lport)
 {
 	if (fc_lport_debug)
-		FC_DBG("Processing RESET state\n");
+		FC_DBG("Port (%6x) entered RESET state from %s state\n",
+		       lport->fid, fc_lport_state(lport));
+
+	fc_lport_state_enter(lport, LPORT_ST_RESET);
 
 	if (lport->dns_rp) {
 		fc_remote_port_delete(lport->dns_rp);
@@ -679,24 +798,13 @@ int fc_lport_enter_reset(struct fc_lport *lport)
 	fc_block_rports(lport);
 
 	lport->tt.rport_reset_list(lport);
-
-	/*
-	 * Setting state RESET keeps fc_lport_error() callbacks
-	 * by exch_mgr_reset() from recursing on the lock.
-	 * It also causes fc_lport_sess_event() to ignore events.
-	 * The lock is held for the duration of the time in RESET state.
-	 */
-	fc_lport_state_enter(lport, LPORT_ST_RESET);
 	lport->tt.exch_mgr_reset(lport->emp, 0, 0);
 	fc_host_fabric_name(lport->host) = 0;
 	lport->fid = 0;
 
 	if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP)
 		fc_lport_enter_flogi(lport);
-
-	return 0;
 }
-EXPORT_SYMBOL(fc_lport_enter_reset);
 
 /**
  * fc_lport_error - Handler for any errors
@@ -729,8 +837,8 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)
 		case LPORT_ST_NONE:
 		case LPORT_ST_READY:
 		case LPORT_ST_RESET:
-		case LPORT_ST_REG_PN:
-		case LPORT_ST_REG_FT:
+		case LPORT_ST_RPN_ID:
+		case LPORT_ST_RFT_ID:
 		case LPORT_ST_SCR:
 		case LPORT_ST_DNS:
 		case LPORT_ST_FLOGI:
@@ -741,60 +849,153 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)
 	}
 }
 
-/*
- * Handle response from name server.
+/**
+ * fc_lport_rft_id_resp - Handle response to Register Fibre
+ *                        Channel Types by ID (RPN_ID) request
+ * @sp: current sequence in RPN_ID exchange
+ * @fp: response frame
+ * @lp_arg: Fibre Channel host port instance
+ *
+ * Locking Note: This function will be called without the lport lock
+ * held, but it will lock, call an _enter_* function or fc_lport_error
+ * and then unlock the lport.
  */
-static void fc_lport_ns_resp(struct fc_seq *sp, struct fc_frame *fp,
-			     void *lp_arg)
+static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp,
+				 void *lp_arg)
 {
 	struct fc_lport *lport = lp_arg;
+	struct fc_frame_header *fh;
+	struct fc_ct_hdr *ct;
 
-	if (!IS_ERR(fp)) {
-		fc_lport_lock(lport);
-		cancel_delayed_work_sync(&lport->retry_work);
-		if (fc_lport_dns_acc(fp)) {
-			if (lport->state == LPORT_ST_REG_PN)
-				fc_lport_enter_reg_ft(lport);
-			else
-				fc_lport_enter_scr(lport);
+	mutex_lock(&lport->lp_mutex);
 
-		} else {
-			fc_lport_error(lport, fp);
-		}
-		fc_lport_unlock(lport);
-		fc_frame_free(fp);
-	} else
+	if (fc_lport_debug)
+		FC_DBG("Received a RFT_ID response\n");
+
+	if (lport->state != LPORT_ST_RFT_ID) {
+		FC_DBG("Received a RFT_ID response, but in state %s\n",
+		       fc_lport_state(lport));
+		goto out;
+	}
+
+	if (IS_ERR(fp)) {
+		fc_lport_error(lport, fp);
+		goto out;
+	}
+
+	fh = fc_frame_header_get(fp);
+	ct = fc_frame_payload_get(fp, sizeof(*ct));
+
+	if (fh && ct && fh->fh_type == FC_TYPE_CT &&
+	    ct->ct_fs_type == FC_FST_DIR &&
+	    ct->ct_fs_subtype == FC_NS_SUBTYPE &&
+	    ntohs(ct->ct_cmd) == FC_FS_ACC)
+		fc_lport_enter_scr(lport);
+	else
 		fc_lport_error(lport, fp);
+out:
+	mutex_unlock(&lport->lp_mutex);
+	fc_frame_free(fp);
+}
+
+/**
+ * fc_lport_rpn_id_resp - Handle response to Register Port
+ *                        Name by ID (RPN_ID) request
+ * @sp: current sequence in RPN_ID exchange
+ * @fp: response frame
+ * @lp_arg: Fibre Channel host port instance
+ *
+ * Locking Note: This function will be called without the lport lock
+ * held, but it will lock, call an _enter_* function or fc_lport_error
+ * and then unlock the lport.
+ */
+static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
+				 void *lp_arg)
+{
+	struct fc_lport *lport = lp_arg;
+	struct fc_frame_header *fh;
+	struct fc_ct_hdr *ct;
+
+	mutex_lock(&lport->lp_mutex);
+
+	if (fc_lport_debug)
+		FC_DBG("Received a RPN_ID response\n");
+
+	if (lport->state != LPORT_ST_RPN_ID) {
+		FC_DBG("Received a RPN_ID response, but in state %s\n",
+		       fc_lport_state(lport));
+		goto out;
+	}
+
+	if (IS_ERR(fp)) {
+		fc_lport_error(lport, fp);
+		goto out;
+	}
+
+	fh = fc_frame_header_get(fp);
+	ct = fc_frame_payload_get(fp, sizeof(*ct));
+	if (fh && ct && fh->fh_type == FC_TYPE_CT &&
+	    ct->ct_fs_type == FC_FST_DIR &&
+	    ct->ct_fs_subtype == FC_NS_SUBTYPE &&
+	    ntohs(ct->ct_cmd) == FC_FS_ACC)
+		fc_lport_enter_rft_id(lport);
+	else
+		fc_lport_error(lport, fp);
+
+out:
+	mutex_unlock(&lport->lp_mutex);
+	fc_frame_free(fp);
 }
 
 /**
  * fc_lport_scr_resp - Handle response to State Change Register (SCR) request
  * @sp: current sequence in SCR exchange
  * @fp: response frame
- * @lp_arg: Fibre Channel host port instance
+ * @lp_arg: Fibre Channel lport port instance that sent the registration request
+ *
+ * Locking Note: This function will be called without the lport lock
+ * held, but it will lock, call an _enter_* function or fc_lport_error
+ * and then unlock the lport.
  */
 static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp,
 			      void *lp_arg)
 {
 	struct fc_lport *lport = lp_arg;
-	int err;
+	u8 op;
+
+	mutex_lock(&lport->lp_mutex);
+
+	if (fc_lport_debug)
+		FC_DBG("Received a SCR response\n");
+
+	if (lport->state != LPORT_ST_SCR) {
+		FC_DBG("Received a SCR response, but in state %s\n",
+		       fc_lport_state(lport));
+		goto out;
+	}
 
-	if (IS_ERR(fp))
+	if (IS_ERR(fp)) {
 		fc_lport_error(lport, fp);
-	else {
-		fc_lport_lock(lport);
-		fc_lport_enter_ready(lport);
-		fc_lport_unlock(lport);
-		err = lport->tt.disc_start(lport);
-		if (err)
-			FC_DBG("target discovery start error\n");
-		fc_frame_free(fp);
+		goto out;
 	}
+
+	op = fc_frame_payload_op(fp);
+	if (op == ELS_LS_ACC)
+		fc_lport_enter_ready(lport);
+	else
+		fc_lport_error(lport, fp);
+
+out:
+	mutex_unlock(&lport->lp_mutex);
+	fc_frame_free(fp);
 }
 
 /**
- * fc_lport_enter scr - Send a State Change Register (SCR) request
- * @lp: Fibre Channel host port instance
+ * fc_lport_enter_scr - Send a State Change Register (SCR) request
+ * @lport: Fibre Channel local port to register for state changes
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
  */
 static void fc_lport_enter_scr(struct fc_lport *lport)
 {
@@ -802,32 +1003,40 @@ static void fc_lport_enter_scr(struct fc_lport *lport)
 	struct fc_els_scr *scr;
 
 	if (fc_lport_debug)
-		FC_DBG("Processing SCR state\n");
+		FC_DBG("Port (%6x) entered SCR state from %s state\n",
+		       lport->fid, fc_lport_state(lport));
 
 	fc_lport_state_enter(lport, LPORT_ST_SCR);
 
 	fp = fc_frame_alloc(lport, sizeof(*scr));
-	if (fp) {
-		scr = fc_frame_payload_get(fp, sizeof(*scr));
-		memset(scr, 0, sizeof(*scr));
-		scr->scr_cmd = ELS_SCR;
-		scr->scr_reg_func = ELS_SCRF_FULL;
+	if (!fp) {
+		fc_lport_error(lport, fp);
+		return;
 	}
+
+	scr = fc_frame_payload_get(fp, sizeof(*scr));
+	memset(scr, 0, sizeof(*scr));
+	scr->scr_cmd = ELS_SCR;
+	scr->scr_reg_func = ELS_SCRF_FULL;
 	fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS);
 	fc_frame_set_offset(fp, 0);
 
-	lport->tt.exch_seq_send(lport, fp,
-				fc_lport_scr_resp, NULL,
-				lport, lport->e_d_tov,
-				lport->fid, FC_FID_FCTRL,
-				FC_FC_SEQ_INIT | FC_FC_END_SEQ);
+	if (!lport->tt.exch_seq_send(lport, fp,
+				     fc_lport_scr_resp, NULL,
+				     lport, lport->e_d_tov,
+				     lport->fid, FC_FID_FCTRL,
+				     FC_FC_SEQ_INIT | FC_FC_END_SEQ))
+		fc_lport_error(lport, fp);
 }
 
 /**
- * fc_lport_enter_reg_ft - Register FC4-types with the name server
- * @lp: Fibre Channel host port instance
+ * fc_lport_enter_rft_id - Register FC4-types with the name server
+ * @lport: Fibre Channel local port to register
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
  */
-static void fc_lport_enter_reg_ft(struct fc_lport *lport)
+static void fc_lport_enter_rft_id(struct fc_lport *lport)
 {
 	struct fc_frame *fp;
 	struct req {
@@ -839,47 +1048,54 @@ static void fc_lport_enter_reg_ft(struct fc_lport *lport)
 	int i;
 
 	if (fc_lport_debug)
-		FC_DBG("Processing REG_FT state\n");
+		FC_DBG("Port (%6x) entered RFT_ID state from %s state\n",
+		       lport->fid, fc_lport_state(lport));
 
-	fc_lport_state_enter(lport, LPORT_ST_REG_FT);
+	fc_lport_state_enter(lport, LPORT_ST_RFT_ID);
 
 	lps = &lport->fcts;
 	i = sizeof(lps->ff_type_map) / sizeof(lps->ff_type_map[0]);
 	while (--i >= 0)
 		if (ntohl(lps->ff_type_map[i]) != 0)
 			break;
-	if (i >= 0) {
+	if (i < 0) {
+		/* nothing to register, move on to SCR */
+		fc_lport_enter_scr(lport);
+	} else {
 		fp = fc_frame_alloc(lport, sizeof(*req));
-		if (fp) {
-			req = fc_frame_payload_get(fp, sizeof(*req));
-			fc_fill_dns_hdr(lport, &req->ct,
-					FC_NS_RFT_ID,
-					sizeof(*req) -
-					sizeof(struct fc_ct_hdr));
-			hton24(req->fid.fp_fid, lport->fid);
-			req->fts = *lps;
-			fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT);
-
-			if (!lport->tt.exch_seq_send(lport, fp,
-						     fc_lport_ns_resp, NULL,
-						     lport, lport->e_d_tov,
-						     lport->fid,
-						     FC_FID_DIR_SERV,
-						     FC_FC_SEQ_INIT |
-						     FC_FC_END_SEQ))
-				fc_lport_error(lport, fp);
-		} else {
+		if (!fp) {
 			fc_lport_error(lport, fp);
+			return;
 		}
-	} else {
-		fc_lport_enter_scr(lport);
+
+		req = fc_frame_payload_get(fp, sizeof(*req));
+		fc_fill_dns_hdr(lport, &req->ct,
+				FC_NS_RFT_ID,
+				sizeof(*req) -
+				sizeof(struct fc_ct_hdr));
+		hton24(req->fid.fp_fid, lport->fid);
+		req->fts = *lps;
+		fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT);
+
+		if (!lport->tt.exch_seq_send(lport, fp,
+					     fc_lport_rft_id_resp, NULL,
+					     lport, lport->e_d_tov,
+					     lport->fid,
+					     FC_FID_DIR_SERV,
+					     FC_FC_SEQ_INIT |
+					     FC_FC_END_SEQ))
+			fc_lport_error(lport, fp);
 	}
 }
 
-/*
- * Register port name with name server.
+/**
+ * fc_rport_enter_rft_id - Register port name with the name server
+ * @lport: Fibre Channel local port to register
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
  */
-static void fc_lport_enter_reg_pn(struct fc_lport *lport)
+static void fc_lport_enter_rpn_id(struct fc_lport *lport)
 {
 	struct fc_frame *fp;
 	struct req {
@@ -888,22 +1104,26 @@ static void fc_lport_enter_reg_pn(struct fc_lport *lport)
 	} *req;
 
 	if (fc_lport_debug)
-		FC_DBG("Processing REG_PN state\n");
+		FC_DBG("Port (%6x) entered RPN_ID state from %s state\n",
+		       lport->fid, fc_lport_state(lport));
+
+	fc_lport_state_enter(lport, LPORT_ST_RPN_ID);
 
-	fc_lport_state_enter(lport, LPORT_ST_REG_PN);
 	fp = fc_frame_alloc(lport, sizeof(*req));
 	if (!fp) {
 		fc_lport_error(lport, fp);
 		return;
 	}
+
 	req = fc_frame_payload_get(fp, sizeof(*req));
 	memset(req, 0, sizeof(*req));
 	fc_fill_dns_hdr(lport, &req->ct, FC_NS_RPN_ID, sizeof(req->rn));
 	hton24(req->rn.fr_fid.fp_fid, lport->fid);
 	put_unaligned_be64(lport->wwpn, &req->rn.fr_wwn);
 	fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT);
+
 	if (!lport->tt.exch_seq_send(lport, fp,
-				     fc_lport_ns_resp, NULL,
+				     fc_lport_rpn_id_resp, NULL,
 				     lport, lport->e_d_tov,
 				     lport->fid,
 				     FC_FID_DIR_SERV,
@@ -911,8 +1131,12 @@ static void fc_lport_enter_reg_pn(struct fc_lport *lport)
 		fc_lport_error(lport, fp);
 }
 
-/*
- * Setup session to dNS if not already set up.
+/**
+ * fc_rport_enter_dns - Create a rport to the name server
+ * @lport: Fibre Channel local port requesting a rport for the name server
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
  */
 static void fc_lport_enter_dns(struct fc_lport *lport)
 {
@@ -926,15 +1150,15 @@ static void fc_lport_enter_dns(struct fc_lport *lport)
 	dp.ids.roles = FC_RPORT_ROLE_UNKNOWN;
 
 	if (fc_lport_debug)
-		FC_DBG("Processing DNS state\n");
+		FC_DBG("Port (%6x) entered DNS state from %s state\n",
+		       lport->fid, fc_lport_state(lport));
 
 	fc_lport_state_enter(lport, LPORT_ST_DNS);
 
 	if (!lport->dns_rp) {
 		/* Set up a dummy rport to directory server */
-		fc_lport_unlock(lport);
 		rport = fc_rport_dummy_create(&dp);
-		fc_lport_lock(lport);
+
 		if (!rport)
 			goto err;
 		lport->dns_rp = rport;
@@ -944,16 +1168,8 @@ static void fc_lport_enter_dns(struct fc_lport *lport)
 	rdata = rport->dd_data;
 	rdata->local_port = lport;
 
-	/*
-	 * If dNS session isn't ready, start its logon.
-	 */
-	if (rdata->rp_state != RPORT_ST_READY) {
-		rdata->event_callback = fc_lport_rport_event;
-		lport->tt.rport_login(rport);
-	} else {
-		cancel_delayed_work_sync(&lport->retry_work);
-		fc_lport_enter_reg_pn(lport);
-	}
+	rdata->event_callback = fc_lport_rport_event;
+	lport->tt.rport_login(rport);
 	return;
 
 err:
@@ -970,7 +1186,7 @@ static void fc_lport_timeout(struct work_struct *work)
 		container_of(work, struct fc_lport,
 			     retry_work.work);
 
-	fc_lport_lock(lport);
+	mutex_lock(&lport->lp_mutex);
 
 	switch (lport->state) {
 	case LPORT_ST_NONE:
@@ -984,11 +1200,11 @@ static void fc_lport_timeout(struct work_struct *work)
 	case LPORT_ST_DNS:
 		fc_lport_enter_dns(lport);
 		break;
-	case LPORT_ST_REG_PN:
-		fc_lport_enter_reg_pn(lport);
+	case LPORT_ST_RPN_ID:
+		fc_lport_enter_rpn_id(lport);
 		break;
-	case LPORT_ST_REG_FT:
-		fc_lport_enter_reg_ft(lport);
+	case LPORT_ST_RFT_ID:
+		fc_lport_enter_rft_id(lport);
 		break;
 	case LPORT_ST_SCR:
 		fc_lport_enter_scr(lport);
@@ -998,32 +1214,67 @@ static void fc_lport_timeout(struct work_struct *work)
 		break;
 	}
 
-	fc_lport_unlock(lport);
+	mutex_unlock(&lport->lp_mutex);
 }
 
+/**
+ * fc_lport_logo_resp - Handle response to LOGO request
+ * @sp: current sequence in LOGO exchange
+ * @fp: response frame
+ * @lp_arg: Fibre Channel lport port instance that sent the LOGO request
+ *
+ * Locking Note: This function will be called without the lport lock
+ * held, but it will lock, call an _enter_* function or fc_lport_error
+ * and then unlock the lport.
+ */
 static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
 			       void *lp_arg)
 {
 	struct fc_lport *lport = lp_arg;
+	u8 op;
+
+	mutex_lock(&lport->lp_mutex);
+
+	if (fc_lport_debug)
+		FC_DBG("Received a LOGO response\n");
 
-	if (IS_ERR(fp))
+	if (lport->state != LPORT_ST_LOGO) {
+		FC_DBG("Received a LOGO response, but in state %s\n",
+		       fc_lport_state(lport));
+		goto out;
+	}
+
+	if (IS_ERR(fp)) {
 		fc_lport_error(lport, fp);
-	else {
-		fc_frame_free(fp);
-		fc_lport_lock(lport);
-		fc_lport_enter_reset(lport);
-		fc_lport_unlock(lport);
+		goto out;
 	}
+
+	op = fc_frame_payload_op(fp);
+	if (op == ELS_LS_ACC)
+		fc_lport_enter_reset(lport);
+	else
+		fc_lport_error(lport, fp);
+
+out:
+	mutex_unlock(&lport->lp_mutex);
+	fc_frame_free(fp);
 }
 
-/* Logout of the FC fabric */
+/**
+ * fc_rport_enter_logo - Logout of the fabric
+ * @lport: Fibre Channel local port to be logged out
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
+ */
 static void fc_lport_enter_logo(struct fc_lport *lport)
 {
 	struct fc_frame *fp;
 	struct fc_els_logo *logo;
 
 	if (fc_lport_debug)
-		FC_DBG("Processing LOGO state\n");
+		FC_DBG("Port (%6x) entered LOGO state from %s state\n",
+		       lport->fid, fc_lport_state(lport));
 
 	fc_lport_state_enter(lport, LPORT_ST_LOGO);
 
@@ -1035,7 +1286,7 @@ static void fc_lport_enter_logo(struct fc_lport *lport)
 
 	fp = fc_frame_alloc(lport, sizeof(*logo));
 	if (!fp) {
-		FC_DBG("failed to allocate frame\n");
+		fc_lport_error(lport, fp);
 		return;
 	}
 
@@ -1044,20 +1295,26 @@ static void fc_lport_enter_logo(struct fc_lport *lport)
 	logo->fl_cmd = ELS_LOGO;
 	hton24(logo->fl_n_port_id, lport->fid);
 	logo->fl_n_port_wwn = htonll(lport->wwpn);
-
 	fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS);
 	fc_frame_set_offset(fp, 0);
 
-	lport->tt.exch_seq_send(lport, fp,
-				fc_lport_logo_resp, NULL,
-				lport, lport->e_d_tov,
-				lport->fid, FC_FID_FLOGI,
-				FC_FC_SEQ_INIT | FC_FC_END_SEQ);
+	if (!lport->tt.exch_seq_send(lport, fp,
+				     fc_lport_logo_resp, NULL,
+				     lport, lport->e_d_tov,
+				     lport->fid, FC_FID_FLOGI,
+				     FC_FC_SEQ_INIT | FC_FC_END_SEQ))
+		fc_lport_error(lport, fp);
 }
 
-/*
- * Handle incoming ELS FLOGI response.
- * Save parameters of remote switch.  Finish exchange.
+/**
+ * fc_lport_flogi_resp - Handle response to FLOGI request
+ * @sp: current sequence in FLOGI exchange
+ * @fp: response frame
+ * @lp_arg: Fibre Channel lport port instance that sent the FLOGI request
+ *
+ * Locking Note: This function will be called without the lport lock
+ * held, but it will lock, call an _enter_* function or fc_lport_error
+ * and then unlock the lport.
  */
 static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 				void *lp_arg)
@@ -1071,17 +1328,28 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 	unsigned int e_d_tov;
 	u16 mfs;
 
+	mutex_lock(&lport->lp_mutex);
+
+	if (fc_lport_debug)
+		FC_DBG("Received a FLOGI response\n");
+
+	if (lport->state != LPORT_ST_FLOGI) {
+		FC_DBG("Received a FLOGI response, but in state %s\n",
+		       fc_lport_state(lport));
+		goto out;
+	}
+
 	if (IS_ERR(fp)) {
 		fc_lport_error(lport, fp);
-		return;
+		goto out;
 	}
 
 	fh = fc_frame_header_get(fp);
 	did = ntoh24(fh->fh_d_id);
 	if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) {
 		if (fc_lport_debug)
-			FC_DBG("assigned fid %x\n", did);
-		fc_lport_lock(lport);
+			FC_DBG("Assigned fid %x\n", did);
+
 		lport->fid = did;
 		flp = fc_frame_payload_get(fp, sizeof(*flp));
 		if (flp) {
@@ -1099,7 +1367,7 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 				if (e_d_tov > lport->e_d_tov)
 					lport->e_d_tov = e_d_tov;
 				lport->r_a_tov = 2 * e_d_tov;
-				FC_DBG("point-to-point mode\n");
+				FC_DBG("Point-to-Point mode\n");
 				fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id),
 						   get_unaligned_be64(
 							   &flp->fl_wwpn),
@@ -1113,22 +1381,29 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 				fc_lport_enter_dns(lport);
 			}
 		}
-		fc_lport_unlock(lport);
+
 		if (flp) {
 			csp_flags = ntohs(flp->fl_csp.sp_features);
 			if ((csp_flags & FC_SP_FT_FPORT) == 0) {
 				if (lport->tt.disc_start(lport))
-					FC_DBG("target disc start error\n");
+					FC_DBG("Target disc start error\n");
 			}
 		}
 	} else {
 		FC_DBG("bad FLOGI response\n");
 	}
+
+out:
+	mutex_unlock(&lport->lp_mutex);
 	fc_frame_free(fp);
 }
 
-/*
- * Send ELS (extended link service) FLOGI request to peer.
+/**
+ * fc_rport_enter_flogi - Send a FLOGI request to the fabric manager
+ * @lport: Fibre Channel local port to be logged in to the fabric
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
  */
 void fc_lport_enter_flogi(struct fc_lport *lport)
 {
@@ -1163,11 +1438,9 @@ void fc_lport_enter_flogi(struct fc_lport *lport)
 int fc_lport_config(struct fc_lport *lport)
 {
 	INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout);
-	spin_lock_init(&lport->state_lock);
+	mutex_init(&lport->lp_mutex);
 
-	fc_lport_lock(lport);
 	fc_lport_state_enter(lport, LPORT_ST_NONE);
-	fc_lport_unlock(lport);
 
 	lport->ns_disc_delay = DNS_DELAY;
 
@@ -1181,10 +1454,10 @@ EXPORT_SYMBOL(fc_lport_config);
 int fc_lport_init(struct fc_lport *lport)
 {
 	if (!lport->tt.lport_recv)
-		lport->tt.lport_recv = fc_lport_recv;
+		lport->tt.lport_recv = fc_lport_recv_req;
 
 	if (!lport->tt.lport_reset)
-		lport->tt.lport_reset = fc_lport_enter_reset;
+		lport->tt.lport_reset = fc_lport_reset;
 
 	if (!lport->tt.event_callback)
 		lport->tt.event_callback = fc_lport_rport_event;
diff --git a/drivers/scsi/libfc/fc_ns.c b/drivers/scsi/libfc/fc_ns.c
index b40cf4e..8881af3 100644
--- a/drivers/scsi/libfc/fc_ns.c
+++ b/drivers/scsi/libfc/fc_ns.c
@@ -154,13 +154,11 @@ static void fc_ns_recv_req(struct fc_seq *sp, struct fc_frame *fp,
  */
 static int fc_ns_restart(struct fc_lport *lp)
 {
-	fc_lport_lock(lp);
 	if (!lp->ns_disc_requested && !lp->ns_disc_pending) {
 		schedule_delayed_work(&lp->ns_disc_work,
 				msecs_to_jiffies(lp->ns_disc_delay * 1000));
 	}
 	lp->ns_disc_requested = 1;
-	fc_lport_unlock(lp);
 	return 0;
 }
 
@@ -180,14 +178,12 @@ int fc_ns_disc_start(struct fc_lport *lp)
 	int error;
 	struct fc_rport_identifiers ids;
 
-	fc_lport_lock(lp);
-
 	/*
 	 * If not ready, or already running discovery, just set request flag.
 	 */
 	if (!fc_lport_test_ready(lp) || lp->ns_disc_pending) {
 		lp->ns_disc_requested = 1;
-		fc_lport_unlock(lp);
+
 		return 0;
 	}
 	lp->ns_disc_pending = 1;
@@ -205,13 +201,13 @@ int fc_ns_disc_start(struct fc_lport *lp)
 		ids.node_name = rport->node_name;
 		ids.roles = FC_RPORT_ROLE_UNKNOWN;
 		get_device(&rport->dev);
-		fc_lport_unlock(lp);
+
 		error = fc_ns_new_target(lp, rport, &ids);
 		put_device(&rport->dev);
 		if (!error)
 			fc_ns_disc_done(lp);
 	} else {
-		fc_lport_unlock(lp);
+
 		fc_block_rports(lp);
 		fc_ns_gpn_ft_req(lp);	/* get ports by FC-4 type */
 		error = 0;
diff --git a/include/scsi/libfc/libfc.h b/include/scsi/libfc/libfc.h
index d115aa6..4f47ece 100644
--- a/include/scsi/libfc/libfc.h
+++ b/include/scsi/libfc/libfc.h
@@ -92,8 +92,8 @@ enum fc_lport_state {
 	LPORT_ST_NONE = 0,
 	LPORT_ST_FLOGI,
 	LPORT_ST_DNS,
-	LPORT_ST_REG_PN,
-	LPORT_ST_REG_FT,
+	LPORT_ST_RPN_ID,
+	LPORT_ST_RFT_ID,
 	LPORT_ST_SCR,
 	LPORT_ST_READY,
 	LPORT_ST_LOGO,
@@ -456,8 +456,8 @@ struct fc_lport {
 	struct fc_ns_fts	fcts;	        /* FC-4 type masks */
 	struct fc_els_rnid_gen	rnid_gen;	/* RNID information */
 
-	/* Locks */
-	spinlock_t		state_lock;	/* serializes state changes */
+	/* Semaphores */
+	struct mutex lp_mutex;
 
 	/* Miscellaneous */
 	struct fc_gpn_ft_resp	ns_disc_buf;	/* partial name buffer */
@@ -491,15 +491,6 @@ static inline void fc_set_wwpn(struct fc_lport *lp, u64 wwnn)
 	lp->wwpn = wwnn;
 }
 
-static inline int fc_lport_locked(struct fc_lport *lp)
-{
-#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
-	return spin_is_locked(&lp->state_lock);
-#else
-	return 1;
-#endif /* CONFIG_SMP || CONFIG_DEBUG_SPINLOCK */
-}
-
 /**
  * fc_fill_dns_hdr - Fill in a name service request header
  * @lp: Fibre Channel host port instance
@@ -517,23 +508,9 @@ static inline void fc_fill_dns_hdr(struct fc_lport *lp, struct fc_ct_hdr *ct,
 	ct->ct_cmd = htons((u16) op);
 }
 
-/*
- * Locking code.
- */
-static inline void fc_lport_lock(struct fc_lport *lp)
-{
-	spin_lock_bh(&lp->state_lock);
-}
-
-static inline void fc_lport_unlock(struct fc_lport *lp)
-{
-	spin_unlock_bh(&lp->state_lock);
-}
-
 static inline void fc_lport_state_enter(struct fc_lport *lp,
 					enum fc_lport_state state)
 {
-	WARN_ON(!fc_lport_locked(lp));
 	if (state != lp->state)
 		lp->retry_count = 0;
 	lp->state = state;
@@ -588,7 +565,7 @@ int fc_lport_config(struct fc_lport *);
 /*
  * Reset the local port.
  */
-int fc_lport_enter_reset(struct fc_lport *);
+int fc_lport_reset(struct fc_lport *);
 
 /*
  * Set the mfs or reset




More information about the devel mailing list