diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_fc.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 82 |
1 files changed, 51 insertions, 31 deletions
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index eabdfe24456e..aab8123c5966 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" |
@@ -98,8 +98,12 @@ static void zfcp_wka_port_offline(struct work_struct *work) | |||
98 | struct zfcp_wka_port *wka_port = | 98 | struct zfcp_wka_port *wka_port = |
99 | container_of(dw, struct zfcp_wka_port, work); | 99 | container_of(dw, struct zfcp_wka_port, work); |
100 | 100 | ||
101 | wait_event(wka_port->completion_wq, | 101 | /* Don't wait forvever. If the wka_port is too busy take it offline |
102 | atomic_read(&wka_port->refcount) == 0); | 102 | through a new call later */ |
103 | if (!wait_event_timeout(wka_port->completion_wq, | ||
104 | atomic_read(&wka_port->refcount) == 0, | ||
105 | HZ >> 1)) | ||
106 | return; | ||
103 | 107 | ||
104 | mutex_lock(&wka_port->mutex); | 108 | mutex_lock(&wka_port->mutex); |
105 | if ((atomic_read(&wka_port->refcount) != 0) || | 109 | if ((atomic_read(&wka_port->refcount) != 0) || |
@@ -145,16 +149,10 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, | |||
145 | struct zfcp_port *port; | 149 | struct zfcp_port *port; |
146 | 150 | ||
147 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 151 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
148 | list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { | 152 | list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) |
149 | if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_PHYS_OPEN)) | 153 | if ((port->d_id & range) == (elem->nport_did & range)) |
150 | /* Try to connect to unused ports anyway. */ | ||
151 | zfcp_erp_port_reopen(port, | ||
152 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
153 | 82, fsf_req); | ||
154 | else if ((port->d_id & range) == (elem->nport_did & range)) | ||
155 | /* Check connection status for connected ports */ | ||
156 | zfcp_test_link(port); | 154 | zfcp_test_link(port); |
157 | } | 155 | |
158 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 156 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
159 | } | 157 | } |
160 | 158 | ||
@@ -196,7 +194,7 @@ static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn) | |||
196 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 194 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
197 | 195 | ||
198 | if (port && (port->wwpn == wwpn)) | 196 | if (port && (port->wwpn == wwpn)) |
199 | zfcp_erp_port_forced_reopen(port, 0, 83, req); | 197 | zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req); |
200 | } | 198 | } |
201 | 199 | ||
202 | static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) | 200 | static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) |
@@ -259,10 +257,9 @@ static void zfcp_fc_ns_gid_pn_eval(unsigned long data) | |||
259 | 257 | ||
260 | if (ct->status) | 258 | if (ct->status) |
261 | return; | 259 | return; |
262 | if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) { | 260 | if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) |
263 | atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); | ||
264 | return; | 261 | return; |
265 | } | 262 | |
266 | /* paranoia */ | 263 | /* paranoia */ |
267 | if (ct_iu_req->wwpn != port->wwpn) | 264 | if (ct_iu_req->wwpn != port->wwpn) |
268 | return; | 265 | return; |
@@ -375,16 +372,22 @@ static void zfcp_fc_adisc_handler(unsigned long data) | |||
375 | 372 | ||
376 | if (adisc->els.status) { | 373 | if (adisc->els.status) { |
377 | /* request rejected or timed out */ | 374 | /* request rejected or timed out */ |
378 | zfcp_erp_port_forced_reopen(port, 0, 63, NULL); | 375 | zfcp_erp_port_forced_reopen(port, 0, "fcadh_1", NULL); |
379 | goto out; | 376 | goto out; |
380 | } | 377 | } |
381 | 378 | ||
382 | if (!port->wwnn) | 379 | if (!port->wwnn) |
383 | port->wwnn = ls_adisc->wwnn; | 380 | port->wwnn = ls_adisc->wwnn; |
384 | 381 | ||
385 | if (port->wwpn != ls_adisc->wwpn) | 382 | if ((port->wwpn != ls_adisc->wwpn) || |
386 | zfcp_erp_port_reopen(port, 0, 64, NULL); | 383 | !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) { |
384 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, | ||
385 | "fcadh_2", NULL); | ||
386 | goto out; | ||
387 | } | ||
387 | 388 | ||
389 | /* port is good, unblock rport without going through erp */ | ||
390 | zfcp_scsi_schedule_rport_register(port); | ||
388 | out: | 391 | out: |
389 | zfcp_port_put(port); | 392 | zfcp_port_put(port); |
390 | kfree(adisc); | 393 | kfree(adisc); |
@@ -422,6 +425,31 @@ static int zfcp_fc_adisc(struct zfcp_port *port) | |||
422 | return zfcp_fsf_send_els(&adisc->els); | 425 | return zfcp_fsf_send_els(&adisc->els); |
423 | } | 426 | } |
424 | 427 | ||
428 | void zfcp_fc_link_test_work(struct work_struct *work) | ||
429 | { | ||
430 | struct zfcp_port *port = | ||
431 | container_of(work, struct zfcp_port, test_link_work); | ||
432 | int retval; | ||
433 | |||
434 | if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_UNBLOCKED)) { | ||
435 | zfcp_port_put(port); | ||
436 | return; /* port erp is running and will update rport status */ | ||
437 | } | ||
438 | |||
439 | zfcp_port_get(port); | ||
440 | port->rport_task = RPORT_DEL; | ||
441 | zfcp_scsi_rport_work(&port->rport_work); | ||
442 | |||
443 | retval = zfcp_fc_adisc(port); | ||
444 | if (retval == 0) | ||
445 | return; | ||
446 | |||
447 | /* send of ADISC was not possible */ | ||
448 | zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL); | ||
449 | |||
450 | zfcp_port_put(port); | ||
451 | } | ||
452 | |||
425 | /** | 453 | /** |
426 | * zfcp_test_link - lightweight link test procedure | 454 | * zfcp_test_link - lightweight link test procedure |
427 | * @port: port to be tested | 455 | * @port: port to be tested |
@@ -432,17 +460,9 @@ static int zfcp_fc_adisc(struct zfcp_port *port) | |||
432 | */ | 460 | */ |
433 | void zfcp_test_link(struct zfcp_port *port) | 461 | void zfcp_test_link(struct zfcp_port *port) |
434 | { | 462 | { |
435 | int retval; | ||
436 | |||
437 | zfcp_port_get(port); | 463 | zfcp_port_get(port); |
438 | retval = zfcp_fc_adisc(port); | 464 | if (!queue_work(zfcp_data.work_queue, &port->test_link_work)) |
439 | if (retval == 0) | 465 | zfcp_port_put(port); |
440 | return; | ||
441 | |||
442 | /* send of ADISC was not possible */ | ||
443 | zfcp_port_put(port); | ||
444 | if (retval != -EBUSY) | ||
445 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); | ||
446 | } | 466 | } |
447 | 467 | ||
448 | static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) | 468 | static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) |
@@ -529,7 +549,7 @@ static void zfcp_validate_port(struct zfcp_port *port) | |||
529 | zfcp_port_put(port); | 549 | zfcp_port_put(port); |
530 | return; | 550 | return; |
531 | } | 551 | } |
532 | zfcp_erp_port_shutdown(port, 0, 151, NULL); | 552 | zfcp_erp_port_shutdown(port, 0, "fcpval1", NULL); |
533 | zfcp_erp_wait(adapter); | 553 | zfcp_erp_wait(adapter); |
534 | zfcp_port_put(port); | 554 | zfcp_port_put(port); |
535 | zfcp_port_dequeue(port); | 555 | zfcp_port_dequeue(port); |
@@ -592,7 +612,7 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) | |||
592 | if (IS_ERR(port)) | 612 | if (IS_ERR(port)) |
593 | ret = PTR_ERR(port); | 613 | ret = PTR_ERR(port); |
594 | else | 614 | else |
595 | zfcp_erp_port_reopen(port, 0, 149, NULL); | 615 | zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL); |
596 | } | 616 | } |
597 | 617 | ||
598 | zfcp_erp_wait(adapter); | 618 | zfcp_erp_wait(adapter); |