From bf8bfa23e2364793ccdfc32627d8094a74ae87aa Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 24 Jun 2011 22:49:10 +0100 Subject: [PATCH] [fc] Maintain a list of Fibre Channel upper-layer protocol users Signed-off-by: Michael Brown --- src/include/ipxe/fc.h | 33 +++++++++++++++++++++++++++----- src/net/fc.c | 44 +++++++++++++++++++++++++++++-------------- src/net/fcp.c | 32 ++++++++++++++----------------- src/usr/fcmgmt.c | 3 +-- 4 files changed, 73 insertions(+), 39 deletions(-) diff --git a/src/include/ipxe/fc.h b/src/include/ipxe/fc.h index ab6b5bae7..06d38baf9 100644 --- a/src/include/ipxe/fc.h +++ b/src/include/ipxe/fc.h @@ -357,7 +357,15 @@ struct fc_peer { /** List of upper-layer protocols */ struct list_head ulps; - /** Active usage count */ + /** Active usage count + * + * A peer (and attached ULPs) may be created in response to + * unsolicited login requests received via the fabric. We + * track our own active usage count independently of the + * existence of the peer, so that if the peer becomes logged + * out (e.g. due to a link failure) then we know whether or + * not we should attempt to relogin. + */ unsigned int usage; }; @@ -424,8 +432,15 @@ struct fc_ulp { /** Service parameter length */ size_t param_len; - /** Active usage count */ - unsigned int usage; + /** Active users of this upper-layer protocol + * + * As with peers, an upper-layer protocol may be created in + * response to an unsolicited login request received via the + * fabric. This list records the number of active users of + * the ULP; the number of entries in the list is equivalent to + * the peer usage count. + */ + struct list_head users; }; /** Fibre Channel upper-layer protocol flags */ @@ -434,6 +449,14 @@ enum fc_ulp_flags { FC_ULP_ORIGINATED_LOGIN_OK = 0x0001, }; +/** A Fibre Channel upper-layer protocol user */ +struct fc_ulp_user { + /** Fibre Channel upper layer protocol */ + struct fc_ulp *ulp; + /** List of users */ + struct list_head list; +}; + /** * Get reference to Fibre Channel upper-layer protocol * @@ -462,8 +485,8 @@ extern struct fc_ulp * fc_ulp_get_port_id_type ( struct fc_port *port, const struct fc_port_id *peer_port_id, unsigned int type ); -extern void fc_ulp_increment ( struct fc_ulp *ulp ); -extern void fc_ulp_decrement ( struct fc_ulp *ulp ); +extern void fc_ulp_attach ( struct fc_ulp *ulp, struct fc_ulp_user *user ); +extern void fc_ulp_detach ( struct fc_ulp_user *user ); extern int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len, int originated ); extern void fc_ulp_logout ( struct fc_ulp *ulp, int rc ); diff --git a/src/net/fc.c b/src/net/fc.c index 1934fab3d..a94456c82 100644 --- a/src/net/fc.c +++ b/src/net/fc.c @@ -1580,7 +1580,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 +1594,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 ( 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 ); } /** @@ -1712,7 +1727,7 @@ void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) { fc_link_err ( &ulp->link, rc ); /* Close ULP if there are no clients attached */ - if ( ulp->usage == 0 ) + if ( list_empty ( &ulp->users ) ) fc_ulp_close ( ulp, rc ); } @@ -1795,6 +1810,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 ); diff --git a/src/net/fcp.c b/src/net/fcp.c index 40cd057e6..28d2095d7 100644 --- a/src/net/fcp.c +++ b/src/net/fcp.c @@ -146,8 +146,8 @@ struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor = { struct fcp_device { /** Reference count */ struct refcnt refcnt; - /** Fibre Channel upper-layer protocol */ - struct fc_ulp *ulp; + /** Fibre Channel upper-layer protocol user */ + struct fc_ulp_user user; /** SCSI command issuing interface */ struct interface scsi; /** List of active commands */ @@ -734,13 +734,13 @@ static struct interface_descriptor fcpcmd_xchg_desc = static int fcpdev_scsi_command ( struct fcp_device *fcpdev, struct interface *parent, struct scsi_cmd *command ) { - struct fcp_prli_service_parameters *param = fcpdev->ulp->param; + struct fcp_prli_service_parameters *param = fcpdev->user.ulp->param; struct fcp_command *fcpcmd; int xchg_id; int rc; /* Check link */ - if ( ( rc = fcpdev->ulp->link.rc ) != 0 ) { + if ( ( rc = fcpdev->user.ulp->link.rc ) != 0 ) { DBGC ( fcpdev, "FCP %p could not issue command while link is " "down: %s\n", fcpdev, strerror ( rc ) ); goto err_link; @@ -748,7 +748,7 @@ static int fcpdev_scsi_command ( struct fcp_device *fcpdev, /* Check target capability */ assert ( param != NULL ); - assert ( fcpdev->ulp->param_len >= sizeof ( *param ) ); + assert ( fcpdev->user.ulp->param_len >= sizeof ( *param ) ); if ( ! ( param->flags & htonl ( FCP_PRLI_TARGET ) ) ) { DBGC ( fcpdev, "FCP %p could not issue command: not a target\n", fcpdev ); @@ -772,8 +772,8 @@ static int fcpdev_scsi_command ( struct fcp_device *fcpdev, /* Create new exchange */ if ( ( xchg_id = fc_xchg_originate ( &fcpcmd->xchg, - fcpdev->ulp->peer->port, - &fcpdev->ulp->peer->port_id, + fcpdev->user.ulp->peer->port, + &fcpdev->user.ulp->peer->port_id, FC_TYPE_FCP ) ) < 0 ) { rc = xchg_id; DBGC ( fcpdev, "FCP %p could not create exchange: %s\n", @@ -822,11 +822,7 @@ static void fcpdev_close ( struct fcp_device *fcpdev, int rc ) { } /* Drop reference to ULP */ - if ( fcpdev->ulp ) { - fc_ulp_decrement ( fcpdev->ulp ); - fc_ulp_put ( fcpdev->ulp ); - fcpdev->ulp = NULL; - } + fc_ulp_detach ( &fcpdev->user ); } /** @@ -836,7 +832,8 @@ static void fcpdev_close ( struct fcp_device *fcpdev, int rc ) { * @ret len Length of window */ static size_t fcpdev_window ( struct fcp_device *fcpdev ) { - return ( fc_link_ok ( &fcpdev->ulp->link ) ? ~( ( size_t ) 0 ) : 0 ); + return ( fc_link_ok ( &fcpdev->user.ulp->link ) ? + ~( ( size_t ) 0 ) : 0 ); } /** @@ -897,15 +894,15 @@ static struct device * fcpdev_identify_device ( struct fcp_device *fcpdev ) { /* We know the underlying device only if the link is up; * otherwise we don't have a port to examine. */ - if ( ! fc_link_ok ( &fcpdev->ulp->link ) ) { + if ( ! fc_link_ok ( &fcpdev->user.ulp->link ) ) { DBGC ( fcpdev, "FCP %p doesn't know underlying device " "until link is up\n", fcpdev ); return NULL; } /* Hand off to port's transport interface */ - assert ( fcpdev->ulp->peer->port != NULL ); - return identify_device ( &fcpdev->ulp->peer->port->transport ); + assert ( fcpdev->user.ulp->peer->port != NULL ); + return identify_device ( &fcpdev->user.ulp->peer->port->transport ); } /** FCP device SCSI interface operations */ @@ -953,8 +950,7 @@ static int fcpdev_open ( struct interface *parent, struct fc_name *wwn, ref_init ( &fcpdev->refcnt, NULL ); intf_init ( &fcpdev->scsi, &fcpdev_scsi_desc, &fcpdev->refcnt ); INIT_LIST_HEAD ( &fcpdev->fcpcmds ); - fcpdev->ulp = fc_ulp_get ( ulp ); - fc_ulp_increment ( fcpdev->ulp ); + fc_ulp_attach ( ulp, &fcpdev->user ); DBGC ( fcpdev, "FCP %p opened for %s\n", fcpdev, fc_ntoa ( wwn ) ); diff --git a/src/usr/fcmgmt.c b/src/usr/fcmgmt.c index 1af723d13..f46c7d6ba 100644 --- a/src/usr/fcmgmt.c +++ b/src/usr/fcmgmt.c @@ -74,8 +74,7 @@ void fcpeerstat ( struct fc_peer *peer ) { } list_for_each_entry ( ulp, &peer->ulps, list ) { - printf ( " [Type %02x usage %d link:", - ulp->type, ulp->usage ); + printf ( " [Type %02x link:", ulp->type ); if ( fc_link_ok ( &ulp->link ) ) { printf ( " up, params" ); param = ulp->param;