summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Brown2011-06-25 00:16:17 +0200
committerMichael Brown2011-06-28 15:45:07 +0200
commit5f608a44a5574ec53c791e55894179dccb85f1c6 (patch)
treed57a92982f17ae989ba52a056f543991c0598921 /src
parent[fc] Maintain a list of Fibre Channel upper-layer protocol users (diff)
downloadipxe-5f608a44a5574ec53c791e55894179dccb85f1c6.tar.gz
ipxe-5f608a44a5574ec53c791e55894179dccb85f1c6.tar.xz
ipxe-5f608a44a5574ec53c791e55894179dccb85f1c6.zip
[fc] Send xfer_window_changed() when FCP link is established
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src')
-rw-r--r--src/include/ipxe/fc.h44
-rw-r--r--src/net/fc.c44
-rw-r--r--src/net/fcp.c25
3 files changed, 100 insertions, 13 deletions
diff --git a/src/include/ipxe/fc.h b/src/include/ipxe/fc.h
index 06d38baf9..6689f394e 100644
--- a/src/include/ipxe/fc.h
+++ b/src/include/ipxe/fc.h
@@ -455,6 +455,13 @@ struct fc_ulp_user {
struct fc_ulp *ulp;
/** List of users */
struct list_head list;
+ /** Containing object reference count, or NULL */
+ struct refcnt *refcnt;
+ /** Examine link state
+ *
+ * @v user Fibre Channel upper-layer-protocol user
+ */
+ void ( * examine ) ( struct fc_ulp_user *user );
};
/**
@@ -479,6 +486,43 @@ fc_ulp_put ( struct fc_ulp *ulp ) {
ref_put ( &ulp->refcnt );
}
+/**
+ * Get reference to Fibre Channel upper-layer protocol user
+ *
+ * @v user Fibre Channel upper-layer protocol user
+ * @ret user Fibre Channel upper-layer protocol user
+ */
+static inline __attribute__ (( always_inline )) struct fc_ulp_user *
+fc_ulp_user_get ( struct fc_ulp_user *user ) {
+ ref_get ( user->refcnt );
+ return user;
+}
+
+/**
+ * Drop reference to Fibre Channel upper-layer protocol user
+ *
+ * @v user Fibre Channel upper-layer protocol user
+ */
+static inline __attribute__ (( always_inline )) void
+fc_ulp_user_put ( struct fc_ulp_user *user ) {
+ ref_put ( user->refcnt );
+}
+
+/**
+ * Initialise Fibre Channel upper-layer protocol user
+ *
+ * @v user Fibre Channel upper-layer protocol user
+ * @v examine Examine link state method
+ * @v refcnt Containing object reference count, or NULL
+ */
+static inline __attribute__ (( always_inline )) void
+fc_ulp_user_init ( struct fc_ulp_user *user,
+ void ( * examine ) ( struct fc_ulp_user *user ),
+ struct refcnt *refcnt ) {
+ user->examine = examine;
+ user->refcnt = refcnt;
+}
+
extern struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_wwn,
unsigned int type );
extern struct fc_ulp *
diff --git a/src/net/fc.c b/src/net/fc.c
index a94456c82..977ad07c7 100644
--- a/src/net/fc.c
+++ b/src/net/fc.c
@@ -1651,6 +1651,8 @@ void fc_ulp_detach ( struct fc_ulp_user *user ) {
*/
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 ) &&
@@ -1659,6 +1661,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 ) ) {
@@ -1685,18 +1703,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;
@@ -1709,6 +1720,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 ) );
@@ -1726,6 +1739,13 @@ 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 ( list_empty ( &ulp->users ) )
fc_ulp_close ( ulp, rc );
diff --git a/src/net/fcp.c b/src/net/fcp.c
index 28d2095d7..419fea3ec 100644
--- a/src/net/fcp.c
+++ b/src/net/fcp.c
@@ -921,6 +921,26 @@ static struct interface_descriptor fcpdev_scsi_desc =
INTF_DESC ( struct fcp_device, scsi, fcpdev_scsi_op );
/**
+ * Examine FCP ULP link state
+ *
+ * @v user Fibre Channel upper-layer protocol user
+ */
+static void fcpdev_examine ( struct fc_ulp_user *user ) {
+ struct fcp_device *fcpdev =
+ container_of ( user, struct fcp_device, user );
+
+ if ( fc_link_ok ( &fcpdev->user.ulp->link ) ) {
+ DBGC ( fcpdev, "FCP %p link is up\n", fcpdev );
+ } else {
+ DBGC ( fcpdev, "FCP %p link is down: %s\n",
+ fcpdev, strerror ( fcpdev->user.ulp->link.rc ) );
+ }
+
+ /* Notify SCSI layer of window change */
+ xfer_window_changed ( &fcpdev->scsi );
+}
+
+/**
* Open FCP device
*
* @v parent Parent interface
@@ -950,10 +970,13 @@ 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 );
- fc_ulp_attach ( ulp, &fcpdev->user );
+ fc_ulp_user_init ( &fcpdev->user, fcpdev_examine, &fcpdev->refcnt );
DBGC ( fcpdev, "FCP %p opened for %s\n", fcpdev, fc_ntoa ( wwn ) );
+ /* Attach to Fibre Channel ULP */
+ fc_ulp_attach ( ulp, &fcpdev->user );
+
/* Preserve parameters required for boot firmware table */
memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) );
memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) );