aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/scsi/zfcp_erp.c
diff options
context:
space:
mode:
authorChristof Schmitt <christof.schmitt@de.ibm.com>2007-05-08 05:16:52 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-05-08 12:55:33 -0400
commit5f852be9e11d62223ea063f6ceed4f9677f54051 (patch)
tree55552b19035695b23329db2b5f03fc7592412b56 /drivers/s390/scsi/zfcp_erp.c
parent801e0ced1891a2b8cad1a435c45234a719b3b6bf (diff)
[SCSI] zfcp: Fix deadlock between zfcp ERP and SCSI
The SCSI stack requires low level drivers to register and unregister devices. For zfcp this leads to the situation where zfcp calls the SCSI stack, the SCSI tries to scan the new device and the scan SCSI command fails. This would require the zfcp erp, but the erp thread is already blocked in the register call. The fix is to make sure that the calls from the ERP thread to the SCSI stack do not block the ERP thread. In detail: 1) Use a workqueue to avoid blocking of the scsi_scan_target calls. 2) When removing a unit make sure that no scsi_scan_target call is pending. 3) Replace scsi_flush_work with scsi_target_unblock. This avoids blocking and has the same result. Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/s390/scsi/zfcp_erp.c')
-rw-r--r--drivers/s390/scsi/zfcp_erp.c64
1 files changed, 60 insertions, 4 deletions
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index f326bbe49fa7..885572300589 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -1591,6 +1591,62 @@ zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result)
1591 return result; 1591 return result;
1592} 1592}
1593 1593
1594struct zfcp_erp_add_work {
1595 struct zfcp_unit *unit;
1596 struct work_struct work;
1597};
1598
1599/**
1600 * zfcp_erp_scsi_scan
1601 * @data: pointer to a struct zfcp_erp_add_work
1602 *
1603 * Registers a logical unit with the SCSI stack.
1604 */
1605static void zfcp_erp_scsi_scan(struct work_struct *work)
1606{
1607 struct zfcp_erp_add_work *p =
1608 container_of(work, struct zfcp_erp_add_work, work);
1609 struct zfcp_unit *unit = p->unit;
1610 struct fc_rport *rport = unit->port->rport;
1611 scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
1612 unit->scsi_lun, 0);
1613 atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
1614 wake_up(&unit->scsi_scan_wq);
1615 zfcp_unit_put(unit);
1616 kfree(p);
1617}
1618
1619/**
1620 * zfcp_erp_schedule_work
1621 * @unit: pointer to unit which should be registered with SCSI stack
1622 *
1623 * Schedules work which registers a unit with the SCSI stack
1624 */
1625static void
1626zfcp_erp_schedule_work(struct zfcp_unit *unit)
1627{
1628 struct zfcp_erp_add_work *p;
1629
1630 p = kmalloc(sizeof(*p), GFP_KERNEL);
1631 if (!p) {
1632 ZFCP_LOG_NORMAL("error: Out of resources. Could not register "
1633 "the FCP-LUN 0x%Lx connected to "
1634 "the port with WWPN 0x%Lx connected to "
1635 "the adapter %s with the SCSI stack.\n",
1636 unit->fcp_lun,
1637 unit->port->wwpn,
1638 zfcp_get_busid_by_unit(unit));
1639 return;
1640 }
1641
1642 zfcp_unit_get(unit);
1643 memset(p, 0, sizeof(*p));
1644 atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
1645 INIT_WORK(&p->work, zfcp_erp_scsi_scan);
1646 p->unit = unit;
1647 schedule_work(&p->work);
1648}
1649
1594/* 1650/*
1595 * function: 1651 * function:
1596 * 1652 *
@@ -3092,9 +3148,9 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
3092 && port->rport) { 3148 && port->rport) {
3093 atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, 3149 atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED,
3094 &unit->status); 3150 &unit->status);
3095 scsi_scan_target(&port->rport->dev, 0, 3151 if (atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
3096 port->rport->scsi_target_id, 3152 &unit->status) == 0)
3097 unit->scsi_lun, 0); 3153 zfcp_erp_schedule_work(unit);
3098 } 3154 }
3099 zfcp_unit_put(unit); 3155 zfcp_unit_put(unit);
3100 break; 3156 break;
@@ -3121,7 +3177,7 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
3121 zfcp_get_busid_by_port(port), 3177 zfcp_get_busid_by_port(port),
3122 port->wwpn); 3178 port->wwpn);
3123 else { 3179 else {
3124 scsi_flush_work(adapter->scsi_host); 3180 scsi_target_unblock(&port->rport->dev);
3125 port->rport->maxframe_size = port->maxframe_size; 3181 port->rport->maxframe_size = port->maxframe_size;
3126 port->rport->supported_classes = 3182 port->rport->supported_classes =
3127 port->supported_classes; 3183 port->supported_classes;