diff options
author | Stefan Weinhuber <wein@de.ibm.com> | 2011-01-05 06:48:04 -0500 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2011-01-05 06:47:30 -0500 |
commit | 5a27e60dec59a95bd7f8ae9a19ae2ede4f76395b (patch) | |
tree | 20595cba0caebf7a8a5f0afac9785c7d717f3e8c /drivers | |
parent | a4d26c6aeceea330ee5e0fb6b017d57e3b252d29 (diff) |
[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')
-rw-r--r-- | drivers/s390/block/dasd.c | 75 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 99 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 51 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eer.c | 1 | ||||
-rw-r--r-- | drivers/s390/block/dasd_fba.c | 18 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 13 |
6 files changed, 188 insertions, 69 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 8f2067bc88c0..f16afe74464f 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -902,6 +902,16 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
902 | return rc; | 902 | return rc; |
903 | } | 903 | } |
904 | device = (struct dasd_device *) cqr->startdev; | 904 | device = (struct dasd_device *) cqr->startdev; |
905 | if (((cqr->block && | ||
906 | test_bit(DASD_FLAG_LOCK_STOLEN, &cqr->block->base->flags)) || | ||
907 | test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) && | ||
908 | !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { | ||
909 | DBF_DEV_EVENT(DBF_DEBUG, device, "start_IO: return request %p " | ||
910 | "because of stolen lock", cqr); | ||
911 | cqr->status = DASD_CQR_ERROR; | ||
912 | cqr->intrc = -EPERM; | ||
913 | return -EPERM; | ||
914 | } | ||
905 | if (cqr->retries < 0) { | 915 | if (cqr->retries < 0) { |
906 | /* internal error 14 - start_IO run out of retries */ | 916 | /* internal error 14 - start_IO run out of retries */ |
907 | sprintf(errorstring, "14 %p", cqr); | 917 | sprintf(errorstring, "14 %p", cqr); |
@@ -1115,16 +1125,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1115 | } | 1125 | } |
1116 | 1126 | ||
1117 | now = get_clock(); | 1127 | now = get_clock(); |
1118 | |||
1119 | /* check for unsolicited interrupts */ | ||
1120 | cqr = (struct dasd_ccw_req *) intparm; | 1128 | cqr = (struct dasd_ccw_req *) intparm; |
1121 | if (!cqr || ((scsw_cc(&irb->scsw) == 1) && | 1129 | /* check for conditions that should be handled immediately */ |
1122 | (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && | 1130 | if (!cqr || |
1123 | ((scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND) || | 1131 | !(scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && |
1124 | (scsw_stctl(&irb->scsw) == (SCSW_STCTL_STATUS_PEND | | 1132 | scsw_cstat(&irb->scsw) == 0)) { |
1125 | SCSW_STCTL_ALERT_STATUS))))) { | ||
1126 | if (cqr && cqr->status == DASD_CQR_IN_IO) | ||
1127 | cqr->status = DASD_CQR_QUEUED; | ||
1128 | if (cqr) | 1133 | if (cqr) |
1129 | memcpy(&cqr->irb, irb, sizeof(*irb)); | 1134 | memcpy(&cqr->irb, irb, sizeof(*irb)); |
1130 | device = dasd_device_from_cdev_locked(cdev); | 1135 | device = dasd_device_from_cdev_locked(cdev); |
@@ -1135,17 +1140,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1135 | dasd_put_device(device); | 1140 | dasd_put_device(device); |
1136 | return; | 1141 | return; |
1137 | } | 1142 | } |
1138 | device->discipline->dump_sense_dbf(device, irb, | 1143 | device->discipline->dump_sense_dbf(device, irb, "int"); |
1139 | "unsolicited"); | 1144 | if (device->features & DASD_FEATURE_ERPLOG) |
1140 | if ((device->features & DASD_FEATURE_ERPLOG)) | 1145 | device->discipline->dump_sense(device, cqr, irb); |
1141 | device->discipline->dump_sense(device, cqr, | 1146 | device->discipline->check_for_device_change(device, cqr, irb); |
1142 | irb); | ||
1143 | dasd_device_clear_timer(device); | ||
1144 | device->discipline->handle_unsolicited_interrupt(device, | ||
1145 | irb); | ||
1146 | dasd_put_device(device); | 1147 | dasd_put_device(device); |
1147 | return; | ||
1148 | } | 1148 | } |
1149 | if (!cqr) | ||
1150 | return; | ||
1149 | 1151 | ||
1150 | device = (struct dasd_device *) cqr->startdev; | 1152 | device = (struct dasd_device *) cqr->startdev; |
1151 | if (!device || | 1153 | if (!device || |
@@ -1185,13 +1187,6 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1185 | struct dasd_ccw_req, devlist); | 1187 | struct dasd_ccw_req, devlist); |
1186 | } | 1188 | } |
1187 | } else { /* error */ | 1189 | } else { /* error */ |
1188 | memcpy(&cqr->irb, irb, sizeof(struct irb)); | ||
1189 | /* log sense for every failed I/O to s390 debugfeature */ | ||
1190 | dasd_log_sense_dbf(cqr, irb); | ||
1191 | if (device->features & DASD_FEATURE_ERPLOG) { | ||
1192 | dasd_log_sense(cqr, irb); | ||
1193 | } | ||
1194 | |||
1195 | /* | 1190 | /* |
1196 | * If we don't want complex ERP for this request, then just | 1191 | * If we don't want complex ERP for this request, then just |
1197 | * reset this and retry it in the fastpath | 1192 | * reset this and retry it in the fastpath |
@@ -1232,13 +1227,13 @@ enum uc_todo dasd_generic_uc_handler(struct ccw_device *cdev, struct irb *irb) | |||
1232 | goto out; | 1227 | goto out; |
1233 | if (test_bit(DASD_FLAG_OFFLINE, &device->flags) || | 1228 | if (test_bit(DASD_FLAG_OFFLINE, &device->flags) || |
1234 | device->state != device->target || | 1229 | device->state != device->target || |
1235 | !device->discipline->handle_unsolicited_interrupt){ | 1230 | !device->discipline->check_for_device_change){ |
1236 | dasd_put_device(device); | 1231 | dasd_put_device(device); |
1237 | goto out; | 1232 | goto out; |
1238 | } | 1233 | } |
1239 | 1234 | if (device->discipline->dump_sense_dbf) | |
1240 | dasd_device_clear_timer(device); | 1235 | device->discipline->dump_sense_dbf(device, irb, "uc"); |
1241 | device->discipline->handle_unsolicited_interrupt(device, irb); | 1236 | device->discipline->check_for_device_change(device, NULL, irb); |
1242 | dasd_put_device(device); | 1237 | dasd_put_device(device); |
1243 | out: | 1238 | out: |
1244 | return UC_TODO_RETRY; | 1239 | return UC_TODO_RETRY; |
@@ -1659,7 +1654,12 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) | |||
1659 | continue; | 1654 | continue; |
1660 | if (cqr->status != DASD_CQR_FILLED) /* could be failed */ | 1655 | if (cqr->status != DASD_CQR_FILLED) /* could be failed */ |
1661 | continue; | 1656 | continue; |
1662 | 1657 | if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) && | |
1658 | !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { | ||
1659 | cqr->status = DASD_CQR_FAILED; | ||
1660 | cqr->intrc = -EPERM; | ||
1661 | continue; | ||
1662 | } | ||
1663 | /* Non-temporary stop condition will trigger fail fast */ | 1663 | /* Non-temporary stop condition will trigger fail fast */ |
1664 | if (device->stopped & ~DASD_STOPPED_PENDING && | 1664 | if (device->stopped & ~DASD_STOPPED_PENDING && |
1665 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && | 1665 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && |
@@ -1667,7 +1667,6 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) | |||
1667 | cqr->status = DASD_CQR_FAILED; | 1667 | cqr->status = DASD_CQR_FAILED; |
1668 | continue; | 1668 | continue; |
1669 | } | 1669 | } |
1670 | |||
1671 | /* Don't try to start requests if device is stopped */ | 1670 | /* Don't try to start requests if device is stopped */ |
1672 | if (interruptible) { | 1671 | if (interruptible) { |
1673 | rc = wait_event_interruptible( | 1672 | rc = wait_event_interruptible( |
@@ -1752,13 +1751,18 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) | |||
1752 | int rc; | 1751 | int rc; |
1753 | 1752 | ||
1754 | device = cqr->startdev; | 1753 | device = cqr->startdev; |
1754 | if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) && | ||
1755 | !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { | ||
1756 | cqr->status = DASD_CQR_FAILED; | ||
1757 | cqr->intrc = -EPERM; | ||
1758 | return -EIO; | ||
1759 | } | ||
1755 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | 1760 | spin_lock_irq(get_ccwdev_lock(device->cdev)); |
1756 | rc = _dasd_term_running_cqr(device); | 1761 | rc = _dasd_term_running_cqr(device); |
1757 | if (rc) { | 1762 | if (rc) { |
1758 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | 1763 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); |
1759 | return rc; | 1764 | return rc; |
1760 | } | 1765 | } |
1761 | |||
1762 | cqr->callback = dasd_wakeup_cb; | 1766 | cqr->callback = dasd_wakeup_cb; |
1763 | cqr->callback_data = DASD_SLEEPON_START_TAG; | 1767 | cqr->callback_data = DASD_SLEEPON_START_TAG; |
1764 | cqr->status = DASD_CQR_QUEUED; | 1768 | cqr->status = DASD_CQR_QUEUED; |
@@ -2062,6 +2066,13 @@ static void __dasd_block_start_head(struct dasd_block *block) | |||
2062 | list_for_each_entry(cqr, &block->ccw_queue, blocklist) { | 2066 | list_for_each_entry(cqr, &block->ccw_queue, blocklist) { |
2063 | if (cqr->status != DASD_CQR_FILLED) | 2067 | if (cqr->status != DASD_CQR_FILLED) |
2064 | continue; | 2068 | continue; |
2069 | if (test_bit(DASD_FLAG_LOCK_STOLEN, &block->base->flags) && | ||
2070 | !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { | ||
2071 | cqr->status = DASD_CQR_FAILED; | ||
2072 | cqr->intrc = -EPERM; | ||
2073 | dasd_schedule_block_bh(block); | ||
2074 | continue; | ||
2075 | } | ||
2065 | /* Non-temporary stop condition will trigger fail fast */ | 2076 | /* Non-temporary stop condition will trigger fail fast */ |
2066 | if (block->base->stopped & ~DASD_STOPPED_PENDING && | 2077 | if (block->base->stopped & ~DASD_STOPPED_PENDING && |
2067 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && | 2078 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 0001df8ad3e6..47fc88692494 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -1127,6 +1127,103 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr, | |||
1127 | 1127 | ||
1128 | static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store); | 1128 | static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store); |
1129 | 1129 | ||
1130 | static ssize_t dasd_reservation_policy_show(struct device *dev, | ||
1131 | struct device_attribute *attr, | ||
1132 | char *buf) | ||
1133 | { | ||
1134 | struct dasd_devmap *devmap; | ||
1135 | int rc = 0; | ||
1136 | |||
1137 | devmap = dasd_find_busid(dev_name(dev)); | ||
1138 | if (IS_ERR(devmap)) { | ||
1139 | rc = snprintf(buf, PAGE_SIZE, "ignore\n"); | ||
1140 | } else { | ||
1141 | spin_lock(&dasd_devmap_lock); | ||
1142 | if (devmap->features & DASD_FEATURE_FAILONSLCK) | ||
1143 | rc = snprintf(buf, PAGE_SIZE, "fail\n"); | ||
1144 | else | ||
1145 | rc = snprintf(buf, PAGE_SIZE, "ignore\n"); | ||
1146 | spin_unlock(&dasd_devmap_lock); | ||
1147 | } | ||
1148 | return rc; | ||
1149 | } | ||
1150 | |||
1151 | static ssize_t dasd_reservation_policy_store(struct device *dev, | ||
1152 | struct device_attribute *attr, | ||
1153 | const char *buf, size_t count) | ||
1154 | { | ||
1155 | struct dasd_devmap *devmap; | ||
1156 | int rc; | ||
1157 | |||
1158 | devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); | ||
1159 | if (IS_ERR(devmap)) | ||
1160 | return PTR_ERR(devmap); | ||
1161 | rc = 0; | ||
1162 | spin_lock(&dasd_devmap_lock); | ||
1163 | if (sysfs_streq("ignore", buf)) | ||
1164 | devmap->features &= ~DASD_FEATURE_FAILONSLCK; | ||
1165 | else if (sysfs_streq("fail", buf)) | ||
1166 | devmap->features |= DASD_FEATURE_FAILONSLCK; | ||
1167 | else | ||
1168 | rc = -EINVAL; | ||
1169 | if (devmap->device) | ||
1170 | devmap->device->features = devmap->features; | ||
1171 | spin_unlock(&dasd_devmap_lock); | ||
1172 | if (rc) | ||
1173 | return rc; | ||
1174 | else | ||
1175 | return count; | ||
1176 | } | ||
1177 | |||
1178 | static DEVICE_ATTR(reservation_policy, 0644, | ||
1179 | dasd_reservation_policy_show, dasd_reservation_policy_store); | ||
1180 | |||
1181 | static ssize_t dasd_reservation_state_show(struct device *dev, | ||
1182 | struct device_attribute *attr, | ||
1183 | char *buf) | ||
1184 | { | ||
1185 | struct dasd_device *device; | ||
1186 | int rc = 0; | ||
1187 | |||
1188 | device = dasd_device_from_cdev(to_ccwdev(dev)); | ||
1189 | if (IS_ERR(device)) | ||
1190 | return snprintf(buf, PAGE_SIZE, "none\n"); | ||
1191 | |||
1192 | if (test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) | ||
1193 | rc = snprintf(buf, PAGE_SIZE, "reserved\n"); | ||
1194 | else if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) | ||
1195 | rc = snprintf(buf, PAGE_SIZE, "lost\n"); | ||
1196 | else | ||
1197 | rc = snprintf(buf, PAGE_SIZE, "none\n"); | ||
1198 | dasd_put_device(device); | ||
1199 | return rc; | ||
1200 | } | ||
1201 | |||
1202 | static ssize_t dasd_reservation_state_store(struct device *dev, | ||
1203 | struct device_attribute *attr, | ||
1204 | const char *buf, size_t count) | ||
1205 | { | ||
1206 | struct dasd_device *device; | ||
1207 | int rc = 0; | ||
1208 | |||
1209 | device = dasd_device_from_cdev(to_ccwdev(dev)); | ||
1210 | if (IS_ERR(device)) | ||
1211 | return -ENODEV; | ||
1212 | if (sysfs_streq("reset", buf)) | ||
1213 | clear_bit(DASD_FLAG_LOCK_STOLEN, &device->flags); | ||
1214 | else | ||
1215 | rc = -EINVAL; | ||
1216 | dasd_put_device(device); | ||
1217 | |||
1218 | if (rc) | ||
1219 | return rc; | ||
1220 | else | ||
1221 | return count; | ||
1222 | } | ||
1223 | |||
1224 | static DEVICE_ATTR(last_known_reservation_state, 0644, | ||
1225 | dasd_reservation_state_show, dasd_reservation_state_store); | ||
1226 | |||
1130 | static struct attribute * dasd_attrs[] = { | 1227 | static struct attribute * dasd_attrs[] = { |
1131 | &dev_attr_readonly.attr, | 1228 | &dev_attr_readonly.attr, |
1132 | &dev_attr_discipline.attr, | 1229 | &dev_attr_discipline.attr, |
@@ -1139,6 +1236,8 @@ static struct attribute * dasd_attrs[] = { | |||
1139 | &dev_attr_erplog.attr, | 1236 | &dev_attr_erplog.attr, |
1140 | &dev_attr_failfast.attr, | 1237 | &dev_attr_failfast.attr, |
1141 | &dev_attr_expires.attr, | 1238 | &dev_attr_expires.attr, |
1239 | &dev_attr_reservation_policy.attr, | ||
1240 | &dev_attr_last_known_reservation_state.attr, | ||
1142 | NULL, | 1241 | NULL, |
1143 | }; | 1242 | }; |
1144 | 1243 | ||
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index a1ebf5722ae5..46eafce3a0a6 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, | |||
817 | 817 | ||
818 | dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buffer, lpm); | 818 | dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buffer, lpm); |
819 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 819 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
820 | set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); | ||
820 | cqr->retries = 5; | 821 | cqr->retries = 5; |
821 | rc = dasd_sleep_on_immediatly(cqr); | 822 | rc = dasd_sleep_on_immediatly(cqr); |
822 | return rc; | 823 | return rc; |
@@ -1947,9 +1948,9 @@ dasd_eckd_erp_postaction(struct dasd_ccw_req * cqr) | |||
1947 | return dasd_default_erp_postaction; | 1948 | return dasd_default_erp_postaction; |
1948 | } | 1949 | } |
1949 | 1950 | ||
1950 | 1951 | static void dasd_eckd_check_for_device_change(struct dasd_device *device, | |
1951 | static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, | 1952 | struct dasd_ccw_req *cqr, |
1952 | struct irb *irb) | 1953 | struct irb *irb) |
1953 | { | 1954 | { |
1954 | char mask; | 1955 | char mask; |
1955 | char *sense = NULL; | 1956 | char *sense = NULL; |
@@ -1973,40 +1974,41 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, | |||
1973 | /* schedule worker to reload device */ | 1974 | /* schedule worker to reload device */ |
1974 | dasd_reload_device(device); | 1975 | dasd_reload_device(device); |
1975 | } | 1976 | } |
1976 | |||
1977 | dasd_generic_handle_state_change(device); | 1977 | dasd_generic_handle_state_change(device); |
1978 | return; | 1978 | return; |
1979 | } | 1979 | } |
1980 | 1980 | ||
1981 | /* summary unit check */ | ||
1982 | sense = dasd_get_sense(irb); | 1981 | sense = dasd_get_sense(irb); |
1983 | if (sense && (sense[7] == 0x0D) && | 1982 | if (!sense) |
1983 | return; | ||
1984 | |||
1985 | /* summary unit check */ | ||
1986 | if ((sense[7] == 0x0D) && | ||
1984 | (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) { | 1987 | (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) { |
1985 | dasd_alias_handle_summary_unit_check(device, irb); | 1988 | dasd_alias_handle_summary_unit_check(device, irb); |
1986 | return; | 1989 | return; |
1987 | } | 1990 | } |
1988 | 1991 | ||
1989 | /* service information message SIM */ | 1992 | /* service information message SIM */ |
1990 | if (sense && !(sense[27] & DASD_SENSE_BIT_0) && | 1993 | if (!cqr && !(sense[27] & DASD_SENSE_BIT_0) && |
1991 | ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { | 1994 | ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { |
1992 | dasd_3990_erp_handle_sim(device, sense); | 1995 | dasd_3990_erp_handle_sim(device, sense); |
1993 | dasd_schedule_device_bh(device); | ||
1994 | return; | 1996 | return; |
1995 | } | 1997 | } |
1996 | 1998 | ||
1997 | if ((scsw_cc(&irb->scsw) == 1) && !sense && | 1999 | /* loss of device reservation is handled via base devices only |
1998 | (scsw_fctl(&irb->scsw) == SCSW_FCTL_START_FUNC) && | 2000 | * as alias devices may be used with several bases |
1999 | (scsw_actl(&irb->scsw) == SCSW_ACTL_START_PEND) && | 2001 | */ |
2000 | (scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND)) { | 2002 | if (device->block && (sense[7] == 0x3F) && |
2001 | /* fake irb do nothing, they are handled elsewhere */ | 2003 | (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && |
2002 | dasd_schedule_device_bh(device); | 2004 | test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) { |
2003 | return; | 2005 | if (device->features & DASD_FEATURE_FAILONSLCK) |
2006 | set_bit(DASD_FLAG_LOCK_STOLEN, &device->flags); | ||
2007 | clear_bit(DASD_FLAG_IS_RESERVED, &device->flags); | ||
2008 | dev_err(&device->cdev->dev, | ||
2009 | "The device reservation was lost\n"); | ||
2004 | } | 2010 | } |
2005 | 2011 | } | |
2006 | dasd_schedule_device_bh(device); | ||
2007 | return; | ||
2008 | }; | ||
2009 | |||
2010 | 2012 | ||
2011 | static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( | 2013 | static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( |
2012 | struct dasd_device *startdev, | 2014 | struct dasd_device *startdev, |
@@ -2931,6 +2933,8 @@ dasd_eckd_release(struct dasd_device *device) | |||
2931 | cqr->status = DASD_CQR_FILLED; | 2933 | cqr->status = DASD_CQR_FILLED; |
2932 | 2934 | ||
2933 | rc = dasd_sleep_on_immediatly(cqr); | 2935 | rc = dasd_sleep_on_immediatly(cqr); |
2936 | if (!rc) | ||
2937 | clear_bit(DASD_FLAG_IS_RESERVED, &device->flags); | ||
2934 | 2938 | ||
2935 | if (useglobal) | 2939 | if (useglobal) |
2936 | mutex_unlock(&dasd_reserve_mutex); | 2940 | mutex_unlock(&dasd_reserve_mutex); |
@@ -2984,6 +2988,8 @@ dasd_eckd_reserve(struct dasd_device *device) | |||
2984 | cqr->status = DASD_CQR_FILLED; | 2988 | cqr->status = DASD_CQR_FILLED; |
2985 | 2989 | ||
2986 | rc = dasd_sleep_on_immediatly(cqr); | 2990 | rc = dasd_sleep_on_immediatly(cqr); |
2991 | if (!rc) | ||
2992 | set_bit(DASD_FLAG_IS_RESERVED, &device->flags); | ||
2987 | 2993 | ||
2988 | if (useglobal) | 2994 | if (useglobal) |
2989 | mutex_unlock(&dasd_reserve_mutex); | 2995 | mutex_unlock(&dasd_reserve_mutex); |
@@ -3036,6 +3042,8 @@ dasd_eckd_steal_lock(struct dasd_device *device) | |||
3036 | cqr->status = DASD_CQR_FILLED; | 3042 | cqr->status = DASD_CQR_FILLED; |
3037 | 3043 | ||
3038 | rc = dasd_sleep_on_immediatly(cqr); | 3044 | rc = dasd_sleep_on_immediatly(cqr); |
3045 | if (!rc) | ||
3046 | set_bit(DASD_FLAG_IS_RESERVED, &device->flags); | ||
3039 | 3047 | ||
3040 | if (useglobal) | 3048 | if (useglobal) |
3041 | mutex_unlock(&dasd_reserve_mutex); | 3049 | mutex_unlock(&dasd_reserve_mutex); |
@@ -3088,6 +3096,7 @@ static int dasd_eckd_snid(struct dasd_device *device, | |||
3088 | cqr->memdev = device; | 3096 | cqr->memdev = device; |
3089 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 3097 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
3090 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | 3098 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); |
3099 | set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); | ||
3091 | cqr->retries = 5; | 3100 | cqr->retries = 5; |
3092 | cqr->expires = 10 * HZ; | 3101 | cqr->expires = 10 * HZ; |
3093 | cqr->buildclk = get_clock(); | 3102 | cqr->buildclk = get_clock(); |
@@ -3832,7 +3841,7 @@ static struct dasd_discipline dasd_eckd_discipline = { | |||
3832 | .format_device = dasd_eckd_format_device, | 3841 | .format_device = dasd_eckd_format_device, |
3833 | .erp_action = dasd_eckd_erp_action, | 3842 | .erp_action = dasd_eckd_erp_action, |
3834 | .erp_postaction = dasd_eckd_erp_postaction, | 3843 | .erp_postaction = dasd_eckd_erp_postaction, |
3835 | .handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt, | 3844 | .check_for_device_change = dasd_eckd_check_for_device_change, |
3836 | .build_cp = dasd_eckd_build_alias_cp, | 3845 | .build_cp = dasd_eckd_build_alias_cp, |
3837 | .free_cp = dasd_eckd_free_alias_cp, | 3846 | .free_cp = dasd_eckd_free_alias_cp, |
3838 | .dump_sense = dasd_eckd_dump_sense, | 3847 | .dump_sense = dasd_eckd_dump_sense, |
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 83b4615a3b62..77f778b7b070 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c | |||
@@ -473,6 +473,7 @@ int dasd_eer_enable(struct dasd_device *device) | |||
473 | cqr->retries = 255; | 473 | cqr->retries = 255; |
474 | cqr->expires = 10 * HZ; | 474 | cqr->expires = 10 * HZ; |
475 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 475 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
476 | set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); | ||
476 | 477 | ||
477 | ccw = cqr->cpaddr; | 478 | ccw = cqr->cpaddr; |
478 | ccw->cmd_code = DASD_ECKD_CCW_SNSS; | 479 | ccw->cmd_code = DASD_ECKD_CCW_SNSS; |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 86bacda2c5f6..be89b3a893da 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -233,24 +233,16 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr) | |||
233 | return NULL; | 233 | return NULL; |
234 | } | 234 | } |
235 | 235 | ||
236 | static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device, | 236 | static void dasd_fba_check_for_device_change(struct dasd_device *device, |
237 | struct irb *irb) | 237 | struct dasd_ccw_req *cqr, |
238 | struct irb *irb) | ||
238 | { | 239 | { |
239 | char mask; | 240 | char mask; |
240 | 241 | ||
241 | /* first of all check for state change pending interrupt */ | 242 | /* first of all check for state change pending interrupt */ |
242 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; | 243 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; |
243 | if ((irb->scsw.cmd.dstat & mask) == mask) { | 244 | if ((irb->scsw.cmd.dstat & mask) == mask) |
244 | dasd_generic_handle_state_change(device); | 245 | dasd_generic_handle_state_change(device); |
245 | return; | ||
246 | } | ||
247 | |||
248 | /* check for unsolicited interrupts */ | ||
249 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | ||
250 | "unsolicited interrupt received"); | ||
251 | device->discipline->dump_sense_dbf(device, irb, "unsolicited"); | ||
252 | dasd_schedule_device_bh(device); | ||
253 | return; | ||
254 | }; | 246 | }; |
255 | 247 | ||
256 | static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, | 248 | static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, |
@@ -605,7 +597,7 @@ static struct dasd_discipline dasd_fba_discipline = { | |||
605 | .handle_terminated_request = dasd_fba_handle_terminated_request, | 597 | .handle_terminated_request = dasd_fba_handle_terminated_request, |
606 | .erp_action = dasd_fba_erp_action, | 598 | .erp_action = dasd_fba_erp_action, |
607 | .erp_postaction = dasd_fba_erp_postaction, | 599 | .erp_postaction = dasd_fba_erp_postaction, |
608 | .handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt, | 600 | .check_for_device_change = dasd_fba_check_for_device_change, |
609 | .build_cp = dasd_fba_build_cp, | 601 | .build_cp = dasd_fba_build_cp, |
610 | .free_cp = dasd_fba_free_cp, | 602 | .free_cp = dasd_fba_free_cp, |
611 | .dump_sense = dasd_fba_dump_sense, | 603 | .dump_sense = dasd_fba_dump_sense, |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index ba038ef57606..df9f6999411d 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -232,6 +232,10 @@ struct dasd_ccw_req { | |||
232 | #define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ | 232 | #define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ |
233 | #define DASD_CQR_FLAGS_FAILFAST 1 /* FAILFAST */ | 233 | #define DASD_CQR_FLAGS_FAILFAST 1 /* FAILFAST */ |
234 | #define DASD_CQR_VERIFY_PATH 2 /* path verification request */ | 234 | #define DASD_CQR_VERIFY_PATH 2 /* path verification request */ |
235 | #define DASD_CQR_ALLOW_SLOCK 3 /* Try this request even when lock was | ||
236 | * stolen. Should not be combined with | ||
237 | * DASD_CQR_FLAGS_USE_ERP | ||
238 | */ | ||
235 | 239 | ||
236 | /* Signature for error recovery functions. */ | 240 | /* Signature for error recovery functions. */ |
237 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); | 241 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); |
@@ -334,9 +338,9 @@ struct dasd_discipline { | |||
334 | void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *, | 338 | void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *, |
335 | struct irb *); | 339 | struct irb *); |
336 | void (*dump_sense_dbf) (struct dasd_device *, struct irb *, char *); | 340 | void (*dump_sense_dbf) (struct dasd_device *, struct irb *, char *); |
337 | 341 | void (*check_for_device_change) (struct dasd_device *, | |
338 | void (*handle_unsolicited_interrupt) (struct dasd_device *, | 342 | struct dasd_ccw_req *, |
339 | struct irb *); | 343 | struct irb *); |
340 | 344 | ||
341 | /* i/o control functions. */ | 345 | /* i/o control functions. */ |
342 | int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); | 346 | int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); |
@@ -473,6 +477,9 @@ struct dasd_block { | |||
473 | * confuse this with the user specified | 477 | * confuse this with the user specified |
474 | * read-only feature. | 478 | * read-only feature. |
475 | */ | 479 | */ |
480 | #define DASD_FLAG_IS_RESERVED 7 /* The device is reserved */ | ||
481 | #define DASD_FLAG_LOCK_STOLEN 8 /* The device lock was stolen */ | ||
482 | |||
476 | 483 | ||
477 | void dasd_put_device_wake(struct dasd_device *); | 484 | void dasd_put_device_wake(struct dasd_device *); |
478 | 485 | ||