diff options
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r-- | drivers/ata/libata-eh.c | 108 |
1 files changed, 79 insertions, 29 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 9f6b7cc74fd9..08ad44b3e48f 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -1136,19 +1136,21 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, | |||
1136 | break; | 1136 | break; |
1137 | 1137 | ||
1138 | case ATA_DEV_ATAPI: | 1138 | case ATA_DEV_ATAPI: |
1139 | tmp = atapi_eh_request_sense(qc->dev, | 1139 | if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) { |
1140 | qc->scsicmd->sense_buffer); | 1140 | tmp = atapi_eh_request_sense(qc->dev, |
1141 | if (!tmp) { | 1141 | qc->scsicmd->sense_buffer); |
1142 | /* ATA_QCFLAG_SENSE_VALID is used to tell | 1142 | if (!tmp) { |
1143 | * atapi_qc_complete() that sense data is | 1143 | /* ATA_QCFLAG_SENSE_VALID is used to |
1144 | * already valid. | 1144 | * tell atapi_qc_complete() that sense |
1145 | * | 1145 | * data is already valid. |
1146 | * TODO: interpret sense data and set | 1146 | * |
1147 | * appropriate err_mask. | 1147 | * TODO: interpret sense data and set |
1148 | */ | 1148 | * appropriate err_mask. |
1149 | qc->flags |= ATA_QCFLAG_SENSE_VALID; | 1149 | */ |
1150 | } else | 1150 | qc->flags |= ATA_QCFLAG_SENSE_VALID; |
1151 | qc->err_mask |= tmp; | 1151 | } else |
1152 | qc->err_mask |= tmp; | ||
1153 | } | ||
1152 | } | 1154 | } |
1153 | 1155 | ||
1154 | if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) | 1156 | if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) |
@@ -1433,16 +1435,39 @@ static void ata_eh_report(struct ata_port *ap) | |||
1433 | } | 1435 | } |
1434 | 1436 | ||
1435 | for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { | 1437 | for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { |
1438 | static const char *dma_str[] = { | ||
1439 | [DMA_BIDIRECTIONAL] = "bidi", | ||
1440 | [DMA_TO_DEVICE] = "out", | ||
1441 | [DMA_FROM_DEVICE] = "in", | ||
1442 | [DMA_NONE] = "", | ||
1443 | }; | ||
1436 | struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); | 1444 | struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); |
1445 | struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; | ||
1446 | unsigned int nbytes; | ||
1437 | 1447 | ||
1438 | if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask) | 1448 | if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask) |
1439 | continue; | 1449 | continue; |
1440 | 1450 | ||
1441 | ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x " | 1451 | nbytes = qc->nbytes; |
1442 | "Emask 0x%x stat 0x%x err 0x%x (%s)\n", | 1452 | if (!nbytes) |
1443 | qc->tag, qc->tf.command, qc->err_mask, | 1453 | nbytes = qc->nsect << 9; |
1444 | qc->result_tf.command, qc->result_tf.feature, | 1454 | |
1445 | ata_err_string(qc->err_mask)); | 1455 | ata_dev_printk(qc->dev, KERN_ERR, |
1456 | "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " | ||
1457 | "tag %d cdb 0x%x data %u %s\n " | ||
1458 | "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " | ||
1459 | "Emask 0x%x (%s)\n", | ||
1460 | cmd->command, cmd->feature, cmd->nsect, | ||
1461 | cmd->lbal, cmd->lbam, cmd->lbah, | ||
1462 | cmd->hob_feature, cmd->hob_nsect, | ||
1463 | cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah, | ||
1464 | cmd->device, qc->tag, qc->cdb[0], nbytes, | ||
1465 | dma_str[qc->dma_dir], | ||
1466 | res->command, res->feature, res->nsect, | ||
1467 | res->lbal, res->lbam, res->lbah, | ||
1468 | res->hob_feature, res->hob_nsect, | ||
1469 | res->hob_lbal, res->hob_lbam, res->hob_lbah, | ||
1470 | res->device, qc->err_mask, ata_err_string(qc->err_mask)); | ||
1446 | } | 1471 | } |
1447 | } | 1472 | } |
1448 | 1473 | ||
@@ -1634,11 +1659,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
1634 | DPRINTK("ENTER\n"); | 1659 | DPRINTK("ENTER\n"); |
1635 | 1660 | ||
1636 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | 1661 | for (i = 0; i < ATA_MAX_DEVICES; i++) { |
1637 | unsigned int action; | 1662 | unsigned int action, readid_flags = 0; |
1638 | 1663 | ||
1639 | dev = &ap->device[i]; | 1664 | dev = &ap->device[i]; |
1640 | action = ata_eh_dev_action(dev); | 1665 | action = ata_eh_dev_action(dev); |
1641 | 1666 | ||
1667 | if (ehc->i.flags & ATA_EHI_DID_RESET) | ||
1668 | readid_flags |= ATA_READID_POSTRESET; | ||
1669 | |||
1642 | if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) { | 1670 | if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) { |
1643 | if (ata_port_offline(ap)) { | 1671 | if (ata_port_offline(ap)) { |
1644 | rc = -EIO; | 1672 | rc = -EIO; |
@@ -1646,13 +1674,17 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
1646 | } | 1674 | } |
1647 | 1675 | ||
1648 | ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE); | 1676 | ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE); |
1649 | rc = ata_dev_revalidate(dev, | 1677 | rc = ata_dev_revalidate(dev, readid_flags); |
1650 | ehc->i.flags & ATA_EHI_DID_RESET); | ||
1651 | if (rc) | 1678 | if (rc) |
1652 | break; | 1679 | break; |
1653 | 1680 | ||
1654 | ata_eh_done(ap, dev, ATA_EH_REVALIDATE); | 1681 | ata_eh_done(ap, dev, ATA_EH_REVALIDATE); |
1655 | 1682 | ||
1683 | /* Configuration may have changed, reconfigure | ||
1684 | * transfer mode. | ||
1685 | */ | ||
1686 | ehc->i.flags |= ATA_EHI_SETMODE; | ||
1687 | |||
1656 | /* schedule the scsi_rescan_device() here */ | 1688 | /* schedule the scsi_rescan_device() here */ |
1657 | queue_work(ata_aux_wq, &(ap->scsi_rescan_task)); | 1689 | queue_work(ata_aux_wq, &(ap->scsi_rescan_task)); |
1658 | } else if (dev->class == ATA_DEV_UNKNOWN && | 1690 | } else if (dev->class == ATA_DEV_UNKNOWN && |
@@ -1660,18 +1692,35 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
1660 | ata_class_enabled(ehc->classes[dev->devno])) { | 1692 | ata_class_enabled(ehc->classes[dev->devno])) { |
1661 | dev->class = ehc->classes[dev->devno]; | 1693 | dev->class = ehc->classes[dev->devno]; |
1662 | 1694 | ||
1663 | rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); | 1695 | rc = ata_dev_read_id(dev, &dev->class, readid_flags, |
1664 | if (rc == 0) | 1696 | dev->id); |
1665 | rc = ata_dev_configure(dev, 1); | 1697 | if (rc == 0) { |
1698 | ehc->i.flags |= ATA_EHI_PRINTINFO; | ||
1699 | rc = ata_dev_configure(dev); | ||
1700 | ehc->i.flags &= ~ATA_EHI_PRINTINFO; | ||
1701 | } else if (rc == -ENOENT) { | ||
1702 | /* IDENTIFY was issued to non-existent | ||
1703 | * device. No need to reset. Just | ||
1704 | * thaw and kill the device. | ||
1705 | */ | ||
1706 | ata_eh_thaw_port(ap); | ||
1707 | dev->class = ATA_DEV_UNKNOWN; | ||
1708 | rc = 0; | ||
1709 | } | ||
1666 | 1710 | ||
1667 | if (rc) { | 1711 | if (rc) { |
1668 | dev->class = ATA_DEV_UNKNOWN; | 1712 | dev->class = ATA_DEV_UNKNOWN; |
1669 | break; | 1713 | break; |
1670 | } | 1714 | } |
1671 | 1715 | ||
1672 | spin_lock_irqsave(ap->lock, flags); | 1716 | if (ata_dev_enabled(dev)) { |
1673 | ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; | 1717 | spin_lock_irqsave(ap->lock, flags); |
1674 | spin_unlock_irqrestore(ap->lock, flags); | 1718 | ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; |
1719 | spin_unlock_irqrestore(ap->lock, flags); | ||
1720 | |||
1721 | /* new device discovered, configure xfermode */ | ||
1722 | ehc->i.flags |= ATA_EHI_SETMODE; | ||
1723 | } | ||
1675 | } | 1724 | } |
1676 | } | 1725 | } |
1677 | 1726 | ||
@@ -1987,13 +2036,14 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
1987 | if (rc) | 2036 | if (rc) |
1988 | goto dev_fail; | 2037 | goto dev_fail; |
1989 | 2038 | ||
1990 | /* configure transfer mode if the port has been reset */ | 2039 | /* configure transfer mode if necessary */ |
1991 | if (ehc->i.flags & ATA_EHI_DID_RESET) { | 2040 | if (ehc->i.flags & ATA_EHI_SETMODE) { |
1992 | rc = ata_set_mode(ap, &dev); | 2041 | rc = ata_set_mode(ap, &dev); |
1993 | if (rc) { | 2042 | if (rc) { |
1994 | down_xfermask = 1; | 2043 | down_xfermask = 1; |
1995 | goto dev_fail; | 2044 | goto dev_fail; |
1996 | } | 2045 | } |
2046 | ehc->i.flags &= ~ATA_EHI_SETMODE; | ||
1997 | } | 2047 | } |
1998 | 2048 | ||
1999 | /* suspend devices */ | 2049 | /* suspend devices */ |