aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/scsi
diff options
context:
space:
mode:
authorSwen Schillig <swen@vnet.ibm.com>2008-05-19 06:17:37 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-06-05 10:27:13 -0400
commitd26ab06ede83287f99067fee3034c5455a75faf9 (patch)
tree6070ae50cded8086ceab61092348790b39876146 /drivers/s390/scsi
parent15424921222f2bed0aa92ef1e8bc94f753d2c6ea (diff)
[SCSI] zfcp: receiving an unsolicted status can lead to I/O stall
Processing of an unsolicted status request can lead to a locking race of the request_queue's queue_lock during the recreation of the used up status read request while still in interrupt context of the response handler. Detaching the 'refill' of the long running status read requests from the handler to a scheduled work is solving this issue. In addition, each refill-run is trying to re-establish the full amount of status read requests, which might have failed in earlier runs. Signed-off-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.c23
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c2
-rw-r--r--drivers/s390/scsi/zfcp_def.h4
-rw-r--r--drivers/s390/scsi/zfcp_erp.c19
-rw-r--r--drivers/s390/scsi/zfcp_ext.h1
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c18
6 files changed, 32 insertions, 35 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index d23027a2f2f0..41635b13ccb1 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -970,6 +970,27 @@ static void zfcp_dummy_release(struct device *dev)
970 return; 970 return;
971} 971}
972 972
973int zfcp_status_read_refill(struct zfcp_adapter *adapter)
974{
975 while (atomic_read(&adapter->stat_miss) > 0)
976 if (zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL))
977 break;
978 else
979 atomic_dec(&adapter->stat_miss);
980
981 if (ZFCP_STATUS_READS_RECOM <= atomic_read(&adapter->stat_miss)) {
982 zfcp_erp_adapter_reopen(adapter, 0, 103, NULL);
983 return 1;
984 }
985 return 0;
986}
987
988static void _zfcp_status_read_scheduler(struct work_struct *work)
989{
990 zfcp_status_read_refill(container_of(work, struct zfcp_adapter,
991 stat_work));
992}
993
973/* 994/*
974 * Enqueues an adapter at the end of the adapter list in the driver data. 995 * Enqueues an adapter at the end of the adapter list in the driver data.
975 * All adapter internal structures are set up. 996 * All adapter internal structures are set up.
@@ -1063,6 +1084,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
1063 1084
1064 /* initialize lock of associated request queue */ 1085 /* initialize lock of associated request queue */
1065 rwlock_init(&adapter->request_queue.queue_lock); 1086 rwlock_init(&adapter->request_queue.queue_lock);
1087 INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
1066 1088
1067 /* mark adapter unusable as long as sysfs registration is not complete */ 1089 /* mark adapter unusable as long as sysfs registration is not complete */
1068 atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); 1090 atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
@@ -1123,6 +1145,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
1123 int retval = 0; 1145 int retval = 0;
1124 unsigned long flags; 1146 unsigned long flags;
1125 1147
1148 cancel_work_sync(&adapter->stat_work);
1126 zfcp_adapter_scsi_unregister(adapter); 1149 zfcp_adapter_scsi_unregister(adapter);
1127 device_unregister(&adapter->generic_services); 1150 device_unregister(&adapter->generic_services);
1128 zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); 1151 zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index c8bad675dbd1..1710c12a32c4 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -268,7 +268,7 @@ void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
268 strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); 268 strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE);
269 strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); 269 strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE);
270 270
271 rec->u.status.failed = adapter->status_read_failed; 271 rec->u.status.failed = atomic_read(&adapter->stat_miss);
272 if (status_buffer != NULL) { 272 if (status_buffer != NULL) {
273 rec->u.status.status_type = status_buffer->status_type; 273 rec->u.status.status_type = status_buffer->status_type;
274 rec->u.status.status_subtype = status_buffer->status_subtype; 274 rec->u.status.status_subtype = status_buffer->status_subtype;
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 306fcd0cae31..adfbbb07448a 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -136,7 +136,6 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
136#define ZFCP_QTCB_VERSION FSF_QTCB_CURRENT_VERSION 136#define ZFCP_QTCB_VERSION FSF_QTCB_CURRENT_VERSION
137/* ATTENTION: value must not be used by hardware */ 137/* ATTENTION: value must not be used by hardware */
138#define FSF_QTCB_UNSOLICITED_STATUS 0x6305 138#define FSF_QTCB_UNSOLICITED_STATUS 0x6305
139#define ZFCP_STATUS_READ_FAILED_THRESHOLD 3
140#define ZFCP_STATUS_READS_RECOM FSF_STATUS_READS_RECOM 139#define ZFCP_STATUS_READS_RECOM FSF_STATUS_READS_RECOM
141 140
142/* Do 1st retry in 1 second, then double the timeout for each following retry */ 141/* Do 1st retry in 1 second, then double the timeout for each following retry */
@@ -759,7 +758,8 @@ struct zfcp_adapter {
759 rwlock_t abort_lock; /* Protects against SCSI 758 rwlock_t abort_lock; /* Protects against SCSI
760 stack abort/command 759 stack abort/command
761 completion races */ 760 completion races */
762 u16 status_read_failed; /* # failed status reads */ 761 atomic_t stat_miss; /* # missing status reads*/
762 struct work_struct stat_work;
763 atomic_t status; /* status of this adapter */ 763 atomic_t status; /* status of this adapter */
764 struct list_head erp_ready_head; /* error recovery for this 764 struct list_head erp_ready_head; /* error recovery for this
765 adapter/devices */ 765 adapter/devices */
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 805484658dd9..55a4fdc42626 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -2139,25 +2139,10 @@ static int
2139zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action 2139zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action
2140 *erp_action) 2140 *erp_action)
2141{ 2141{
2142 int retval = ZFCP_ERP_SUCCEEDED;
2143 int temp_ret;
2144 struct zfcp_adapter *adapter = erp_action->adapter; 2142 struct zfcp_adapter *adapter = erp_action->adapter;
2145 int i;
2146 2143
2147 adapter->status_read_failed = 0; 2144 atomic_set(&adapter->stat_miss, 16);
2148 for (i = 0; i < ZFCP_STATUS_READS_RECOM; i++) { 2145 return zfcp_status_read_refill(adapter);
2149 temp_ret = zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL);
2150 if (temp_ret < 0) {
2151 ZFCP_LOG_INFO("error: set-up of unsolicited status "
2152 "notification failed on adapter %s\n",
2153 zfcp_get_busid_by_adapter(adapter));
2154 retval = ZFCP_ERP_FAILED;
2155 i--;
2156 break;
2157 }
2158 }
2159
2160 return retval;
2161} 2146}
2162 2147
2163/* 2148/*
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 6abf178fda5d..250565794fa5 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -92,6 +92,7 @@ extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long);
92extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); 92extern void zfcp_erp_start_timer(struct zfcp_fsf_req *);
93extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); 93extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
94extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); 94extern int zfcp_fsf_status_read(struct zfcp_adapter *, int);
95extern int zfcp_status_read_refill(struct zfcp_adapter *adapter);
95extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *, 96extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *,
96 unsigned long *, struct zfcp_fsf_req **); 97 unsigned long *, struct zfcp_fsf_req **);
97extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, 98extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *,
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 1e7136483c1b..b344e8a72f1f 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -1029,21 +1029,9 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
1029 * FIXME: 1029 * FIXME:
1030 * allocation failure possible? (Is this code needed?) 1030 * allocation failure possible? (Is this code needed?)
1031 */ 1031 */
1032 retval = zfcp_fsf_status_read(adapter, 0); 1032
1033 if (retval < 0) { 1033 atomic_inc(&adapter->stat_miss);
1034 ZFCP_LOG_INFO("Failed to create unsolicited status read " 1034 schedule_work(&adapter->stat_work);
1035 "request for the adapter %s.\n",
1036 zfcp_get_busid_by_adapter(adapter));
1037 /* temporary fix to avoid status read buffer shortage */
1038 adapter->status_read_failed++;
1039 if ((ZFCP_STATUS_READS_RECOM - adapter->status_read_failed)
1040 < ZFCP_STATUS_READ_FAILED_THRESHOLD) {
1041 ZFCP_LOG_INFO("restart adapter %s due to status read "
1042 "buffer shortage\n",
1043 zfcp_get_busid_by_adapter(adapter));
1044 zfcp_erp_adapter_reopen(adapter, 0, 103, fsf_req);
1045 }
1046 }
1047 out: 1035 out:
1048 return retval; 1036 return retval;
1049} 1037}