1) removes fc_rport_lock/unlock and replaces with spin_lock_irqsave/restore
2) re-implements rport locking using the following scheme
Action Funtions (called without lock, will lock, call enter_* function and
unlock)
fc_rport_gpn_id_resp
fc_rport_gnn_id_resp
fc_rport_plogi_resp
fc_rport_prli_resp
fc_rport_rtv_resp
fc_rport_logo_resp
fc_rport_login
fc_rport_logout
fc_rport_reset
fc_rport_timeout
fc_rport_recv_req
- Calls one of the request handlers with the lock held
Request Handlers (need lock held before calling)
fc_rport_recv_plogi_req
fc_rport_recv_prli_req
fc_rport_recv_prlo_req
fc_rport_recv_logo_req
Enter Funtions (need lock held before calling)
fc_rport_enter_gpn_id
fc_rport_enter_gnn_id
fc_rport_enter_plogi
fc_rport_enter_prli
fc_rport_enter_rtv
fc_rport_enter_logo
Helpers (Lock required)
fc_rport_state_enter
- Changing the state so the lock must be held
fc_rport_error
- Always called by an action or enter function
Helpers (Lock not required)
fc_rport_create_dummy
fc_rport_destroy_dummy
fc_rport_lookup
fc_remote_port_create
fc_rport_lock
fc_rport_unlock
fc_plogi_get_maxframe
fc_lport_plogi_fill
fc_rport_init
fc_rport_reset_list
Unknown
fc_rport_ns_error
- Merge with fc_rport_error
fc_rport_retry
- Merge with fc_rport_error
Signed-off-by: Robert Love <[EMAIL PROTECTED]>
---
drivers/scsi/libfc/fc_rport.c | 856 +++++++++++++++++++++--------------------
include/scsi/libfc/libfc.h | 6
2 files changed, 445 insertions(+), 417 deletions(-)
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 27f485a..159c365 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -68,7 +68,6 @@ static const char *fc_rport_state_names[] = {
[RPORT_ST_GPN_ID] = "GPN_ID",
[RPORT_ST_GNN_ID] = "GNN_ID",
[RPORT_ST_PLOGI] = "PLOGI",
- [RPORT_ST_PLOGI_RECV] = "PLOGI recv",
[RPORT_ST_PRLI] = "PRLI",
[RPORT_ST_RTV] = "RTV",
[RPORT_ST_READY] = "Ready",
@@ -173,18 +172,6 @@ static struct fc_rport *fc_remote_port_create(struct
fc_lport *lp,
return rport;
}
-static inline void fc_rport_lock(struct fc_rport *rport)
-{
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- spin_lock_bh(&rp->rp_lock);
-}
-
-static inline void fc_rport_unlock(struct fc_rport *rport)
-{
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- spin_unlock_bh(&rp->rp_lock);
-}
-
static void fc_rport_state_enter(struct fc_rport *rport,
enum fc_rport_state new)
{
@@ -214,40 +201,37 @@ static void fc_rport_enter_ready(struct fc_rport *rp)
/**
* fc_rport_enter_gpn_id - Send Get Port Name by ID (GPN_ID) request
- * @work: The work member of the fc_ns_port structure
+ * @rp: The fc_rport
*
- * XXX - this the following statement still valid?
- * The remote port is held by the caller for us.
+ * Locking Note: The rport lock is expected to be held before calling
+ * this routine.
*/
void fc_rport_enter_gpn_id(struct fc_rport *rp)
{
- struct fc_rport_libfc_priv *rpp;
- struct fc_lport *lp;
+ 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;
- rpp = rp->dd_data;
- lp = rpp->local_port;
-
fc_rport_state_enter(rp, RPORT_ST_GPN_ID);
if (fc_rp_debug)
FC_DBG("Entered GPN_ID for port (%6x)\n", rp->port_id);
fp = fc_frame_alloc(lp, sizeof(*cp));
- if (!fp)
+ if (!fp) {
+ fc_rport_error(rp, 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, 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_rport_gpn_id_resp,
rp, lp->e_d_tov,
@@ -262,30 +246,43 @@ void fc_rport_enter_gpn_id(struct fc_rport *rp)
* @sp: Current sequence of GPN_ID exchange
* @fp: response frame
* @dp_arg: Temporary discovery port for holding IDs and world wide names
+ *
+ * Locking Note: This is an action function so we lock and then call
+ * the next _enter_* function, unlock when it returns.
*/
static void fc_rport_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
- void *rp_arg)
+ void *rp_arg)
{
struct fc_rport *rp = rp_arg;
struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ unsigned long flags;
- struct fc_lport *lp;
struct resp {
struct fc_ct_hdr ct;
__be64 wwn;
} *cp;
unsigned int cmd;
+ spin_lock_irqsave(&rpp->rp_lock, flags);
+
+ if (rpp->rp_state != RPORT_ST_GPN_ID) {
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ FC_DBG("Recieved a GPN_ID response, but port (%6x) is in "
+ "the %s state\n", rp->port_id, fc_rport_state(rp));
+ return;
+ }
+
if (IS_ERR(fp)) {
fc_rport_error(rp, fp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
return;
}
- lp = rpp->local_port;
WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */
cp = fc_frame_payload_get(fp, sizeof(cp->ct));
- if (cp == NULL) {
+ if (!cp) {
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
FC_DBG("GPN_ID response too short, len %d\n", fr_len(fp));
return;
}
@@ -293,20 +290,22 @@ static void fc_rport_gpn_id_resp(struct fc_seq *sp,
struct fc_frame *fp,
switch (cmd) {
case FC_FS_ACC:
cp = fc_frame_payload_get(fp, sizeof(*cp));
- if (cp == NULL) {
+ if (!cp) {
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
FC_DBG("GPN_ID response payload too short, len %d\n",
fr_len(fp));
break;
}
rp->port_name = ntohll(cp->wwn);
-
fc_rport_enter_gnn_id(rp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
break;
case FC_FS_RJT:
- lp->tt.lport_event_callback(lp, rp, LPORT_EV_RPORT_FAILED);
- fc_rport_destroy_dummy(rp);
+ fc_rport_error(rp, fp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
break;
default:
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
FC_DBG("GPN_ID unexpected CT response cmd %x\n", cmd);
break;
}
@@ -315,41 +314,37 @@ static void fc_rport_gpn_id_resp(struct fc_seq *sp,
struct fc_frame *fp,
/**
* fc_rport_enter_gnn_id - 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: The fc_rport object
*
- * XXX- Is the following statement still true?
- * The remote port is held by the caller for us.
+ * Locking Note: The rport lock is expected to be held before calling
+ * this routine.
*/
void fc_rport_enter_gnn_id(struct fc_rport *rp)
{
- struct fc_rport_libfc_priv *rpp;
- struct fc_lport *lp;
+ 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;
- rpp = rp->dd_data;
- lp = rpp->local_port;
+ fc_rport_state_enter(rp, RPORT_ST_GNN_ID);
if (fc_rp_debug)
FC_DBG("Entered GNN_ID for port (%6x)\n", rp->port_id);
- fc_rport_state_enter(rp, RPORT_ST_GNN_ID);
-
fp = fc_frame_alloc(lp, sizeof(*cp));
- if (!fp)
+ if (!fp) {
+ fc_rport_error(rp, 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, 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_rport_gnn_id_resp,
rp, lp->e_d_tov,
@@ -364,14 +359,21 @@ void fc_rport_enter_gnn_id(struct fc_rport *rp)
* @sp: Current sequence of GNN_ID exchange
* @fp: response frame
* @dp_arg: Temporary discovery port for holding IDs and world wide names
+ *
+ * Locking Note: This is an action function so we hold the lock and then
+ * call an _enter_* function. This method is special though becuase this
+ * is where we transition from the dummy rport to the one the the
+ * transport class is aware of. We must transition the lock, state, WWNN,
+ * WWPN and FID from the dummy to the new rport.
*/
static void fc_rport_gnn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
void *rp_arg)
{
struct fc_rport *rp = rp_arg;
- struct fc_rport_libfc_priv *rpp;
- struct fc_lport *lp;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ struct fc_lport *lp = rpp->local_port;
struct fc_rport_identifiers ids;
+ unsigned long flags;
struct resp {
struct fc_ct_hdr ct;
@@ -379,19 +381,27 @@ static void fc_rport_gnn_id_resp(struct fc_seq *sp,
struct fc_frame *fp,
} *cp;
unsigned int cmd;
- rpp = rp->dd_data;
+ spin_lock_irqsave(&rpp->rp_lock, flags);
+
+ if (rpp->rp_state != RPORT_ST_GNN_ID) {
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ FC_DBG("Recieved a GNN_ID response, but port (%6x) is in "
+ "the %s state\n", rp->port_id, fc_rport_state(rp));
+ return;
+ }
if (IS_ERR(fp)) {
fc_rport_error(rp, fp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
return;
}
- lp = rpp->local_port;
- WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */
+ WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */
cp = fc_frame_payload_get(fp, sizeof(cp->ct));
- if (cp == NULL) {
- FC_DBG("GNN_ID response too short, len %d\n", fr_len(fp));
+ if (!cp) {
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ FC_DBG("GNN_ID response too short, len %d\n", fr_len(fp));
return;
}
@@ -399,7 +409,8 @@ static void fc_rport_gnn_id_resp(struct fc_seq *sp, struct
fc_frame *fp,
switch (cmd) {
case FC_FS_ACC:
cp = fc_frame_payload_get(fp, sizeof(*cp));
- if (cp == NULL) {
+ if (!cp) {
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
FC_DBG("GNN_ID response payload too short, len %d\n",
fr_len(fp));
break;
@@ -411,31 +422,52 @@ static void fc_rport_gnn_id_resp(struct fc_seq *sp,
struct fc_frame *fp,
ids.node_name = rp->node_name;
ids.roles = rp->roles;
- fc_rport_destroy_dummy(rp);
-
if ((ids.port_name != -1) && (ids.port_id != -1) &&
(ids.port_id != lp->fid) && (ids.port_name != lp->wwpn)) {
- rp = lp->tt.rport_lookup(lp, ids.port_id);
- if (!rp)
- rp = lp->tt.rport_create(lp, &ids);
+ struct fc_rport *new_rp;
+ new_rp = lp->tt.rport_lookup(lp, ids.port_id);
+ if (!new_rp) {
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ new_rp = lp->tt.rport_create(lp, &ids);
+ spin_lock_irqsave(&rpp->rp_lock, flags);
+ }
+
+ if (new_rp) {
+ /*
+ * Transition locking and state from
+ * the dummy rport to the real rport
+ */
+ unsigned long new_flags;
+ struct fc_rport_libfc_priv *new_rpp =
+ new_rp->dd_data;
+
+ spin_lock_irqsave(&new_rpp->rp_lock, new_flags);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+
+ fc_rport_destroy_dummy(rp);
+ fc_rport_state_enter(new_rp, RPORT_ST_GNN_ID);
+ fc_rport_enter_plogi(new_rp);
+ spin_unlock_irqrestore(&new_rpp->rp_lock,
+ new_flags);
+ } else {
+ lp->tt.lport_event_callback(lp, rp,
+
LPORT_EV_RPORT_FAILED);
- if (!rp)
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ fc_rport_destroy_dummy(rp);
FC_DBG("Could not create a remote port, "
"WWNN (%llux), WWNN (%llux), "
"FID (%6x)\n", ids.node_name,
ids.port_name, ids.port_id);
- else {
- rpp = rp->dd_data;
- rpp->rp_state = RPORT_ST_GNN_ID;
- fc_rport_enter_plogi(rp);
}
}
break;
case FC_FS_RJT:
- lp->tt.lport_event_callback(lp, rp, LPORT_EV_RPORT_FAILED);
- fc_rport_destroy_dummy(rp);
+ fc_rport_error(rp, fp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
break;
default:
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
FC_DBG("GNN_ID unexpected CT response cmd %x\n", cmd);
break;
}
@@ -506,115 +538,76 @@ fc_lport_plogi_fill(struct fc_lport *lp,
/**
* fc_rport_login - Start the remote port login state machine
* @work: member of the fc_rport_libfc_priv structure
+ *
+ * Locking Note: This is an action function so we grab the
+ * lock, call an _enter_* state and then unlock.
*/
void fc_rport_login(struct work_struct *work)
{
- struct fc_rport *rport;
- struct fc_rport_libfc_priv *rp;
+ struct fc_rport *rp;
+ struct fc_rport_libfc_priv *rpp;
struct fc_lport *lp;
+ unsigned long flags;
- rp = container_of(work,
+ rpp = container_of(work,
struct fc_rport_libfc_priv,
login_work);
+ rp = (((void *)rpp) - sizeof(struct fc_rport));
+ lp = rpp->local_port;
- rport = (((void *)rp) - sizeof(struct fc_rport));
- lp = rp->local_port;
+ spin_lock_irqsave(&rpp->rp_lock, flags);
- fc_rport_lock(rport);
- if (rp->rp_state == RPORT_ST_ERROR) {
- fc_rport_state_enter(rport, RPORT_ST_INIT);
- fc_rport_unlock(rport);
- if (fc_rp_debug)
- FC_DBG("remote %6x closed\n", rport->port_id);
+ /*
+ * This should be the only non _enter_* function
+ * that sets the state.
+ */
+ fc_rport_state_enter(rp, RPORT_ST_INIT);
- lp->tt.lport_event_callback(lp, rport, LPORT_EV_RPORT_FAILED);
- } else {
- fc_rport_unlock(rport);
- if (rport->port_id == FC_FID_DIR_SERV)
- fc_rport_enter_plogi(rport);
- else if (rport->port_name == -1)
- fc_rport_enter_gpn_id(rport);
- else if (rport->node_name == -1)
- fc_rport_enter_gnn_id(rport);
- }
+ if (rp->port_id == FC_FID_DIR_SERV)
+ fc_rport_enter_plogi(rp);
+ else if (rp->port_name == -1)
+ fc_rport_enter_gpn_id(rp);
+ else if (rp->node_name == -1)
+ fc_rport_enter_gnn_id(rp);
+
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
}
-/*
- * Stop the session - log it off.
+/**
+ * fc_rport_logout - Stop the remote port state machine
+ * @rp: The fc_rport to logout
+ *
+ * Locking Note: This is an action function so we grab the
+ * lock, call an _enter_* state and then unlock.
*/
-int fc_rport_logout(struct fc_rport *rport)
+void fc_rport_logout(struct fc_rport *rp)
{
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- struct fc_lport *lp = rp->local_port;
-
- fc_rport_lock(rport);
- switch (rp->rp_state) {
- case RPORT_ST_PRLI:
- case RPORT_ST_RTV:
- case RPORT_ST_READY:
- fc_rport_enter_logo(rport);
- fc_rport_unlock(rport);
- break;
- default:
- fc_rport_state_enter(rport, RPORT_ST_INIT);
- fc_rport_unlock(rport);
- if (fc_rp_debug)
- FC_DBG("remote %6x closed\n", rport->port_id);
- if (rport == lp->dns_rp &&
- lp->state != LPORT_ST_RESET) {
- fc_lport_lock(lp);
- del_timer(&lp->state_timer);
- lp->dns_rp = NULL;
-
- if (lp->state == LPORT_ST_DNS_STOP) {
- fc_lport_unlock(lp);
- lp->tt.lport_logout(lp);
- } else {
- lp->tt.lport_login(lp);
- fc_lport_unlock(lp);
- }
-
- fc_remote_port_delete(rport);
- }
- break;
- }
-
- return 0;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ unsigned long flags;
+ spin_lock_irqsave(&rpp->rp_lock, flags);
+ fc_rport_enter_logo(rp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
}
-/*
- * Reset the session - assume it is logged off. Used after fabric
logoff.
- * The local port code takes care of resetting the exchange manager.
+/**
+ * fc_rport_reset - Stop and then start the remote port state machine
+ * @rp: The fc_rport to reset
+ *
+ * Locking Note: This is an action function so we grab the
+ * lock, call an _enter_* state and then unlock.
*/
-void fc_rport_reset(struct fc_rport *rport)
+void fc_rport_reset(struct fc_rport *rp)
{
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- struct fc_lport *lp;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ unsigned long flags;
+ spin_lock_irqsave(&rpp->rp_lock, flags);
if (fc_rp_debug)
- FC_DBG("sess to %6x reset\n", rport->port_id);
- fc_rport_lock(rport);
-
- lp = rp->local_port;
- fc_rport_state_enter(rport, RPORT_ST_INIT);
- fc_rport_unlock(rport);
+ FC_DBG("Port %6x reset\n", rp->port_id);
- if (fc_rp_debug)
- FC_DBG("remote %6x closed\n", rport->port_id);
- if (rport == lp->dns_rp &&
- lp->state != LPORT_ST_RESET) {
- fc_lport_lock(lp);
- del_timer(&lp->state_timer);
- lp->dns_rp = NULL;
- if (lp->state == LPORT_ST_DNS_STOP) {
- fc_lport_unlock(lp);
- lp->tt.lport_logout(lp);
- } else {
- lp->tt.lport_login(lp);
- fc_lport_unlock(lp);
- }
- fc_remote_port_delete(rport);
- }
+ fc_rport_state_enter(rp, RPORT_ST_INIT);
+ fc_rport_enter_gpn_id(rp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
}
/*
@@ -689,7 +682,6 @@ static void fc_rport_reject(struct fc_rport *rport)
case RPORT_ST_NONE:
case RPORT_ST_READY:
case RPORT_ST_ERROR:
- case RPORT_ST_PLOGI_RECV:
case RPORT_ST_INIT:
BUG();
break;
@@ -700,41 +692,51 @@ static void fc_rport_reject(struct fc_rport *rport)
/*
* Timeout handler for retrying after allocation failures or exchange timeout.
*/
+
+/**
+ * fc_rport_timeout - Handler for the retry_work timer.
+ * Simply determine what should be done next.
+ * @work: The work struct of the fc_rport_libfc_priv
+ *
+ * Locking Note: This is an action function so we grab the
+ * lock, call an _enter_* state and then unlock.
+ */
static void fc_rport_timeout(struct work_struct *work)
{
- struct fc_rport_libfc_priv *rp =
+ struct fc_rport_libfc_priv *rpp =
container_of(work, struct fc_rport_libfc_priv, retry_work.work);
- struct fc_rport *rport = (((void *)rp) - sizeof(struct fc_rport));
+ struct fc_rport *rp = (((void *)rpp) - sizeof(struct fc_rport));
+ unsigned long flags;
- switch (rp->rp_state) {
+ spin_lock_irqsave(&rpp->rp_lock, flags);
+ switch (rpp->rp_state) {
case RPORT_ST_GPN_ID:
- fc_rport_enter_gpn_id(rport);
+ fc_rport_enter_gpn_id(rp);
break;
case RPORT_ST_GNN_ID:
- fc_rport_enter_gnn_id(rport);
+ fc_rport_enter_gnn_id(rp);
break;
case RPORT_ST_PLOGI:
- fc_rport_enter_plogi(rport);
+ fc_rport_enter_plogi(rp);
break;
case RPORT_ST_PRLI:
- fc_rport_enter_prli(rport);
+ fc_rport_enter_prli(rp);
break;
case RPORT_ST_RTV:
- fc_rport_enter_rtv(rport);
+ fc_rport_enter_rtv(rp);
break;
case RPORT_ST_LOGO:
- fc_rport_enter_logo(rport);
+ fc_rport_enter_logo(rp);
break;
case RPORT_ST_READY:
case RPORT_ST_ERROR:
case RPORT_ST_INIT:
- break;
case RPORT_ST_NONE:
- case RPORT_ST_PLOGI_RECV:
BUG();
break;
}
- put_device(&rport->dev);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ put_device(&rp->dev);
}
/*
@@ -764,89 +766,103 @@ static void fc_rport_error(struct fc_rport *rport,
struct fc_frame *fp)
static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
void *rp_arg)
{
- struct fc_els_ls_rjt *rjp;
+ struct fc_rport *rp = rp_arg;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+
struct fc_els_flogi *plp;
u64 wwpn, wwnn;
unsigned int tov;
u16 csp_seq;
u16 cssp_seq;
u8 op;
- struct fc_rport *rport = rp_arg;
- struct fc_rport_libfc_priv *rp = rport->dd_data;
+ unsigned long flags;
- if (!IS_ERR(fp)) {
- op = fc_frame_payload_op(fp);
- fc_rport_lock(rport);
- if (op == ELS_LS_ACC &&
- (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) {
- wwpn = get_unaligned_be64(&plp->fl_wwpn);
- wwnn = get_unaligned_be64(&plp->fl_wwnn);
-
- fc_rport_set_name(rport, wwpn, wwnn);
- tov = ntohl(plp->fl_csp.sp_e_d_tov);
- if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
- tov /= 1000;
- if (tov > rp->e_d_tov)
- rp->e_d_tov = tov;
- csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
- cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
- if (cssp_seq < csp_seq)
- csp_seq = cssp_seq;
- rp->max_seq = csp_seq;
- rport->maxframe_size =
- fc_plogi_get_maxframe(plp, rp->local_port->mfs);
- if (rp->rp_state == RPORT_ST_PLOGI)
- fc_rport_enter_prli(rport);
- } else {
- if (fc_rp_debug)
- FC_DBG("bad PLOGI response\n");
-
- rjp = fc_frame_payload_get(fp, sizeof(*rjp));
- if (op == ELS_LS_RJT && rjp != NULL &&
- rjp->er_reason == ELS_RJT_INPROG)
- fc_rport_error(rport, fp); /* try again */
- else
- fc_rport_reject(rport); /* error */
- }
- fc_rport_unlock(rport);
- fc_frame_free(fp);
+ spin_lock_irqsave(&rpp->rp_lock, flags);
+
+ if (rpp->rp_state != RPORT_ST_PLOGI) {
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ FC_DBG("Recieved a PLOGI response, but port (%6x) is in "
+ "the %s state\n", rp->port_id, fc_rport_state(rp));
+ return;
+ }
+
+ if (IS_ERR(fp)) {
+ fc_rport_error(rp, fp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ }
+
+ op = fc_frame_payload_op(fp);
+ if (op == ELS_LS_ACC &&
+ (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) {
+ wwpn = get_unaligned_be64(&plp->fl_wwpn);
+ wwnn = get_unaligned_be64(&plp->fl_wwnn);
+ fc_rport_set_name(rp, wwpn, wwnn);
+ tov = ntohl(plp->fl_csp.sp_e_d_tov);
+
+ if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
+ tov /= 1000;
+ if (tov > rpp->e_d_tov)
+ rpp->e_d_tov = tov;
+
+ csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
+ cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
+
+ if (cssp_seq < csp_seq)
+ csp_seq = cssp_seq;
+
+ rpp->max_seq = csp_seq;
+ rp->maxframe_size =
+ fc_plogi_get_maxframe(plp, rpp->local_port->mfs);
+
+ fc_rport_enter_prli(rp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
} else {
- fc_rport_error(rport, fp);
+ if (fc_rp_debug)
+ FC_DBG("Bad PLOGI response\n");
+ fc_rport_error(rp, fp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
}
+ fc_frame_free(fp);
}
/**
* fc_rport_enter_plogi - Send Port Login (PLOGI) request to peer
- * @rport: Fibre Channel remote port to send PLOGI to
+ * @rp: Fibre Channel remote port to send PLOGI to
+ *
+ * Locking Note: The rport lock is expected to be held before calling
+ * this routine.
*/
-static void fc_rport_enter_plogi(struct fc_rport *rport)
+static void fc_rport_enter_plogi(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 fc_els_flogi *plogi;
- struct fc_lport *lp;
- struct fc_rport_libfc_priv *rp = rport->dd_data;
+
+ fc_rport_state_enter(rp, RPORT_ST_PLOGI);
if (fc_rp_debug)
- FC_DBG("Entered PLOGI for port (%6x)\n", rport->port_id);
+ FC_DBG("Entered PLOGI for port (%6x)\n", rp->port_id);
+
+ rp->maxframe_size = FC_MIN_MAX_PAYLOAD;
- lp = rp->local_port;
- fc_rport_state_enter(rport, RPORT_ST_PLOGI);
- rport->maxframe_size = FC_MIN_MAX_PAYLOAD;
fp = fc_frame_alloc(lp, sizeof(*plogi));
- if (!fp)
- return fc_rport_error(rport, fp);
+ if (!fp) {
+ fc_rport_error(rp, fp);
+ return;
+ }
+
plogi = fc_frame_payload_get(fp, sizeof(*plogi));
- WARN_ON(!plogi);
- fc_lport_plogi_fill(rp->local_port, plogi, ELS_PLOGI);
- rp->e_d_tov = lp->e_d_tov;
+ fc_lport_plogi_fill(lp, plogi, ELS_PLOGI);
+ rpp->e_d_tov = lp->e_d_tov;
fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS);
+
if (!lp->tt.exch_seq_send(lp, fp,
fc_rport_plogi_resp,
- rport, lp->e_d_tov,
- rp->local_port->fid,
- rport->port_id,
+ rp, lp->e_d_tov,
+ lp->fid, rp->port_id,
FC_FC_SEQ_INIT | FC_FC_END_SEQ))
- fc_rport_error(rport, fp);
+ fc_rport_error(rp, fp);
}
/**
@@ -854,13 +870,15 @@ static void fc_rport_enter_plogi(struct fc_rport *rport)
* @sp: current sequence in the PRLI exchange
* @fp: response frame
* @rp_arg: Fibre Channel remote port
+ *
+ * Locking Note: This is an action function, grab the lock and
+ * call the next _enter_* function.
*/
static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
void *rp_arg)
{
- struct fc_rport *rport = rp_arg;
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- struct fc_lport *lp = rp->local_port;
+ struct fc_rport *rp = rp_arg;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
struct {
struct fc_els_prli prli;
struct fc_els_spp spp;
@@ -868,49 +886,45 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct
fc_frame *fp,
u32 roles = FC_RPORT_ROLE_UNKNOWN;
u32 fcp_parm = 0;
u8 op;
+ unsigned long flags;
- if (IS_ERR(fp)) {
- fc_rport_error(rport, fp);
+ spin_lock_irqsave(&rpp->rp_lock, flags);
+
+ if (rpp->rp_state != RPORT_ST_PRLI) {
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ FC_DBG("Recieved a PRLI response, but port (%6x) is in "
+ "the %s state\n", rp->port_id, fc_rport_state(rp));
return;
}
- fc_rport_lock(rport);
+ if (IS_ERR(fp)) {
+ fc_rport_error(rp, fp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ }
+
op = fc_frame_payload_op(fp);
if (op == ELS_LS_ACC) {
pp = fc_frame_payload_get(fp, sizeof(*pp));
if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) {
fcp_parm = ntohl(pp->spp.spp_params);
if (fcp_parm & FCP_SPPF_RETRY)
- rp->flags |= FC_RP_FLAGS_RETRY;
+ rpp->flags |= FC_RP_FLAGS_RETRY;
}
- rport->supported_classes = FC_COS_CLASS3;
+ rp->supported_classes = FC_COS_CLASS3;
if (fcp_parm & FCP_SPPF_INIT_FCN)
roles |= FC_RPORT_ROLE_FCP_INITIATOR;
if (fcp_parm & FCP_SPPF_TARG_FCN)
roles |= FC_RPORT_ROLE_FCP_TARGET;
- fc_rport_enter_rtv(rport);
- fc_rport_unlock(rport);
-
- fc_remote_port_rolechg(rport, roles);
+ fc_rport_enter_rtv(rp);
+ fc_remote_port_rolechg(rp, roles);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
} else {
- FC_DBG("bad ELS response\n");
- fc_rport_state_enter(rport, RPORT_ST_ERROR);
- fc_rport_unlock(rport);
- if (rport == lp->dns_rp && lp->state != LPORT_ST_RESET) {
- fc_lport_lock(lp);
- del_timer(&lp->state_timer);
- lp->dns_rp = NULL;
- if (lp->state == LPORT_ST_DNS_STOP) {
- fc_lport_unlock(lp);
- lp->tt.lport_logout(lp);
- } else {
- lp->tt.lport_login(lp);
- fc_lport_unlock(lp);
- }
- fc_remote_port_delete(rport);
- }
+ if (fc_rp_debug)
+ FC_DBG("Bad PRLI response\n");
+ fc_rport_error(rp, fp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
}
fc_frame_free(fp);
@@ -921,95 +935,91 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct
fc_frame *fp,
* @sp: current sequence in the LOGO exchange
* @fp: response frame
* @rp_arg: Fibre Channel remote port
+ *
+ * Locking Note: This is an action function, but all we care about
+ * is retrying or removing the rport that we just logged out of.
*/
static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
void *rp_arg)
{
- struct fc_rport *rport = rp_arg;
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- struct fc_lport *lp = rp->local_port;
- u8 op;
+ struct fc_rport *rp = rp_arg;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ unsigned long flags;
- if (IS_ERR(fp)) {
- fc_rport_error(rport, fp);
+ spin_lock_irqsave(&rpp->rp_lock, flags);
+
+ if (rpp->rp_state != RPORT_ST_LOGO) {
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ FC_DBG("Recieved a LOGO response, but port (%6x) is in "
+ "the %s state\n", rp->port_id, fc_rport_state(rp));
return;
}
- fc_rport_lock(rport);
- op = fc_frame_payload_op(fp);
- if (op == ELS_LS_ACC) {
- fc_rport_enter_rtv(rport);
- fc_rport_unlock(rport);
- } else {
- FC_DBG("bad ELS response\n");
- fc_rport_state_enter(rport, RPORT_ST_ERROR);
- fc_rport_unlock(rport);
- if (rport == lp->dns_rp && lp->state != LPORT_ST_RESET) {
- fc_lport_lock(lp);
- del_timer(&lp->state_timer);
- lp->dns_rp = NULL;
- if (lp->state == LPORT_ST_DNS_STOP) {
- fc_lport_unlock(lp);
- lp->tt.lport_logout(lp);
- } else {
- lp->tt.lport_login(lp);
- fc_lport_unlock(lp);
- }
- fc_remote_port_delete(rport);
- }
+ if (IS_ERR(fp)) {
+ fc_rport_error(rp, fp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
}
+ if (fc_rp_debug)
+ FC_DBG("Logged out of port (%6x)\n", rp->port_id);
+ fc_remote_port_delete(rp);
fc_frame_free(fp);
}
/**
* fc_rport_enter_prli - Send Process Login (PRLI) request to peer
- * @rport: Fibre Channel remote port to send PRLI to
+ * @rp: Fibre Channel remote port to send PRLI to
+ *
+ * Locking Note: The rport lock is expected to be held before calling
+ * this routine.
*/
-static void fc_rport_enter_prli(struct fc_rport *rport)
+static void fc_rport_enter_prli(struct fc_rport *rp)
{
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ struct fc_lport *lp = rpp->local_port;
+
struct {
struct fc_els_prli prli;
struct fc_els_spp spp;
} *pp;
struct fc_frame *fp;
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- struct fc_lport *lp = rp->local_port;
- if (fc_rp_debug)
- FC_DBG("Entered PRLI for port (%6x)\n", rport->port_id);
+ fc_rport_state_enter(rp, RPORT_ST_PRLI);
- fc_rport_state_enter(rport, RPORT_ST_PRLI);
+ if (fc_rp_debug)
+ FC_DBG("Entered PRLI for port (%6x)\n", rp->port_id);
/*
- * Special case if session is for name server or any other
- * well-known address: Skip the PRLI step.
- * This should be made more general, possibly moved to the FCP layer.
+ * Special case if the RP is a well-known address then skip PRLI
*/
- if (rport->port_id >= FC_FID_DOM_MGR) {
- fc_rport_enter_ready(rport);
+
+ if (rp->port_id >= FC_FID_DOM_MGR) {
+ fc_rport_enter_ready(rp);
return;
}
+
fp = fc_frame_alloc(lp, sizeof(*pp));
- if (!fp)
- return fc_rport_error(rport, fp);
+ if (!fp) {
+ fc_rport_error(rp, fp);
+ return;
+ }
+
pp = fc_frame_payload_get(fp, sizeof(*pp));
- WARN_ON(!pp);
memset(pp, 0, sizeof(*pp));
pp->prli.prli_cmd = ELS_PRLI;
pp->prli.prli_spp_len = sizeof(struct fc_els_spp);
pp->prli.prli_len = htons(sizeof(*pp));
pp->spp.spp_type = FC_TYPE_FCP;
pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR;
- pp->spp.spp_params = htonl(rp->local_port->service_params);
+ pp->spp.spp_params = htonl(lp->service_params);
fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS);
+
if (!lp->tt.exch_seq_send(lp, fp,
fc_rport_prli_resp,
- rport, lp->e_d_tov,
- rp->local_port->fid,
- rport->port_id,
+ rp, lp->e_d_tov,
+ lp->fid, rp->port_id,
FC_FC_SEQ_INIT | FC_FC_END_SEQ))
- fc_rport_error(rport, fp);
+ fc_rport_error(rp, fp);
}
/**
@@ -1023,16 +1033,26 @@ static void fc_rport_enter_prli(struct fc_rport *rport)
static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,
void *rp_arg)
{
- struct fc_rport *rport = rp_arg;
- struct fc_rport_libfc_priv *rp = rport->dd_data;
+ struct fc_rport *rp = rp_arg;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
u8 op;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rpp->rp_lock, flags);
+
+ if (rpp->rp_state != RPORT_ST_RTV) {
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
+ FC_DBG("Recieved a RTV response, but port (%6x) is in "
+ "the %s state\n", rp->port_id, fc_rport_state(rp));
+ return;
+ }
if (IS_ERR(fp)) {
- fc_rport_error(rport, fp);
+ fc_rport_error(rp, fp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
return;
}
- fc_rport_lock(rport);
op = fc_frame_payload_op(fp);
if (op == ELS_LS_ACC) {
struct fc_els_rtv_acc *rtv;
@@ -1045,106 +1065,119 @@ static void fc_rport_rtv_resp(struct fc_seq *sp,
struct fc_frame *fp,
tov = ntohl(rtv->rtv_r_a_tov);
if (tov == 0)
tov = 1;
- rp->r_a_tov = tov;
+ rpp->r_a_tov = tov;
tov = ntohl(rtv->rtv_e_d_tov);
if (toq & FC_ELS_RTV_EDRES)
tov /= 1000000;
if (tov == 0)
tov = 1;
- rp->e_d_tov = tov;
+ rpp->e_d_tov = tov;
}
}
- fc_rport_state_enter(rport, RPORT_ST_READY);
- fc_rport_unlock(rport);
- if (fc_rp_debug)
- FC_DBG("remote %6x ready\n", rport->port_id);
+ fc_rport_enter_ready(rp);
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
fc_frame_free(fp);
}
/**
* fc_rport_enter_rtv - Send Request Timeout Value (RTV) request to peer
- * @rport: Fibre Channel remote port to send RTV to
+ * @rp: Fibre Channel remote port to send RTV to
+ *
+ * Locking Note: This function expects that the rport lock is held before
+ * being called.
*/
-static void fc_rport_enter_rtv(struct fc_rport *rport)
+static void fc_rport_enter_rtv(struct fc_rport *rp)
{
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ struct fc_lport *lp = rpp->local_port;
struct fc_els_rtv *rtv;
struct fc_frame *fp;
- struct fc_lport *lp;
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- lp = rp->local_port;
+ fc_rport_state_enter(rp, RPORT_ST_RTV);
if (fc_rp_debug)
- FC_DBG("Entered RTV for port (%6x)\n", rport->port_id);
+ FC_DBG("Entered RTV for port (%6x)\n", rp->port_id);
- fc_rport_state_enter(rport, RPORT_ST_RTV);
fp = fc_frame_alloc(lp, sizeof(*rtv));
- if (!fp)
- return fc_rport_error(rport, fp);
+ if (!fp) {
+ fc_rport_error(rp, fp);
+ return;
+ }
+
rtv = fc_frame_payload_get(fp, sizeof(*rtv));
- WARN_ON(!rtv);
memset(rtv, 0, sizeof(*rtv));
rtv->rtv_cmd = ELS_RTV;
fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS);
+
if (!lp->tt.exch_seq_send(lp, fp,
fc_rport_rtv_resp,
- rport, lp->e_d_tov,
- rp->local_port->fid,
- rport->port_id,
+ rp, lp->e_d_tov,
+ lp->fid, rp->port_id,
FC_FC_SEQ_INIT | FC_FC_END_SEQ))
- fc_rport_error(rport, fp);
+ fc_rport_error(rp, fp);
}
/**
* fc_rport_enter_logo - Send Logout (LOGO) request to peer
- * @rport: Fibre Channel remote port to send LOGO to
+ * @rp: Fibre Channel remote port to send LOGO to
+ *
+ * Locking Note: This function expects that the rport lock is held before
+ * being called.
*/
-static void fc_rport_enter_logo(struct fc_rport *rport)
+static void fc_rport_enter_logo(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 fc_els_logo *logo;
- struct fc_lport *lp;
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- if (fc_rp_debug)
- FC_DBG("Entered LOGO for port (%6x)\n", rport->port_id);
+ fc_rport_state_enter(rp, RPORT_ST_LOGO);
- fc_rport_state_enter(rport, RPORT_ST_LOGO);
+ if (fc_rp_debug)
+ FC_DBG("Entered LOGO for port (%6x)\n", rp->port_id);
- lp = rp->local_port;
fp = fc_frame_alloc(lp, sizeof(*logo));
- if (!fp)
- return fc_rport_error(rport, fp);
+ if (!fp) {
+ fc_rport_error(rp, fp);
+ return;
+ }
+
logo = fc_frame_payload_get(fp, sizeof(*logo));
memset(logo, 0, sizeof(*logo));
logo->fl_cmd = ELS_LOGO;
hton24(logo->fl_n_port_id, lp->fid);
logo->fl_n_port_wwn = htonll(lp->wwpn);
-
fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS);
+
if (!lp->tt.exch_seq_send(lp, fp,
fc_rport_logo_resp,
- rport, lp->e_d_tov,
- rp->local_port->fid,
- rport->port_id,
+ rp, lp->e_d_tov,
+ lp->fid, rp->port_id,
FC_FC_SEQ_INIT | FC_FC_END_SEQ))
- fc_rport_error(rport, fp);
+ fc_rport_error(rp, fp);
}
-/*
- * Handle a request received by the exchange manager for the session.
- * This may be an entirely new session, or a PLOGI or LOGO for an existing one.
- * This will free the frame.
+/**
+ * fc_rport_recv_req - Handle an incoming request
+ * @sp: A pointer to the sequence
+ * @fp: A pointer to the frame
+ * @rp_arg: A void pointer to the fc_rport object
+ *
+ * Locking Note: This function calls one of the request handlers. We need
+ * to lock, call the request handler and then unlock when it returns to us.
*/
void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, void *rp_arg)
{
- struct fc_rport *rport = rp_arg;
- struct fc_rport_libfc_priv *rp = rport->dd_data;
+ struct fc_rport *rp = rp_arg;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ struct fc_lport *lp = rpp->local_port;
struct fc_frame_header *fh;
- struct fc_lport *lp = rp->local_port;
struct fc_seq_els_data els_data;
u8 op;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rpp->rp_lock, flags);
els_data.fp = NULL;
els_data.explan = ELS_EXPL_NONE;
@@ -1156,16 +1189,16 @@ void fc_rport_recv_req(struct fc_seq *sp, struct
fc_frame *fp, void *rp_arg)
op = fc_frame_payload_op(fp);
switch (op) {
case ELS_PLOGI:
- fc_rport_recv_plogi_req(rport, sp, fp);
+ fc_rport_recv_plogi_req(rp, sp, fp);
break;
case ELS_PRLI:
- fc_rport_recv_prli_req(rport, sp, fp);
+ fc_rport_recv_prli_req(rp, sp, fp);
break;
case ELS_PRLO:
- fc_rport_recv_prlo_req(rport, sp, fp);
+ fc_rport_recv_prlo_req(rp, sp, fp);
break;
case ELS_LOGO:
- fc_rport_recv_logo_req(rport, sp, fp);
+ fc_rport_recv_logo_req(rp, sp, fp);
break;
case ELS_RRQ:
els_data.fp = fp;
@@ -1184,27 +1217,31 @@ void fc_rport_recv_req(struct fc_seq *sp, struct
fc_frame *fp, void *rp_arg)
} else {
fc_frame_free(fp);
}
+ spin_unlock_irqrestore(&rpp->rp_lock, flags);
}
/**
* fc_rport_recv_plogi_req - Handle incoming Port Login (PLOGI) request
- * @rport: Fibre Channel remote port that initiated PLOGI
+ * @rp: Fibre Channel remote port that initiated PLOGI
* @sp: current sequence in the PLOGI exchange
* @fp: PLOGI request frame
+ *
+ * Locking Note: This function expects that the rport lock is held before
+ * being called.
*/
-static void fc_rport_recv_plogi_req(struct fc_rport *rport,
+static void fc_rport_recv_plogi_req(struct fc_rport *rp,
struct fc_seq *sp, struct fc_frame *rx_fp)
{
- struct fc_rport_libfc_priv *rp = rport->dd_data;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ struct fc_lport *lp = rpp->local_port;
struct fc_frame *fp = rx_fp;
struct fc_frame_header *fh;
- struct fc_lport *lp;
struct fc_els_flogi *pl;
struct fc_seq_els_data rjt_data;
+ enum fc_els_rjt_reason reject = 0;
u32 sid;
u64 wwpn;
u64 wwnn;
- enum fc_els_rjt_reason reject = 0;
u32 f_ctl;
rjt_data.fp = NULL;
@@ -1220,8 +1257,6 @@ static void fc_rport_recv_plogi_req(struct fc_rport
*rport,
}
wwpn = get_unaligned_be64(&pl->fl_wwpn);
wwnn = get_unaligned_be64(&pl->fl_wwnn);
- fc_rport_lock(rport);
- lp = rp->local_port;
/*
* If the session was just created, possibly due to the incoming PLOGI,
@@ -1234,7 +1269,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport
*rport,
* XXX TBD: If the session was ready before, the PLOGI should result in
* all outstanding exchanges being reset.
*/
- switch (rp->rp_state) {
+ switch (rpp->rp_state) {
case RPORT_ST_INIT:
if (fc_rp_debug)
FC_DBG("incoming PLOGI from %6x wwpn %llx state INIT "
@@ -1244,7 +1279,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport
*rport,
case RPORT_ST_PLOGI:
if (fc_rp_debug)
FC_DBG("incoming PLOGI from %x in PLOGI state %d\n",
- sid, rp->rp_state);
+ sid, rpp->rp_state);
if (wwpn < lp->wwpn)
reject = ELS_RJT_INPROG;
break;
@@ -1253,14 +1288,14 @@ static void fc_rport_recv_plogi_req(struct fc_rport
*rport,
case RPORT_ST_READY:
if (fc_rp_debug)
FC_DBG("incoming PLOGI from %x in logged - in state %d "
- "- ignored for now\n", sid, rp->rp_state);
+ "- ignored for now\n", sid, rpp->rp_state);
/* XXX TBD - should reset */
break;
case RPORT_ST_NONE:
default:
if (fc_rp_debug)
FC_DBG("incoming PLOGI from %x in unexpected "
- "state %d\n", sid, rp->rp_state);
+ "state %d\n", sid, rpp->rp_state);
break;
}
@@ -1271,7 +1306,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport
*rport,
fc_frame_free(fp);
} else {
fp = fc_frame_alloc(lp, sizeof(*pl));
- if (fp == NULL) {
+ if (!fp) {
fp = rx_fp;
rjt_data.reason = ELS_RJT_UNAB;
rjt_data.explan = ELS_EXPL_NONE;
@@ -1280,12 +1315,12 @@ static void fc_rport_recv_plogi_req(struct fc_rport
*rport,
} else {
sp = lp->tt.seq_start_next(sp);
WARN_ON(!sp);
- fc_rport_set_name(rport, wwpn, wwnn);
+ fc_rport_set_name(rp, wwpn, wwnn);
/*
* Get session payload size from incoming PLOGI.
*/
- rport->maxframe_size =
+ rp->maxframe_size =
fc_plogi_get_maxframe(pl, lp->mfs);
fc_frame_free(rx_fp);
pl = fc_frame_payload_get(fp, sizeof(*pl));
@@ -1299,14 +1334,11 @@ static void fc_rport_recv_plogi_req(struct fc_rport
*rport,
f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS);
lp->tt.seq_send(lp, sp, fp, f_ctl);
- if (rp->rp_state == RPORT_ST_PLOGI)
- fc_rport_enter_prli(rport);
- else
- fc_rport_state_enter(rport,
- RPORT_ST_PLOGI_RECV);
+ if (rpp->rp_state == RPORT_ST_PLOGI)
+ fc_rport_enter_prli(rp);
}
}
- fc_rport_unlock(rport);
+
}
/**
@@ -1314,11 +1346,14 @@ static void fc_rport_recv_plogi_req(struct fc_rport
*rport,
* @rport: Fibre Channel remote port that initiated PRLI
* @sp: current sequence in the PRLI exchange
* @fp: PRLI request frame
+ *
+ * Locking Note: This function expects that the rport lock is held before
+ * being called.
*/
-static void fc_rport_recv_prli_req(struct fc_rport *rport,
+static void fc_rport_recv_prli_req(struct fc_rport *rp,
struct fc_seq *sp, struct fc_frame *rx_fp)
{
- struct fc_rport_libfc_priv *rp = rport->dd_data;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
struct fc_frame *fp;
struct fc_frame_header *fh;
struct fc_lport *lp;
@@ -1340,9 +1375,8 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport,
rjt_data.fp = NULL;
fh = fc_frame_header_get(rx_fp);
- lp = rp->local_port;
- switch (rp->rp_state) {
- case RPORT_ST_PLOGI_RECV:
+ lp = rpp->local_port;
+ switch (rpp->rp_state) {
case RPORT_ST_PRLI:
case RPORT_ST_READY:
reason = ELS_RJT_NONE;
@@ -1406,16 +1440,16 @@ static void fc_rport_recv_prli_req(struct fc_rport
*rport,
case FC_TYPE_FCP:
fcp_parm = ntohl(rspp->spp_params);
if (fcp_parm * FCP_SPPF_RETRY)
- rp->flags |= FC_RP_FLAGS_RETRY;
- rport->supported_classes = FC_COS_CLASS3;
+ rpp->flags |= FC_RP_FLAGS_RETRY;
+ rp->supported_classes = FC_COS_CLASS3;
if (fcp_parm & FCP_SPPF_INIT_FCN)
roles |= FC_RPORT_ROLE_FCP_INITIATOR;
if (fcp_parm & FCP_SPPF_TARG_FCN)
roles |= FC_RPORT_ROLE_FCP_TARGET;
- fc_remote_port_rolechg(rport, roles);
+ fc_remote_port_rolechg(rp, roles);
spp->spp_params =
- htonl(rp->local_port->service_params);
+ htonl(rpp->local_port->service_params);
break;
default:
resp = FC_SPP_RESP_INVL;
@@ -1437,14 +1471,12 @@ static void fc_rport_recv_prli_req(struct fc_rport
*rport,
/*
* Get lock and re-check state.
*/
- fc_rport_lock(rport);
- switch (rp->rp_state) {
- case RPORT_ST_PLOGI_RECV:
+ switch (rpp->rp_state) {
case RPORT_ST_PRLI:
- fc_rport_state_enter(rport, RPORT_ST_READY);
+ fc_rport_state_enter(rp, RPORT_ST_READY);
if (fc_rp_debug)
- FC_DBG("remote %6x ready\n", rport->port_id);
- if (rport == lp->dns_rp &&
+ FC_DBG("remote %6x ready\n", rp->port_id);
+ if (rp == lp->dns_rp &&
lp->state == LPORT_ST_DNS) {
fc_lport_lock(lp);
del_timer(&lp->state_timer);
@@ -1457,28 +1489,31 @@ static void fc_rport_recv_prli_req(struct fc_rport
*rport,
default:
break;
}
- fc_rport_unlock(rport);
+
}
fc_frame_free(rx_fp);
}
/**
* fc_rport_recv_prlo_req - Handle incoming Process Logout (PRLO) request
- * @rport: Fibre Channel remote port that initiated PRLO
+ * @rp: Fibre Channel remote port that initiated PRLO
* @sp: current sequence in the PRLO exchange
* @fp: PRLO request frame
+ *
+ * Locking Note: This function expects that the rport lock is held before
+ * being called.
*/
-static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp,
+static void fc_rport_recv_prlo_req(struct fc_rport *rp, struct fc_seq *sp,
struct fc_frame *fp)
{
- struct fc_rport_libfc_priv *rp = rport->dd_data;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
struct fc_frame_header *fh;
- struct fc_lport *lp = rp->local_port;
+ struct fc_lport *lp = rpp->local_port;
struct fc_seq_els_data rjt_data;
fh = fc_frame_header_get(fp);
FC_DBG("incoming PRLO from %x state %d\n",
- ntoh24(fh->fh_s_id), rp->rp_state);
+ ntoh24(fh->fh_s_id), rpp->rp_state);
rjt_data.fp = NULL;
rjt_data.reason = ELS_RJT_UNAB;
rjt_data.explan = ELS_EXPL_NONE;
@@ -1491,34 +1526,27 @@ static void fc_rport_recv_prlo_req(struct fc_rport
*rport, struct fc_seq *sp,
* @rport: Fibre Channel remote port that initiated LOGO
* @sp: current sequence in the LOGO exchange
* @fp: LOGO request frame
+ *
+ * Locking Note: This function expects that the rport lock is held before
+ * being called.
*/
-static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp,
+static void fc_rport_recv_logo_req(struct fc_rport *rp, struct fc_seq *sp,
struct fc_frame *fp)
{
struct fc_frame_header *fh;
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- struct fc_lport *lp = rp->local_port;
+ struct fc_rport_libfc_priv *rpp = rp->dd_data;
+ struct fc_lport *lp = rpp->local_port;
- fh = fc_frame_header_get(fp);
- fc_rport_lock(rport);
- fc_rport_state_enter(rport, RPORT_ST_INIT);
- fc_rport_unlock(rport);
if (fc_rp_debug)
- FC_DBG("remote %6x closed\n", rport->port_id);
- if (rport == lp->dns_rp &&
- lp->state != LPORT_ST_RESET) {
- fc_lport_lock(lp);
- del_timer(&lp->state_timer);
- lp->dns_rp = NULL;
- if (lp->state == LPORT_ST_DNS_STOP) {
- fc_lport_unlock(lp);
- lp->tt.lport_logout(lp);
- } else {
- lp->tt.lport_login(lp);
- fc_lport_unlock(lp);
- }
- fc_remote_port_delete(rport);
- }
+ FC_DBG("Received LOGO request for port (%6x)\n", rp->port_id);
+
+ fh = fc_frame_header_get(fp);
+
+ if (rp->port_id == FC_FID_DIR_SERV)
+ lp->tt.lport_event_callback(lp, rp, LPORT_EV_RPORT_LOGO);
+
+ fc_remote_port_delete(rp);
+
lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
fc_frame_free(fp);
}
diff --git a/include/scsi/libfc/libfc.h b/include/scsi/libfc/libfc.h
index ef0bb8e..61a7d59 100644
--- a/include/scsi/libfc/libfc.h
+++ b/include/scsi/libfc/libfc.h
@@ -103,7 +103,8 @@ enum fc_lport_state {
enum fc_lport_event {
LPORT_EV_RPORT_CREATED = 0,
- LPORT_EV_RPORT_FAILED
+ LPORT_EV_RPORT_FAILED,
+ LPORT_EV_RPORT_LOGO,
};
enum fc_rport_state {
@@ -112,7 +113,6 @@ enum fc_rport_state {
RPORT_ST_GPN_ID, /* get the WWPN from the name server */
RPORT_ST_GNN_ID, /* get the WWNN from the name server */
RPORT_ST_PLOGI, /* waiting for PLOGI completion */
- RPORT_ST_PLOGI_RECV, /* received PLOGI (as target) */
RPORT_ST_PRLI, /* waiting for PRLI completion */
RPORT_ST_RTV, /* waiting for RTV completion */
RPORT_ST_ERROR, /* error */
@@ -361,7 +361,7 @@ struct libfc_function_template {
* Logs the specified local port out of a N_Port identified
* by the ID provided.
*/
- int (*rport_logout)(struct fc_rport *rport);
+ void (*rport_logout)(struct fc_rport *rport);
void (*rport_recv_req)(struct fc_seq *, struct fc_frame *, void *);
_______________________________________________
devel mailing list
[email protected]
http://www.open-fcoe.org/mailman/listinfo/devel