diff options
author | Christof Schmitt <christof.schmitt@de.ibm.com> | 2009-03-02 07:09:08 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-03-12 13:58:21 -0400 |
commit | a2fa0aede07c9488239dcac1eae58233181c355a (patch) | |
tree | 406836319208a5f8597010b0f25f599eae922e66 /drivers/s390 | |
parent | 24095490681d130979c18685dc0b5a308057e225 (diff) |
[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')
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 4 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 4 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 56 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 6 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 21 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 3 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 119 |
7 files changed, 157 insertions, 56 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 69a31187e54d..b2be6593b563 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Module interface and handling of zfcp data structures. | 4 | * Module interface and handling of zfcp data structures. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2002, 2008 | 6 | * Copyright IBM Corporation 2002, 2009 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
@@ -606,10 +606,12 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, | |||
606 | INIT_LIST_HEAD(&port->unit_list_head); | 606 | INIT_LIST_HEAD(&port->unit_list_head); |
607 | INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup); | 607 | INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup); |
608 | INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); | 608 | INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); |
609 | INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); | ||
609 | 610 | ||
610 | port->adapter = adapter; | 611 | port->adapter = adapter; |
611 | port->d_id = d_id; | 612 | port->d_id = d_id; |
612 | port->wwpn = wwpn; | 613 | port->wwpn = wwpn; |
614 | port->rport_task = RPORT_NONE; | ||
613 | 615 | ||
614 | /* mark port unusable as long as sysfs registration is not complete */ | 616 | /* mark port unusable as long as sysfs registration is not complete */ |
615 | atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); | 617 | atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 22e418db4518..a0318630f047 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Global definitions for the zfcp device driver. | 4 | * Global definitions for the zfcp device driver. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2002, 2008 | 6 | * Copyright IBM Corporation 2002, 2009 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #ifndef ZFCP_DEF_H | 9 | #ifndef ZFCP_DEF_H |
@@ -512,6 +512,8 @@ struct zfcp_port { | |||
512 | u32 supported_classes; | 512 | u32 supported_classes; |
513 | struct work_struct gid_pn_work; | 513 | struct work_struct gid_pn_work; |
514 | struct work_struct test_link_work; | 514 | struct work_struct test_link_work; |
515 | struct work_struct rport_work; | ||
516 | enum { RPORT_NONE, RPORT_ADD, RPORT_DEL } rport_task; | ||
515 | }; | 517 | }; |
516 | 518 | ||
517 | struct zfcp_unit { | 519 | struct zfcp_unit { |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 65addf6a91ec..dee1cc3ce21b 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Error Recovery Procedures (ERP). | 4 | * Error Recovery Procedures (ERP). |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2002, 2008 | 6 | * Copyright IBM Corporation 2002, 2009 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define KMSG_COMPONENT "zfcp" | 9 | #define KMSG_COMPONENT "zfcp" |
@@ -240,6 +240,7 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, | |||
240 | int clear_mask, char *id, void *ref) | 240 | int clear_mask, char *id, void *ref) |
241 | { | 241 | { |
242 | zfcp_erp_adapter_block(adapter, clear_mask); | 242 | zfcp_erp_adapter_block(adapter, clear_mask); |
243 | zfcp_scsi_schedule_rports_block(adapter); | ||
243 | 244 | ||
244 | /* ensure propagation of failed status to new devices */ | 245 | /* ensure propagation of failed status to new devices */ |
245 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { | 246 | 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, | |||
322 | int clear, char *id, void *ref) | 323 | int clear, char *id, void *ref) |
323 | { | 324 | { |
324 | zfcp_erp_port_block(port, clear); | 325 | zfcp_erp_port_block(port, clear); |
326 | zfcp_scsi_schedule_rport_block(port); | ||
325 | 327 | ||
326 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) | 328 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) |
327 | return; | 329 | return; |
@@ -353,6 +355,7 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, | |||
353 | void *ref) | 355 | void *ref) |
354 | { | 356 | { |
355 | zfcp_erp_port_block(port, clear); | 357 | zfcp_erp_port_block(port, clear); |
358 | zfcp_scsi_schedule_rport_block(port); | ||
356 | 359 | ||
357 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { | 360 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
358 | /* ensure propagation of failed status to new devices */ | 361 | /* ensure propagation of failed status to new devices */ |
@@ -1211,37 +1214,6 @@ static void zfcp_erp_schedule_work(struct zfcp_unit *unit) | |||
1211 | queue_work(zfcp_data.work_queue, &p->work); | 1214 | queue_work(zfcp_data.work_queue, &p->work); |
1212 | } | 1215 | } |
1213 | 1216 | ||
1214 | static void zfcp_erp_rport_register(struct zfcp_port *port) | ||
1215 | { | ||
1216 | struct fc_rport_identifiers ids; | ||
1217 | ids.node_name = port->wwnn; | ||
1218 | ids.port_name = port->wwpn; | ||
1219 | ids.port_id = port->d_id; | ||
1220 | ids.roles = FC_RPORT_ROLE_FCP_TARGET; | ||
1221 | port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); | ||
1222 | if (!port->rport) { | ||
1223 | dev_err(&port->adapter->ccw_device->dev, | ||
1224 | "Registering port 0x%016Lx failed\n", | ||
1225 | (unsigned long long)port->wwpn); | ||
1226 | return; | ||
1227 | } | ||
1228 | |||
1229 | scsi_target_unblock(&port->rport->dev); | ||
1230 | port->rport->maxframe_size = port->maxframe_size; | ||
1231 | port->rport->supported_classes = port->supported_classes; | ||
1232 | } | ||
1233 | |||
1234 | static void zfcp_erp_rports_del(struct zfcp_adapter *adapter) | ||
1235 | { | ||
1236 | struct zfcp_port *port; | ||
1237 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
1238 | if (!port->rport) | ||
1239 | continue; | ||
1240 | fc_remote_port_delete(port->rport); | ||
1241 | port->rport = NULL; | ||
1242 | } | ||
1243 | } | ||
1244 | |||
1245 | static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | 1217 | static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) |
1246 | { | 1218 | { |
1247 | struct zfcp_adapter *adapter = act->adapter; | 1219 | struct zfcp_adapter *adapter = act->adapter; |
@@ -1250,8 +1222,8 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | |||
1250 | 1222 | ||
1251 | switch (act->action) { | 1223 | switch (act->action) { |
1252 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 1224 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
1253 | if ((result == ZFCP_ERP_SUCCEEDED) && | 1225 | flush_work(&port->rport_work); |
1254 | !unit->device && port->rport) { | 1226 | if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { |
1255 | if (!(atomic_read(&unit->status) & | 1227 | if (!(atomic_read(&unit->status) & |
1256 | ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)) | 1228 | ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)) |
1257 | zfcp_erp_schedule_work(unit); | 1229 | zfcp_erp_schedule_work(unit); |
@@ -1261,23 +1233,17 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | |||
1261 | 1233 | ||
1262 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 1234 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
1263 | case ZFCP_ERP_ACTION_REOPEN_PORT: | 1235 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
1264 | if ((result == ZFCP_ERP_SUCCEEDED) && !port->rport) | 1236 | if (result == ZFCP_ERP_SUCCEEDED) |
1265 | zfcp_erp_rport_register(port); | 1237 | zfcp_scsi_schedule_rport_register(port); |
1266 | if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) { | ||
1267 | fc_remote_port_delete(port->rport); | ||
1268 | port->rport = NULL; | ||
1269 | } | ||
1270 | zfcp_port_put(port); | 1238 | zfcp_port_put(port); |
1271 | break; | 1239 | break; |
1272 | 1240 | ||
1273 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1241 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
1274 | if (result != ZFCP_ERP_SUCCEEDED) { | 1242 | if (result == ZFCP_ERP_SUCCEEDED) { |
1275 | unregister_service_level(&adapter->service_level); | ||
1276 | zfcp_erp_rports_del(adapter); | ||
1277 | } else { | ||
1278 | register_service_level(&adapter->service_level); | 1243 | register_service_level(&adapter->service_level); |
1279 | schedule_work(&adapter->scan_work); | 1244 | schedule_work(&adapter->scan_work); |
1280 | } | 1245 | } else |
1246 | unregister_service_level(&adapter->service_level); | ||
1281 | zfcp_adapter_put(adapter); | 1247 | zfcp_adapter_put(adapter); |
1282 | break; | 1248 | break; |
1283 | } | 1249 | } |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 569d2437e99b..f6399ca97bcb 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * External function declarations. | 4 | * External function declarations. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2002, 2008 | 6 | * Copyright IBM Corporation 2002, 2009 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #ifndef ZFCP_EXT_H | 9 | #ifndef ZFCP_EXT_H |
@@ -154,6 +154,10 @@ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); | |||
154 | extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); | 154 | extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); |
155 | extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); | 155 | extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); |
156 | extern struct fc_function_template zfcp_transport_functions; | 156 | extern struct fc_function_template zfcp_transport_functions; |
157 | extern void zfcp_scsi_rport_work(struct work_struct *); | ||
158 | extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); | ||
159 | extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *); | ||
160 | extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); | ||
157 | 161 | ||
158 | /* zfcp_sysfs.c */ | 162 | /* zfcp_sysfs.c */ |
159 | extern struct attribute_group zfcp_sysfs_unit_attrs; | 163 | extern struct attribute_group zfcp_sysfs_unit_attrs; |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 49a7a90501b6..c22c47868550 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Fibre Channel related functions for the zfcp device driver. | 4 | * Fibre Channel related functions for the zfcp device driver. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2008 | 6 | * Copyright IBM Corporation 2008, 2009 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define KMSG_COMPONENT "zfcp" | 9 | #define KMSG_COMPONENT "zfcp" |
@@ -376,10 +376,14 @@ static void zfcp_fc_adisc_handler(unsigned long data) | |||
376 | port->wwnn = ls_adisc->wwnn; | 376 | port->wwnn = ls_adisc->wwnn; |
377 | 377 | ||
378 | if ((port->wwpn != ls_adisc->wwpn) || | 378 | if ((port->wwpn != ls_adisc->wwpn) || |
379 | !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) | 379 | !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) { |
380 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, | 380 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, |
381 | "fcadh_2", NULL); | 381 | "fcadh_2", NULL); |
382 | goto out; | ||
383 | } | ||
382 | 384 | ||
385 | /* port is good, unblock rport without going through erp */ | ||
386 | zfcp_scsi_schedule_rport_register(port); | ||
383 | out: | 387 | out: |
384 | zfcp_port_put(port); | 388 | zfcp_port_put(port); |
385 | kfree(adisc); | 389 | kfree(adisc); |
@@ -423,14 +427,23 @@ void zfcp_fc_link_test_work(struct work_struct *work) | |||
423 | container_of(work, struct zfcp_port, test_link_work); | 427 | container_of(work, struct zfcp_port, test_link_work); |
424 | int retval; | 428 | int retval; |
425 | 429 | ||
430 | if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_UNBLOCKED)) { | ||
431 | zfcp_port_put(port); | ||
432 | return; /* port erp is running and will update rport status */ | ||
433 | } | ||
434 | |||
435 | zfcp_port_get(port); | ||
436 | port->rport_task = RPORT_DEL; | ||
437 | zfcp_scsi_rport_work(&port->rport_work); | ||
438 | |||
426 | retval = zfcp_fc_adisc(port); | 439 | retval = zfcp_fc_adisc(port); |
427 | if (retval == 0) | 440 | if (retval == 0) |
428 | return; | 441 | return; |
429 | 442 | ||
430 | /* send of ADISC was not possible */ | 443 | /* send of ADISC was not possible */ |
444 | zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL); | ||
445 | |||
431 | zfcp_port_put(port); | 446 | zfcp_port_put(port); |
432 | if (retval != -EBUSY) | ||
433 | zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL); | ||
434 | } | 447 | } |
435 | 448 | ||
436 | /** | 449 | /** |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 71c32f3ffcb7..9fa8c8990a11 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Implementation of FSF commands. | 4 | * Implementation of FSF commands. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2002, 2008 | 6 | * Copyright IBM Corporation 2002, 2009 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define KMSG_COMPONENT "zfcp" | 9 | #define KMSG_COMPONENT "zfcp" |
@@ -177,6 +177,7 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id, | |||
177 | return; | 177 | return; |
178 | 178 | ||
179 | atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); | 179 | atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); |
180 | zfcp_scsi_schedule_rports_block(adapter); | ||
180 | 181 | ||
181 | if (!link_down) | 182 | if (!link_down) |
182 | goto out; | 183 | goto out; |
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 2af8cfbc3890..7141f9a675df 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Interface to Linux SCSI midlayer. | 4 | * Interface to Linux SCSI midlayer. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2002, 2008 | 6 | * Copyright IBM Corporation 2002, 2009 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define KMSG_COMPONENT "zfcp" | 9 | #define KMSG_COMPONENT "zfcp" |
@@ -57,8 +57,8 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | |||
57 | { | 57 | { |
58 | struct zfcp_unit *unit; | 58 | struct zfcp_unit *unit; |
59 | struct zfcp_adapter *adapter; | 59 | struct zfcp_adapter *adapter; |
60 | int status; | 60 | int status, scsi_result, ret; |
61 | int ret; | 61 | struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device)); |
62 | 62 | ||
63 | /* reset the status for this request */ | 63 | /* reset the status for this request */ |
64 | scpnt->result = 0; | 64 | scpnt->result = 0; |
@@ -80,6 +80,14 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | |||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | scsi_result = fc_remote_port_chkready(rport); | ||
84 | if (unlikely(scsi_result)) { | ||
85 | scpnt->result = scsi_result; | ||
86 | zfcp_scsi_dbf_event_result("fail", 4, adapter, scpnt, NULL); | ||
87 | scpnt->scsi_done(scpnt); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
83 | status = atomic_read(&unit->status); | 91 | status = atomic_read(&unit->status); |
84 | if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || | 92 | if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || |
85 | !(status & ZFCP_STATUS_COMMON_RUNNING))) { | 93 | !(status & ZFCP_STATUS_COMMON_RUNNING))) { |
@@ -473,6 +481,109 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) | |||
473 | rport->dev_loss_tmo = timeout; | 481 | rport->dev_loss_tmo = timeout; |
474 | } | 482 | } |
475 | 483 | ||
484 | /** | ||
485 | * zfcp_scsi_dev_loss_tmo_callbk - Free any reference to rport | ||
486 | * @rport: The rport that is about to be deleted. | ||
487 | */ | ||
488 | static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport) | ||
489 | { | ||
490 | struct zfcp_port *port = rport->dd_data; | ||
491 | |||
492 | write_lock_irq(&zfcp_data.config_lock); | ||
493 | port->rport = NULL; | ||
494 | write_unlock_irq(&zfcp_data.config_lock); | ||
495 | } | ||
496 | |||
497 | /** | ||
498 | * zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport | ||
499 | * @rport: The FC rport where to teminate I/O | ||
500 | * | ||
501 | * Abort all pending SCSI commands for a port by closing the | ||
502 | * port. Using a reopen for avoids a conflict with a shutdown | ||
503 | * overwriting a reopen. | ||
504 | */ | ||
505 | static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) | ||
506 | { | ||
507 | struct zfcp_port *port = rport->dd_data; | ||
508 | |||
509 | zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL); | ||
510 | } | ||
511 | |||
512 | static void zfcp_scsi_rport_register(struct zfcp_port *port) | ||
513 | { | ||
514 | struct fc_rport_identifiers ids; | ||
515 | struct fc_rport *rport; | ||
516 | |||
517 | ids.node_name = port->wwnn; | ||
518 | ids.port_name = port->wwpn; | ||
519 | ids.port_id = port->d_id; | ||
520 | ids.roles = FC_RPORT_ROLE_FCP_TARGET; | ||
521 | |||
522 | rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); | ||
523 | if (!rport) { | ||
524 | dev_err(&port->adapter->ccw_device->dev, | ||
525 | "Registering port 0x%016Lx failed\n", | ||
526 | (unsigned long long)port->wwpn); | ||
527 | return; | ||
528 | } | ||
529 | |||
530 | rport->dd_data = port; | ||
531 | rport->maxframe_size = port->maxframe_size; | ||
532 | rport->supported_classes = port->supported_classes; | ||
533 | port->rport = rport; | ||
534 | } | ||
535 | |||
536 | static void zfcp_scsi_rport_block(struct zfcp_port *port) | ||
537 | { | ||
538 | if (port->rport) | ||
539 | fc_remote_port_delete(port->rport); | ||
540 | } | ||
541 | |||
542 | void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) | ||
543 | { | ||
544 | zfcp_port_get(port); | ||
545 | port->rport_task = RPORT_ADD; | ||
546 | |||
547 | if (!queue_work(zfcp_data.work_queue, &port->rport_work)) | ||
548 | zfcp_port_put(port); | ||
549 | } | ||
550 | |||
551 | void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) | ||
552 | { | ||
553 | zfcp_port_get(port); | ||
554 | port->rport_task = RPORT_DEL; | ||
555 | |||
556 | if (!queue_work(zfcp_data.work_queue, &port->rport_work)) | ||
557 | zfcp_port_put(port); | ||
558 | } | ||
559 | |||
560 | void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) | ||
561 | { | ||
562 | struct zfcp_port *port; | ||
563 | |||
564 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
565 | zfcp_scsi_schedule_rport_block(port); | ||
566 | } | ||
567 | |||
568 | void zfcp_scsi_rport_work(struct work_struct *work) | ||
569 | { | ||
570 | struct zfcp_port *port = container_of(work, struct zfcp_port, | ||
571 | rport_work); | ||
572 | |||
573 | while (port->rport_task) { | ||
574 | if (port->rport_task == RPORT_ADD) { | ||
575 | port->rport_task = RPORT_NONE; | ||
576 | zfcp_scsi_rport_register(port); | ||
577 | } else { | ||
578 | port->rport_task = RPORT_NONE; | ||
579 | zfcp_scsi_rport_block(port); | ||
580 | } | ||
581 | } | ||
582 | |||
583 | zfcp_port_put(port); | ||
584 | } | ||
585 | |||
586 | |||
476 | struct fc_function_template zfcp_transport_functions = { | 587 | struct fc_function_template zfcp_transport_functions = { |
477 | .show_starget_port_id = 1, | 588 | .show_starget_port_id = 1, |
478 | .show_starget_port_name = 1, | 589 | .show_starget_port_name = 1, |
@@ -491,6 +602,8 @@ struct fc_function_template zfcp_transport_functions = { | |||
491 | .reset_fc_host_stats = zfcp_reset_fc_host_stats, | 602 | .reset_fc_host_stats = zfcp_reset_fc_host_stats, |
492 | .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, | 603 | .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, |
493 | .get_host_port_state = zfcp_get_host_port_state, | 604 | .get_host_port_state = zfcp_get_host_port_state, |
605 | .dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk, | ||
606 | .terminate_rport_io = zfcp_scsi_terminate_rport_io, | ||
494 | .show_host_port_state = 1, | 607 | .show_host_port_state = 1, |
495 | /* no functions registered for following dynamic attributes but | 608 | /* no functions registered for following dynamic attributes but |
496 | directly set by LLDD */ | 609 | directly set by LLDD */ |