From 18edcdbdb2911baa5aaeb0ed781e3424cbf98d64 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Mon, 5 Nov 2007 12:37:45 +0100 Subject: [SCSI] zfcp: Specify waiting times in ERP in seconds It is not necessary to use jiffies or milliseconds to specify waiting times that last a couple of seconds. Signed-off-by: Christof Schmitt Signed-off-by: Martin Schwidefsky Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/s390/scsi/zfcp_erp.c') diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 07fa824d179f..9c6ea9962cd2 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -131,7 +131,7 @@ static void zfcp_close_qdio(struct zfcp_adapter *adapter) debug_text_event(adapter->erp_dbf, 3, "qdio_down2a"); while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) - msleep(1000); + ssleep(1); debug_text_event(adapter->erp_dbf, 3, "qdio_down2b"); /* cleanup used outbound sbals */ @@ -1900,7 +1900,7 @@ zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action) ZFCP_LOG_INFO("Waiting to allow the adapter %s " "to recover itself\n", zfcp_get_busid_by_adapter(adapter)); - msleep(jiffies_to_msecs(ZFCP_TYPE2_RECOVERY_TIME)); + ssleep(ZFCP_TYPE2_RECOVERY_TIME); } return retval; @@ -2080,7 +2080,7 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) debug_text_event(adapter->erp_dbf, 3, "qdio_down1a"); while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) - msleep(1000); + ssleep(1); debug_text_event(adapter->erp_dbf, 3, "qdio_down1b"); failed_qdio_establish: @@ -2165,7 +2165,7 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) ZFCP_LOG_DEBUG("host connection still initialising... " "waiting and retrying...\n"); /* sleep a little bit before retry */ - msleep(jiffies_to_msecs(sleep)); + ssleep(sleep); sleep *= 2; } -- cgit v1.2.3-59-g8ed1b From 1de1b43b5f0bb536126e31f07ec833e01969ed1c Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Mon, 5 Nov 2007 12:37:47 +0100 Subject: [SCSI] zfcp: Fix deadlock when adding invalid LUN When adding an invalid LUN, there is a deadlock between the add via scsi_scan_target and the slave_destroy handler: The handler waits for the scan to complete, but for an invalid unit, scsi_scan_target directly calls the slave_destroy handler. Fix the deadlock by removing the wait in the slave_destroy handler, it was not necessary anyway. Signed-off-by: Christof Schmitt Signed-off-by: Martin Schwidefsky Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 2 -- drivers/s390/scsi/zfcp_def.h | 4 ---- drivers/s390/scsi/zfcp_erp.c | 1 - drivers/s390/scsi/zfcp_scsi.c | 3 --- 4 files changed, 10 deletions(-) (limited to 'drivers/s390/scsi/zfcp_erp.c') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 00118499018b..874b55ed00a3 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -844,8 +844,6 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) unit->sysfs_device.release = zfcp_sysfs_unit_release; dev_set_drvdata(&unit->sysfs_device, unit); - init_waitqueue_head(&unit->scsi_scan_wq); - /* mark unit unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 3d2d2dc0d6f8..294d0792e82b 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -983,10 +983,6 @@ struct zfcp_unit { struct scsi_device *device; /* scsi device struct pointer */ struct zfcp_erp_action erp_action; /* pending error recovery */ atomic_t erp_counter; - wait_queue_head_t scsi_scan_wq; /* can be used to wait until - all scsi_scan_target - requests have been - completed. */ }; /* FSF request */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 9c6ea9962cd2..67d74ed0f25c 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1609,7 +1609,6 @@ static void zfcp_erp_scsi_scan(struct work_struct *work) scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, unit->scsi_lun, 0); atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); - wake_up(&unit->scsi_scan_wq); zfcp_unit_put(unit); kfree(p); } diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index c6b6295395b0..3298fd35000c 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -180,9 +180,6 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) if (unit) { zfcp_erp_wait(unit->port->adapter); - wait_event(unit->scsi_scan_wq, - atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, - &unit->status) == 0); atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); sdpnt->hostdata = NULL; unit->device = NULL; -- cgit v1.2.3-59-g8ed1b From d1ad09db2fd551d49d65ef040591cb9298e70fb6 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 20 Dec 2007 12:30:22 +0100 Subject: [SCSI] zfcp: fix use after free bug. zfcp_erp_strategy_check_fsfreq() checks if it is safe to access the fsf_req associated with the erp_action that gets passed. To test if it is safe it accesses the fsf_req in order to get its index into the hash list. This is broken since the fsf_req might be freed already and the read index has no meaning. It could lead to memory corruption. Fix this by introducing a new zfcp_reqlist_find_safe() method which just checks if addresses are equal. This is slower, but only gets called in case of error recovery. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Christof Schmitt Signed-off-by: Martin Peschke Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 14 ++++++++++++++ drivers/s390/scsi/zfcp_erp.c | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/s390/scsi/zfcp_erp.c') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 294d0792e82b..9e9f6c1e4e5d 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -1123,6 +1123,20 @@ zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id) return NULL; } +static inline struct zfcp_fsf_req * +zfcp_reqlist_find_safe(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req) +{ + struct zfcp_fsf_req *request; + unsigned int idx; + + for (idx = 0; idx < REQUEST_LIST_SIZE; idx++) { + list_for_each_entry(request, &adapter->req_list[idx], list) + if (request == req) + return request; + } + return NULL; +} + /* * functions needed for reference/usage counting */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 67d74ed0f25c..76fef3f6387e 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -846,7 +846,8 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) if (erp_action->fsf_req) { /* take lock to ensure that request is not deleted meanwhile */ spin_lock(&adapter->req_list_lock); - if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) { + if (zfcp_reqlist_find_safe(adapter, erp_action->fsf_req) && + erp_action->fsf_req->erp_action == erp_action) { /* fsf_req still exists */ debug_text_event(adapter->erp_dbf, 3, "a_ca_req"); debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req, -- cgit v1.2.3-59-g8ed1b From 3f0ca62add34010241db682e63bb68ba765bf4a9 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 20 Dec 2007 12:30:25 +0100 Subject: [SCSI] zfcp: Hold queue lock when checking port handle for ELS command We need to hold the queue-lock when checking whether we still have a valid port handle for the ELS command, i.e whether we can issue this request for this port. If the error recovery is about to close this port, then it competes for the queue-lock. If the close request issued by the error recovery wins, then it is guaranteed that this port has been blocked for other requests. Signed-off-by: Christof Schmitt Signed-off-by: Martin Peschke Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 2 +- drivers/s390/scsi/zfcp_fsf.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/s390/scsi/zfcp_erp.c') diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 76fef3f6387e..4f86c0e12961 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -456,7 +456,7 @@ zfcp_test_link(struct zfcp_port *port) zfcp_port_get(port); retval = zfcp_erp_adisc(port); - if (retval != 0) { + if (retval != 0 && retval != -EBUSY) { zfcp_port_put(port); ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx " "on adapter %s\n ", port->wwpn, diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 665fcb6ec5d5..908e8b2107c1 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1668,6 +1668,12 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) goto failed_req; } + if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, + &els->port->status))) { + ret = -EBUSY; + goto port_blocked; + } + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); if (zfcp_use_one_sbal(els->req, els->req_count, els->resp, els->resp_count)){ @@ -1749,6 +1755,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); goto out; + port_blocked: failed_send: zfcp_fsf_req_free(fsf_req); -- cgit v1.2.3-59-g8ed1b