--- /dev/null
+Subject: Open-FCoE bugfixes for fnic
+From: Hannes Reinecke <hare@suse.de>
+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 <abjoglek@cisco.com>
+Acked-by: Hannes Reinecke <hare@suse.de>
+
+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 */
+ };
+