static void fc_lport_recv_flogi_req(struct fc_lport *lport, struct fc_frame *rx_fp) { struct fc_frame *fp; struct fc_frame_header *fh; struct fc_els_flogi *flp; struct fc_els_flogi *new_flp; u64 remote_wwpn; u32 remote_fid; u32 local_fid; FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n", fc_lport_state(lport)); remote_fid = fc_frame_sid(rx_fp); flp = fc_frame_payload_get(rx_fp, sizeof(*flp)); if (!flp) goto out; remote_wwpn = get_unaligned_be64(&flp->fl_wwpn); if (remote_wwpn == lport->wwpn) { printk(KERN_WARNING "host%d: libfc: Received FLOGI from port " "with same WWPN %16.16llx\n", lport->host->host_no, remote_wwpn); goto out; } FC_LPORT_DBG(lport, "FLOGI from port WWPN %16.16llx\n", remote_wwpn); local_fid = FC_LOCAL_PTP_FID_LO; if (remote_wwpn < lport->wwpn) { local_fid = FC_LOCAL_PTP_FID_HI; if (!remote_fid || remote_fid == local_fid) remote_fid = FC_LOCAL_PTP_FID_LO; } else if (!remote_fid) { remote_fid = FC_LOCAL_PTP_FID_HI; } fc_lport_set_port_id(lport, local_fid, rx_fp); fp = fc_frame_alloc(lport, sizeof(*flp)); if (fp) { new_flp = fc_frame_payload_get(fp, sizeof(*flp)); fc_lport_flogi_fill(lport, new_flp, ELS_FLOGI); new_flp->fl_cmd = (u8) ELS_LS_ACC; fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); fh = fc_frame_header_get(fp); hton24(fh->fh_s_id, local_fid); hton24(fh->fh_d_id, remote_fid); lport->tt.frame_send(lport, fp); } else { fc_lport_error(lport, fp); } fc_lport_ptp_setup(lport, remote_fid, remote_wwpn, get_unaligned_be64(&flp->fl_wwnn)); out: fc_frame_free(rx_fp); }
/** * fc_lport_recv_req() - The generic lport request handler * @lport: The local port that received the request * @fp: The request frame * * This function will see if the lport handles the request or * if an rport should handle the request. * * Locking Note: This function should not be called with the lport * lock held becuase it will grab the lock. */ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp) { struct fc_frame_header *fh = fc_frame_header_get(fp); void (*recv)(struct fc_lport *, struct fc_frame *); mutex_lock(&lport->lp_mutex); /* * Handle special ELS cases like FLOGI, LOGO, and * RSCN here. These don't require a session. * Even if we had a session, it might not be ready. */ if (!lport->link_up) fc_frame_free(fp); else if (fh->fh_type == FC_TYPE_ELS && fh->fh_r_ctl == FC_RCTL_ELS_REQ) { /* * Check opcode. */ recv = lport->tt.rport_recv_req; switch (fc_frame_payload_op(fp)) { case ELS_FLOGI: if (!lport->point_to_multipoint) recv = fc_lport_recv_flogi_req; break; case ELS_LOGO: if (fc_frame_sid(fp) == FC_FID_FLOGI) recv = fc_lport_recv_logo_req; break; case ELS_RSCN: recv = lport->tt.disc_recv_req; break; case ELS_ECHO: recv = fc_lport_recv_echo_req; break; case ELS_RLIR: recv = fc_lport_recv_rlir_req; break; case ELS_RNID: recv = fc_lport_recv_rnid_req; break; } recv(lport, fp); } else { FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n", fr_eof(fp)); fc_frame_free(fp); } mutex_unlock(&lport->lp_mutex); }
/** * fc_lport_recv_els_req() - The generic lport ELS request handler * @lport: The local port that received the request * @fp: The request frame * * This function will see if the lport handles the request or * if an rport should handle the request. * * Locking Note: This function should not be called with the lport * lock held because it will grab the lock. */ static void fc_lport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp) { void (*recv)(struct fc_lport *, struct fc_frame *); mutex_lock(&lport->lp_mutex); /* * Handle special ELS cases like FLOGI, LOGO, and * RSCN here. These don't require a session. * Even if we had a session, it might not be ready. */ if (!lport->link_up) fc_frame_free(fp); else { /* * Check opcode. */ recv = lport->tt.rport_recv_req; switch (fc_frame_payload_op(fp)) { case ELS_FLOGI: if (!lport->point_to_multipoint) recv = fc_lport_recv_flogi_req; break; case ELS_LOGO: if (fc_frame_sid(fp) == FC_FID_FLOGI) recv = fc_lport_recv_logo_req; break; case ELS_RSCN: recv = lport->tt.disc_recv_req; break; case ELS_ECHO: recv = fc_lport_recv_echo_req; break; case ELS_RLIR: recv = fc_lport_recv_rlir_req; break; case ELS_RNID: recv = fc_lport_recv_rnid_req; break; } recv(lport, fp); } mutex_unlock(&lport->lp_mutex); }
static void fc_lport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp) { void (*recv)(struct fc_lport *, struct fc_frame *); mutex_lock(&lport->lp_mutex); if (!lport->link_up) fc_frame_free(fp); else { recv = lport->tt.rport_recv_req; switch (fc_frame_payload_op(fp)) { case ELS_FLOGI: if (!lport->point_to_multipoint) recv = fc_lport_recv_flogi_req; break; case ELS_LOGO: if (fc_frame_sid(fp) == FC_FID_FLOGI) recv = fc_lport_recv_logo_req; break; case ELS_RSCN: recv = lport->tt.disc_recv_req; break; case ELS_ECHO: recv = fc_lport_recv_echo_req; break; case ELS_RLIR: recv = fc_lport_recv_rlir_req; break; case ELS_RNID: recv = fc_lport_recv_rnid_req; break; } recv(lport, fp); } mutex_unlock(&lport->lp_mutex); }
/** * fc_lport_recv_flogi_req() - Receive a FLOGI request * @lport: The local port that recieved the request * @rx_fp: The FLOGI frame * * A received FLOGI request indicates a point-to-point connection. * Accept it with the common service parameters indicating our N port. * Set up to do a PLOGI if we have the higher-number WWPN. * * Locking Note: The lport lock is expected to be held before calling * this function. */ static void fc_lport_recv_flogi_req(struct fc_lport *lport, struct fc_frame *rx_fp) { struct fc_frame *fp; struct fc_frame_header *fh; struct fc_els_flogi *flp; struct fc_els_flogi *new_flp; u64 remote_wwpn; u32 remote_fid; u32 local_fid; FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n", fc_lport_state(lport)); remote_fid = fc_frame_sid(rx_fp); flp = fc_frame_payload_get(rx_fp, sizeof(*flp)); if (!flp) goto out; remote_wwpn = get_unaligned_be64(&flp->fl_wwpn); if (remote_wwpn == lport->wwpn) { printk(KERN_WARNING "host%d: libfc: Received FLOGI from port " "with same WWPN %16.16llx\n", lport->host->host_no, remote_wwpn); goto out; } FC_LPORT_DBG(lport, "FLOGI from port WWPN %16.16llx\n", remote_wwpn); /* * XXX what is the right thing to do for FIDs? * The originator might expect our S_ID to be 0xfffffe. * But if so, both of us could end up with the same FID. */ local_fid = FC_LOCAL_PTP_FID_LO; if (remote_wwpn < lport->wwpn) { local_fid = FC_LOCAL_PTP_FID_HI; if (!remote_fid || remote_fid == local_fid) remote_fid = FC_LOCAL_PTP_FID_LO; } else if (!remote_fid) { remote_fid = FC_LOCAL_PTP_FID_HI; } fc_lport_set_port_id(lport, local_fid, rx_fp); fp = fc_frame_alloc(lport, sizeof(*flp)); if (fp) { new_flp = fc_frame_payload_get(fp, sizeof(*flp)); fc_lport_flogi_fill(lport, new_flp, ELS_FLOGI); new_flp->fl_cmd = (u8) ELS_LS_ACC; /* * Send the response. If this fails, the originator should * repeat the sequence. */ fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); fh = fc_frame_header_get(fp); hton24(fh->fh_s_id, local_fid); hton24(fh->fh_d_id, remote_fid); lport->tt.frame_send(lport, fp); } else { fc_lport_error(lport, fp); } fc_lport_ptp_setup(lport, remote_fid, remote_wwpn, get_unaligned_be64(&flp->fl_wwnn)); out: fc_frame_free(rx_fp); }
/** * fc_lport_flogi_resp() - Handle response to FLOGI request * @sp: The sequence that the FLOGI was on * @fp: The FLOGI response frame * @lp_arg: The lport port that received the FLOGI response * * Locking Note: This function will be called without the lport lock * held, but it will lock, call an _enter_* function or fc_lport_error() * and then unlock the lport. */ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, void *lp_arg) { struct fc_lport *lport = lp_arg; struct fc_els_flogi *flp; u32 did; u16 csp_flags; unsigned int r_a_tov; unsigned int e_d_tov; u16 mfs; FC_LPORT_DBG(lport, "Received a FLOGI %s\n", fc_els_resp_type(fp)); if (fp == ERR_PTR(-FC_EX_CLOSED)) return; mutex_lock(&lport->lp_mutex); if (lport->state != LPORT_ST_FLOGI) { FC_LPORT_DBG(lport, "Received a FLOGI response, but in state " "%s\n", fc_lport_state(lport)); if (IS_ERR(fp)) goto err; goto out; } if (IS_ERR(fp)) { fc_lport_error(lport, fp); goto err; } did = fc_frame_did(fp); if (fc_frame_payload_op(fp) == ELS_LS_ACC && did) { flp = fc_frame_payload_get(fp, sizeof(*flp)); if (flp) { mfs = ntohs(flp->fl_csp.sp_bb_data) & FC_SP_BB_DATA_MASK; if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < lport->mfs) lport->mfs = mfs; csp_flags = ntohs(flp->fl_csp.sp_features); r_a_tov = ntohl(flp->fl_csp.sp_r_a_tov); e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov); if (csp_flags & FC_SP_FT_EDTR) e_d_tov /= 1000000; lport->npiv_enabled = !!(csp_flags & FC_SP_FT_NPIV_ACC); if ((csp_flags & FC_SP_FT_FPORT) == 0) { if (e_d_tov > lport->e_d_tov) lport->e_d_tov = e_d_tov; lport->r_a_tov = 2 * e_d_tov; fc_lport_set_port_id(lport, did, fp); printk(KERN_INFO "host%d: libfc: " "Port (%6.6x) entered " "point-to-point mode\n", lport->host->host_no, did); fc_lport_ptp_setup(lport, fc_frame_sid(fp), get_unaligned_be64( &flp->fl_wwpn), get_unaligned_be64( &flp->fl_wwnn)); } else { lport->e_d_tov = e_d_tov; lport->r_a_tov = r_a_tov; fc_host_fabric_name(lport->host) = get_unaligned_be64(&flp->fl_wwnn); fc_lport_set_port_id(lport, did, fp); fc_lport_enter_dns(lport); } } } else { FC_LPORT_DBG(lport, "FLOGI RJT or bad response\n"); fc_lport_error(lport, fp); } out: fc_frame_free(fp); err: mutex_unlock(&lport->lp_mutex); }