summaryrefslogtreecommitdiff
path: root/roms/ipxe/src/net/fc.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/ipxe/src/net/fc.c')
-rw-r--r--roms/ipxe/src/net/fc.c91
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 );