aboutsummaryrefslogtreecommitdiff
path: root/drivers/ata/libata-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r--drivers/ata/libata-core.c194
1 files changed, 167 insertions, 27 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 8cb0b360bfd8..bc6695e3c848 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -612,7 +612,7 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
if (tf->flags & ATA_TFLAG_LBA48) {
block |= (u64)tf->hob_lbah << 40;
block |= (u64)tf->hob_lbam << 32;
- block |= tf->hob_lbal << 24;
+ block |= (u64)tf->hob_lbal << 24;
} else
block |= (tf->device & 0xf) << 24;
@@ -1268,7 +1268,7 @@ u64 ata_tf_to_lba48(const struct ata_taskfile *tf)
sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40;
sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32;
- sectors |= (tf->hob_lbal & 0xff) << 24;
+ sectors |= ((u64)(tf->hob_lbal & 0xff)) << 24;
sectors |= (tf->lbah & 0xff) << 16;
sectors |= (tf->lbam & 0xff) << 8;
sectors |= (tf->lbal & 0xff);
@@ -1602,7 +1602,6 @@ unsigned long ata_id_xfermask(const u16 *id)
/**
* ata_pio_queue_task - Queue port_task
* @ap: The ata_port to queue port_task for
- * @fn: workqueue function to be scheduled
* @data: data for @fn to use
* @delay: delay time in msecs for workqueue function
*
@@ -1713,6 +1712,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
else
tag = 0;
+ if (test_and_set_bit(tag, &ap->qc_allocated))
+ BUG();
qc = __ata_qc_from_tag(ap, tag);
qc->tag = tag;
@@ -2159,6 +2160,10 @@ retry:
static inline u8 ata_dev_knobble(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
+
+ if (ata_dev_blacklisted(dev) & ATA_HORKAGE_BRIDGE_OK)
+ return 0;
+
return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
}
@@ -2487,6 +2492,13 @@ int ata_dev_configure(struct ata_device *dev)
}
}
+ if ((dev->horkage & ATA_HORKAGE_FIRMWARE_WARN) && print_info) {
+ ata_dev_printk(dev, KERN_WARNING, "WARNING: device requires "
+ "firmware update to be fully functional.\n");
+ ata_dev_printk(dev, KERN_WARNING, " contact the vendor "
+ "or visit http://ata.wiki.kernel.org.\n");
+ }
+
return 0;
err_out_nosup:
@@ -4021,6 +4033,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Weird ATAPI devices */
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
+ { "QUANTUM DAT DAT72-000", NULL, ATA_HORKAGE_ATAPI_MOD16_DMA },
/* Devices we expect to fail diagnostics */
@@ -4036,6 +4049,73 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "ST380817AS", "3.42", ATA_HORKAGE_NONCQ },
{ "ST3160023AS", "3.42", ATA_HORKAGE_NONCQ },
+ /* Seagate NCQ + FLUSH CACHE firmware bug */
+ { "ST31500341AS", "SD15", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST31500341AS", "SD16", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST31500341AS", "SD17", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST31500341AS", "SD18", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST31500341AS", "SD19", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+
+ { "ST31000333AS", "SD15", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST31000333AS", "SD16", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST31000333AS", "SD17", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST31000333AS", "SD18", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST31000333AS", "SD19", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+
+ { "ST3640623AS", "SD15", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3640623AS", "SD16", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3640623AS", "SD17", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3640623AS", "SD18", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3640623AS", "SD19", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+
+ { "ST3640323AS", "SD15", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3640323AS", "SD16", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3640323AS", "SD17", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3640323AS", "SD18", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3640323AS", "SD19", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+
+ { "ST3320813AS", "SD15", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3320813AS", "SD16", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3320813AS", "SD17", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3320813AS", "SD18", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3320813AS", "SD19", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+
+ { "ST3320613AS", "SD15", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3320613AS", "SD16", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3320613AS", "SD17", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3320613AS", "SD18", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+ { "ST3320613AS", "SD19", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+
/* Blacklist entries taken from Silicon Image 3124/3132
Windows driver .inf file - also several Linux problem reports */
{ "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, },
@@ -4063,6 +4143,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "TSSTcorp CDDVDW SH-S202N", "SB00", ATA_HORKAGE_IVB, },
{ "TSSTcorp CDDVDW SH-S202N", "SB01", ATA_HORKAGE_IVB, },
+ /* Devices that do not need bridging limits applied */
+ { "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, },
+
/* End Marker */
{ }
};
@@ -4156,29 +4239,33 @@ static int cable_is_40wire(struct ata_port *ap)
struct ata_link *link;
struct ata_device *dev;
- /* If the controller thinks we are 40 wire, we are */
+ /* If the controller thinks we are 40 wire, we are. */
if (ap->cbl == ATA_CBL_PATA40)
return 1;
- /* If the controller thinks we are 80 wire, we are */
+
+ /* If the controller thinks we are 80 wire, we are. */
if (ap->cbl == ATA_CBL_PATA80 || ap->cbl == ATA_CBL_SATA)
return 0;
- /* If the system is known to be 40 wire short cable (eg laptop),
- then we allow 80 wire modes even if the drive isn't sure */
+
+ /* If the system is known to be 40 wire short cable (eg
+ * laptop), then we allow 80 wire modes even if the drive
+ * isn't sure.
+ */
if (ap->cbl == ATA_CBL_PATA40_SHORT)
return 0;
- /* If the controller doesn't know we scan
-
- - Note: We look for all 40 wire detects at this point.
- Any 80 wire detect is taken to be 80 wire cable
- because
- - In many setups only the one drive (slave if present)
- will give a valid detect
- - If you have a non detect capable drive you don't
- want it to colour the choice
- */
+
+ /* If the controller doesn't know, we scan.
+ *
+ * Note: We look for all 40 wire detects at this point. Any
+ * 80 wire detect is taken to be 80 wire cable because
+ * - in many setups only the one drive (slave if present) will
+ * give a valid detect
+ * - if you have a non detect capable drive you don't want it
+ * to colour the choice
+ */
ata_port_for_each_link(link, ap) {
ata_link_for_each_dev(dev, link) {
- if (!ata_is_40wire(dev))
+ if (ata_dev_enabled(dev) && !ata_is_40wire(dev))
return 0;
}
}
@@ -4434,7 +4521,8 @@ int atapi_check_dma(struct ata_queued_cmd *qc)
/* Don't allow DMA if it isn't multiple of 16 bytes. Quite a
* few ATAPI devices choke on such DMA requests.
*/
- if (unlikely(qc->nbytes & 15))
+ if (!(qc->dev->horkage & ATA_HORKAGE_ATAPI_MOD16_DMA) &&
+ unlikely(qc->nbytes & 15))
return 1;
if (ap->ops->check_atapi_dma)
@@ -4551,27 +4639,55 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
}
/**
- * ata_qc_new_init - Request an available ATA command, and initialize it
+ * ata_qc_new - Request an available ATA command, for queueing
+ * @ap: Port associated with device @dev
* @dev: Device from whom we request an available command structure
*
* LOCKING:
* None.
*/
-struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag)
+static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
{
- struct ata_port *ap = dev->link->ap;
- struct ata_queued_cmd *qc;
+ struct ata_queued_cmd *qc = NULL;
+ unsigned int i;
+ /* no command while frozen */
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
return NULL;
- qc = __ata_qc_from_tag(ap, tag);
+ /* the last tag is reserved for internal command. */
+ for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
+ if (!test_and_set_bit(i, &ap->qc_allocated)) {
+ qc = __ata_qc_from_tag(ap, i);
+ break;
+ }
+
+ if (qc)
+ qc->tag = i;
+
+ return qc;
+}
+
+/**
+ * ata_qc_new_init - Request an available ATA command, and initialize it
+ * @dev: Device from whom we request an available command structure
+ * @tag: command tag
+ *
+ * LOCKING:
+ * None.
+ */
+
+struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->link->ap;
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_new(ap);
if (qc) {
qc->scsicmd = NULL;
qc->ap = ap;
qc->dev = dev;
- qc->tag = tag;
ata_qc_reinit(qc);
}
@@ -4579,6 +4695,31 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag)
return qc;
}
+/**
+ * ata_qc_free - free unused ata_queued_cmd
+ * @qc: Command to complete
+ *
+ * Designed to free unused ata_queued_cmd object
+ * in case something prevents using it.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_qc_free(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int tag;
+
+ WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+
+ qc->flags = 0;
+ tag = qc->tag;
+ if (likely(ata_tag_valid(tag))) {
+ qc->tag = ATA_TAG_POISON;
+ clear_bit(tag, &ap->qc_allocated);
+ }
+}
+
void __ata_qc_complete(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
@@ -4643,7 +4784,6 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc)
/**
* ata_qc_complete - Complete an active ATA command
* @qc: Command to complete
- * @err_mask: ATA Status register contents
*
* Indicate to the mid and upper layers that an ATA
* command has completed, with either an ok or not-ok status.
@@ -5924,7 +6064,7 @@ static void ata_port_detach(struct ata_port *ap)
* to us. Restore SControl and disable all existing devices.
*/
__ata_port_for_each_link(link, ap) {
- sata_scr_write(link, SCR_CONTROL, link->saved_scontrol);
+ sata_scr_write(link, SCR_CONTROL, link->saved_scontrol & 0xff0);
ata_link_for_each_dev(dev, link)
ata_dev_disable(dev);
}