diff options
author | Christof Schmitt <christof.schmitt@de.ibm.com> | 2009-03-02 07:09:01 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-03-12 13:58:19 -0400 |
commit | 8fdf30d5429605a4c30cc515c73e5eab140035de (patch) | |
tree | 8aeaa2409b6f770a4dfafb00955579ae9288ba5e /drivers/s390/scsi | |
parent | 63caf367e1c92e0667a344d9b687c04e6ef054b5 (diff) |
[SCSI] zfcp: Send ELS ADISC from workqueue
Issue ELS ADISC requests from workqueue. This allows the link test
request to be sent when the request queue is full due to I/O load for
other remote ports. It also simplifies request queue locking,
zfcp_fsf_send_fcp_command_task is now the only function that has
interrupts disabled from the caller. This is also a prereq for the FC
passthrough support that issues ELS requests from userspace.
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')
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 28 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 18 |
5 files changed, 27 insertions, 22 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 969a3f093037..1e16ab58b242 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -604,6 +604,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, | |||
604 | init_waitqueue_head(&port->remove_wq); | 604 | init_waitqueue_head(&port->remove_wq); |
605 | INIT_LIST_HEAD(&port->unit_list_head); | 605 | INIT_LIST_HEAD(&port->unit_list_head); |
606 | INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup); | 606 | INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup); |
607 | INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); | ||
607 | 608 | ||
608 | port->adapter = adapter; | 609 | port->adapter = adapter; |
609 | port->d_id = d_id; | 610 | port->d_id = d_id; |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index ff15f11923e9..8412bb992ea1 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -513,6 +513,7 @@ struct zfcp_port { | |||
513 | u32 maxframe_size; | 513 | u32 maxframe_size; |
514 | u32 supported_classes; | 514 | u32 supported_classes; |
515 | struct work_struct gid_pn_work; | 515 | struct work_struct gid_pn_work; |
516 | struct work_struct test_link_work; | ||
516 | }; | 517 | }; |
517 | 518 | ||
518 | struct zfcp_unit { | 519 | struct zfcp_unit { |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 799ce1db1f56..a2b4987ac652 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -101,6 +101,7 @@ extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); | |||
101 | extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *); | 101 | extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *); |
102 | extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); | 102 | extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); |
103 | extern void zfcp_test_link(struct zfcp_port *); | 103 | extern void zfcp_test_link(struct zfcp_port *); |
104 | extern void zfcp_fc_link_test_work(struct work_struct *); | ||
104 | extern void zfcp_fc_nameserver_init(struct zfcp_adapter *); | 105 | extern void zfcp_fc_nameserver_init(struct zfcp_adapter *); |
105 | 106 | ||
106 | /* zfcp_fsf.c */ | 107 | /* zfcp_fsf.c */ |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 67e6b7177870..0f435ed9d1a0 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -421,19 +421,12 @@ static int zfcp_fc_adisc(struct zfcp_port *port) | |||
421 | return zfcp_fsf_send_els(&adisc->els); | 421 | return zfcp_fsf_send_els(&adisc->els); |
422 | } | 422 | } |
423 | 423 | ||
424 | /** | 424 | void zfcp_fc_link_test_work(struct work_struct *work) |
425 | * zfcp_test_link - lightweight link test procedure | ||
426 | * @port: port to be tested | ||
427 | * | ||
428 | * Test status of a link to a remote port using the ELS command ADISC. | ||
429 | * If there is a problem with the remote port, error recovery steps | ||
430 | * will be triggered. | ||
431 | */ | ||
432 | void zfcp_test_link(struct zfcp_port *port) | ||
433 | { | 425 | { |
426 | struct zfcp_port *port = | ||
427 | container_of(work, struct zfcp_port, test_link_work); | ||
434 | int retval; | 428 | int retval; |
435 | 429 | ||
436 | zfcp_port_get(port); | ||
437 | retval = zfcp_fc_adisc(port); | 430 | retval = zfcp_fc_adisc(port); |
438 | if (retval == 0) | 431 | if (retval == 0) |
439 | return; | 432 | return; |
@@ -444,6 +437,21 @@ void zfcp_test_link(struct zfcp_port *port) | |||
444 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); | 437 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); |
445 | } | 438 | } |
446 | 439 | ||
440 | /** | ||
441 | * zfcp_test_link - lightweight link test procedure | ||
442 | * @port: port to be tested | ||
443 | * | ||
444 | * Test status of a link to a remote port using the ELS command ADISC. | ||
445 | * If there is a problem with the remote port, error recovery steps | ||
446 | * will be triggered. | ||
447 | */ | ||
448 | void zfcp_test_link(struct zfcp_port *port) | ||
449 | { | ||
450 | zfcp_port_get(port); | ||
451 | if (!queue_work(zfcp_data.work_queue, &port->test_link_work)) | ||
452 | zfcp_port_put(port); | ||
453 | } | ||
454 | |||
447 | static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) | 455 | static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) |
448 | { | 456 | { |
449 | struct scatterlist *sg = &gpn_ft->sg_req; | 457 | struct scatterlist *sg = &gpn_ft->sg_req; |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index cc69db3b71e7..9c3f91a343f3 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -647,14 +647,6 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) | |||
647 | } | 647 | } |
648 | } | 648 | } |
649 | 649 | ||
650 | static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter) | ||
651 | { | ||
652 | if (atomic_read(&adapter->req_q.count) > 0) | ||
653 | return 1; | ||
654 | atomic_inc(&adapter->qdio_outb_full); | ||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) | 650 | static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) |
659 | __releases(&adapter->req_q_lock) | 651 | __releases(&adapter->req_q_lock) |
660 | __acquires(&adapter->req_q_lock) | 652 | __acquires(&adapter->req_q_lock) |
@@ -1177,8 +1169,8 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) | |||
1177 | ZFCP_STATUS_COMMON_UNBLOCKED))) | 1169 | ZFCP_STATUS_COMMON_UNBLOCKED))) |
1178 | return -EBUSY; | 1170 | return -EBUSY; |
1179 | 1171 | ||
1180 | spin_lock(&adapter->req_q_lock); | 1172 | spin_lock_bh(&adapter->req_q_lock); |
1181 | if (!zfcp_fsf_sbal_available(adapter)) | 1173 | if (zfcp_fsf_req_sbal_get(adapter)) |
1182 | goto out; | 1174 | goto out; |
1183 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, | 1175 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, |
1184 | ZFCP_REQ_AUTO_CLEANUP, NULL); | 1176 | ZFCP_REQ_AUTO_CLEANUP, NULL); |
@@ -1211,7 +1203,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) | |||
1211 | failed_send: | 1203 | failed_send: |
1212 | zfcp_fsf_req_free(req); | 1204 | zfcp_fsf_req_free(req); |
1213 | out: | 1205 | out: |
1214 | spin_unlock(&adapter->req_q_lock); | 1206 | spin_unlock_bh(&adapter->req_q_lock); |
1215 | return ret; | 1207 | return ret; |
1216 | } | 1208 | } |
1217 | 1209 | ||
@@ -2324,8 +2316,10 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, | |||
2324 | return -EBUSY; | 2316 | return -EBUSY; |
2325 | 2317 | ||
2326 | spin_lock(&adapter->req_q_lock); | 2318 | spin_lock(&adapter->req_q_lock); |
2327 | if (!zfcp_fsf_sbal_available(adapter)) | 2319 | if (atomic_read(&adapter->req_q.count) <= 0) { |
2320 | atomic_inc(&adapter->qdio_outb_full); | ||
2328 | goto out; | 2321 | goto out; |
2322 | } | ||
2329 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, | 2323 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, |
2330 | ZFCP_REQ_AUTO_CLEANUP, | 2324 | ZFCP_REQ_AUTO_CLEANUP, |
2331 | adapter->pool.fsf_req_scsi); | 2325 | adapter->pool.fsf_req_scsi); |