diff options
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r-- | drivers/ata/libata-core.c | 286 |
1 files changed, 188 insertions, 98 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9ad8cafd56b0..772be09b4689 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -71,6 +71,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); static void ata_dev_xfermask(struct ata_device *dev); +static unsigned long ata_dev_blacklisted(const struct ata_device *dev); unsigned int ata_print_id = 1; static struct workqueue_struct *ata_wq; @@ -110,8 +111,9 @@ MODULE_VERSION(DRV_VERSION); /** * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure * @tf: Taskfile to convert - * @fis: Buffer into which data will output * @pmp: Port multiplier port + * @is_cmd: This FIS is for command + * @fis: Buffer into which data will output * * Converts a standard ATA taskfile to a Serial ATA * FIS structure (Register - Host to Device). @@ -119,12 +121,13 @@ MODULE_VERSION(DRV_VERSION); * LOCKING: * Inherited from caller. */ - -void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp) +void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis) { - fis[0] = 0x27; /* Register - Host to Device FIS */ - fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number, - bit 7 indicates Command FIS */ + fis[0] = 0x27; /* Register - Host to Device FIS */ + fis[1] = pmp & 0xf; /* Port multiplier number*/ + if (is_cmd) + fis[1] |= (1 << 7); /* bit 7 indicates Command FIS */ + fis[2] = tf->command; fis[3] = tf->feature; @@ -1283,18 +1286,11 @@ static unsigned int ata_id_xfermask(const u16 *id) void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data, unsigned long delay) { - int rc; - - if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK) - return; - PREPARE_DELAYED_WORK(&ap->port_task, fn); ap->port_task_data = data; - rc = queue_delayed_work(ata_wq, &ap->port_task, delay); - - /* rc == 0 means that another user is using port task */ - WARN_ON(rc == 0); + /* may fail if ata_port_flush_task() in progress */ + queue_delayed_work(ata_wq, &ap->port_task, delay); } /** @@ -1309,32 +1305,9 @@ void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data, */ void ata_port_flush_task(struct ata_port *ap) { - unsigned long flags; - DPRINTK("ENTER\n"); - spin_lock_irqsave(ap->lock, flags); - ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK; - spin_unlock_irqrestore(ap->lock, flags); - - DPRINTK("flush #1\n"); - cancel_work_sync(&ap->port_task.work); /* akpm: seems unneeded */ - - /* - * At this point, if a task is running, it's guaranteed to see - * the FLUSH flag; thus, it will never queue pio tasks again. - * Cancel and flush. - */ - if (!cancel_delayed_work(&ap->port_task)) { - if (ata_msg_ctl(ap)) - ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n", - __FUNCTION__); - cancel_work_sync(&ap->port_task.work); - } - - spin_lock_irqsave(ap->lock, flags); - ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK; - spin_unlock_irqrestore(ap->lock, flags); + cancel_rearming_delayed_work(&ap->port_task); if (ata_msg_ctl(ap)) ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__); @@ -1750,7 +1723,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, tf.protocol = ATA_PROT_NODATA; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err_mask) { + if (err_mask && id[2] != 0x738c) { rc = -EIO; reason = "SPINUP failed"; goto err_out; @@ -1814,7 +1787,7 @@ static void ata_dev_config_ncq(struct ata_device *dev, desc[0] = '\0'; return; } - if (ata_device_blacklisted(dev) & ATA_HORKAGE_NONCQ) { + if (dev->horkage & ATA_HORKAGE_NONCQ) { snprintf(desc, desc_sz, "NCQ (not used)"); return; } @@ -1845,7 +1818,8 @@ static void ata_dev_config_ncq(struct ata_device *dev, int ata_dev_configure(struct ata_device *dev) { struct ata_port *ap = dev->ap; - int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; + struct ata_eh_context *ehc = &ap->eh_context; + int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; const u16 *id = dev->id; unsigned int xfer_mask; char revbuf[7]; /* XYZ-99\0 */ @@ -1862,15 +1836,13 @@ int ata_dev_configure(struct ata_device *dev) if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__); - /* set _SDD */ - rc = ata_acpi_push_id(dev); - if (rc) { - ata_dev_printk(dev, KERN_WARNING, "failed to set _SDD(%d)\n", - rc); - } + /* set horkage */ + dev->horkage |= ata_dev_blacklisted(dev); - /* retrieve and execute the ATA task file of _GTF */ - ata_acpi_exec_tfs(ap); + /* let ACPI work its magic */ + rc = ata_acpi_on_devcfg(dev); + if (rc) + return rc; /* print device capabilities */ if (ata_msg_probe(ap)) @@ -1939,8 +1911,9 @@ int ata_dev_configure(struct ata_device *dev) dev->flags |= ATA_DFLAG_FLUSH_EXT; } - if (ata_id_hpa_enabled(dev->id)) - dev->n_sectors = ata_hpa_resize(dev); + if (!(dev->horkage & ATA_HORKAGE_BROKEN_HPA) && + ata_id_hpa_enabled(dev->id)) + dev->n_sectors = ata_hpa_resize(dev); /* config NCQ */ ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); @@ -2042,7 +2015,7 @@ int ata_dev_configure(struct ata_device *dev) dev->max_sectors = ATA_MAX_SECTORS; } - if (ata_device_blacklisted(dev) & ATA_HORKAGE_MAX_SEC_128) + if (dev->horkage & ATA_HORKAGE_MAX_SEC_128) dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128, dev->max_sectors); @@ -2417,21 +2390,35 @@ int sata_down_spd_limit(struct ata_port *ap) u32 sstatus, spd, mask; int rc, highbit; + if (!sata_scr_valid(ap)) + return -EOPNOTSUPP; + + /* If SCR can be read, use it to determine the current SPD. + * If not, use cached value in ap->sata_spd. + */ rc = sata_scr_read(ap, SCR_STATUS, &sstatus); - if (rc) - return rc; + if (rc == 0) + spd = (sstatus >> 4) & 0xf; + else + spd = ap->sata_spd; mask = ap->sata_spd_limit; if (mask <= 1) return -EINVAL; + + /* unconditionally mask off the highest bit */ highbit = fls(mask) - 1; mask &= ~(1 << highbit); - spd = (sstatus >> 4) & 0xf; - if (spd <= 1) - return -EINVAL; - spd--; - mask &= (1 << spd) - 1; + /* Mask off all speeds higher than or equal to the current + * one. Force 1.5Gbps if current SPD is not available. + */ + if (spd > 1) + mask &= (1 << (spd - 1)) - 1; + else + mask &= 1; + + /* were we already at the bottom? */ if (!mask) return -EINVAL; @@ -3194,9 +3181,6 @@ void ata_bus_reset(struct ata_port *ap) if ((slave_possible) && (err != 0x81)) ap->device[1].class = ata_dev_try_classify(ap, 1, &err); - /* re-enable interrupts */ - ap->ops->irq_on(ap); - /* is double-select really necessary? */ if (ap->device[1].class != ATA_DEV_NONE) ap->ops->dev_select(ap, 1); @@ -3284,9 +3268,11 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, last = cur; last_jiffies = jiffies; - /* check deadline */ + /* Check deadline. If debouncing failed, return + * -EPIPE to tell upper layer to lower link speed. + */ if (time_after(jiffies, deadline)) - return -EBUSY; + return -EPIPE; } } @@ -3359,7 +3345,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) return 0; /* if SATA, resume phy */ - if (ap->cbl == ATA_CBL_SATA) { + if (ap->flags & ATA_FLAG_SATA) { rc = sata_phy_resume(ap, timing, deadline); /* whine about phy resume failure but proceed */ if (rc && rc != -EOPNOTSUPP) @@ -3581,10 +3567,6 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes) if (sata_scr_read(ap, SCR_ERROR, &serror) == 0) sata_scr_write(ap, SCR_ERROR, serror); - /* re-enable interrupts */ - if (!ap->ops->error_handler) - ap->ops->irq_on(ap); - /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) ap->ops->dev_select(ap, 1); @@ -3719,11 +3701,16 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags) goto fail; /* verify n_sectors hasn't changed */ - if (dev->class == ATA_DEV_ATA && dev->n_sectors != n_sectors) { + if (dev->class == ATA_DEV_ATA && n_sectors && + dev->n_sectors != n_sectors) { ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch " "%llu != %llu\n", (unsigned long long)n_sectors, (unsigned long long)dev->n_sectors); + + /* restore original n_sectors */ + dev->n_sectors = n_sectors; + rc = -ENODEV; goto fail; } @@ -3774,6 +3761,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "SAMSUNG CD-ROM SN-124","N001", ATA_HORKAGE_NODMA }, { "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA }, { "IOMEGA ZIP 250 ATAPI", NULL, ATA_HORKAGE_NODMA }, /* temporary fix */ + { "IOMEGA ZIP 250 ATAPI Floppy", + NULL, ATA_HORKAGE_NODMA }, /* Weird ATAPI devices */ { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 }, @@ -3787,7 +3776,13 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ }, /* NCQ is broken */ { "Maxtor 6L250S0", "BANC1G10", ATA_HORKAGE_NONCQ }, + { "Maxtor 6B200M0", "BANC1BM0", ATA_HORKAGE_NONCQ }, { "Maxtor 6B200M0", "BANC1B10", ATA_HORKAGE_NONCQ }, + { "Maxtor 7B250S0", "BANC1B70", ATA_HORKAGE_NONCQ, }, + { "Maxtor 7B300S0", "BANC1B70", ATA_HORKAGE_NONCQ }, + { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, + { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI", + ATA_HORKAGE_NONCQ }, /* NCQ hard hangs device under heavier load, needs hard power cycle */ { "Maxtor 6B250S0", "BANC1B70", ATA_HORKAGE_NONCQ }, /* Blacklist entries taken from Silicon Image 3124/3132 @@ -3801,14 +3796,21 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, }, { "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, }, { "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, }, + { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, }, + { "ST3160812AS", "3.AD", ATA_HORKAGE_NONCQ, }, + { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, }, - /* Devices with NCQ limits */ + /* devices which puke on READ_NATIVE_MAX */ + { "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, }, + { "WDC WD3200JD-00KLB0", "WD-WCAMR1130137", ATA_HORKAGE_BROKEN_HPA }, + { "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA }, + { "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA }, /* End Marker */ { } }; -unsigned long ata_device_blacklisted(const struct ata_device *dev) +static unsigned long ata_dev_blacklisted(const struct ata_device *dev) { unsigned char model_num[ATA_ID_PROD_LEN + 1]; unsigned char model_rev[ATA_ID_FW_REV_LEN + 1]; @@ -3838,7 +3840,7 @@ static int ata_dma_blacklisted(const struct ata_device *dev) if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && (dev->flags & ATA_DFLAG_CDB_INTR)) return 1; - return (ata_device_blacklisted(dev) & ATA_HORKAGE_NODMA) ? 1 : 0; + return (dev->horkage & ATA_HORKAGE_NODMA) ? 1 : 0; } /** @@ -3992,6 +3994,11 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + /* A clean abort indicates an original or just out of spec drive + and we should continue as we issue the setup based on the + drive reported working geometry */ + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + err_mask = 0; DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -4108,6 +4115,68 @@ static void ata_fill_sg(struct ata_queued_cmd *qc) } /** + * ata_fill_sg_dumb - Fill PCI IDE PRD table + * @qc: Metadata associated with taskfile to be transferred + * + * Fill PCI IDE PRD (scatter-gather) table with segments + * associated with the current disk command. Perform the fill + * so that we avoid writing any length 64K records for + * controllers that don't follow the spec. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + */ +static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scatterlist *sg; + unsigned int idx; + + WARN_ON(qc->__sg == NULL); + WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); + + idx = 0; + ata_for_each_sg(sg, qc) { + u32 addr, offset; + u32 sg_len, len, blen; + + /* determine if physical DMA addr spans 64K boundary. + * Note h/w doesn't support 64-bit, so we unconditionally + * truncate dma_addr_t to u32. + */ + addr = (u32) sg_dma_address(sg); + sg_len = sg_dma_len(sg); + + while (sg_len) { + offset = addr & 0xffff; + len = sg_len; + if ((offset + sg_len) > 0x10000) + len = 0x10000 - offset; + + blen = len & 0xffff; + ap->prd[idx].addr = cpu_to_le32(addr); + if (blen == 0) { + /* Some PATA chipsets like the CS5530 can't + cope with 0x0000 meaning 64K as the spec says */ + ap->prd[idx].flags_len = cpu_to_le32(0x8000); + blen = 0x8000; + ap->prd[++idx].addr = cpu_to_le32(addr + 0x8000); + } + ap->prd[idx].flags_len = cpu_to_le32(blen); + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); + + idx++; + sg_len -= len; + addr += len; + } + } + + if (idx) + ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); +} + +/** * ata_check_atapi_dma - Check whether ATAPI DMA can be supported * @qc: Metadata associated with taskfile to check * @@ -4154,6 +4223,23 @@ void ata_qc_prep(struct ata_queued_cmd *qc) ata_fill_sg(qc); } +/** + * ata_dumb_qc_prep - Prepare taskfile for submission + * @qc: Metadata associated with taskfile to be prepared + * + * Prepare ATA taskfile for submission. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +void ata_dumb_qc_prep(struct ata_queued_cmd *qc) +{ + if (!(qc->flags & ATA_QCFLAG_DMAMAP)) + return; + + ata_fill_sg_dumb(qc); +} + void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } /** @@ -5661,7 +5747,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance) */ int sata_scr_valid(struct ata_port *ap) { - return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read; + return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read; } /** @@ -5682,10 +5768,8 @@ int sata_scr_valid(struct ata_port *ap) */ int sata_scr_read(struct ata_port *ap, int reg, u32 *val) { - if (sata_scr_valid(ap)) { - *val = ap->ops->scr_read(ap, reg); - return 0; - } + if (sata_scr_valid(ap)) + return ap->ops->scr_read(ap, reg, val); return -EOPNOTSUPP; } @@ -5707,10 +5791,8 @@ int sata_scr_read(struct ata_port *ap, int reg, u32 *val) */ int sata_scr_write(struct ata_port *ap, int reg, u32 val) { - if (sata_scr_valid(ap)) { - ap->ops->scr_write(ap, reg, val); - return 0; - } + if (sata_scr_valid(ap)) + return ap->ops->scr_write(ap, reg, val); return -EOPNOTSUPP; } @@ -5731,10 +5813,13 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val) */ int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) { + int rc; + if (sata_scr_valid(ap)) { - ap->ops->scr_write(ap, reg, val); - ap->ops->scr_read(ap, reg); - return 0; + rc = ap->ops->scr_write(ap, reg, val); + if (rc == 0) + rc = ap->ops->scr_read(ap, reg, &val); + return rc; } return -EOPNOTSUPP; } @@ -5946,6 +6031,7 @@ void ata_dev_init(struct ata_device *dev) /* SATA spd limit is bound to the first device */ ap->sata_spd_limit = ap->hw_sata_spd_limit; + ap->sata_spd = 0; /* High bits of dev->flags are used to record warm plug * requests which occur asynchronously. Synchronize using @@ -5953,6 +6039,7 @@ void ata_dev_init(struct ata_device *dev) */ spin_lock_irqsave(ap->lock, flags); dev->flags &= ~ATA_DFLAG_INIT_MASK; + dev->horkage = 0; spin_unlock_irqrestore(ap->lock, flags); memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0, @@ -6011,6 +6098,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host) INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); INIT_LIST_HEAD(&ap->eh_done_q); init_waitqueue_head(&ap->eh_wait_q); + init_timer_deferrable(&ap->fastdrain_timer); + ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn; + ap->fastdrain_timer.data = (unsigned long)ap; ap->cbl = ATA_CBL_NONE; @@ -6294,6 +6384,9 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) if (rc) return rc; + /* associate with ACPI nodes */ + ata_acpi_associate(host); + /* set cable, sata_spd_limit and report */ for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; @@ -6325,7 +6418,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) if (!ata_port_is_dummy(ap)) ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p " "ctl 0x%p bmdma 0x%p irq %d\n", - ap->cbl == ATA_CBL_SATA ? 'S' : 'P', + (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P', ata_mode_string(xfer_mask), ap->ioaddr.cmd_addr, ap->ioaddr.ctl_addr, @@ -6384,7 +6477,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - ata_scsi_scan_host(ap); + ata_scsi_scan_host(ap, 1); } return 0; @@ -6480,13 +6573,7 @@ void ata_port_detach(struct ata_port *ap) spin_unlock_irqrestore(ap->lock, flags); ata_port_wait_eh(ap); - - /* Flush hotplug task. The sequence is similar to - * ata_port_flush_task(). - */ - cancel_work_sync(&ap->hotplug_task.work); /* akpm: why? */ - cancel_delayed_work(&ap->hotplug_task); - cancel_work_sync(&ap->hotplug_task.work); + cancel_rearming_delayed_work(&ap->hotplug_task); skip_eh: /* remove the associated SCSI host */ @@ -6823,6 +6910,7 @@ EXPORT_SYMBOL_GPL(ata_do_set_mode); EXPORT_SYMBOL_GPL(ata_data_xfer); EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); EXPORT_SYMBOL_GPL(ata_qc_prep); +EXPORT_SYMBOL_GPL(ata_dumb_qc_prep); EXPORT_SYMBOL_GPL(ata_noop_qc_prep); EXPORT_SYMBOL_GPL(ata_bmdma_setup); EXPORT_SYMBOL_GPL(ata_bmdma_start); @@ -6874,7 +6962,6 @@ EXPORT_SYMBOL_GPL(ata_host_resume); EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); EXPORT_SYMBOL_GPL(ata_id_to_dma_mode); -EXPORT_SYMBOL_GPL(ata_device_blacklisted); EXPORT_SYMBOL_GPL(ata_scsi_simulate); EXPORT_SYMBOL_GPL(ata_pio_need_iordy); @@ -6883,9 +6970,9 @@ EXPORT_SYMBOL_GPL(ata_timing_merge); #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); -EXPORT_SYMBOL_GPL(ata_pci_init_native_host); +EXPORT_SYMBOL_GPL(ata_pci_init_sff_host); EXPORT_SYMBOL_GPL(ata_pci_init_bmdma); -EXPORT_SYMBOL_GPL(ata_pci_prepare_native_host); +EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); #ifdef CONFIG_PM @@ -6898,6 +6985,9 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ +EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); +EXPORT_SYMBOL_GPL(ata_ehi_push_desc); +EXPORT_SYMBOL_GPL(ata_ehi_clear_desc); EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_port_schedule_eh); EXPORT_SYMBOL_GPL(ata_port_abort); |