• Abhijeet Joglekar's avatar
    [SCSI] libfc: Track rogue remote ports · b4c6f546
    Abhijeet Joglekar authored
    
    
    Rogue ports are currently not tracked on any list. The only reference
    to them is through any outstanding exchanges pending on the rogue ports.
    If the module is removed while a retry is set on a rogue port
    (say a Plogi retry for instance), this retry is not cancelled because there
    is no reference to the rogue port in the discovery rports list. Thus the
    local port can clean itself up, delete the exchange pool, and then the
    rogue port timeout can fire and try to start up another exchange.
    
    This patch tracks the rogue ports in a new list disc->rogue_rports. Creating
    a new list instead of using the disc->rports list keeps remote port code
    change to a minimum.
    
    1)  Whenever a rogue port is created, it is immediately added to the
    disc->rogue_rports list.
    
    2) When the rogues port goes to ready, it is removed from the rogue list
    and the real remote port is added to the disc->rports list
    
    3) The removal of the rogue from the disc->rogue_rports list is done in
    the context of the fc_rport_work() workQ thread in discovery callback.
    
    4) Real rports are removed from the disc->rports list like before. Lookup
    is done only in the real rports list. This avoids making large changes
    to the remote port code.
    
    5) In fc_disc_stop_rports, the rogues list is traversed in addition to the
    real list to stop the rogue ports and issue logoffs on them. This way, rogue
    ports get cleaned up when the local port goes away.
    
    6) rogue remote ports are not removed from the list right away, but
    removed late in fc_rport_work() context, multiple threads can find the same
    remote port in the list and call rport_logoff(). Rport_logoff() only
    continues with the logoff if port is not in NONE state, thus preventing
    multiple logoffs and multiple list deletions.
    
    7) Since the rport is removed from the disc list at a later stage
    (in the disc callback), incoming frames can find the rport even if
    rport_logoff() has been called on the rport. When rport_logoff() is called,
    the rport state is set to NONE, and we are trying to cancel all exchanges
    and retries on that port. While in this state, if an incoming
    Plogi/Prli/Logo or other frames match the rport, we should not reply
    because the rport is in the NONE state. Just drop the frame, since the
    rport will be deleted soon in the disc callback (fc_rport_work)
    
    8)  In fc_disc_single(), remove rport lookup and call to fc_disc_del_target.
    fc_disc_single() is called from recv_rscn_req() where rport lookup
    and rport_logoff is already done.
    Signed-off-by: default avatarAbhijeet Joglekar <abjoglek@cisco.com>
    Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
    Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
    b4c6f546
libfc.h 25.6 KB