summaryrefslogtreecommitdiffstats
path: root/drivers/s390/scsi/zfcp_erp.c
diff options
context:
space:
mode:
authorChristof Schmitt <christof.schmitt@de.ibm.com>2009-03-02 13:09:08 +0100
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-03-12 12:58:21 -0500
commita2fa0aede07c9488239dcac1eae58233181c355a (patch)
tree406836319208a5f8597010b0f25f599eae922e66 /drivers/s390/scsi/zfcp_erp.c
parent24095490681d130979c18685dc0b5a308057e225 (diff)
downloadop-kernel-dev-a2fa0aede07c9488239dcac1eae58233181c355a.zip
op-kernel-dev-a2fa0aede07c9488239dcac1eae58233181c355a.tar.gz
[SCSI] zfcp: Block FC transport rports early on errors
Use the I/O blocking mechanism in the FC transport class to allow faster failovers for multipathing: - Call fc_remote_port_delete early to set the rport to BLOCKED. - Check the rport status in queuecommand with fc_remote_portchkready to no longer accept new I/O for this port and fail the I/O with the appropriate scsi_cmnd result. - Implement the terminate_rport_io handler to abort all pending I/O requests - Return SCSI commands with DID_TRANSPORT_DISRUPTED while erp is running. - When updating the remote port status, check for late changes and update the remote ports status accordingly. Acked-by: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/s390/scsi/zfcp_erp.c')
-rw-r--r--drivers/s390/scsi/zfcp_erp.c56
1 files changed, 11 insertions, 45 deletions
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 65addf6..dee1cc3 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -3,7 +3,7 @@
*
* Error Recovery Procedures (ERP).
*
- * Copyright IBM Corporation 2002, 2008
+ * Copyright IBM Corporation 2002, 2009
*/
#define KMSG_COMPONENT "zfcp"
@@ -240,6 +240,7 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
int clear_mask, char *id, void *ref)
{
zfcp_erp_adapter_block(adapter, clear_mask);
+ zfcp_scsi_schedule_rports_block(adapter);
/* ensure propagation of failed status to new devices */
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
@@ -322,6 +323,7 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
int clear, char *id, void *ref)
{
zfcp_erp_port_block(port, clear);
+ zfcp_scsi_schedule_rport_block(port);
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
return;
@@ -353,6 +355,7 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
void *ref)
{
zfcp_erp_port_block(port, clear);
+ zfcp_scsi_schedule_rport_block(port);
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
/* ensure propagation of failed status to new devices */
@@ -1211,37 +1214,6 @@ static void zfcp_erp_schedule_work(struct zfcp_unit *unit)
queue_work(zfcp_data.work_queue, &p->work);
}
-static void zfcp_erp_rport_register(struct zfcp_port *port)
-{
- struct fc_rport_identifiers ids;
- ids.node_name = port->wwnn;
- ids.port_name = port->wwpn;
- ids.port_id = port->d_id;
- ids.roles = FC_RPORT_ROLE_FCP_TARGET;
- port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
- if (!port->rport) {
- dev_err(&port->adapter->ccw_device->dev,
- "Registering port 0x%016Lx failed\n",
- (unsigned long long)port->wwpn);
- return;
- }
-
- scsi_target_unblock(&port->rport->dev);
- port->rport->maxframe_size = port->maxframe_size;
- port->rport->supported_classes = port->supported_classes;
-}
-
-static void zfcp_erp_rports_del(struct zfcp_adapter *adapter)
-{
- struct zfcp_port *port;
- list_for_each_entry(port, &adapter->port_list_head, list) {
- if (!port->rport)
- continue;
- fc_remote_port_delete(port->rport);
- port->rport = NULL;
- }
-}
-
static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
{
struct zfcp_adapter *adapter = act->adapter;
@@ -1250,8 +1222,8 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
switch (act->action) {
case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if ((result == ZFCP_ERP_SUCCEEDED) &&
- !unit->device && port->rport) {
+ flush_work(&port->rport_work);
+ if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
if (!(atomic_read(&unit->status) &
ZFCP_STATUS_UNIT_SCSI_WORK_PENDING))
zfcp_erp_schedule_work(unit);
@@ -1261,23 +1233,17 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT:
- if ((result == ZFCP_ERP_SUCCEEDED) && !port->rport)
- zfcp_erp_rport_register(port);
- if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) {
- fc_remote_port_delete(port->rport);
- port->rport = NULL;
- }
+ if (result == ZFCP_ERP_SUCCEEDED)
+ zfcp_scsi_schedule_rport_register(port);
zfcp_port_put(port);
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
- if (result != ZFCP_ERP_SUCCEEDED) {
- unregister_service_level(&adapter->service_level);
- zfcp_erp_rports_del(adapter);
- } else {
+ if (result == ZFCP_ERP_SUCCEEDED) {
register_service_level(&adapter->service_level);
schedule_work(&adapter->scan_work);
- }
+ } else
+ unregister_service_level(&adapter->service_level);
zfcp_adapter_put(adapter);
break;
}
OpenPOWER on IntegriCloud