Upon receiving ELS_RLS, send the Link Error Status Block (LESB) back.

Signed-off-by: Yi Zou <[email protected]>
---

 drivers/scsi/libfc/fc_lport.c |  124 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 124 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index bbf4152..48b8aae 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -526,6 +526,127 @@ static void fc_lport_recv_logo_req(struct fc_seq *sp, 
struct fc_frame *fp,
 }
 
 /**
+ * fc_lport_get_lesb() - Fill the Link Error Status Block
+ * @lport: The local port recieving the RLS
+ * @lesb: The FC-BB-5 Link Error Status Block to be filled in
+ *
+ * Fill the LESB with from the per-cpu fcoe statistics, return 0
+ * when stats are successfully retrieved.
+ */
+static int fc_lport_get_lesb(struct fc_lport *lport,
+                            struct fc_els_lesb_bb5 *lesb)
+{
+       unsigned int cpu;
+       u32 lfc, vlfc, mdac;
+       struct fcoe_dev_stats *devst;
+       struct fcoe_lld_stats *lldst;
+
+       lfc = 0;
+       vlfc = 0;
+       mdac = 0;
+       memset(lesb, 0, sizeof(*lesb));
+       for_each_possible_cpu(cpu) {
+               devst = per_cpu_ptr(lport->dev_stats, cpu);
+               lfc += devst->LinkFailureCount;
+               vlfc += devst->VLinkFailureCount;
+               mdac += devst->MissDiscAdvCount;
+       }
+       lesb->lesb_link_fail = __cpu_to_be32(lfc);
+       lesb->lesb_vlink_fail = __cpu_to_be32(vlfc);
+       lesb->lesb_miss_fip = __cpu_to_be32(mdac);
+
+       lldst = &lport->lld_stats;
+       if (lport->tt.lld_stats) {
+               lport->tt.lld_stats(lport, lldst);
+               lesb->lesb_symb_err = __cpu_to_be32(lldst->SymbolErrorCount);
+               lesb->lesb_err_block = __cpu_to_be32(lldst->ErroredBlockCount);
+               lesb->lesb_fcs_error = __cpu_to_be32(lldst->FCSErrorCount);
+       }
+       return 0;
+}
+
+/**
+ * fc_lport_recv_rls_req() - Handle received Request Node ID data request
+ * @sp:           The sequence in the RLS exchange
+ * @fp:           The RLS request frame
+ * @lport: The local port recieving the RLS
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this function.
+ *
+ * FIXME: how to check/indicate if we want support RLS for LESB?
+ *
+ */
+static void fc_lport_recv_rls_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_rls *rls;
+       struct fc_els_rls_resp *rsp;
+       struct fc_seq_els_data rjt_data;
+       struct fc_els_lesb_bb5 *lesb;
+       struct fc_rport_priv *rdata;
+       struct fc_frame_header *fh;
+       size_t len;
+       u32 f_ctl;
+       u32 sid;
+
+       FC_LPORT_DBG(lport, "Received RLS request while in state %s\n",
+                    fc_lport_state(lport));
+
+       /* check if this port is logged in */
+       fh = fc_frame_header_get(in_fp);
+       sid = ntoh24(fh->fh_s_id);
+       mutex_lock(&lport->disc.disc_mutex);
+       rdata = lport->tt.rport_lookup(lport, sid);
+       mutex_unlock(&lport->disc.disc_mutex);
+       if (!rdata) {
+               FC_LPORT_DBG(lport, "LS_RJT %x:PLOGI needed\n", sid);
+               rjt_data.reason = ELS_RJT_UNAB;
+               rjt_data.explan = ELS_EXPL_PLOGI_REQD;
+               goto out_rjt;
+       }
+       /* no rls payload */
+       rls = fc_frame_payload_get(in_fp, sizeof(*rls));
+       if (!rls) {
+               rjt_data.reason = ELS_RJT_LOGIC;
+               rjt_data.explan = ELS_EXPL_NONE;
+               goto out_rjt;
+       }
+
+       len = sizeof(*rsp);
+       fp = fc_frame_alloc(lport, len);
+       if (!fp) {
+               rjt_data.reason = ELS_RJT_UNAB;
+               rjt_data.explan = ELS_EXPL_INSUF_RES;
+               goto out_rjt;
+       }
+       rsp = fc_frame_payload_get(fp, len);
+       memset(rsp, 0, len);
+       rsp->rls_cmd = ELS_LS_ACC;
+       lesb = (struct fc_els_lesb_bb5 *)&rsp->rls_lesb;
+       if (fc_lport_get_lesb(lport, lesb)) {
+               FC_LPORT_DBG(lport, "LS_RJT %x:failed to get lesb\n", sid);
+               rjt_data.reason = ELS_RJT_UNAB;
+               rjt_data.explan = ELS_EXPL_INSUF_RES;
+               goto out_rjt;
+       }
+       /* send response */
+       sp = lport->tt.seq_start_next(sp);
+       f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
+       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);
+       goto out;
+out_rjt:
+       rjt_data.fp = NULL;
+       lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+out:
+       fc_frame_free(in_fp);
+}
+
+/**
  * fc_fabric_login() - Start the lport state machine
  * @lport: The local port that should log into the fabric
  *
@@ -898,6 +1019,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_RLS:
+                       recv = fc_lport_recv_rls_req;
+                       break;
                }
 
                recv(sp, fp, lport);

_______________________________________________
devel mailing list
[email protected]
http://www.open-fcoe.org/mailman/listinfo/devel

Reply via email to