diff options
author | andrew.vasquez@qlogic.com <andrew.vasquez@qlogic.com> | 2006-01-20 17:53:13 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2006-01-26 08:16:50 -0500 |
commit | d97994dc1fddcbb8212b745d9c9c9ce96262155c (patch) | |
tree | 860d0034485f06dc8cb52c23efb6fe5252a25c99 /drivers/scsi/qla2xxx/qla_os.c | |
parent | 1d12d98d284665c37b75b9538916b5fbb8fcde37 (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_os.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 4916847d84ec..089e0f500363 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -756,7 +756,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) | |||
756 | if (ret == SUCCESS) { | 756 | if (ret == SUCCESS) { |
757 | if (fcport->flags & FC_FABRIC_DEVICE) { | 757 | if (fcport->flags & FC_FABRIC_DEVICE) { |
758 | ha->isp_ops.fabric_logout(ha, fcport->loop_id); | 758 | ha->isp_ops.fabric_logout(ha, fcport->loop_id); |
759 | qla2x00_mark_device_lost(ha, fcport); | 759 | qla2x00_mark_device_lost(ha, fcport, 0, 0); |
760 | } | 760 | } |
761 | } | 761 | } |
762 | #endif | 762 | #endif |
@@ -1642,6 +1642,31 @@ qla2x00_free_device(scsi_qla_host_t *ha) | |||
1642 | pci_disable_device(ha->pdev); | 1642 | pci_disable_device(ha->pdev); |
1643 | } | 1643 | } |
1644 | 1644 | ||
1645 | static inline void | ||
1646 | qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport, | ||
1647 | int defer) | ||
1648 | { | ||
1649 | unsigned long flags; | ||
1650 | struct fc_rport *rport; | ||
1651 | |||
1652 | if (!fcport->rport) | ||
1653 | return; | ||
1654 | |||
1655 | rport = fcport->rport; | ||
1656 | if (defer) { | ||
1657 | spin_lock_irqsave(&fcport->rport_lock, flags); | ||
1658 | fcport->drport = rport; | ||
1659 | fcport->rport = NULL; | ||
1660 | spin_unlock_irqrestore(&fcport->rport_lock, flags); | ||
1661 | set_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags); | ||
1662 | } else { | ||
1663 | spin_lock_irqsave(&fcport->rport_lock, flags); | ||
1664 | fcport->rport = NULL; | ||
1665 | spin_unlock_irqrestore(&fcport->rport_lock, flags); | ||
1666 | fc_remote_port_delete(rport); | ||
1667 | } | ||
1668 | } | ||
1669 | |||
1645 | /* | 1670 | /* |
1646 | * qla2x00_mark_device_lost Updates fcport state when device goes offline. | 1671 | * qla2x00_mark_device_lost Updates fcport state when device goes offline. |
1647 | * | 1672 | * |
@@ -1652,10 +1677,10 @@ qla2x00_free_device(scsi_qla_host_t *ha) | |||
1652 | * Context: | 1677 | * Context: |
1653 | */ | 1678 | */ |
1654 | void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport, | 1679 | void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport, |
1655 | int do_login) | 1680 | int do_login, int defer) |
1656 | { | 1681 | { |
1657 | if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->rport) | 1682 | if (atomic_read(&fcport->state) == FCS_ONLINE) |
1658 | schedule_work(&fcport->rport_del_work); | 1683 | qla2x00_schedule_rport_del(ha, fcport, defer); |
1659 | 1684 | ||
1660 | /* | 1685 | /* |
1661 | * We may need to retry the login, so don't change the state of the | 1686 | * We may need to retry the login, so don't change the state of the |
@@ -1702,7 +1727,7 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport, | |||
1702 | * Context: | 1727 | * Context: |
1703 | */ | 1728 | */ |
1704 | void | 1729 | void |
1705 | qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha) | 1730 | qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) |
1706 | { | 1731 | { |
1707 | fc_port_t *fcport; | 1732 | fc_port_t *fcport; |
1708 | 1733 | ||
@@ -1716,10 +1741,13 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha) | |||
1716 | */ | 1741 | */ |
1717 | if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) | 1742 | if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) |
1718 | continue; | 1743 | continue; |
1719 | if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->rport) | 1744 | if (atomic_read(&fcport->state) == FCS_ONLINE) |
1720 | schedule_work(&fcport->rport_del_work); | 1745 | qla2x00_schedule_rport_del(ha, fcport, defer); |
1721 | atomic_set(&fcport->state, FCS_DEVICE_LOST); | 1746 | atomic_set(&fcport->state, FCS_DEVICE_LOST); |
1722 | } | 1747 | } |
1748 | |||
1749 | if (defer && ha->dpc_wait && !ha->dpc_active) | ||
1750 | up(ha->dpc_wait); | ||
1723 | } | 1751 | } |
1724 | 1752 | ||
1725 | /* | 1753 | /* |
@@ -2161,6 +2189,9 @@ qla2x00_do_dpc(void *data) | |||
2161 | ha->host_no)); | 2189 | ha->host_no)); |
2162 | } | 2190 | } |
2163 | 2191 | ||
2192 | if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags)) | ||
2193 | qla2x00_update_fcports(ha); | ||
2194 | |||
2164 | if (test_and_clear_bit(LOOP_RESET_NEEDED, &ha->dpc_flags)) { | 2195 | if (test_and_clear_bit(LOOP_RESET_NEEDED, &ha->dpc_flags)) { |
2165 | DEBUG(printk("scsi(%ld): dpc: sched loop_reset()\n", | 2196 | DEBUG(printk("scsi(%ld): dpc: sched loop_reset()\n", |
2166 | ha->host_no)); | 2197 | ha->host_no)); |
@@ -2469,6 +2500,7 @@ qla2x00_timer(scsi_qla_host_t *ha) | |||
2469 | if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || | 2500 | if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || |
2470 | test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || | 2501 | test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || |
2471 | test_bit(LOOP_RESET_NEEDED, &ha->dpc_flags) || | 2502 | test_bit(LOOP_RESET_NEEDED, &ha->dpc_flags) || |
2503 | test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags) || | ||
2472 | start_dpc || | 2504 | start_dpc || |
2473 | test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) || | 2505 | test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) || |
2474 | test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) || | 2506 | test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) || |