aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd_eckd.c
diff options
context:
space:
mode:
authorHorst Hummel <horst.hummel@de.ibm.com>2006-06-29 08:57:52 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2006-06-29 08:57:52 -0400
commit445b5b499e0ca1584ee3aa8af298c9ef8c84d711 (patch)
tree8ba190d75ff787f61bca06b59017ffea43b5aeb7 /drivers/s390/block/dasd_eckd.c
parentf45a43d847c96949d22e702879e52385a1547f6b (diff)
[S390] dasd_eckd_dump_sense bug.
The ccw dump function dasd_eckd_dump_ccw_range can crash because it does not take care about the IDAL flag in the ccw. Check for IDALs flag set in CCW and follow the indirect list to print the data that is refered by the ccw. Signed-off-by: Horst Hummel <horst.hummel@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.c145
1 files changed, 74 insertions, 71 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 7d5a6cee4bd8..7565d30f8c2f 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1522,6 +1522,40 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
1522} 1522}
1523 1523
1524/* 1524/*
1525 * Dump the range of CCWs into 'page' buffer
1526 * and return number of printed chars.
1527 */
1528static inline int
1529dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
1530{
1531 int len, count;
1532 char *datap;
1533
1534 len = 0;
1535 while (from <= to) {
1536 len += sprintf(page + len, KERN_ERR PRINTK_HEADER
1537 " CCW %p: %08X %08X DAT:",
1538 from, ((int *) from)[0], ((int *) from)[1]);
1539
1540 /* get pointer to data (consider IDALs) */
1541 if (from->flags & CCW_FLAG_IDA)
1542 datap = (char *) *((addr_t *) (addr_t) from->cda);
1543 else
1544 datap = (char *) ((addr_t) from->cda);
1545
1546 /* dump data (max 32 bytes) */
1547 for (count = 0; count < from->count && count < 32; count++) {
1548 if (count % 8 == 0) len += sprintf(page + len, " ");
1549 if (count % 4 == 0) len += sprintf(page + len, " ");
1550 len += sprintf(page + len, "%02x", datap[count]);
1551 }
1552 len += sprintf(page + len, "\n");
1553 from++;
1554 }
1555 return len;
1556}
1557
1558/*
1525 * Print sense data and related channel program. 1559 * Print sense data and related channel program.
1526 * Parts are printed because printk buffer is only 1024 bytes. 1560 * Parts are printed because printk buffer is only 1024 bytes.
1527 */ 1561 */
@@ -1530,8 +1564,8 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
1530 struct irb *irb) 1564 struct irb *irb)
1531{ 1565{
1532 char *page; 1566 char *page;
1533 struct ccw1 *act, *end, *last; 1567 struct ccw1 *first, *last, *fail, *from, *to;
1534 int len, sl, sct, count; 1568 int len, sl, sct;
1535 1569
1536 page = (char *) get_zeroed_page(GFP_ATOMIC); 1570 page = (char *) get_zeroed_page(GFP_ATOMIC);
1537 if (page == NULL) { 1571 if (page == NULL) {
@@ -1539,7 +1573,8 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
1539 "No memory to dump sense data"); 1573 "No memory to dump sense data");
1540 return; 1574 return;
1541 } 1575 }
1542 len = sprintf(page, KERN_ERR PRINTK_HEADER 1576 /* dump the sense data */
1577 len = sprintf(page, KERN_ERR PRINTK_HEADER
1543 " I/O status report for device %s:\n", 1578 " I/O status report for device %s:\n",
1544 device->cdev->dev.bus_id); 1579 device->cdev->dev.bus_id);
1545 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 1580 len += sprintf(page + len, KERN_ERR PRINTK_HEADER
@@ -1564,87 +1599,55 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
1564 1599
1565 if (irb->ecw[27] & DASD_SENSE_BIT_0) { 1600 if (irb->ecw[27] & DASD_SENSE_BIT_0) {
1566 /* 24 Byte Sense Data */ 1601 /* 24 Byte Sense Data */
1567 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 1602 sprintf(page + len, KERN_ERR PRINTK_HEADER
1568 " 24 Byte: %x MSG %x, " 1603 " 24 Byte: %x MSG %x, "
1569 "%s MSGb to SYSOP\n", 1604 "%s MSGb to SYSOP\n",
1570 irb->ecw[7] >> 4, irb->ecw[7] & 0x0f, 1605 irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
1571 irb->ecw[1] & 0x10 ? "" : "no"); 1606 irb->ecw[1] & 0x10 ? "" : "no");
1572 } else { 1607 } else {
1573 /* 32 Byte Sense Data */ 1608 /* 32 Byte Sense Data */
1574 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 1609 sprintf(page + len, KERN_ERR PRINTK_HEADER
1575 " 32 Byte: Format: %x " 1610 " 32 Byte: Format: %x "
1576 "Exception class %x\n", 1611 "Exception class %x\n",
1577 irb->ecw[6] & 0x0f, irb->ecw[22] >> 4); 1612 irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
1578 } 1613 }
1579 } else { 1614 } else {
1580 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 1615 sprintf(page + len, KERN_ERR PRINTK_HEADER
1581 " SORRY - NO VALID SENSE AVAILABLE\n"); 1616 " SORRY - NO VALID SENSE AVAILABLE\n");
1582 } 1617 }
1583 MESSAGE_LOG(KERN_ERR, "%s", 1618 printk("%s", page);
1584 page + sizeof(KERN_ERR PRINTK_HEADER)); 1619
1585 1620 /* dump the Channel Program (max 140 Bytes per line) */
1586 /* dump the Channel Program */ 1621 /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
1587 /* print first CCWs (maximum 8) */ 1622 first = req->cpaddr;
1588 act = req->cpaddr; 1623 for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
1589 for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++); 1624 to = min(first + 6, last);
1590 end = min(act + 8, last); 1625 len = sprintf(page, KERN_ERR PRINTK_HEADER
1591 len = sprintf(page, KERN_ERR PRINTK_HEADER
1592 " Related CP in req: %p\n", req); 1626 " Related CP in req: %p\n", req);
1593 while (act <= end) { 1627 dasd_eckd_dump_ccw_range(first, to, page + len);
1594 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 1628 printk("%s", page);
1595 " CCW %p: %08X %08X DAT:",
1596 act, ((int *) act)[0], ((int *) act)[1]);
1597 for (count = 0; count < 32 && count < act->count;
1598 count += sizeof(int))
1599 len += sprintf(page + len, " %08X",
1600 ((int *) (addr_t) act->cda)
1601 [(count>>2)]);
1602 len += sprintf(page + len, "\n");
1603 act++;
1604 }
1605 MESSAGE_LOG(KERN_ERR, "%s",
1606 page + sizeof(KERN_ERR PRINTK_HEADER));
1607 1629
1608 /* print failing CCW area */ 1630 /* print failing CCW area (maximum 4) */
1631 /* scsw->cda is either valid or zero */
1609 len = 0; 1632 len = 0;
1610 if (act < ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) { 1633 from = ++to;
1611 act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2; 1634 fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
1612 len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); 1635 if (from < fail - 2) {
1613 } 1636 from = fail - 2; /* there is a gap - print header */
1614 end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last); 1637 len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
1615 while (act <= end) {
1616 len += sprintf(page + len, KERN_ERR PRINTK_HEADER
1617 " CCW %p: %08X %08X DAT:",
1618 act, ((int *) act)[0], ((int *) act)[1]);
1619 for (count = 0; count < 32 && count < act->count;
1620 count += sizeof(int))
1621 len += sprintf(page + len, " %08X",
1622 ((int *) (addr_t) act->cda)
1623 [(count>>2)]);
1624 len += sprintf(page + len, "\n");
1625 act++;
1626 } 1638 }
1639 to = min(fail + 1, last);
1640 len += dasd_eckd_dump_ccw_range(from, to, page + len);
1627 1641
1628 /* print last CCWs */ 1642 /* print last CCWs (maximum 2) */
1629 if (act < last - 2) { 1643 from = max(from, ++to);
1630 act = last - 2; 1644 if (from < last - 1) {
1645 from = last - 1; /* there is a gap - print header */
1631 len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); 1646 len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
1632 } 1647 }
1633 while (act <= last) { 1648 len += dasd_eckd_dump_ccw_range(from, last, page + len);
1634 len += sprintf(page + len, KERN_ERR PRINTK_HEADER
1635 " CCW %p: %08X %08X DAT:",
1636 act, ((int *) act)[0], ((int *) act)[1]);
1637 for (count = 0; count < 32 && count < act->count;
1638 count += sizeof(int))
1639 len += sprintf(page + len, " %08X",
1640 ((int *) (addr_t) act->cda)
1641 [(count>>2)]);
1642 len += sprintf(page + len, "\n");
1643 act++;
1644 }
1645 if (len > 0) 1649 if (len > 0)
1646 MESSAGE_LOG(KERN_ERR, "%s", 1650 printk("%s", page);
1647 page + sizeof(KERN_ERR PRINTK_HEADER));
1648 free_page((unsigned long) page); 1651 free_page((unsigned long) page);
1649} 1652}
1650 1653