diff options
Diffstat (limited to 'roms/ipxe/src/net/fc.c')
-rw-r--r-- | roms/ipxe/src/net/fc.c | 91 |
1 files changed, 64 insertions, 27 deletions
diff --git a/roms/ipxe/src/net/fc.c b/roms/ipxe/src/net/fc.c index 1934fab3d..58008995c 100644 --- a/roms/ipxe/src/net/fc.c +++ b/roms/ipxe/src/net/fc.c @@ -13,7 +13,8 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ FILE_LICENCE ( GPL2_OR_LATER ); @@ -1580,7 +1581,7 @@ static void fc_ulp_close ( struct fc_ulp *ulp, int rc ) { fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) ); /* Sanity check */ - assert ( ulp->usage == 0 ); + assert ( list_empty ( &ulp->users ) ); /* Stop link monitor */ fc_link_stop ( &ulp->link ); @@ -1594,35 +1595,50 @@ static void fc_ulp_close ( struct fc_ulp *ulp, int rc ) { } /** - * Increment Fibre Channel upper-layer protocol active usage count + * Attach Fibre Channel upper-layer protocol user * - * @v ulp Fibre Channel ulp + * @v ulp Fibre Channel upper-layer protocol + * @v user Fibre Channel upper-layer protocol user */ -void fc_ulp_increment ( struct fc_ulp *ulp ) { +void fc_ulp_attach ( struct fc_ulp *ulp, struct fc_ulp_user *user ) { + + /* Sanity check */ + assert ( user->ulp == NULL ); /* Increment peer's usage count */ fc_peer_increment ( ulp->peer ); - /* Increment our usage count */ - ulp->usage++; + /* Attach user */ + user->ulp = fc_ulp_get ( ulp ); + list_add ( &user->list, &ulp->users ); } /** - * Decrement Fibre Channel upper-layer protocol active usage count + * Detach Fibre Channel upper-layer protocol user * - * @v ulp Fibre Channel ulp + * @v user Fibre Channel upper-layer protocol user */ -void fc_ulp_decrement ( struct fc_ulp *ulp ) { +void fc_ulp_detach ( struct fc_ulp_user *user ) { + struct fc_ulp *ulp = user->ulp; - /* Sanity check */ - assert ( ulp->usage > 0 ); + /* Do nothing if not attached */ + if ( ! ulp ) + return; - /* Decrement our usage count and log out if we reach zero */ - if ( --(ulp->usage) == 0 ) + /* Sanity checks */ + list_check_contains_entry ( user, &ulp->users, list ); + + /* Detach user and log out if no users remain */ + list_del ( &user->list ); + if ( list_empty ( &ulp->users ) ) fc_ulp_logout ( ulp, 0 ); /* Decrement our peer's usage count */ fc_peer_decrement ( ulp->peer ); + + /* Drop reference */ + user->ulp = NULL; + fc_ulp_put ( ulp ); } /** @@ -1636,6 +1652,8 @@ void fc_ulp_decrement ( struct fc_ulp *ulp ) { */ int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len, int originated ) { + struct fc_ulp_user *user; + struct fc_ulp_user *tmp; /* Perform implicit logout if logged in and service parameters differ */ if ( fc_link_ok ( &ulp->link ) && @@ -1644,6 +1662,22 @@ int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len, fc_ulp_logout ( ulp, 0 ); } + /* Work around a bug in some versions of the Linux Fibre + * Channel stack, which fail to fully initialise image pairs + * established via a PRLI originated by the Linux stack + * itself. + */ + if ( originated ) + ulp->flags |= FC_ULP_ORIGINATED_LOGIN_OK; + if ( ! ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) ) { + DBGC ( ulp, "FCULP %s/%02x sending extra PRLI to work around " + "Linux bug\n", + fc_ntoa ( &ulp->peer->port_wwn ), ulp->type ); + fc_link_stop ( &ulp->link ); + fc_link_start ( &ulp->link ); + return 0; + } + /* Log in, if applicable */ if ( ! fc_link_ok ( &ulp->link ) ) { @@ -1670,18 +1704,11 @@ int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len, /* Record login */ fc_link_up ( &ulp->link ); - /* Work around a bug in some versions of the Linux Fibre - * Channel stack, which fail to fully initialise image pairs - * established via a PRLI originated by the Linux stack - * itself. - */ - if ( originated ) - ulp->flags |= FC_ULP_ORIGINATED_LOGIN_OK; - if ( ! ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) ) { - DBGC ( ulp, "FCULP %s/%02x sending extra PRLI to work around " - "Linux bug\n", - fc_ntoa ( &ulp->peer->port_wwn ), ulp->type ); - fc_link_start ( &ulp->link ); + /* Notify users of link state change */ + list_for_each_entry_safe ( user, tmp, &ulp->users, list ) { + fc_ulp_user_get ( user ); + user->examine ( user ); + fc_ulp_user_put ( user ); } return 0; @@ -1694,6 +1721,8 @@ int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len, * @v rc Reason for logout */ void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) { + struct fc_ulp_user *user; + struct fc_ulp_user *tmp; DBGC ( ulp, "FCULP %s/%02x logged out: %s\n", fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) ); @@ -1711,8 +1740,15 @@ void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) { /* Record logout */ fc_link_err ( &ulp->link, rc ); + /* Notify users of link state change */ + list_for_each_entry_safe ( user, tmp, &ulp->users, list ) { + fc_ulp_user_get ( user ); + user->examine ( user ); + fc_ulp_user_put ( user ); + } + /* Close ULP if there are no clients attached */ - if ( ulp->usage == 0 ) + if ( list_empty ( &ulp->users ) ) fc_ulp_close ( ulp, rc ); } @@ -1795,6 +1831,7 @@ static struct fc_ulp * fc_ulp_create ( struct fc_peer *peer, ulp->peer = fc_peer_get ( peer ); list_add_tail ( &ulp->list, &peer->ulps ); ulp->type = type; + INIT_LIST_HEAD ( &ulp->users ); /* Start link state monitor */ fc_link_start ( &ulp->link ); |