diff options
| -rw-r--r-- | arch/s390/include/asm/dasd.h | 1 | ||||
| -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 |
7 files changed, 189 insertions, 69 deletions
diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h index b604a9186f8..47fcdada5d2 100644 --- a/arch/s390/include/asm/dasd.h +++ b/arch/s390/include/asm/dasd.h | |||
| @@ -80,6 +80,7 @@ typedef struct dasd_information2_t { | |||
| 80 | #define DASD_FEATURE_INITIAL_ONLINE 0x04 | 80 | #define DASD_FEATURE_INITIAL_ONLINE 0x04 |
| 81 | #define DASD_FEATURE_ERPLOG 0x08 | 81 | #define DASD_FEATURE_ERPLOG 0x08 |
| 82 | #define DASD_FEATURE_FAILFAST 0x10 | 82 | #define DASD_FEATURE_FAILFAST 0x10 |
| 83 | #define DASD_FEATURE_FAILONSLCK 0x20 | ||
| 83 | 84 | ||
| 84 | #define DASD_PARTN_BITS 2 | 85 | #define DASD_PARTN_BITS 2 |
| 85 | 86 | ||
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 8f2067bc88c..f16afe74464 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 0001df8ad3e..47fc8869249 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 a1ebf5722ae..46eafce3a0a 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 83b4615a3b6..77f778b7b07 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 86bacda2c5f..be89b3a893d 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 ba038ef5760..df9f6999411 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 | ||
