aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_init.c
diff options
context:
space:
mode:
authorandrew.vasquez@qlogic.com <andrew.vasquez@qlogic.com>2006-01-20 17:53:13 -0500
committerJames Bottomley <jejb@mulgrave.(none)>2006-01-26 08:16:50 -0500
commitd97994dc1fddcbb8212b745d9c9c9ce96262155c (patch)
tree860d0034485f06dc8cb52c23efb6fe5252a25c99 /drivers/scsi/qla2xxx/qla_init.c
parent1d12d98d284665c37b75b9538916b5fbb8fcde37 (diff)
[SCSI] qla2xxx: Correct synchronization issues during rport addition/deletion.
The driver can typically detect port-loss during an interrupt context (i.e. via interrogation of a status IOCB's completion status [CS_PORT_LOGGED_OUT]. Due to the calling requirements of the fc_rport APIs, the driver would defer removal of the device to the default workqueue. If the work-item was preceded by an event which caused the port to obtain visibility (relogin successful, target re-logged into the topology), deferred removal could inadvertently drop the rport. The code also no longer defers removal via the default workqueue, instead opting for use of the driver's own DPC thread. Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_init.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c54
1 files changed, 38 insertions, 16 deletions
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index a91fea69ad63..4c7caece4ca7 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1688,10 +1688,16 @@ static void
1688qla2x00_rport_del(void *data) 1688qla2x00_rport_del(void *data)
1689{ 1689{
1690 fc_port_t *fcport = data; 1690 fc_port_t *fcport = data;
1691 struct fc_rport *rport;
1692 unsigned long flags;
1693
1694 spin_lock_irqsave(&fcport->rport_lock, flags);
1695 rport = fcport->drport;
1696 fcport->drport = NULL;
1697 spin_unlock_irqrestore(&fcport->rport_lock, flags);
1698 if (rport)
1699 fc_remote_port_delete(rport);
1691 1700
1692 if (fcport->rport)
1693 fc_remote_port_delete(fcport->rport);
1694 fcport->rport = NULL;
1695} 1701}
1696 1702
1697/** 1703/**
@@ -1719,6 +1725,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
1719 atomic_set(&fcport->state, FCS_UNCONFIGURED); 1725 atomic_set(&fcport->state, FCS_UNCONFIGURED);
1720 fcport->flags = FCF_RLC_SUPPORT; 1726 fcport->flags = FCF_RLC_SUPPORT;
1721 fcport->supported_classes = FC_COS_UNSPECIFIED; 1727 fcport->supported_classes = FC_COS_UNSPECIFIED;
1728 spin_lock_init(&fcport->rport_lock);
1722 INIT_WORK(&fcport->rport_add_work, qla2x00_rport_add, fcport); 1729 INIT_WORK(&fcport->rport_add_work, qla2x00_rport_add, fcport);
1723 INIT_WORK(&fcport->rport_del_work, qla2x00_rport_del, fcport); 1730 INIT_WORK(&fcport->rport_del_work, qla2x00_rport_del, fcport);
1724 1731
@@ -2008,7 +2015,7 @@ qla2x00_probe_for_all_luns(scsi_qla_host_t *ha)
2008{ 2015{
2009 fc_port_t *fcport; 2016 fc_port_t *fcport;
2010 2017
2011 qla2x00_mark_all_devices_lost(ha); 2018 qla2x00_mark_all_devices_lost(ha, 0);
2012 list_for_each_entry(fcport, &ha->fcports, list) { 2019 list_for_each_entry(fcport, &ha->fcports, list) {
2013 if (fcport->port_type != FCT_TARGET) 2020 if (fcport->port_type != FCT_TARGET)
2014 continue; 2021 continue;
@@ -2084,24 +2091,29 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
2084{ 2091{
2085 struct fc_rport_identifiers rport_ids; 2092 struct fc_rport_identifiers rport_ids;
2086 struct fc_rport *rport; 2093 struct fc_rport *rport;
2094 unsigned long flags;
2087 2095
2088 if (fcport->rport) { 2096 if (fcport->drport)
2089 fc_remote_port_delete(fcport->rport); 2097 qla2x00_rport_del(fcport);
2090 fcport->rport = NULL; 2098 if (fcport->rport)
2091 } 2099 return;
2092 2100
2093 rport_ids.node_name = wwn_to_u64(fcport->node_name); 2101 rport_ids.node_name = wwn_to_u64(fcport->node_name);
2094 rport_ids.port_name = wwn_to_u64(fcport->port_name); 2102 rport_ids.port_name = wwn_to_u64(fcport->port_name);
2095 rport_ids.port_id = fcport->d_id.b.domain << 16 | 2103 rport_ids.port_id = fcport->d_id.b.domain << 16 |
2096 fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa; 2104 fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
2097 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; 2105 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
2098 fcport->rport = rport = fc_remote_port_add(ha->host, 0, &rport_ids); 2106 rport = fc_remote_port_add(ha->host, 0, &rport_ids);
2099 if (!rport) { 2107 if (!rport) {
2100 qla_printk(KERN_WARNING, ha, 2108 qla_printk(KERN_WARNING, ha,
2101 "Unable to allocate fc remote port!\n"); 2109 "Unable to allocate fc remote port!\n");
2102 return; 2110 return;
2103 } 2111 }
2112 spin_lock_irqsave(&fcport->rport_lock, flags);
2113 fcport->rport = rport;
2104 *((fc_port_t **)rport->dd_data) = fcport; 2114 *((fc_port_t **)rport->dd_data) = fcport;
2115 spin_unlock_irqrestore(&fcport->rport_lock, flags);
2116
2105 rport->supported_classes = fcport->supported_classes; 2117 rport->supported_classes = fcport->supported_classes;
2106 2118
2107 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; 2119 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
@@ -2217,12 +2229,11 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
2217 2229
2218 if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) { 2230 if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
2219 qla2x00_mark_device_lost(ha, fcport, 2231 qla2x00_mark_device_lost(ha, fcport,
2220 ql2xplogiabsentdevice); 2232 ql2xplogiabsentdevice, 0);
2221 if (fcport->loop_id != FC_NO_LOOP_ID && 2233 if (fcport->loop_id != FC_NO_LOOP_ID &&
2222 (fcport->flags & FCF_TAPE_PRESENT) == 0 && 2234 (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
2223 fcport->port_type != FCT_INITIATOR && 2235 fcport->port_type != FCT_INITIATOR &&
2224 fcport->port_type != FCT_BROADCAST) { 2236 fcport->port_type != FCT_BROADCAST) {
2225
2226 ha->isp_ops.fabric_logout(ha, 2237 ha->isp_ops.fabric_logout(ha,
2227 fcport->loop_id, 2238 fcport->loop_id,
2228 fcport->d_id.b.domain, 2239 fcport->d_id.b.domain,
@@ -2694,7 +2705,8 @@ qla2x00_device_resync(scsi_qla_host_t *ha)
2694 if (atomic_read(&fcport->state) == FCS_ONLINE) { 2705 if (atomic_read(&fcport->state) == FCS_ONLINE) {
2695 if (format != 3 || 2706 if (format != 3 ||
2696 fcport->port_type != FCT_INITIATOR) { 2707 fcport->port_type != FCT_INITIATOR) {
2697 qla2x00_mark_device_lost(ha, fcport, 0); 2708 qla2x00_mark_device_lost(ha, fcport,
2709 0, 0);
2698 } 2710 }
2699 } 2711 }
2700 fcport->flags &= ~FCF_FARP_DONE; 2712 fcport->flags &= ~FCF_FARP_DONE;
@@ -2741,8 +2753,7 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *ha, fc_port_t *fcport,
2741 ha->isp_ops.fabric_logout(ha, fcport->loop_id, 2753 ha->isp_ops.fabric_logout(ha, fcport->loop_id,
2742 fcport->d_id.b.domain, fcport->d_id.b.area, 2754 fcport->d_id.b.domain, fcport->d_id.b.area,
2743 fcport->d_id.b.al_pa); 2755 fcport->d_id.b.al_pa);
2744 qla2x00_mark_device_lost(ha, fcport, 1); 2756 qla2x00_mark_device_lost(ha, fcport, 1, 0);
2745
2746 } else { 2757 } else {
2747 qla2x00_update_fcport(ha, fcport); 2758 qla2x00_update_fcport(ha, fcport);
2748 } 2759 }
@@ -2855,7 +2866,7 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
2855 ha->isp_ops.fabric_logout(ha, fcport->loop_id, 2866 ha->isp_ops.fabric_logout(ha, fcport->loop_id,
2856 fcport->d_id.b.domain, fcport->d_id.b.area, 2867 fcport->d_id.b.domain, fcport->d_id.b.area,
2857 fcport->d_id.b.al_pa); 2868 fcport->d_id.b.al_pa);
2858 qla2x00_mark_device_lost(ha, fcport, 1); 2869 qla2x00_mark_device_lost(ha, fcport, 1, 0);
2859 2870
2860 rval = 1; 2871 rval = 1;
2861 break; 2872 break;
@@ -2990,6 +3001,17 @@ qla2x00_rescan_fcports(scsi_qla_host_t *ha)
2990 qla2x00_probe_for_all_luns(ha); 3001 qla2x00_probe_for_all_luns(ha);
2991} 3002}
2992 3003
3004void
3005qla2x00_update_fcports(scsi_qla_host_t *ha)
3006{
3007 fc_port_t *fcport;
3008
3009 /* Go with deferred removal of rport references. */
3010 list_for_each_entry(fcport, &ha->fcports, list)
3011 if (fcport->drport)
3012 qla2x00_rport_del(fcport);
3013}
3014
2993/* 3015/*
2994* qla2x00_abort_isp 3016* qla2x00_abort_isp
2995* Resets ISP and aborts all outstanding commands. 3017* Resets ISP and aborts all outstanding commands.
@@ -3019,7 +3041,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
3019 atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME); 3041 atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
3020 if (atomic_read(&ha->loop_state) != LOOP_DOWN) { 3042 if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
3021 atomic_set(&ha->loop_state, LOOP_DOWN); 3043 atomic_set(&ha->loop_state, LOOP_DOWN);
3022 qla2x00_mark_all_devices_lost(ha); 3044 qla2x00_mark_all_devices_lost(ha, 0);
3023 } else { 3045 } else {
3024 if (!atomic_read(&ha->loop_down_timer)) 3046 if (!atomic_read(&ha->loop_down_timer))
3025 atomic_set(&ha->loop_down_timer, 3047 atomic_set(&ha->loop_down_timer,