]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[fc] Maintain a list of Fibre Channel upper-layer protocol users
authorMichael Brown <mcb30@ipxe.org>
Fri, 24 Jun 2011 21:49:10 +0000 (22:49 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 28 Jun 2011 13:45:01 +0000 (14:45 +0100)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/include/ipxe/fc.h
src/net/fc.c
src/net/fcp.c
src/usr/fcmgmt.c

index ab6b5bae77cf5bc2516f822a08f869063c92d324..06d38baf9000994585d6164b34cf62e81fe54f11 100644 (file)
@@ -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 );
index 1934fab3d4c32d0dce868d4f5031efa07917b522..a94456c82b0fecb567e46ce819be8bfc67ef056b 100644 (file)
@@ -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 );
index 40cd057e6c93b2bb91f086095ab06d8ab2ab0228..28d2095d7680c4350eb9d51efcb4cfb43b1e0815 100644 (file)
@@ -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 ) );
 
index 1af723d1313bd36dbc0583cf158d8ada6ad2a840..f46c7d6ba1dd94410b158ec825a747560847621f 100644 (file)
@@ -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;