[fc] Send xfer_window_changed() when FCP link is established
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
bf8bfa23e2
commit
5f608a44a5
|
@ -455,6 +455,13 @@ struct fc_ulp_user {
|
||||||
struct fc_ulp *ulp;
|
struct fc_ulp *ulp;
|
||||||
/** List of users */
|
/** List of users */
|
||||||
struct list_head list;
|
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 );
|
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,
|
extern struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_wwn,
|
||||||
unsigned int type );
|
unsigned int type );
|
||||||
extern struct fc_ulp *
|
extern struct fc_ulp *
|
||||||
|
|
44
src/net/fc.c
44
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 fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
|
||||||
int originated ) {
|
int originated ) {
|
||||||
|
struct fc_ulp_user *user;
|
||||||
|
struct fc_ulp_user *tmp;
|
||||||
|
|
||||||
/* Perform implicit logout if logged in and service parameters differ */
|
/* Perform implicit logout if logged in and service parameters differ */
|
||||||
if ( fc_link_ok ( &ulp->link ) &&
|
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 );
|
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 */
|
/* Log in, if applicable */
|
||||||
if ( ! fc_link_ok ( &ulp->link ) ) {
|
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 */
|
/* Record login */
|
||||||
fc_link_up ( &ulp->link );
|
fc_link_up ( &ulp->link );
|
||||||
|
|
||||||
/* Work around a bug in some versions of the Linux Fibre
|
/* Notify users of link state change */
|
||||||
* Channel stack, which fail to fully initialise image pairs
|
list_for_each_entry_safe ( user, tmp, &ulp->users, list ) {
|
||||||
* established via a PRLI originated by the Linux stack
|
fc_ulp_user_get ( user );
|
||||||
* itself.
|
user->examine ( user );
|
||||||
*/
|
fc_ulp_user_put ( user );
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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
|
* @v rc Reason for logout
|
||||||
*/
|
*/
|
||||||
void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) {
|
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",
|
DBGC ( ulp, "FCULP %s/%02x logged out: %s\n",
|
||||||
fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
|
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 */
|
/* Record logout */
|
||||||
fc_link_err ( &ulp->link, rc );
|
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 */
|
/* Close ULP if there are no clients attached */
|
||||||
if ( list_empty ( &ulp->users ) )
|
if ( list_empty ( &ulp->users ) )
|
||||||
fc_ulp_close ( ulp, rc );
|
fc_ulp_close ( ulp, rc );
|
||||||
|
|
|
@ -920,6 +920,26 @@ static struct interface_operation fcpdev_scsi_op[] = {
|
||||||
static struct interface_descriptor fcpdev_scsi_desc =
|
static struct interface_descriptor fcpdev_scsi_desc =
|
||||||
INTF_DESC ( struct fcp_device, scsi, fcpdev_scsi_op );
|
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
|
* Open FCP device
|
||||||
*
|
*
|
||||||
|
@ -950,10 +970,13 @@ static int fcpdev_open ( struct interface *parent, struct fc_name *wwn,
|
||||||
ref_init ( &fcpdev->refcnt, NULL );
|
ref_init ( &fcpdev->refcnt, NULL );
|
||||||
intf_init ( &fcpdev->scsi, &fcpdev_scsi_desc, &fcpdev->refcnt );
|
intf_init ( &fcpdev->scsi, &fcpdev_scsi_desc, &fcpdev->refcnt );
|
||||||
INIT_LIST_HEAD ( &fcpdev->fcpcmds );
|
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 ) );
|
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 */
|
/* Preserve parameters required for boot firmware table */
|
||||||
memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) );
|
memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) );
|
||||||
memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) );
|
memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) );
|
||||||
|
|
Reference in New Issue