aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorStefan Weinhuber <wein@de.ibm.com>2010-10-25 10:10:47 -0400
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-10-25 10:10:20 -0400
commita5a0061fb3a22bbd9b108af8382142fd0f41ebee (patch)
tree03e643e12b634b201201cddb162de46aa744595b /drivers/s390
parent26cffecf84c8cb33787dd13a72bd2124d107d413 (diff)
[S390] dasd: fix unsolicited interrupt recognition
The dasd interrupt handler needs to distinguish solicited from unsolicited interrupts, as unsolicited interrupts may require special handling (e.g. summary unit checks) and solicited interrupts require proper error recovery for the failed I/O request. The interrupt handler needs to check several bit fields in the interrupt response block (irb) to make this distinction. So far our check of the status control bits has not been specific enough, which may lead to a failed request getting just retried instead of the necessary error recovery. Signed-off-by: Stefan Weinhuber <wein@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c11
-rw-r--r--drivers/s390/block/dasd_eckd.c70
2 files changed, 40 insertions, 41 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index aa95f1001761..80e45de096a9 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1099,11 +1099,20 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
1099 cqr = (struct dasd_ccw_req *) intparm; 1099 cqr = (struct dasd_ccw_req *) intparm;
1100 if (!cqr || ((scsw_cc(&irb->scsw) == 1) && 1100 if (!cqr || ((scsw_cc(&irb->scsw) == 1) &&
1101 (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && 1101 (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) &&
1102 (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))) { 1102 ((scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND) ||
1103 (scsw_stctl(&irb->scsw) == (SCSW_STCTL_STATUS_PEND |
1104 SCSW_STCTL_ALERT_STATUS))))) {
1103 if (cqr && cqr->status == DASD_CQR_IN_IO) 1105 if (cqr && cqr->status == DASD_CQR_IN_IO)
1104 cqr->status = DASD_CQR_QUEUED; 1106 cqr->status = DASD_CQR_QUEUED;
1107 if (cqr)
1108 memcpy(&cqr->irb, irb, sizeof(*irb));
1105 device = dasd_device_from_cdev_locked(cdev); 1109 device = dasd_device_from_cdev_locked(cdev);
1106 if (!IS_ERR(device)) { 1110 if (!IS_ERR(device)) {
1111 device->discipline->dump_sense_dbf(device, irb,
1112 "unsolicited");
1113 if ((device->features & DASD_FEATURE_ERPLOG))
1114 device->discipline->dump_sense(device, cqr,
1115 irb);
1107 dasd_device_clear_timer(device); 1116 dasd_device_clear_timer(device);
1108 device->discipline->handle_unsolicited_interrupt(device, 1117 device->discipline->handle_unsolicited_interrupt(device,
1109 irb); 1118 irb);
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index ea0e565ebc9d..50cf96389d2c 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1776,13 +1776,13 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
1776 } 1776 }
1777 1777
1778 /* summary unit check */ 1778 /* summary unit check */
1779 if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && 1779 sense = dasd_get_sense(irb);
1780 (irb->ecw[7] == 0x0D)) { 1780 if (sense && (sense[7] == 0x0D) &&
1781 (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) {
1781 dasd_alias_handle_summary_unit_check(device, irb); 1782 dasd_alias_handle_summary_unit_check(device, irb);
1782 return; 1783 return;
1783 } 1784 }
1784 1785
1785 sense = dasd_get_sense(irb);
1786 /* service information message SIM */ 1786 /* service information message SIM */
1787 if (sense && !(sense[27] & DASD_SENSE_BIT_0) && 1787 if (sense && !(sense[27] & DASD_SENSE_BIT_0) &&
1788 ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { 1788 ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) {
@@ -1791,26 +1791,15 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
1791 return; 1791 return;
1792 } 1792 }
1793 1793
1794 if ((scsw_cc(&irb->scsw) == 1) && 1794 if ((scsw_cc(&irb->scsw) == 1) && !sense &&
1795 (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && 1795 (scsw_fctl(&irb->scsw) == SCSW_FCTL_START_FUNC) &&
1796 (scsw_actl(&irb->scsw) & SCSW_ACTL_START_PEND) && 1796 (scsw_actl(&irb->scsw) == SCSW_ACTL_START_PEND) &&
1797 (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) { 1797 (scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND)) {
1798 /* fake irb do nothing, they are handled elsewhere */ 1798 /* fake irb do nothing, they are handled elsewhere */
1799 dasd_schedule_device_bh(device); 1799 dasd_schedule_device_bh(device);
1800 return; 1800 return;
1801 } 1801 }
1802 1802
1803 if (!sense) {
1804 /* just report other unsolicited interrupts */
1805 DBF_DEV_EVENT(DBF_ERR, device, "%s",
1806 "unsolicited interrupt received");
1807 } else {
1808 DBF_DEV_EVENT(DBF_ERR, device, "%s",
1809 "unsolicited interrupt received "
1810 "(sense available)");
1811 device->discipline->dump_sense_dbf(device, irb, "unsolicited");
1812 }
1813
1814 dasd_schedule_device_bh(device); 1803 dasd_schedule_device_bh(device);
1815 return; 1804 return;
1816}; 1805};
@@ -3093,23 +3082,19 @@ dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct irb *irb,
3093 char *reason) 3082 char *reason)
3094{ 3083{
3095 u64 *sense; 3084 u64 *sense;
3096 u32 stat; 3085 u64 *stat;
3097 3086
3098 sense = (u64 *) dasd_get_sense(irb); 3087 sense = (u64 *) dasd_get_sense(irb);
3099 stat = scsw_cstat(&irb->scsw); 3088 stat = (u64 *) &irb->scsw;
3100 stat <<= 8;
3101 stat |= scsw_dstat(&irb->scsw);
3102 stat <<= 8;
3103 stat |= scsw_cc(&irb->scsw);
3104
3105 if (sense) { 3089 if (sense) {
3106 DBF_DEV_EVENT(DBF_EMERG, device, 3090 DBF_DEV_EVENT(DBF_EMERG, device, "%s: %016llx %08x : "
3107 "%s: %s %06x %016llx %016llx %016llx %016llx", 3091 "%016llx %016llx %016llx %016llx",
3108 reason, scsw_is_tm(&irb->scsw) ? "t" : "c", stat, 3092 reason, *stat, *((u32 *) (stat + 1)),
3109 sense[0], sense[1], sense[2], sense[3]); 3093 sense[0], sense[1], sense[2], sense[3]);
3110 } else { 3094 } else {
3111 DBF_DEV_EVENT(DBF_EMERG, device, "%s", 3095 DBF_DEV_EVENT(DBF_EMERG, device, "%s: %016llx %08x : %s",
3112 "SORRY - NO VALID SENSE AVAILABLE\n"); 3096 reason, *stat, *((u32 *) (stat + 1)),
3097 "NO VALID SENSE");
3113 } 3098 }
3114} 3099}
3115 3100
@@ -3135,9 +3120,12 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
3135 " I/O status report for device %s:\n", 3120 " I/O status report for device %s:\n",
3136 dev_name(&device->cdev->dev)); 3121 dev_name(&device->cdev->dev));
3137 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 3122 len += sprintf(page + len, KERN_ERR PRINTK_HEADER
3138 " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d\n", 3123 " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X "
3139 req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), 3124 "CS:%02X RC:%d\n",
3140 scsw_cc(&irb->scsw), req ? req->intrc : 0); 3125 req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw),
3126 scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw),
3127 scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw),
3128 req ? req->intrc : 0);
3141 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 3129 len += sprintf(page + len, KERN_ERR PRINTK_HEADER
3142 " device %s: Failing CCW: %p\n", 3130 " device %s: Failing CCW: %p\n",
3143 dev_name(&device->cdev->dev), 3131 dev_name(&device->cdev->dev),
@@ -3238,11 +3226,13 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
3238 " I/O status report for device %s:\n", 3226 " I/O status report for device %s:\n",
3239 dev_name(&device->cdev->dev)); 3227 dev_name(&device->cdev->dev));
3240 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 3228 len += sprintf(page + len, KERN_ERR PRINTK_HEADER
3241 " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d " 3229 " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X "
3242 "fcxs: 0x%02X schxs: 0x%02X\n", req, 3230 "CS:%02X fcxs:%02X schxs:%02X RC:%d\n",
3243 scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), 3231 req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw),
3244 scsw_cc(&irb->scsw), req->intrc, 3232 scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw),
3245 irb->scsw.tm.fcxs, irb->scsw.tm.schxs); 3233 scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw),
3234 irb->scsw.tm.fcxs, irb->scsw.tm.schxs,
3235 req ? req->intrc : 0);
3246 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 3236 len += sprintf(page + len, KERN_ERR PRINTK_HEADER
3247 " device %s: Failing TCW: %p\n", 3237 " device %s: Failing TCW: %p\n",
3248 dev_name(&device->cdev->dev), 3238 dev_name(&device->cdev->dev),
@@ -3250,7 +3240,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
3250 3240
3251 tsb = NULL; 3241 tsb = NULL;
3252 sense = NULL; 3242 sense = NULL;
3253 if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs == 0x01)) 3243 if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs & 0x01))
3254 tsb = tcw_get_tsb( 3244 tsb = tcw_get_tsb(
3255 (struct tcw *)(unsigned long)irb->scsw.tm.tcw); 3245 (struct tcw *)(unsigned long)irb->scsw.tm.tcw);
3256 3246
@@ -3348,7 +3338,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
3348static void dasd_eckd_dump_sense(struct dasd_device *device, 3338static void dasd_eckd_dump_sense(struct dasd_device *device,
3349 struct dasd_ccw_req *req, struct irb *irb) 3339 struct dasd_ccw_req *req, struct irb *irb)
3350{ 3340{
3351 if (req && scsw_is_tm(&req->irb.scsw)) 3341 if (scsw_is_tm(&irb->scsw))
3352 dasd_eckd_dump_sense_tcw(device, req, irb); 3342 dasd_eckd_dump_sense_tcw(device, req, irb);
3353 else 3343 else
3354 dasd_eckd_dump_sense_ccw(device, req, irb); 3344 dasd_eckd_dump_sense_ccw(device, req, irb);