diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 185 |
1 files changed, 93 insertions, 92 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index d014b285cd1a..e121ff92c8ea 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -63,7 +63,7 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *); static void fc_rport_enter_ready(struct fc_rport_priv *); static void fc_rport_enter_logo(struct fc_rport_priv *); -static void fc_rport_recv_plogi_req(struct fc_rport_priv *, +static void fc_rport_recv_plogi_req(struct fc_lport *, struct fc_seq *, struct fc_frame *); static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); @@ -576,15 +576,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, csp_seq = cssp_seq; rdata->max_seq = csp_seq; rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs); - - /* - * If the rport is one of the well known addresses - * we skip PRLI and RTV and go straight to READY. - */ - if (rdata->ids.port_id >= FC_FID_DOM_MGR) - fc_rport_enter_ready(rdata); - else - fc_rport_enter_prli(rdata); + fc_rport_enter_prli(rdata); } else fc_rport_error_retry(rdata, fp); @@ -763,6 +755,15 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) } *pp; struct fc_frame *fp; + /* + * If the rport is one of the well known addresses + * we skip PRLI and RTV and go straight to READY. + */ + if (rdata->ids.port_id >= FC_FID_DOM_MGR) { + fc_rport_enter_ready(rdata); + return; + } + FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n", fc_rport_state(rdata)); @@ -929,6 +930,15 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, els_data.explan = ELS_EXPL_NONE; els_data.reason = ELS_RJT_NONE; + op = fc_frame_payload_op(fp); + switch (op) { + case ELS_PLOGI: + fc_rport_recv_plogi_req(lport, sp, fp); + return; + default: + break; + } + fh = fc_frame_header_get(fp); s_id = ntoh24(fh->fh_s_id); @@ -944,11 +954,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); mutex_unlock(&lport->disc.disc_mutex); - op = fc_frame_payload_op(fp); switch (op) { - case ELS_PLOGI: - fc_rport_recv_plogi_req(rdata, sp, fp); - break; case ELS_PRLI: fc_rport_recv_prli_req(rdata, sp, fp); break; @@ -977,48 +983,56 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, /** * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request - * @rdata: private remote port data + * @lport: local port * @sp: current sequence in the PLOGI exchange * @fp: PLOGI request frame * - * Locking Note: The rport lock is exected to be held before calling - * this function. + * Locking Note: The rport lock is held before calling this function. */ -static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, +static void fc_rport_recv_plogi_req(struct fc_lport *lport, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_lport *lport = rdata->local_port; + struct fc_disc *disc; + struct fc_rport_priv *rdata; struct fc_frame *fp = rx_fp; struct fc_exch *ep; struct fc_frame_header *fh; struct fc_els_flogi *pl; struct fc_seq_els_data rjt_data; - u32 sid; - u64 wwpn; - u64 wwnn; - enum fc_els_rjt_reason reject = 0; - u32 f_ctl; - rjt_data.fp = NULL; + u32 sid, f_ctl; + rjt_data.fp = NULL; fh = fc_frame_header_get(fp); + sid = ntoh24(fh->fh_s_id); - FC_RPORT_DBG(rdata, "Received PLOGI request while in state %s\n", - fc_rport_state(rdata)); + FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n"); - sid = ntoh24(fh->fh_s_id); pl = fc_frame_payload_get(fp, sizeof(*pl)); if (!pl) { - FC_RPORT_DBG(rdata, "Received PLOGI too short\n"); - WARN_ON(1); - /* XXX TBD: send reject? */ - fc_frame_free(fp); - return; + FC_RPORT_ID_DBG(lport, sid, "Received PLOGI too short\n"); + rjt_data.reason = ELS_RJT_PROT; + rjt_data.explan = ELS_EXPL_INV_LEN; + goto reject; + } + + disc = &lport->disc; + mutex_lock(&disc->disc_mutex); + rdata = lport->tt.rport_create(lport, sid); + if (!rdata) { + mutex_unlock(&disc->disc_mutex); + rjt_data.reason = ELS_RJT_UNAB; + rjt_data.explan = ELS_EXPL_INSUF_RES; + goto reject; } - wwpn = get_unaligned_be64(&pl->fl_wwpn); - wwnn = get_unaligned_be64(&pl->fl_wwnn); + + mutex_lock(&rdata->rp_mutex); + mutex_unlock(&disc->disc_mutex); + + rdata->ids.port_name = get_unaligned_be64(&pl->fl_wwpn); + rdata->ids.node_name = get_unaligned_be64(&pl->fl_wwnn); /* - * If the session was just created, possibly due to the incoming PLOGI, + * If the rport was just created, possibly due to the incoming PLOGI, * set the state appropriately and accept the PLOGI. * * If we had also sent a PLOGI, and if the received PLOGI is from a @@ -1030,72 +1044,58 @@ static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, */ switch (rdata->rp_state) { case RPORT_ST_INIT: - FC_RPORT_DBG(rdata, "Received PLOGI, wwpn %llx state INIT " - "- reject\n", (unsigned long long)wwpn); - reject = ELS_RJT_UNSUP; + FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n"); break; case RPORT_ST_PLOGI: - FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state %d\n", - rdata->rp_state); - if (wwpn < lport->wwpn) - reject = ELS_RJT_INPROG; + FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n"); + if (rdata->ids.port_name < lport->wwpn) { + mutex_unlock(&rdata->rp_mutex); + rjt_data.reason = ELS_RJT_INPROG; + rjt_data.explan = ELS_EXPL_NONE; + goto reject; + } break; case RPORT_ST_PRLI: case RPORT_ST_READY: - FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d " - "- ignored for now\n", rdata->rp_state); - /* XXX TBD - should reset */ break; case RPORT_ST_DELETE: default: - FC_RPORT_DBG(rdata, "Received PLOGI in unexpected " - "state %d\n", rdata->rp_state); - fc_frame_free(fp); - return; - break; + FC_RPORT_DBG(rdata, "Received PLOGI in unexpected state %d\n", + rdata->rp_state); + fc_frame_free(rx_fp); + goto out; } - if (reject) { - rjt_data.reason = reject; - rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); - fc_frame_free(fp); - } else { - fp = fc_frame_alloc(lport, sizeof(*pl)); - if (fp == NULL) { - fp = rx_fp; - rjt_data.reason = ELS_RJT_UNAB; - rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); - fc_frame_free(fp); - } else { - sp = lport->tt.seq_start_next(sp); - WARN_ON(!sp); - rdata->ids.port_name = wwpn; - rdata->ids.node_name = wwnn; - - /* - * Get session payload size from incoming PLOGI. - */ - rdata->maxframe_size = - fc_plogi_get_maxframe(pl, lport->mfs); - fc_frame_free(rx_fp); - fc_plogi_fill(lport, fp, ELS_LS_ACC); - - /* - * Send LS_ACC. If this fails, - * the originator should retry. - */ - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; - f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; - ep = fc_seq_exch(sp); - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, f_ctl, 0); - lport->tt.seq_send(lport, sp, fp); - if (rdata->rp_state == RPORT_ST_PLOGI) - fc_rport_enter_prli(rdata); - } - } + /* + * Get session payload size from incoming PLOGI. + */ + rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs); + fc_frame_free(rx_fp); + + /* + * Send LS_ACC. If this fails, the originator should retry. + */ + sp = lport->tt.seq_start_next(sp); + if (!sp) + goto out; + fp = fc_frame_alloc(lport, sizeof(*pl)); + if (!fp) + goto out; + + fc_plogi_fill(lport, fp, ELS_LS_ACC); + f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; + ep = fc_seq_exch(sp); + fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, + FC_TYPE_ELS, f_ctl, 0); + lport->tt.seq_send(lport, sp, fp); + fc_rport_enter_prli(rdata); +out: + mutex_unlock(&rdata->rp_mutex); + return; + +reject: + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + fc_frame_free(fp); } /** @@ -1138,6 +1138,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, switch (rdata->rp_state) { case RPORT_ST_PRLI: + case RPORT_ST_RTV: case RPORT_ST_READY: reason = ELS_RJT_NONE; break; |