On Mon, 2009-08-10 at 12:23 -0700, Joe Eykholt wrote: > When an RSCN indicates changes to individual remote ports, > don't blindly log them out and then back in. Instead, determine > whether they're still in the directory, by doing GPN_ID. > > If that is successful, call login, which will send ADISC and reverify, > otherwise, call logoff. Perhaps we should just delete the rport, > not send LOGO, but it seems safer. > > Also, fix a possible issue where if a mix of records in the RSCN > cause us to queue disc_ports for disc_single and then we decide > to do full rediscovery, we leak memory for those disc_ports queued. > > So, go through the list of disc_ports even if doing full discovery. > Free the disc_ports in any case. If any of the disc_single() calls > return error, do a full discovery. > > The ability to fill in GPN_ID requests was added to fc_ct_fill(). > For this, it needs the FC_ID to be passed in as an arg. > The did parameter for fc_elsct_send() is used for that, since the > actual D_DID will always be 0xfffffc for all CT requests so far. > > Signed-off-by: Joe Eykholt <[email protected]> > --- > drivers/scsi/libfc/fc_disc.c | 139 > ++++++++++++++++++++++++++++++++++------- > drivers/scsi/libfc/fc_elsct.c | 2 - > include/scsi/fc_encode.h | 16 ++++- > 3 files changed, 130 insertions(+), 27 deletions(-) > > > diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c > index 1a699f4..f694394 100644 > --- a/drivers/scsi/libfc/fc_disc.c > +++ b/drivers/scsi/libfc/fc_disc.c > @@ -47,7 +47,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *); > static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); > static void fc_disc_done(struct fc_disc *, enum fc_disc_event); > static void fc_disc_timeout(struct work_struct *); > -static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); > +static int fc_disc_single(struct fc_lport *, struct fc_disc_port *); > static void fc_disc_restart(struct fc_disc *); > > /** > @@ -83,7 +83,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct > fc_frame *fp, > struct fc_disc *disc) > { > struct fc_lport *lport; > - struct fc_rport_priv *rdata; > struct fc_els_rscn *rp; > struct fc_els_rscn_page *pp; > struct fc_seq_els_data rjt_data; > @@ -153,6 +152,19 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, > struct fc_frame *fp, > } > } > lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); > + > + /* > + * If not doing a complete rediscovery, do GPN_ID on > + * the individual ports mentioned in the list. > + * If any of these get an error, do a full rediscovery. > + * In any case, go through the list and free the entries. > + */ > + list_for_each_entry_safe(dp, next, &disc_ports, peers) { > + list_del(&dp->peers); > + if (!redisc) > + redisc = fc_disc_single(lport, dp); > + kfree(dp); > + } > if (redisc) { > FC_DISC_DBG(disc, "RSCN received: rediscovering\n"); > fc_disc_restart(disc); > @@ -160,14 +172,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, > struct fc_frame *fp, > FC_DISC_DBG(disc, "RSCN received: not rediscovering. " > "redisc %d state %d in_prog %d\n", > redisc, lport->state, disc->pending); > - list_for_each_entry_safe(dp, next, &disc_ports, peers) { > - list_del(&dp->peers); > - rdata = lport->tt.rport_lookup(lport, dp->ids.port_id); > - if (rdata) { > - lport->tt.rport_logoff(rdata); > - } > - fc_disc_single(disc, dp); > - } > } > fc_frame_free(fp); > return; > @@ -566,32 +570,119 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, > struct fc_frame *fp, > } > > /** > - * fc_disc_single() - Discover the directory information for a single target > - * @lport: FC local port > - * @dp: The port to rediscover > + * fc_disc_gpn_id_resp() - Handle a response frame from Get Port Names > (GPN_ID) > + * @sp: exchange sequence > + * @fp: response frame > + * @rdata_arg: remote port private data > * > - * Locking Note: This function expects that the disc_mutex is locked > - * before it is called. > + * Locking Note: This function is called without disc mutex held. > */ > -static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) > +static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, > + void *rdata_arg) > { > + struct fc_rport_priv *rdata = rdata_arg; > + struct fc_rport_priv *new_rdata; > struct fc_lport *lport; > - struct fc_rport_priv *rdata; > + struct fc_disc *disc; > + struct fc_ct_hdr *cp; > + struct fc_ns_gid_pn *pn; > + struct fc_rport_identifiers ids; > > - lport = disc->lport; > + lport = rdata->local_port; > + disc = &lport->disc; > > - if (dp->ids.port_id == fc_host_port_id(lport->host)) > + mutex_lock(&disc->disc_mutex); > + if (PTR_ERR(fp) == -FC_EX_CLOSED) > goto out; > + if (IS_ERR(fp)) > + goto redisc; > + > + cp = fc_frame_payload_get(fp, sizeof(*cp)); > + if (!cp) > + goto redisc; > + if (ntohs(cp->ct_cmd) == FC_FS_ACC) { > + if (fr_len(fp) < sizeof(struct fc_frame_header) + > + sizeof(*cp) + sizeof(*pn)) > + goto redisc; > + pn = (struct fc_ns_gid_pn *)(cp + 1); > + ids.port_name = get_unaligned_be64(&pn->fn_wwpn); > + if (rdata->ids.port_name == -1) > + rdata->ids.port_name = ids.port_name; > + else if (rdata->ids.port_name != ids.port_name) { > + FC_DISC_DBG(disc, "GPN_ID accepted. WWPN changed. " > + "Port-id %x wwpn %llx\n", > + rdata->ids.port_id, > + (unsigned long long)ids.port_name); > + lport->tt.rport_logoff(rdata); > > - rdata = lport->tt.rport_create(lport, &dp->ids); > - if (rdata) { > + ids.node_name = -1; > + ids.roles = FC_PORT_ROLE_UNKNOWN; > + new_rdata = lport->tt.rport_create(lport, &ids);
Hey Joe, can you help me understand the intent here? You want to pass in the port ID of the existing rport/rdata if possible in the ids instance, right? I've created a patch before these last two series of yours to pass the port_id and not the fc_rport_identifiers into rport_create(). I'm going through your patches and fixing merge conflicts, but I'm stuck on this line- I'm not sure what port_id to pass in. _______________________________________________ devel mailing list [email protected] http://www.open-fcoe.org/mailman/listinfo/devel
