aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd_eckd.c
diff options
context:
space:
mode:
authorStefan Weinhuber <wein@de.ibm.com>2011-01-05 12:48:04 +0100
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2011-01-05 12:47:30 +0100
commit5a27e60dec59a95bd7f8ae9a19ae2ede4f76395b (patch)
tree20595cba0caebf7a8a5f0afac9785c7d717f3e8c /drivers/s390/block/dasd_eckd.c
parenta4d26c6aeceea330ee5e0fb6b017d57e3b252d29 (diff)
downloadlinux-5a27e60dec59a95bd7f8ae9a19ae2ede4f76395b.tar.gz
[S390] dasd: Improve handling of stolen DASD reservation
If a DASD device has been reserved by a Linux system, and later this reservation is ‘stolen’ by a second system by means of an unconditional reserve, then the first system receives a notification about this fact. With this patch such an event can be either ignored, as before, or it can be used to let the device fail all I/O request, so that the device will not block anymore. Signed-off-by: Stefan Weinhuber <wein@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r--drivers/s390/block/dasd_eckd.c51
1 files changed, 30 insertions, 21 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index a1ebf5722ae550..46eafce3a0a6ed 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -817,6 +817,7 @@ static int dasd_eckd_read_conf_immediately(struct dasd_device *device,
dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buffer, lpm);
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags);
cqr->retries = 5;
rc = dasd_sleep_on_immediatly(cqr);
return rc;
@@ -1947,9 +1948,9 @@ dasd_eckd_erp_postaction(struct dasd_ccw_req * cqr)
return dasd_default_erp_postaction;
}
-
-static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
- struct irb *irb)
+static void dasd_eckd_check_for_device_change(struct dasd_device *device,
+ struct dasd_ccw_req *cqr,
+ struct irb *irb)
{
char mask;
char *sense = NULL;
@@ -1973,40 +1974,41 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
/* schedule worker to reload device */
dasd_reload_device(device);
}
-
dasd_generic_handle_state_change(device);
return;
}
- /* summary unit check */
sense = dasd_get_sense(irb);
- if (sense && (sense[7] == 0x0D) &&
+ if (!sense)
+ return;
+
+ /* summary unit check */
+ if ((sense[7] == 0x0D) &&
(scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) {
dasd_alias_handle_summary_unit_check(device, irb);
return;
}
/* service information message SIM */
- if (sense && !(sense[27] & DASD_SENSE_BIT_0) &&
+ if (!cqr && !(sense[27] & DASD_SENSE_BIT_0) &&
((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) {
dasd_3990_erp_handle_sim(device, sense);
- dasd_schedule_device_bh(device);
return;
}
- if ((scsw_cc(&irb->scsw) == 1) && !sense &&
- (scsw_fctl(&irb->scsw) == SCSW_FCTL_START_FUNC) &&
- (scsw_actl(&irb->scsw) == SCSW_ACTL_START_PEND) &&
- (scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND)) {
- /* fake irb do nothing, they are handled elsewhere */
- dasd_schedule_device_bh(device);
- return;
+ /* loss of device reservation is handled via base devices only
+ * as alias devices may be used with several bases
+ */
+ if (device->block && (sense[7] == 0x3F) &&
+ (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&
+ test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) {
+ if (device->features & DASD_FEATURE_FAILONSLCK)
+ set_bit(DASD_FLAG_LOCK_STOLEN, &device->flags);
+ clear_bit(DASD_FLAG_IS_RESERVED, &device->flags);
+ dev_err(&device->cdev->dev,
+ "The device reservation was lost\n");
}
-
- dasd_schedule_device_bh(device);
- return;
-};
-
+}
static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
struct dasd_device *startdev,
@@ -2931,6 +2933,8 @@ dasd_eckd_release(struct dasd_device *device)
cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr);
+ if (!rc)
+ clear_bit(DASD_FLAG_IS_RESERVED, &device->flags);
if (useglobal)
mutex_unlock(&dasd_reserve_mutex);
@@ -2984,6 +2988,8 @@ dasd_eckd_reserve(struct dasd_device *device)
cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr);
+ if (!rc)
+ set_bit(DASD_FLAG_IS_RESERVED, &device->flags);
if (useglobal)
mutex_unlock(&dasd_reserve_mutex);
@@ -3036,6 +3042,8 @@ dasd_eckd_steal_lock(struct dasd_device *device)
cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr);
+ if (!rc)
+ set_bit(DASD_FLAG_IS_RESERVED, &device->flags);
if (useglobal)
mutex_unlock(&dasd_reserve_mutex);
@@ -3088,6 +3096,7 @@ static int dasd_eckd_snid(struct dasd_device *device,
cqr->memdev = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+ set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags);
cqr->retries = 5;
cqr->expires = 10 * HZ;
cqr->buildclk = get_clock();
@@ -3832,7 +3841,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
.format_device = dasd_eckd_format_device,
.erp_action = dasd_eckd_erp_action,
.erp_postaction = dasd_eckd_erp_postaction,
- .handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt,
+ .check_for_device_change = dasd_eckd_check_for_device_change,
.build_cp = dasd_eckd_build_alias_cp,
.free_cp = dasd_eckd_free_alias_cp,
.dump_sense = dasd_eckd_dump_sense,