Subject: Open-FCoE bugfixes for fnic From: Hannes Reinecke Date: Fri Dec 5 16:40:29 2008 +0100: The fnic driver requires some bugfixes for the open-FCoE stack. Signed-off-by: Abhijeet Joglekar Acked-by: Hannes Reinecke diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 0cd8d0c..2b13e7b 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -101,12 +101,8 @@ struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, } } - if (!disc_found) { - FC_DEBUG_DISC("The rport (%6x) for lport (%6x) " - "is not maintained by the discovery layer\n", - port_id, fc_host_port_id(lport->host)); + if (!disc_found) found = NULL; - } return found; } diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 12a1196..d81ed95 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -378,7 +378,6 @@ int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec) return -ENOMEM; } - sp->f_ctl |= FC_FC_SEQ_INIT; ep->esb_stat |= ESB_ST_SEQ_INIT | ESB_ST_ABNORMAL; if (timer_msec) fc_exch_timer_set_locked(ep, timer_msec); @@ -466,7 +465,6 @@ static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id) sp = &ep->seq; sp->ssb_stat = 0; - sp->f_ctl = 0; sp->cnt = 0; sp->id = seq_id; return sp; @@ -530,7 +528,7 @@ static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp) struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, struct fc_frame *fp, u16 xid) { - struct fc_exch *ep = NULL; + struct fc_exch *ep; /* allocate memory for exchange */ ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); @@ -834,8 +832,8 @@ static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp) struct fc_exch *ep = fc_seq_exch(sp); sp = fc_seq_alloc(ep, ep->seq_id++); - FC_DEBUG_EXCH("exch %4x f_ctl %6x seq %2x f_ctl %6x\n", - ep->xid, ep->f_ctl, sp->id, sp->f_ctl); + FC_DEBUG_EXCH("exch %4x f_ctl %6x seq %2x\n", + ep->xid, ep->f_ctl, sp->id); return sp; } /* @@ -860,12 +858,13 @@ int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, struct fc_frame *fp) struct fc_exch *ep; struct fc_frame_header *fh = fc_frame_header_get(fp); int error; + u32 f_ctl; ep = fc_seq_exch(sp); WARN_ON((ep->esb_stat & ESB_ST_SEQ_INIT) != ESB_ST_SEQ_INIT); - sp->f_ctl = ntoh24(fh->fh_f_ctl); - fc_exch_setup_hdr(ep, fp, sp->f_ctl); + f_ctl = ntoh24(fh->fh_f_ctl); + fc_exch_setup_hdr(ep, fp, f_ctl); /* * update sequence count if this frame is carrying @@ -889,9 +888,8 @@ int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, struct fc_frame *fp) * We can only be called to send once for each sequence. */ spin_lock_bh(&ep->ex_lock); - ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ - sp->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ - if (sp->f_ctl & (FC_FC_END_SEQ | FC_FC_SEQ_INIT)) + ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ; /* not first seq */ + if (f_ctl & (FC_FC_END_SEQ | FC_FC_SEQ_INIT)) ep->esb_stat &= ~ESB_ST_SEQ_INIT; spin_unlock_bh(&ep->ex_lock); return error; @@ -930,8 +928,9 @@ static void fc_seq_send_last(struct fc_seq *sp, struct fc_frame *fp, struct fc_exch *ep = fc_seq_exch(sp); f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; + f_ctl |= ep->f_ctl; fc_fill_fc_hdr(fp, rctl, ep->did, ep->sid, fh_type, f_ctl, 0); - fc_seq_send(fc_seq_exch(sp)->lp, sp, fp); + fc_seq_send(ep->lp, sp, fp); } /* @@ -952,7 +951,6 @@ static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp) */ if (fc_sof_needs_ack(fr_sof(rx_fp))) { fp = fc_frame_alloc(lp, 0); - BUG_ON(!fp); if (!fp) return; @@ -1848,7 +1846,6 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, ep->r_a_tov = FC_DEF_R_A_TOV; ep->lp = lp; sp = &ep->seq; - WARN_ON((sp->f_ctl & FC_FC_END_SEQ) != 0); ep->fh_type = fh->fh_type; /* save for possbile timeout handling */ ep->f_ctl = ntoh24(fh->fh_f_ctl); @@ -1861,7 +1858,6 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, if (timer_msec) fc_exch_timer_set_locked(ep, timer_msec); ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ - sp->f_ctl = ep->f_ctl; /* save for possible abort */ if (ep->f_ctl & FC_FC_SEQ_INIT) ep->esb_stat &= ~ESB_ST_SEQ_INIT; diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index de16203..591d160 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -465,6 +465,56 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, } /** + * fc_lport_recv_adisc_req - Handle received Address Discovery Request + * @lport: Fibre Channel local port recieving the ADISC + * @sp: current sequence in the ADISC exchange + * @fp: ADISC request frame + * + * Locking Note: The lport lock is exected to be held before calling + * this function. + */ +static void fc_lport_recv_adisc_req(struct fc_seq *sp, struct fc_frame *in_fp, + struct fc_lport *lport) +{ + struct fc_frame *fp; + struct fc_exch *ep = fc_seq_exch(sp); + struct fc_els_adisc *req, *rp; + struct fc_seq_els_data rjt_data; + size_t len; + u32 f_ctl; + + FC_DEBUG_LPORT("Received ADISC 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; + rjt_data.reason = ELS_RJT_LOGIC; + rjt_data.explan = ELS_EXPL_NONE; + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + } else { + len = sizeof(*rp); + fp = fc_frame_alloc(lport, len); + if (fp) { + rp = fc_frame_payload_get(fp, len); + memset(rp, 0, len); + rp->adisc_cmd = ELS_LS_ACC; + rp->adisc_wwpn = htonll(lport->wwpn); + rp->adisc_wwnn = htonll(lport->wwnn); + hton24(rp->adisc_port_id, + fc_host_port_id(lport->host)); + sp = lport->tt.seq_start_next(sp); + f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; + f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; + 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_frame_free(in_fp); +} + +/** * 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 @@ -821,6 +871,9 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, case ELS_RNID: recv = fc_lport_recv_rnid_req; break; + case ELS_ADISC: + recv = fc_lport_recv_adisc_req; + break; } if (recv) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index d081af5..3ea7fc9 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -333,8 +333,12 @@ int fc_rport_logoff(struct fc_rport *rport) */ fc_rport_state_enter(rport, RPORT_ST_NONE); + mutex_unlock(&rdata->rp_mutex); + cancel_delayed_work_sync(&rdata->retry_work); + mutex_lock(&rdata->rp_mutex); + rdata->event = RPORT_EV_STOP; queue_work(rport_event_queue, &rdata->event_work); diff --git a/include/scsi/fc/fc_els.h b/include/scsi/fc/fc_els.h index af4bf0c..195ca01 100644 --- a/include/scsi/fc/fc_els.h +++ b/include/scsi/fc/fc_els.h @@ -401,6 +401,20 @@ struct fc_els_prli { }; /* + * ELS_ADISC payload + */ +struct fc_els_adisc { + __u8 adisc_cmd; + __u8 adisc_resv[3]; + __u8 adisc_resv1; + __u8 adisc_hard_addr[3]; + __be64 adisc_wwpn; + __be64 adisc_wwnn; + __u8 adisc_resv2; + __u8 adisc_port_id[3]; +} __attribute__((__packed__)); + +/* * ELS_LOGO - process or fabric logout. */ struct fc_els_logo { diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 587be50..a7095cb 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -287,7 +287,6 @@ struct fc_seq { u8 id; /* seq ID */ u16 ssb_stat; /* status flags for sequence status block */ u16 cnt; /* frames sent so far on sequence */ - u32 f_ctl; /* F_CTL flags for frames */ u32 rec_data; /* FC-4 value for REC */ };