diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2012-10-15 06:24:56 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-10-18 11:50:08 -0400 |
commit | cec8546638dc634824b629e33968d6c68f8b07d6 (patch) | |
tree | eb97150bedd22afb3ee503e6b6bf159a65fc8ee8 /drivers/s390/cio | |
parent | aa92b33c6b93b5ef4ccbaa72afa9c387a96c2ee2 (diff) |
s390/css: stop stsch loop after cc 3
Receiving cc=3 from store subchannel means 2 things:
* the subchannel is not provided
* there are no further subchannels in this subchannel set
With this patch we abort the store subchannel loop after cc=3 (or an
exception) and clear the subsequent bits in the subchannel id set.
Reported-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Acked-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/css.c | 7 | ||||
-rw-r--r-- | drivers/s390/cio/idset.c | 8 | ||||
-rw-r--r-- | drivers/s390/cio/idset.h | 3 |
3 files changed, 16 insertions, 2 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index b4d572f65f07..fd00afd8b850 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -377,7 +377,11 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) | |||
377 | /* Will be done on the slow path. */ | 377 | /* Will be done on the slow path. */ |
378 | return -EAGAIN; | 378 | return -EAGAIN; |
379 | } | 379 | } |
380 | if (stsch_err(schid, &schib) || !css_sch_is_valid(&schib)) { | 380 | if (stsch_err(schid, &schib)) { |
381 | /* Subchannel is not provided. */ | ||
382 | return -ENXIO; | ||
383 | } | ||
384 | if (!css_sch_is_valid(&schib)) { | ||
381 | /* Unusable - ignore. */ | 385 | /* Unusable - ignore. */ |
382 | return 0; | 386 | return 0; |
383 | } | 387 | } |
@@ -536,6 +540,7 @@ static int slow_eval_unknown_fn(struct subchannel_id schid, void *data) | |||
536 | case -ENOMEM: | 540 | case -ENOMEM: |
537 | case -EIO: | 541 | case -EIO: |
538 | /* These should abort looping */ | 542 | /* These should abort looping */ |
543 | idset_sch_del_subseq(slow_subchannel_set, schid); | ||
539 | break; | 544 | break; |
540 | default: | 545 | default: |
541 | rc = 0; | 546 | rc = 0; |
diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index f0973a04ec49..199bc6791177 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c | |||
@@ -90,6 +90,14 @@ void idset_sch_del(struct idset *set, struct subchannel_id schid) | |||
90 | idset_del(set, schid.ssid, schid.sch_no); | 90 | idset_del(set, schid.ssid, schid.sch_no); |
91 | } | 91 | } |
92 | 92 | ||
93 | /* Clear ids starting from @schid up to end of subchannel set. */ | ||
94 | void idset_sch_del_subseq(struct idset *set, struct subchannel_id schid) | ||
95 | { | ||
96 | int pos = schid.ssid * set->num_id + schid.sch_no; | ||
97 | |||
98 | bitmap_clear(set->bitmap, pos, set->num_id - schid.sch_no); | ||
99 | } | ||
100 | |||
93 | int idset_sch_contains(struct idset *set, struct subchannel_id schid) | 101 | int idset_sch_contains(struct idset *set, struct subchannel_id schid) |
94 | { | 102 | { |
95 | return idset_contains(set, schid.ssid, schid.sch_no); | 103 | return idset_contains(set, schid.ssid, schid.sch_no); |
diff --git a/drivers/s390/cio/idset.h b/drivers/s390/cio/idset.h index 3d943f03591e..06d3bc01bb09 100644 --- a/drivers/s390/cio/idset.h +++ b/drivers/s390/cio/idset.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright IBM Corp. 2007 | 2 | * Copyright IBM Corp. 2007, 2012 |
3 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 3 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> |
4 | */ | 4 | */ |
5 | 5 | ||
@@ -17,6 +17,7 @@ void idset_fill(struct idset *set); | |||
17 | struct idset *idset_sch_new(void); | 17 | struct idset *idset_sch_new(void); |
18 | void idset_sch_add(struct idset *set, struct subchannel_id id); | 18 | void idset_sch_add(struct idset *set, struct subchannel_id id); |
19 | void idset_sch_del(struct idset *set, struct subchannel_id id); | 19 | void idset_sch_del(struct idset *set, struct subchannel_id id); |
20 | void idset_sch_del_subseq(struct idset *set, struct subchannel_id schid); | ||
20 | int idset_sch_contains(struct idset *set, struct subchannel_id id); | 21 | int idset_sch_contains(struct idset *set, struct subchannel_id id); |
21 | int idset_sch_get_first(struct idset *set, struct subchannel_id *id); | 22 | int idset_sch_get_first(struct idset *set, struct subchannel_id *id); |
22 | int idset_is_empty(struct idset *set); | 23 | int idset_is_empty(struct idset *set); |