diff options
author | Christof Schmitt <christof.schmitt@de.ibm.com> | 2009-03-02 12:09:08 (GMT) |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-03-12 17:58:21 (GMT) |
commit | a2fa0aede07c9488239dcac1eae58233181c355a (patch) | |
tree | 406836319208a5f8597010b0f25f599eae922e66 /drivers/s390/scsi/zfcp_erp.c | |
parent | 24095490681d130979c18685dc0b5a308057e225 (diff) | |
download | linux-a2fa0aede07c9488239dcac1eae58233181c355a.tar.xz |
[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.c | 56 |
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; } |