diff options
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 145 |
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 | */ | ||
1528 | static inline int | ||
1529 | dasd_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 | ||