NPIV vports are managed in libfc by changing their virtual link state when the parent N_Ports internal state changes. The vport link is only online when the N_Port is in a read state (logged into the fabric).
Signed-off-by: Chris Leech <[email protected]> --- drivers/scsi/libfc/fc_lport.c | 53 ++++++++++++++++++++++++++++++----------- drivers/scsi/libfc/fc_npiv.c | 45 +++++++++++++++++++++++++++++++++++ include/scsi/libfc.h | 8 ++++++ 3 files changed, 92 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index a430335..df555a3 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -561,40 +561,62 @@ int fc_fabric_login(struct fc_lport *lport) EXPORT_SYMBOL(fc_fabric_login); /** - * fc_linkup() - Handler for transport linkup events + * __fc_linkup() - Handler for transport linkup events * @lport: The lport whose link is up + * + * Locking: must be called with the lp_mutex held */ -void fc_linkup(struct fc_lport *lport) +void __fc_linkup(struct fc_lport *lport) { - printk(KERN_INFO "libfc: Link up on port (%6x)\n", - fc_host_port_id(lport->host)); - - mutex_lock(&lport->lp_mutex); if (!lport->link_up) { lport->link_up = 1; if (lport->state == LPORT_ST_RESET) fc_lport_enter_flogi(lport); } +} + +/** + * fc_linkup() - Handler for transport linkup events + * @lport: The lport whose link is up + */ +void fc_linkup(struct fc_lport *lport) +{ + printk(KERN_INFO "libfc: Link up on port (%6x)\n", + fc_host_port_id(lport->host)); + + mutex_lock(&lport->lp_mutex); + __fc_linkup(lport); mutex_unlock(&lport->lp_mutex); } EXPORT_SYMBOL(fc_linkup); /** - * fc_linkdown() - Handler for transport linkdown events + * __fc_linkdown() - Handler for transport linkdown events * @lport: The lport whose link is down + * + * Locking: must be called with the lp_mutex held */ -void fc_linkdown(struct fc_lport *lport) +void __fc_linkdown(struct fc_lport *lport) { - mutex_lock(&lport->lp_mutex); - printk(KERN_INFO "libfc: Link down on port (%6x)\n", - fc_host_port_id(lport->host)); - if (lport->link_up) { lport->link_up = 0; fc_lport_enter_reset(lport); lport->tt.fcp_cleanup(lport); } +} + +/** + * fc_linkdown() - Handler for transport linkdown events + * @lport: The lport whose link is down + */ +void fc_linkdown(struct fc_lport *lport) +{ + printk(KERN_INFO "libfc: Link down on port (%6x)\n", + fc_host_port_id(lport->host)); + + mutex_lock(&lport->lp_mutex); + __fc_linkdown(lport); mutex_unlock(&lport->lp_mutex); } EXPORT_SYMBOL(fc_linkdown); @@ -722,7 +744,7 @@ static void fc_lport_enter_ready(struct fc_lport *lport) fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_READY); - + fc_vports_linkup(lport); lport->tt.disc_start(fc_lport_disc_callback, lport); } @@ -971,8 +993,10 @@ static void fc_lport_enter_reset(struct fc_lport *lport) fc_lport_state_enter(lport, LPORT_ST_RESET); fc_lport_reset_locked(lport); - if (lport->link_up) + if (lport->link_up) { + fc_vports_linkdown(lport); fc_lport_enter_flogi(lport); + } } /** @@ -1438,6 +1462,7 @@ static void fc_lport_enter_logo(struct fc_lport *lport) fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_LOGO); + fc_vports_linkdown(lport); fp = fc_frame_alloc(lport, sizeof(*logo)); if (!fp) { diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c index 07cb5a6..e51c5ef 100644 --- a/drivers/scsi/libfc/fc_npiv.c +++ b/drivers/scsi/libfc/fc_npiv.c @@ -77,3 +77,48 @@ struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id) return lport; } +/* + * When setting the link state of vports during an lport state change, it's + * necessary to hold the lp_mutex of both the N_Port and the VN_Port. + * This tells the lockdep engine to treat the nested locking of the VN_Port + * as a different lock class. + */ +enum libfc_lport_mutex_class { + LPORT_MUTEX_NORMAL = 0, + LPORT_MUTEX_VN_PORT = 1, +}; + +/** + * fc_vports_linkup() - change the link state of all vports to up + * @n_port: Parent N_Port that is now in a ready state + * + * Locking: called with the n_port lp_mutex held + */ +void fc_vports_linkup(struct fc_lport *n_port) +{ + struct fc_lport *vn_port; + + list_for_each_entry(vn_port, &n_port->vports, list) { + mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT); + __fc_linkup(vn_port); + mutex_unlock(&vn_port->lp_mutex); + } +} + +/** + * fc_vports_linkdown() - change the link state of all vports to down + * @n_port: Parent N_Port + * + * Locking: called with the n_port lp_mutex held + */ +void fc_vports_linkdown(struct fc_lport *n_port) +{ + struct fc_lport *vn_port; + + list_for_each_entry(vn_port, &n_port->vports, list) { + mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT); + __fc_linkdown(vn_port); + mutex_unlock(&vn_port->lp_mutex); + } +} + diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 6047b4d..1686aba 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -835,11 +835,13 @@ int fc_fabric_login(struct fc_lport *lp); /* * The link is up for the given local port. */ +void __fc_linkup(struct fc_lport *); void fc_linkup(struct fc_lport *); /* * Link is down for the given local port. */ +void __fc_linkdown(struct fc_lport *); void fc_linkdown(struct fc_lport *); /* @@ -868,6 +870,12 @@ struct fc_lport *libfc_vport_create(struct fc_vport *vport, int privsize); struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id); /* + * NPIV VN_Port link state management + */ +void fc_vports_linkup(struct fc_lport *n_port); +void fc_vports_linkdown(struct fc_lport *n_port); + +/* * REMOTE PORT LAYER *****************************/ int fc_rport_init(struct fc_lport *lp); _______________________________________________ devel mailing list [email protected] http://www.open-fcoe.org/mailman/listinfo/devel
