diff options
Diffstat (limited to 'drivers/ata/libata-core.c')
| -rw-r--r-- | drivers/ata/libata-core.c | 350 |
1 files changed, 263 insertions, 87 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 82af7011f2dd..fecca4223f8e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -163,43 +163,119 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -/* - * Iterator helpers. Don't use directly. +/** + * ata_link_next - link iteration helper + * @link: the previous link, NULL to start + * @ap: ATA port containing links to iterate + * @mode: iteration mode, one of ATA_LITER_* + * + * LOCKING: + * Host lock or EH context. * - * LOCKING: - * Host lock or EH context. + * RETURNS: + * Pointer to the next link. */ -struct ata_link *__ata_port_next_link(struct ata_port *ap, - struct ata_link *link, bool dev_only) +struct ata_link *ata_link_next(struct ata_link *link, struct ata_port *ap, + enum ata_link_iter_mode mode) { + BUG_ON(mode != ATA_LITER_EDGE && + mode != ATA_LITER_PMP_FIRST && mode != ATA_LITER_HOST_FIRST); + /* NULL link indicates start of iteration */ - if (!link) { - if (dev_only && sata_pmp_attached(ap)) - return ap->pmp_link; - return &ap->link; - } + if (!link) + switch (mode) { + case ATA_LITER_EDGE: + case ATA_LITER_PMP_FIRST: + if (sata_pmp_attached(ap)) + return ap->pmp_link; + /* fall through */ + case ATA_LITER_HOST_FIRST: + return &ap->link; + } - /* we just iterated over the host master link, what's next? */ - if (link == &ap->link) { - if (!sata_pmp_attached(ap)) { - if (unlikely(ap->slave_link) && !dev_only) + /* we just iterated over the host link, what's next? */ + if (link == &ap->link) + switch (mode) { + case ATA_LITER_HOST_FIRST: + if (sata_pmp_attached(ap)) + return ap->pmp_link; + /* fall through */ + case ATA_LITER_PMP_FIRST: + if (unlikely(ap->slave_link)) return ap->slave_link; + /* fall through */ + case ATA_LITER_EDGE: return NULL; } - return ap->pmp_link; - } /* slave_link excludes PMP */ if (unlikely(link == ap->slave_link)) return NULL; - /* iterate to the next PMP link */ + /* we were over a PMP link */ if (++link < ap->pmp_link + ap->nr_pmp_links) return link; + + if (mode == ATA_LITER_PMP_FIRST) + return &ap->link; + return NULL; } /** + * ata_dev_next - device iteration helper + * @dev: the previous device, NULL to start + * @link: ATA link containing devices to iterate + * @mode: iteration mode, one of ATA_DITER_* + * + * LOCKING: + * Host lock or EH context. + * + * RETURNS: + * Pointer to the next device. + */ +struct ata_device *ata_dev_next(struct ata_device *dev, struct ata_link *link, + enum ata_dev_iter_mode mode) +{ + BUG_ON(mode != ATA_DITER_ENABLED && mode != ATA_DITER_ENABLED_REVERSE && + mode != ATA_DITER_ALL && mode != ATA_DITER_ALL_REVERSE); + + /* NULL dev indicates start of iteration */ + if (!dev) + switch (mode) { + case ATA_DITER_ENABLED: + case ATA_DITER_ALL: + dev = link->device; + goto check; + case ATA_DITER_ENABLED_REVERSE: + case ATA_DITER_ALL_REVERSE: + dev = link->device + ata_link_max_devices(link) - 1; + goto check; + } + + next: + /* move to the next one */ + switch (mode) { + case ATA_DITER_ENABLED: + case ATA_DITER_ALL: + if (++dev < link->device + ata_link_max_devices(link)) + goto check; + return NULL; + case ATA_DITER_ENABLED_REVERSE: + case ATA_DITER_ALL_REVERSE: + if (--dev >= link->device) + goto check; + return NULL; + } + + check: + if ((mode == ATA_DITER_ENABLED || mode == ATA_DITER_ENABLED_REVERSE) && + !ata_dev_enabled(dev)) + goto next; + return dev; +} + +/** * ata_dev_phys_link - find physical link for a device * @dev: ATA device to look up physical link for * @@ -612,7 +688,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; @@ -1107,8 +1183,8 @@ static void ata_lpm_enable(struct ata_host *host) for (i = 0; i < host->n_ports; i++) { ap = host->ports[i]; - ata_port_for_each_link(link, ap) { - ata_link_for_each_dev(dev, link) + ata_for_each_link(link, ap, EDGE) { + ata_for_each_dev(dev, link, ALL) ata_dev_disable_pm(dev); } } @@ -1712,6 +1788,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; @@ -2490,6 +2568,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: @@ -2585,11 +2670,11 @@ int ata_bus_probe(struct ata_port *ap) ata_port_probe(ap); - ata_link_for_each_dev(dev, &ap->link) + ata_for_each_dev(dev, &ap->link, ALL) tries[dev->devno] = ATA_PROBE_MAX_TRIES; retry: - ata_link_for_each_dev(dev, &ap->link) { + ata_for_each_dev(dev, &ap->link, ALL) { /* If we issue an SRST then an ATA drive (not ATAPI) * may change configuration and be in PIO0 timing. If * we do a hard reset (or are coming from power on) @@ -2611,7 +2696,7 @@ int ata_bus_probe(struct ata_port *ap) /* reset and determine device classes */ ap->ops->phy_reset(ap); - ata_link_for_each_dev(dev, &ap->link) { + ata_for_each_dev(dev, &ap->link, ALL) { if (!(ap->flags & ATA_FLAG_DISABLED) && dev->class != ATA_DEV_UNKNOWN) classes[dev->devno] = dev->class; @@ -2627,7 +2712,7 @@ int ata_bus_probe(struct ata_port *ap) specific sequence bass-ackwards so that PDIAG- is released by the slave device */ - ata_link_for_each_dev_reverse(dev, &ap->link) { + ata_for_each_dev(dev, &ap->link, ALL_REVERSE) { if (tries[dev->devno]) dev->class = classes[dev->devno]; @@ -2644,24 +2729,19 @@ int ata_bus_probe(struct ata_port *ap) if (ap->ops->cable_detect) ap->cbl = ap->ops->cable_detect(ap); - /* We may have SATA bridge glue hiding here irrespective of the - reported cable types and sensed types */ - ata_link_for_each_dev(dev, &ap->link) { - if (!ata_dev_enabled(dev)) - continue; - /* SATA drives indicate we have a bridge. We don't know which - end of the link the bridge is which is a problem */ + /* We may have SATA bridge glue hiding here irrespective of + * the reported cable types and sensed types. When SATA + * drives indicate we have a bridge, we don't know which end + * of the link the bridge is which is a problem. + */ + ata_for_each_dev(dev, &ap->link, ENABLED) if (ata_id_is_sata(dev->id)) ap->cbl = ATA_CBL_SATA; - } /* After the identify sequence we can now set up the devices. We do this in the normal order so that the user doesn't get confused */ - ata_link_for_each_dev(dev, &ap->link) { - if (!ata_dev_enabled(dev)) - continue; - + ata_for_each_dev(dev, &ap->link, ENABLED) { ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO; rc = ata_dev_configure(dev); ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO; @@ -2674,9 +2754,8 @@ int ata_bus_probe(struct ata_port *ap) if (rc) goto fail; - ata_link_for_each_dev(dev, &ap->link) - if (ata_dev_enabled(dev)) - return 0; + ata_for_each_dev(dev, &ap->link, ENABLED) + return 0; /* no device present, disable port */ ata_port_disable(ap); @@ -3322,13 +3401,10 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) int rc = 0, used_dma = 0, found = 0; /* step 1: calculate xfer_mask */ - ata_link_for_each_dev(dev, link) { + ata_for_each_dev(dev, link, ENABLED) { unsigned long pio_mask, dma_mask; unsigned int mode_mask; - if (!ata_dev_enabled(dev)) - continue; - mode_mask = ATA_DMA_MASK_ATA; if (dev->class == ATA_DEV_ATAPI) mode_mask = ATA_DMA_MASK_ATAPI; @@ -3357,10 +3433,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) goto out; /* step 2: always set host PIO timings */ - ata_link_for_each_dev(dev, link) { - if (!ata_dev_enabled(dev)) - continue; - + ata_for_each_dev(dev, link, ENABLED) { if (dev->pio_mode == 0xff) { ata_dev_printk(dev, KERN_WARNING, "no PIO support\n"); rc = -EINVAL; @@ -3374,8 +3447,8 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) } /* step 3: set host DMA timings */ - ata_link_for_each_dev(dev, link) { - if (!ata_dev_enabled(dev) || !ata_dma_enabled(dev)) + ata_for_each_dev(dev, link, ENABLED) { + if (!ata_dma_enabled(dev)) continue; dev->xfer_mode = dev->dma_mode; @@ -3385,11 +3458,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) } /* step 4: update devices' xfer mode */ - ata_link_for_each_dev(dev, link) { - /* don't update suspended devices' xfer mode */ - if (!ata_dev_enabled(dev)) - continue; - + ata_for_each_dev(dev, link, ENABLED) { rc = ata_dev_set_mode(dev); if (rc) goto out; @@ -4024,6 +4093,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 */ @@ -4038,6 +4108,74 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, { "ST380817AS", "3.42", ATA_HORKAGE_NONCQ }, { "ST3160023AS", "3.42", ATA_HORKAGE_NONCQ }, + { "OCZ CORE_SSD", "02.10104", 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 */ @@ -4186,9 +4324,9 @@ static int cable_is_40wire(struct ata_port *ap) * - 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_dev_enabled(dev) && !ata_is_40wire(dev)) + ata_for_each_link(link, ap, EDGE) { + ata_for_each_dev(dev, link, ENABLED) { + if (!ata_is_40wire(dev)) return 0; } } @@ -4444,7 +4582,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) @@ -4561,28 +4700,54 @@ 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 - * @tag: command tag * * 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 + * + * 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); } @@ -4590,6 +4755,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; @@ -5088,7 +5278,7 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, } ap->pflags |= ATA_PFLAG_PM_PENDING; - __ata_port_for_each_link(link, ap) { + ata_for_each_link(link, ap, HOST_FIRST) { link->eh_info.action |= action; link->eh_info.flags |= ehi_flags; } @@ -5917,8 +6107,6 @@ int ata_host_activate(struct ata_host *host, int irq, static void ata_port_detach(struct ata_port *ap) { unsigned long flags; - struct ata_link *link; - struct ata_device *dev; if (!ap->ops->error_handler) goto skip_eh; @@ -5926,28 +6114,15 @@ static void ata_port_detach(struct ata_port *ap) /* tell EH we're leaving & flush EH */ spin_lock_irqsave(ap->lock, flags); ap->pflags |= ATA_PFLAG_UNLOADING; + ata_port_schedule_eh(ap); spin_unlock_irqrestore(ap->lock, flags); + /* wait till EH commits suicide */ ata_port_wait_eh(ap); - /* EH is now guaranteed to see UNLOADING - EH context belongs - * 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); - ata_link_for_each_dev(dev, link) - ata_dev_disable(dev); - } - - /* Final freeze & EH. All in-flight commands are aborted. EH - * will be skipped and retrials will be terminated with bad - * target. - */ - spin_lock_irqsave(ap->lock, flags); - ata_port_freeze(ap); /* won't be thawed */ - spin_unlock_irqrestore(ap->lock, flags); + /* it better be dead now */ + WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED)); - ata_port_wait_eh(ap); cancel_rearming_delayed_work(&ap->hotplug_task); skip_eh: @@ -6398,7 +6573,8 @@ EXPORT_SYMBOL_GPL(ata_base_port_ops); EXPORT_SYMBOL_GPL(sata_port_ops); EXPORT_SYMBOL_GPL(ata_dummy_port_ops); EXPORT_SYMBOL_GPL(ata_dummy_port_info); -EXPORT_SYMBOL_GPL(__ata_port_next_link); +EXPORT_SYMBOL_GPL(ata_link_next); +EXPORT_SYMBOL_GPL(ata_dev_next); EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_host_init); EXPORT_SYMBOL_GPL(ata_host_alloc); |