const struct ata_port_operations ata_sff_port_ops = {
.inherits = &ata_base_port_ops,
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
-
- .freeze = ata_bmdma_freeze,
- .thaw = ata_bmdma_thaw,
- .softreset = ata_std_softreset,
- .error_handler = ata_bmdma_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
-
- .dev_select = ata_std_dev_select,
- .check_status = ata_check_status,
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .exec_command = ata_exec_command,
- .data_xfer = ata_data_xfer,
- .irq_on = ata_irq_on,
+ .qc_prep = ata_sff_qc_prep,
+ .qc_issue = ata_sff_qc_issue,
+ .qc_fill_rtf = ata_sff_qc_fill_rtf,
+
+ .freeze = ata_sff_freeze,
+ .thaw = ata_sff_thaw,
+ .prereset = ata_sff_prereset,
+ .softreset = ata_sff_softreset,
+ .hardreset = sata_sff_hardreset,
+ .postreset = ata_sff_postreset,
+ .error_handler = ata_sff_error_handler,
+ .post_internal_cmd = ata_sff_post_internal_cmd,
+
+ .sff_dev_select = ata_sff_dev_select,
+ .sff_check_status = ata_sff_check_status,
+ .sff_tf_load = ata_sff_tf_load,
+ .sff_tf_read = ata_sff_tf_read,
+ .sff_exec_command = ata_sff_exec_command,
+ .sff_data_xfer = ata_sff_data_xfer,
+ .sff_irq_on = ata_sff_irq_on,
+ .sff_irq_clear = ata_sff_irq_clear,
.port_start = ata_sff_port_start,
};
+EXPORT_SYMBOL_GPL(ata_sff_port_ops);
const struct ata_port_operations ata_bmdma_port_ops = {
.inherits = &ata_sff_port_ops,
- .mode_filter = ata_pci_default_filter,
+ .mode_filter = ata_bmdma_mode_filter,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
- .irq_clear = ata_bmdma_irq_clear,
};
+EXPORT_SYMBOL_GPL(ata_bmdma_port_ops);
+
+const struct ata_port_operations ata_bmdma32_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+
+ .sff_data_xfer = ata_sff_data_xfer32,
+};
+EXPORT_SYMBOL_GPL(ata_bmdma32_port_ops);
/**
* ata_fill_sg - Fill PCI IDE PRD table
blen = len & 0xffff;
ap->prd[pi].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 */
+ /* Some PATA chipsets like the CS5530 can't
+ cope with 0x0000 meaning 64K as the spec
+ says */
ap->prd[pi].flags_len = cpu_to_le32(0x8000);
blen = 0x8000;
ap->prd[++pi].addr = cpu_to_le32(addr + 0x8000);
}
/**
- * ata_qc_prep - Prepare taskfile for submission
+ * ata_sff_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_qc_prep(struct ata_queued_cmd *qc)
+void ata_sff_qc_prep(struct ata_queued_cmd *qc)
{
if (!(qc->flags & ATA_QCFLAG_DMAMAP))
return;
ata_fill_sg(qc);
}
+EXPORT_SYMBOL_GPL(ata_sff_qc_prep);
/**
- * ata_dumb_qc_prep - Prepare taskfile for submission
+ * ata_sff_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)
+void ata_sff_dumb_qc_prep(struct ata_queued_cmd *qc)
{
if (!(qc->flags & ATA_QCFLAG_DMAMAP))
return;
ata_fill_sg_dumb(qc);
}
+EXPORT_SYMBOL_GPL(ata_sff_dumb_qc_prep);
/**
- * ata_check_status - Read device status reg & clear interrupt
+ * ata_sff_check_status - Read device status reg & clear interrupt
* @ap: port where the device is
*
* Reads ATA taskfile status register for currently-selected device
* LOCKING:
* Inherited from caller.
*/
-u8 ata_check_status(struct ata_port *ap)
+u8 ata_sff_check_status(struct ata_port *ap)
{
return ioread8(ap->ioaddr.status_addr);
}
+EXPORT_SYMBOL_GPL(ata_sff_check_status);
/**
- * ata_altstatus - Read device alternate status reg
+ * ata_sff_altstatus - Read device alternate status reg
* @ap: port where the device is
*
* Reads ATA taskfile alternate status register for
* LOCKING:
* Inherited from caller.
*/
-u8 ata_altstatus(struct ata_port *ap)
+static u8 ata_sff_altstatus(struct ata_port *ap)
{
- if (ap->ops->check_altstatus)
- return ap->ops->check_altstatus(ap);
+ if (ap->ops->sff_check_altstatus)
+ return ap->ops->sff_check_altstatus(ap);
return ioread8(ap->ioaddr.altstatus_addr);
}
/**
- * ata_busy_sleep - sleep until BSY clears, or timeout
+ * ata_sff_irq_status - Check if the device is busy
+ * @ap: port where the device is
+ *
+ * Determine if the port is currently busy. Uses altstatus
+ * if available in order to avoid clearing shared IRQ status
+ * when finding an IRQ source. Non ctl capable devices don't
+ * share interrupt lines fortunately for us.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static u8 ata_sff_irq_status(struct ata_port *ap)
+{
+ u8 status;
+
+ if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
+ status = ata_sff_altstatus(ap);
+ /* Not us: We are busy */
+ if (status & ATA_BUSY)
+ return status;
+ }
+ /* Clear INTRQ latch */
+ status = ap->ops->sff_check_status(ap);
+ return status;
+}
+
+/**
+ * ata_sff_sync - Flush writes
+ * @ap: Port to wait for.
+ *
+ * CAUTION:
+ * If we have an mmio device with no ctl and no altstatus
+ * method this will fail. No such devices are known to exist.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_sff_sync(struct ata_port *ap)
+{
+ if (ap->ops->sff_check_altstatus)
+ ap->ops->sff_check_altstatus(ap);
+ else if (ap->ioaddr.altstatus_addr)
+ ioread8(ap->ioaddr.altstatus_addr);
+}
+
+/**
+ * ata_sff_pause - Flush writes and wait 400nS
+ * @ap: Port to pause for.
+ *
+ * CAUTION:
+ * If we have an mmio device with no ctl and no altstatus
+ * method this will fail. No such devices are known to exist.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_sff_pause(struct ata_port *ap)
+{
+ ata_sff_sync(ap);
+ ndelay(400);
+}
+EXPORT_SYMBOL_GPL(ata_sff_pause);
+
+/**
+ * ata_sff_dma_pause - Pause before commencing DMA
+ * @ap: Port to pause for.
+ *
+ * Perform I/O fencing and ensure sufficient cycle delays occur
+ * for the HDMA1:0 transition
+ */
+
+void ata_sff_dma_pause(struct ata_port *ap)
+{
+ if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
+ /* An altstatus read will cause the needed delay without
+ messing up the IRQ status */
+ ata_sff_altstatus(ap);
+ return;
+ }
+ /* There are no DMA controllers without ctl. BUG here to ensure
+ we never violate the HDMA1:0 transition timing and risk
+ corruption. */
+ BUG();
+}
+EXPORT_SYMBOL_GPL(ata_sff_dma_pause);
+
+/**
+ * ata_sff_busy_sleep - sleep until BSY clears, or timeout
* @ap: port containing status register to be polled
- * @tmout_pat: impatience timeout
- * @tmout: overall timeout
+ * @tmout_pat: impatience timeout in msecs
+ * @tmout: overall timeout in msecs
*
* Sleep until ATA Status register bit BSY clears,
* or a timeout occurs.
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_busy_sleep(struct ata_port *ap,
- unsigned long tmout_pat, unsigned long tmout)
+int ata_sff_busy_sleep(struct ata_port *ap,
+ unsigned long tmout_pat, unsigned long tmout)
{
unsigned long timer_start, timeout;
u8 status;
- status = ata_busy_wait(ap, ATA_BUSY, 300);
+ status = ata_sff_busy_wait(ap, ATA_BUSY, 300);
timer_start = jiffies;
- timeout = timer_start + tmout_pat;
+ timeout = ata_deadline(timer_start, tmout_pat);
while (status != 0xff && (status & ATA_BUSY) &&
time_before(jiffies, timeout)) {
msleep(50);
- status = ata_busy_wait(ap, ATA_BUSY, 3);
+ status = ata_sff_busy_wait(ap, ATA_BUSY, 3);
}
if (status != 0xff && (status & ATA_BUSY))
"port is slow to respond, please be patient "
"(Status 0x%x)\n", status);
- timeout = timer_start + tmout;
+ timeout = ata_deadline(timer_start, tmout);
while (status != 0xff && (status & ATA_BUSY) &&
time_before(jiffies, timeout)) {
msleep(50);
- status = ata_chk_status(ap);
+ status = ap->ops->sff_check_status(ap);
}
if (status == 0xff)
if (status & ATA_BUSY) {
ata_port_printk(ap, KERN_ERR, "port failed to respond "
"(%lu secs, Status 0x%x)\n",
- tmout / HZ, status);
+ DIV_ROUND_UP(tmout, 1000), status);
return -EBUSY;
}
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_busy_sleep);
+
+static int ata_sff_check_ready(struct ata_link *link)
+{
+ u8 status = link->ap->ops->sff_check_status(link->ap);
+
+ return ata_check_ready(status);
+}
/**
- * ata_wait_ready - sleep until BSY clears, or timeout
- * @ap: port containing status register to be polled
+ * ata_sff_wait_ready - sleep until BSY clears, or timeout
+ * @link: SFF link to wait ready status for
* @deadline: deadline jiffies for the operation
*
* Sleep until ATA Status register bit BSY clears, or timeout
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_wait_ready(struct ata_port *ap, unsigned long deadline)
+int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline)
{
- unsigned long start = jiffies;
- int warned = 0;
-
- while (1) {
- u8 status = ata_chk_status(ap);
- unsigned long now = jiffies;
-
- if (!(status & ATA_BUSY))
- return 0;
- if (!ata_link_online(&ap->link) && status == 0xff)
- return -ENODEV;
- if (time_after(now, deadline))
- return -EBUSY;
-
- if (!warned && time_after(now, start + 5 * HZ) &&
- (deadline - now > 3 * HZ)) {
- ata_port_printk(ap, KERN_WARNING,
- "port is slow to respond, please be patient "
- "(Status 0x%x)\n", status);
- warned = 1;
- }
-
- msleep(50);
- }
+ return ata_wait_ready(link, deadline, ata_sff_check_ready);
}
+EXPORT_SYMBOL_GPL(ata_sff_wait_ready);
/**
- * ata_std_dev_select - Select device 0/1 on ATA bus
+ * ata_sff_dev_select - Select device 0/1 on ATA bus
* @ap: ATA channel to manipulate
* @device: ATA device (numbered from zero) to select
*
* LOCKING:
* caller.
*/
-void ata_std_dev_select(struct ata_port *ap, unsigned int device)
+void ata_sff_dev_select(struct ata_port *ap, unsigned int device)
{
u8 tmp;
tmp = ATA_DEVICE_OBS | ATA_DEV1;
iowrite8(tmp, ap->ioaddr.device_addr);
- ata_pause(ap); /* needed; also flushes, for mmio */
+ ata_sff_pause(ap); /* needed; also flushes, for mmio */
}
+EXPORT_SYMBOL_GPL(ata_sff_dev_select);
/**
* ata_dev_select - Select device 0/1 on ATA bus
* make either device 0, or device 1, active on the
* ATA channel.
*
- * This is a high-level version of ata_std_dev_select(),
- * which additionally provides the services of inserting
- * the proper pauses and status polling, where needed.
+ * This is a high-level version of ata_sff_dev_select(), which
+ * additionally provides the services of inserting the proper
+ * pauses and status polling, where needed.
*
* LOCKING:
* caller.
if (wait)
ata_wait_idle(ap);
- ap->ops->dev_select(ap, device);
+ ap->ops->sff_dev_select(ap, device);
if (wait) {
if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
}
/**
- * ata_irq_on - Enable interrupts on a port.
+ * ata_sff_irq_on - Enable interrupts on a port.
* @ap: Port on which interrupts are enabled.
*
* Enable interrupts on a legacy IDE device using MMIO or PIO,
* LOCKING:
* Inherited from caller.
*/
-u8 ata_irq_on(struct ata_port *ap)
+u8 ata_sff_irq_on(struct ata_port *ap)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
u8 tmp;
iowrite8(ap->ctl, ioaddr->ctl_addr);
tmp = ata_wait_idle(ap);
- ap->ops->irq_clear(ap);
+ ap->ops->sff_irq_clear(ap);
return tmp;
}
+EXPORT_SYMBOL_GPL(ata_sff_irq_on);
/**
- * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
+ * ata_sff_irq_clear - Clear PCI IDE BMDMA interrupt.
* @ap: Port associated with this ATA transaction.
*
* Clear interrupt and error flags in DMA status register.
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-void ata_bmdma_irq_clear(struct ata_port *ap)
+void ata_sff_irq_clear(struct ata_port *ap)
{
void __iomem *mmio = ap->ioaddr.bmdma_addr;
iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS);
}
+EXPORT_SYMBOL_GPL(ata_sff_irq_clear);
/**
- * ata_tf_load - send taskfile registers to host controller
+ * ata_sff_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
* @tf: ATA taskfile register set
*
* LOCKING:
* Inherited from caller.
*/
-void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- WARN_ON(!ioaddr->ctl_addr);
+ WARN_ON_ONCE(!ioaddr->ctl_addr);
iowrite8(tf->hob_feature, ioaddr->feature_addr);
iowrite8(tf->hob_nsect, ioaddr->nsect_addr);
iowrite8(tf->hob_lbal, ioaddr->lbal_addr);
ata_wait_idle(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_tf_load);
/**
- * ata_tf_read - input device's ATA taskfile shadow registers
+ * ata_sff_tf_read - input device's ATA taskfile shadow registers
* @ap: Port from which input is read
* @tf: ATA taskfile register set for storing input
*
* LOCKING:
* Inherited from caller.
*/
-void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+void ata_sff_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
- tf->command = ata_check_status(ap);
+ tf->command = ata_sff_check_status(ap);
tf->feature = ioread8(ioaddr->error_addr);
tf->nsect = ioread8(ioaddr->nsect_addr);
tf->lbal = ioread8(ioaddr->lbal_addr);
iowrite8(tf->ctl, ioaddr->ctl_addr);
ap->last_ctl = tf->ctl;
} else
- WARN_ON(1);
+ WARN_ON_ONCE(1);
}
}
+EXPORT_SYMBOL_GPL(ata_sff_tf_read);
/**
- * ata_exec_command - issue ATA command to host controller
+ * ata_sff_exec_command - issue ATA command to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
+void ata_sff_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
{
DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
iowrite8(tf->command, ap->ioaddr.command_addr);
- ata_pause(ap);
+ ata_sff_pause(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_exec_command);
/**
* ata_tf_to_host - issue ATA taskfile to host controller
static inline void ata_tf_to_host(struct ata_port *ap,
const struct ata_taskfile *tf)
{
- ap->ops->tf_load(ap, tf);
- ap->ops->exec_command(ap, tf);
+ ap->ops->sff_tf_load(ap, tf);
+ ap->ops->sff_exec_command(ap, tf);
}
/**
- * ata_data_xfer - Transfer data by PIO
+ * ata_sff_data_xfer - Transfer data by PIO
* @dev: device to target
* @buf: data buffer
* @buflen: buffer length
* RETURNS:
* Bytes consumed.
*/
-unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf,
- unsigned int buflen, int rw)
+unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
{
struct ata_port *ap = dev->link->ap;
void __iomem *data_addr = ap->ioaddr.data_addr;
return words << 1;
}
+EXPORT_SYMBOL_GPL(ata_sff_data_xfer);
+
+/**
+ * ata_sff_data_xfer32 - Transfer data by PIO
+ * @dev: device to target
+ * @buf: data buffer
+ * @buflen: buffer length
+ * @rw: read/write
+ *
+ * Transfer data from/to the device data register by PIO using 32bit
+ * I/O operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * Bytes consumed.
+ */
+
+unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned int words = buflen >> 2;
+ int slop = buflen & 3;
+
+ /* Transfer multiple of 4 bytes */
+ if (rw == READ)
+ ioread32_rep(data_addr, buf, words);
+ else
+ iowrite32_rep(data_addr, buf, words);
+
+ if (unlikely(slop)) {
+ __le32 pad;
+ if (rw == READ) {
+ pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
+ memcpy(buf + buflen - slop, &pad, slop);
+ } else {
+ memcpy(&pad, buf + buflen - slop, slop);
+ iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ }
+ words++;
+ }
+ return words << 2;
+}
+EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
/**
- * ata_data_xfer_noirq - Transfer data by PIO
+ * ata_sff_data_xfer_noirq - Transfer data by PIO
* @dev: device to target
* @buf: data buffer
* @buflen: buffer length
* RETURNS:
* Bytes consumed.
*/
-unsigned int ata_data_xfer_noirq(struct ata_device *dev, unsigned char *buf,
- unsigned int buflen, int rw)
+unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
{
unsigned long flags;
unsigned int consumed;
local_irq_save(flags);
- consumed = ata_data_xfer(dev, buf, buflen, rw);
+ consumed = ata_sff_data_xfer(dev, buf, buflen, rw);
local_irq_restore(flags);
return consumed;
}
+EXPORT_SYMBOL_GPL(ata_sff_data_xfer_noirq);
/**
* ata_pio_sector - Transfer a sector of data.
buf = kmap_atomic(page, KM_IRQ0);
/* do the actual data transfer */
- ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write);
+ ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size,
+ do_write);
kunmap_atomic(buf, KM_IRQ0);
local_irq_restore(flags);
} else {
buf = page_address(page);
- ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write);
+ ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size,
+ do_write);
}
qc->curbytes += qc->sect_size;
/* READ/WRITE MULTIPLE */
unsigned int nsect;
- WARN_ON(qc->dev->multi_count == 0);
+ WARN_ON_ONCE(qc->dev->multi_count == 0);
nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size,
qc->dev->multi_count);
} else
ata_pio_sector(qc);
- ata_altstatus(qc->ap); /* flush */
+ ata_sff_sync(qc->ap); /* flush */
}
/**
{
/* send SCSI cdb */
DPRINTK("send cdb\n");
- WARN_ON(qc->dev->cdb_len < 12);
-
- ap->ops->data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
- ata_altstatus(ap); /* flush */
+ WARN_ON_ONCE(qc->dev->cdb_len < 12);
+ ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
+ ata_sff_sync(ap);
+ /* FIXME: If the CDB is for DMA do we need to do the transition delay
+ or is bmdma_start guaranteed to do it ? */
switch (qc->tf.protocol) {
case ATAPI_PROT_PIO:
ap->hsm_task_state = HSM_ST;
buf = kmap_atomic(page, KM_IRQ0);
/* do the actual data transfer */
- consumed = ap->ops->data_xfer(dev, buf + offset, count, rw);
+ consumed = ap->ops->sff_data_xfer(dev, buf + offset,
+ count, rw);
kunmap_atomic(buf, KM_IRQ0);
local_irq_restore(flags);
} else {
buf = page_address(page);
- consumed = ap->ops->data_xfer(dev, buf + offset, count, rw);
+ consumed = ap->ops->sff_data_xfer(dev, buf + offset,
+ count, rw);
}
bytes -= min(bytes, consumed);
qc->cursg_ofs = 0;
}
- /* consumed can be larger than count only for the last transfer */
- WARN_ON(qc->cursg && count != consumed);
-
+ /*
+ * There used to be a WARN_ON_ONCE(qc->cursg && count != consumed);
+ * Unfortunately __atapi_pio_bytes doesn't know enough to do the WARN
+ * check correctly as it doesn't know if it is the last request being
+ * made. Somebody should implement a proper sanity check.
+ */
if (bytes)
goto next_sg;
return 0;
* error, qc->result_tf is later overwritten by ata_qc_complete().
* So, the correctness of qc->result_tf is not affected.
*/
- ap->ops->tf_read(ap, &qc->result_tf);
+ ap->ops->sff_tf_read(ap, &qc->result_tf);
ireason = qc->result_tf.nsect;
bc_lo = qc->result_tf.lbam;
bc_hi = qc->result_tf.lbah;
if (unlikely(__atapi_pio_bytes(qc, bytes)))
goto err_out;
- ata_altstatus(ap); /* flush */
+ ata_sff_sync(ap); /* flush */
return;
* RETURNS:
* 1 if ok in workqueue, 0 otherwise.
*/
-static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc)
+static inline int ata_hsm_ok_in_wq(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
{
if (qc->tf.flags & ATA_TFLAG_POLLING)
return 1;
if (ap->hsm_task_state == HSM_ST_FIRST) {
if (qc->tf.protocol == ATA_PROT_PIO &&
- (qc->tf.flags & ATA_TFLAG_WRITE))
+ (qc->tf.flags & ATA_TFLAG_WRITE))
return 1;
if (ata_is_atapi(qc->tf.protocol) &&
- !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
return 1;
}
qc = ata_qc_from_tag(ap, qc->tag);
if (qc) {
if (likely(!(qc->err_mask & AC_ERR_HSM))) {
- ap->ops->irq_on(ap);
+ ap->ops->sff_irq_on(ap);
ata_qc_complete(qc);
} else
ata_port_freeze(ap);
} else {
if (in_wq) {
spin_lock_irqsave(ap->lock, flags);
- ap->ops->irq_on(ap);
+ ap->ops->sff_irq_on(ap);
ata_qc_complete(qc);
spin_unlock_irqrestore(ap->lock, flags);
} else
}
/**
- * ata_hsm_move - move the HSM to the next state.
+ * ata_sff_hsm_move - move the HSM to the next state.
* @ap: the target ata_port
* @qc: qc on going
* @status: current device status
* RETURNS:
* 1 when poll next status needed, 0 otherwise.
*/
-int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
- u8 status, int in_wq)
+int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u8 status, int in_wq)
{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
unsigned long flags = 0;
int poll_next;
- WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
+ WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
- /* Make sure ata_qc_issue_prot() does not throw things
+ /* Make sure ata_sff_qc_issue() does not throw things
* like DMA polling into the workqueue. Notice that
* in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING).
*/
- WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc));
+ WARN_ON_ONCE(in_wq != ata_hsm_ok_in_wq(ap, qc));
fsm_start:
DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
if (likely(status & (ATA_ERR | ATA_DF)))
/* device stops HSM for abort/error */
qc->err_mask |= AC_ERR_DEV;
- else
+ else {
/* HSM violation. Let EH handle this */
+ ata_ehi_push_desc(ehi,
+ "ST_FIRST: !(DRQ|ERR|DF)");
qc->err_mask |= AC_ERR_HSM;
+ }
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
* the CDB.
*/
if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) {
- ata_port_printk(ap, KERN_WARNING,
- "DRQ=1 with device error, "
- "dev_stat 0x%X\n", status);
+ ata_ehi_push_desc(ehi, "ST_FIRST: "
+ "DRQ=1 with device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
* let the EH abort the command or reset the device.
*/
if (unlikely(status & (ATA_ERR | ATA_DF))) {
- ata_port_printk(ap, KERN_WARNING, "DRQ=1 with "
- "device error, dev_stat 0x%X\n",
- status);
+ ata_ehi_push_desc(ehi, "ST-ATAPI: "
+ "DRQ=1 with device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
/* ATA PIO protocol */
if (unlikely((status & ATA_DRQ) == 0)) {
/* handle BSY=0, DRQ=0 as error */
- if (likely(status & (ATA_ERR | ATA_DF)))
+ if (likely(status & (ATA_ERR | ATA_DF))) {
/* device stops HSM for abort/error */
qc->err_mask |= AC_ERR_DEV;
- else
+
+ /* If diagnostic failed and this is
+ * IDENTIFY, it's likely a phantom
+ * device. Mark hint.
+ */
+ if (qc->dev->horkage &
+ ATA_HORKAGE_DIAGNOSTIC)
+ qc->err_mask |=
+ AC_ERR_NODEV_HINT;
+ } else {
/* HSM violation. Let EH handle this.
* Phantom devices also trigger this
* condition. Mark hint.
*/
+ ata_ehi_push_desc(ehi, "ST-ATA: "
+ "DRQ=1 with device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM |
AC_ERR_NODEV_HINT;
+ }
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
status = ata_wait_idle(ap);
}
- if (status & (ATA_BUSY | ATA_DRQ))
+ if (status & (ATA_BUSY | ATA_DRQ)) {
+ ata_ehi_push_desc(ehi, "ST-ATA: "
+ "BUSY|DRQ persists on ERR|DF, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
+ }
/* ata_pio_sectors() might change the
* state to HSM_ST_LAST. so, the state
DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n",
ap->print_id, qc->dev->devno, status);
- WARN_ON(qc->err_mask);
+ WARN_ON_ONCE(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM));
ap->hsm_task_state = HSM_ST_IDLE;
break;
case HSM_ST_ERR:
- /* make sure qc->err_mask is available to
- * know what's wrong and recover
- */
- WARN_ON(qc->err_mask == 0);
-
ap->hsm_task_state = HSM_ST_IDLE;
/* complete taskfile transaction */
return poll_next;
}
+EXPORT_SYMBOL_GPL(ata_sff_hsm_move);
void ata_pio_task(struct work_struct *work)
{
int poll_next;
fsm_start:
- WARN_ON(ap->hsm_task_state == HSM_ST_IDLE);
+ WARN_ON_ONCE(ap->hsm_task_state == HSM_ST_IDLE);
/*
* This is purely heuristic. This is a fast path.
* or something. Snooze for a couple msecs, then
* chk-status again. If still busy, queue delayed work.
*/
- status = ata_busy_wait(ap, ATA_BUSY, 5);
+ status = ata_sff_busy_wait(ap, ATA_BUSY, 5);
if (status & ATA_BUSY) {
msleep(2);
- status = ata_busy_wait(ap, ATA_BUSY, 10);
+ status = ata_sff_busy_wait(ap, ATA_BUSY, 10);
if (status & ATA_BUSY) {
ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE);
return;
}
/* move the HSM */
- poll_next = ata_hsm_move(ap, qc, status, 1);
+ poll_next = ata_sff_hsm_move(ap, qc, status, 1);
/* another command or interrupt handler
* may be running at this point.
}
/**
- * ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
+ * ata_sff_qc_issue - issue taskfile to device in proto-dependent manner
* @qc: command to issue to device
*
* Using various libata functions and hooks, this function
* RETURNS:
* Zero on success, AC_ERR_* mask on failure
*/
-unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
break;
case ATA_PROT_DMA:
- WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+ WARN_ON_ONCE(qc->tf.flags & ATA_TFLAG_POLLING);
- ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
+ ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
ap->ops->bmdma_start(qc); /* initiate bmdma */
ap->hsm_task_state = HSM_ST_LAST;
break;
case ATAPI_PROT_DMA:
- WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+ WARN_ON_ONCE(qc->tf.flags & ATA_TFLAG_POLLING);
- ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
+ ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
ap->hsm_task_state = HSM_ST_FIRST;
break;
default:
- WARN_ON(1);
+ WARN_ON_ONCE(1);
return AC_ERR_SYSTEM;
}
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_qc_issue);
/**
- * ata_host_intr - Handle host interrupt for given (port, task)
+ * ata_sff_qc_fill_rtf - fill result TF using ->sff_tf_read
+ * @qc: qc to fill result TF for
+ *
+ * @qc is finished and result TF needs to be filled. Fill it
+ * using ->sff_tf_read.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * true indicating that result TF is successfully filled.
+ */
+bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+ qc->ap->ops->sff_tf_read(qc->ap, &qc->result_tf);
+ return true;
+}
+EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf);
+
+/**
+ * ata_sff_host_intr - Handle host interrupt for given (port, task)
* @ap: Port on which interrupt arrived (possibly...)
* @qc: Taskfile currently active in engine
*
* RETURNS:
* One if interrupt was handled, zero if not (shared irq).
*/
-inline unsigned int ata_host_intr(struct ata_port *ap,
- struct ata_queued_cmd *qc)
+inline unsigned int ata_sff_host_intr(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
{
struct ata_eh_info *ehi = &ap->link.eh_info;
u8 status, host_stat = 0;
goto idle_irq;
}
- /* check altstatus */
- status = ata_altstatus(ap);
- if (status & ATA_BUSY)
- goto idle_irq;
- /* check main status, clearing INTRQ */
- status = ata_chk_status(ap);
- if (unlikely(status & ATA_BUSY))
+ /* check main status, clearing INTRQ if needed */
+ status = ata_sff_irq_status(ap);
+ if (status & ATA_BUSY)
goto idle_irq;
/* ack bmdma irq events */
- ap->ops->irq_clear(ap);
+ ap->ops->sff_irq_clear(ap);
- ata_hsm_move(ap, qc, status, 0);
+ ata_sff_hsm_move(ap, qc, status, 0);
if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
qc->tf.protocol == ATAPI_PROT_DMA))
#ifdef ATA_IRQ_TRAP
if ((ap->stats.idle_irq % 1000) == 0) {
- ata_chk_status(ap);
- ap->ops->irq_clear(ap);
+ ap->ops->sff_check_status(ap);
+ ap->ops->sff_irq_clear(ap);
ata_port_printk(ap, KERN_WARNING, "irq trap\n");
return 1;
}
#endif
return 0; /* irq not handled */
}
+EXPORT_SYMBOL_GPL(ata_sff_host_intr);
/**
- * ata_interrupt - Default ATA host interrupt handler
+ * ata_sff_interrupt - Default ATA host interrupt handler
* @irq: irq line (unused)
* @dev_instance: pointer to our ata_host information structure
*
* Default interrupt handler for PCI IDE devices. Calls
- * ata_host_intr() for each port that is not disabled.
+ * ata_sff_host_intr() for each port that is not disabled.
*
* LOCKING:
* Obtains host lock during operation.
* RETURNS:
* IRQ_NONE or IRQ_HANDLED.
*/
-irqreturn_t ata_interrupt(int irq, void *dev_instance)
+irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int i;
qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
(qc->flags & ATA_QCFLAG_ACTIVE))
- handled |= ata_host_intr(ap, qc);
+ handled |= ata_sff_host_intr(ap, qc);
}
}
return IRQ_RETVAL(handled);
}
+EXPORT_SYMBOL_GPL(ata_sff_interrupt);
/**
- * ata_bmdma_freeze - Freeze BMDMA controller port
+ * ata_sff_freeze - Freeze SFF controller port
* @ap: port to freeze
*
* Freeze BMDMA controller port.
* LOCKING:
* Inherited from caller.
*/
-void ata_bmdma_freeze(struct ata_port *ap)
+void ata_sff_freeze(struct ata_port *ap)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
* ATA_NIEN manipulation. Also, many controllers fail to mask
* previously pending IRQ on ATA_NIEN assertion. Clear it.
*/
- ata_chk_status(ap);
+ ap->ops->sff_check_status(ap);
- ap->ops->irq_clear(ap);
+ ap->ops->sff_irq_clear(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_freeze);
/**
- * ata_bmdma_thaw - Thaw BMDMA controller port
+ * ata_sff_thaw - Thaw SFF controller port
* @ap: port to thaw
*
- * Thaw BMDMA controller port.
+ * Thaw SFF controller port.
*
* LOCKING:
* Inherited from caller.
*/
-void ata_bmdma_thaw(struct ata_port *ap)
+void ata_sff_thaw(struct ata_port *ap)
{
/* clear & re-enable interrupts */
- ata_chk_status(ap);
- ap->ops->irq_clear(ap);
- ap->ops->irq_on(ap);
+ ap->ops->sff_check_status(ap);
+ ap->ops->sff_irq_clear(ap);
+ ap->ops->sff_irq_on(ap);
+}
+EXPORT_SYMBOL_GPL(ata_sff_thaw);
+
+/**
+ * ata_sff_prereset - prepare SFF link for reset
+ * @link: SFF link to be reset
+ * @deadline: deadline jiffies for the operation
+ *
+ * SFF link @link is about to be reset. Initialize it. It first
+ * calls ata_std_prereset() and wait for !BSY if the port is
+ * being softreset.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_sff_prereset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_eh_context *ehc = &link->eh_context;
+ int rc;
+
+ rc = ata_std_prereset(link, deadline);
+ if (rc)
+ return rc;
+
+ /* if we're about to do hardreset, nothing more to do */
+ if (ehc->i.action & ATA_EH_HARDRESET)
+ return 0;
+
+ /* wait for !BSY if we don't know that no device is attached */
+ if (!ata_link_offline(link)) {
+ rc = ata_sff_wait_ready(link, deadline);
+ if (rc && rc != -ENODEV) {
+ ata_link_printk(link, KERN_WARNING, "device not ready "
+ "(errno=%d), forcing hardreset\n", rc);
+ ehc->i.action |= ATA_EH_HARDRESET;
+ }
+ }
+
+ return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_prereset);
/**
* ata_devchk - PATA device presence detection
struct ata_ioports *ioaddr = &ap->ioaddr;
u8 nsect, lbal;
- ap->ops->dev_select(ap, device);
+ ap->ops->sff_dev_select(ap, device);
iowrite8(0x55, ioaddr->nsect_addr);
iowrite8(0xaa, ioaddr->lbal_addr);
}
/**
- * ata_dev_try_classify - Parse returned ATA device signature
+ * ata_sff_dev_classify - Parse returned ATA device signature
* @dev: ATA device to classify (starting at zero)
* @present: device seems present
* @r_err: Value of error register on completion
* RETURNS:
* Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
*/
-unsigned int ata_dev_try_classify(struct ata_device *dev, int present,
+unsigned int ata_sff_dev_classify(struct ata_device *dev, int present,
u8 *r_err)
{
struct ata_port *ap = dev->link->ap;
unsigned int class;
u8 err;
- ap->ops->dev_select(ap, dev->devno);
+ ap->ops->sff_dev_select(ap, dev->devno);
memset(&tf, 0, sizeof(tf));
- ap->ops->tf_read(ap, &tf);
+ ap->ops->sff_tf_read(ap, &tf);
err = tf.feature;
if (r_err)
*r_err = err;
class = ATA_DEV_ATA;
else
class = ATA_DEV_NONE;
- } else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
+ } else if ((class == ATA_DEV_ATA) &&
+ (ap->ops->sff_check_status(ap) == 0))
class = ATA_DEV_NONE;
return class;
}
+EXPORT_SYMBOL_GPL(ata_sff_dev_classify);
-static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask,
- unsigned long deadline)
+/**
+ * ata_sff_wait_after_reset - wait for devices to become ready after reset
+ * @link: SFF link which is just reset
+ * @devmask: mask of present devices
+ * @deadline: deadline jiffies for the operation
+ *
+ * Wait devices attached to SFF @link to become ready after
+ * reset. It contains preceding 150ms wait to avoid accessing TF
+ * status register too early.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -ENODEV if some or all of devices in @devmask
+ * don't seem to exist. -errno on other errors.
+ */
+int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
+ unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int dev0 = devmask & (1 << 0);
unsigned int dev1 = devmask & (1 << 1);
int rc, ret = 0;
- /* if device 0 was found in ata_devchk, wait for its
- * BSY bit to clear
+ msleep(ATA_WAIT_AFTER_RESET);
+
+ /* always check readiness of the master device */
+ rc = ata_sff_wait_ready(link, deadline);
+ /* -ENODEV means the odd clown forgot the D7 pulldown resistor
+ * and TF status is 0xff, bail out on it too.
*/
- if (dev0) {
- rc = ata_wait_ready(ap, deadline);
- if (rc) {
- if (rc != -ENODEV)
- return rc;
- ret = rc;
- }
- }
+ if (rc)
+ return rc;
/* if device 1 was found in ata_devchk, wait for register
* access briefly, then wait for BSY to clear.
if (dev1) {
int i;
- ap->ops->dev_select(ap, 1);
+ ap->ops->sff_dev_select(ap, 1);
/* Wait for register access. Some ATAPI devices fail
* to set nsect/lbal after reset, so don't waste too
msleep(50); /* give drive a breather */
}
- rc = ata_wait_ready(ap, deadline);
+ rc = ata_sff_wait_ready(link, deadline);
if (rc) {
if (rc != -ENODEV)
return rc;
}
/* is all this really necessary? */
- ap->ops->dev_select(ap, 0);
+ ap->ops->sff_dev_select(ap, 0);
if (dev1)
- ap->ops->dev_select(ap, 1);
+ ap->ops->sff_dev_select(ap, 1);
if (dev0)
- ap->ops->dev_select(ap, 0);
+ ap->ops->sff_dev_select(ap, 0);
return ret;
}
-
-/**
- * ata_wait_after_reset - wait before checking status after reset
- * @ap: port containing status register to be polled
- * @deadline: deadline jiffies for the operation
- *
- * After reset, we need to pause a while before reading status.
- * Also, certain combination of controller and device report 0xff
- * for some duration (e.g. until SATA PHY is up and running)
- * which is interpreted as empty port in ATA world. This
- * function also waits for such devices to get out of 0xff
- * status.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- */
-void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline)
-{
- unsigned long until = jiffies + ATA_TMOUT_FF_WAIT;
-
- if (time_before(until, deadline))
- deadline = until;
-
- /* Spec mandates ">= 2ms" before checking status. We wait
- * 150ms, because that was the magic delay used for ATAPI
- * devices in Hale Landis's ATADRVR, for the period of time
- * between when the ATA command register is written, and then
- * status is checked. Because waiting for "a while" before
- * checking status is fine, post SRST, we perform this magic
- * delay here as well.
- *
- * Old drivers/ide uses the 2mS rule and then waits for ready.
- */
- msleep(150);
-
- /* Wait for 0xff to clear. Some SATA devices take a long time
- * to clear 0xff after reset. For example, HHD424020F7SV00
- * iVDR needs >= 800ms while. Quantum GoVault needs even more
- * than that.
- *
- * Note that some PATA controllers (pata_ali) explode if
- * status register is read more than once when there's no
- * device attached.
- */
- if (ap->flags & ATA_FLAG_SATA) {
- while (1) {
- u8 status = ata_chk_status(ap);
-
- if (status != 0xff || time_after(jiffies, deadline))
- return;
-
- msleep(50);
- }
- }
-}
+EXPORT_SYMBOL_GPL(ata_sff_wait_after_reset);
static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
unsigned long deadline)
udelay(20); /* FIXME: flush */
iowrite8(ap->ctl, ioaddr->ctl_addr);
- /* wait a while before checking status */
- ata_wait_after_reset(ap, deadline);
-
- /* Before we perform post reset processing we want to see if
- * the bus shows 0xFF because the odd clown forgets the D7
- * pulldown resistor.
- */
- if (ata_chk_status(ap) == 0xFF)
- return -ENODEV;
-
- return ata_bus_post_reset(ap, devmask, deadline);
+ /* wait the port to become ready */
+ return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
}
/**
- * ata_std_softreset - reset host port via ATA SRST
+ * ata_sff_softreset - reset host port via ATA SRST
* @link: ATA link to reset
* @classes: resulting classes of attached devices
* @deadline: deadline jiffies for the operation
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_std_softreset(struct ata_link *link, unsigned int *classes,
+int ata_sff_softreset(struct ata_link *link, unsigned int *classes,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
DPRINTK("ENTER\n");
- if (ata_link_offline(link)) {
- classes[0] = ATA_DEV_NONE;
- goto out;
- }
-
/* determine if device 0/1 are present */
if (ata_devchk(ap, 0))
devmask |= (1 << 0);
devmask |= (1 << 1);
/* select device 0 again */
- ap->ops->dev_select(ap, 0);
+ ap->ops->sff_dev_select(ap, 0);
/* issue bus reset */
DPRINTK("about to softreset, devmask=%x\n", devmask);
}
/* determine by signature whether we have ATA or ATAPI devices */
- classes[0] = ata_dev_try_classify(&link->device[0],
+ classes[0] = ata_sff_dev_classify(&link->device[0],
devmask & (1 << 0), &err);
if (slave_possible && err != 0x81)
- classes[1] = ata_dev_try_classify(&link->device[1],
+ classes[1] = ata_sff_dev_classify(&link->device[1],
devmask & (1 << 1), &err);
- out:
DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_softreset);
/**
- * sata_std_hardreset - reset host port via SATA phy reset
+ * sata_sff_hardreset - reset host port via SATA phy reset
* @link: link to reset
* @class: resulting class of attached device
* @deadline: deadline jiffies for the operation
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int sata_std_hardreset(struct ata_link *link, unsigned int *class,
+int sata_sff_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
- struct ata_port *ap = link->ap;
- const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ struct ata_eh_context *ehc = &link->eh_context;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
+ bool online;
int rc;
- DPRINTK("ENTER\n");
-
- /* do hardreset */
- rc = sata_link_hardreset(link, timing, deadline);
- if (rc) {
- ata_link_printk(link, KERN_ERR,
- "COMRESET failed (errno=%d)\n", rc);
- return rc;
- }
+ rc = sata_link_hardreset(link, timing, deadline, &online,
+ ata_sff_check_ready);
+ if (online)
+ *class = ata_sff_dev_classify(link->device, 1, NULL);
- /* TODO: phy layer with polling, timeouts, etc. */
- if (ata_link_offline(link)) {
- *class = ATA_DEV_NONE;
- DPRINTK("EXIT, link offline\n");
- return 0;
- }
+ DPRINTK("EXIT, class=%u\n", *class);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(sata_sff_hardreset);
- /* wait a while before checking status */
- ata_wait_after_reset(ap, deadline);
+/**
+ * ata_sff_postreset - SFF postreset callback
+ * @link: the target SFF ata_link
+ * @classes: classes of attached devices
+ *
+ * This function is invoked after a successful reset. It first
+ * calls ata_std_postreset() and performs SFF specific postreset
+ * processing.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_sff_postreset(struct ata_link *link, unsigned int *classes)
+{
+ struct ata_port *ap = link->ap;
- /* If PMP is supported, we have to do follow-up SRST. Note
- * that some PMPs don't send D2H Reg FIS after hardreset at
- * all if the first port is empty. Wait for it just for a
- * second and request follow-up SRST.
- */
- if (ap->flags & ATA_FLAG_PMP) {
- ata_wait_ready(ap, jiffies + HZ);
- return -EAGAIN;
- }
+ ata_std_postreset(link, classes);
- rc = ata_wait_ready(ap, deadline);
- /* link occupied, -ENODEV too is an error */
- if (rc) {
- ata_link_printk(link, KERN_ERR,
- "COMRESET failed (errno=%d)\n", rc);
- return rc;
+ /* is double-select really necessary? */
+ if (classes[0] != ATA_DEV_NONE)
+ ap->ops->sff_dev_select(ap, 1);
+ if (classes[1] != ATA_DEV_NONE)
+ ap->ops->sff_dev_select(ap, 0);
+
+ /* bail out if no device is present */
+ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+ DPRINTK("EXIT, no device\n");
+ return;
}
- ap->ops->dev_select(ap, 0); /* probably unnecessary */
-
- *class = ata_dev_try_classify(link->device, 1, NULL);
-
- DPRINTK("EXIT, class=%u\n", *class);
- return 0;
+ /* set up device control */
+ if (ap->ioaddr.ctl_addr)
+ iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
}
+EXPORT_SYMBOL_GPL(ata_sff_postreset);
/**
- * ata_bmdma_error_handler - Stock error handler for BMDMA controller
+ * ata_sff_error_handler - Stock error handler for BMDMA controller
* @ap: port to handle error for
*
- * Stock error handler for BMDMA controller. It can handle both
+ * Stock error handler for SFF controller. It can handle both
* PATA and SATA controllers. Many controllers should be able to
* use this EH as-is or with some added handling before and
* after.
* LOCKING:
* Kernel thread context (may sleep)
*/
-void ata_bmdma_error_handler(struct ata_port *ap)
+void ata_sff_error_handler(struct ata_port *ap)
{
ata_reset_fn_t softreset = ap->ops->softreset;
ata_reset_fn_t hardreset = ap->ops->hardreset;
ap->hsm_task_state = HSM_ST_IDLE;
- if (qc && (qc->tf.protocol == ATA_PROT_DMA ||
+ if (ap->ioaddr.bmdma_addr &&
+ qc && (qc->tf.protocol == ATA_PROT_DMA ||
qc->tf.protocol == ATAPI_PROT_DMA)) {
u8 host_stat;
ap->ops->bmdma_stop(qc);
}
- ata_altstatus(ap);
- ata_chk_status(ap);
- ap->ops->irq_clear(ap);
+ ata_sff_sync(ap); /* FIXME: We don't need this */
+ ap->ops->sff_check_status(ap);
+ ap->ops->sff_irq_clear(ap);
spin_unlock_irqrestore(ap->lock, flags);
/* PIO and DMA engines have been stopped, perform recovery */
- /* ata_std_softreset and sata_std_hardreset are inherited to
- * all SFF drivers from ata_sff_port_ops. Ignore softreset if
- * ctl isn't accessible. Ignore hardreset if SCR access isn't
- * available.
+ /* Ignore ata_sff_softreset if ctl isn't accessible and
+ * built-in hardresets if SCR access isn't available.
*/
- if (softreset == ata_std_softreset && !ap->ioaddr.ctl_addr)
+ if (softreset == ata_sff_softreset && !ap->ioaddr.ctl_addr)
softreset = NULL;
- if (hardreset == sata_std_hardreset && !sata_scr_valid(&ap->link))
+ if (ata_is_builtin_hardreset(hardreset) && !sata_scr_valid(&ap->link))
hardreset = NULL;
ata_do_eh(ap, ap->ops->prereset, softreset, hardreset,
ap->ops->postreset);
}
+EXPORT_SYMBOL_GPL(ata_sff_error_handler);
/**
- * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for
- * BMDMA controller
+ * ata_sff_post_internal_cmd - Stock post_internal_cmd for SFF controller
* @qc: internal command to clean up
*
* LOCKING:
* Kernel thread context (may sleep)
*/
-void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
+void ata_sff_post_internal_cmd(struct ata_queued_cmd *qc)
{
- if (qc->ap->ioaddr.bmdma_addr)
+ struct ata_port *ap = qc->ap;
+ unsigned long flags;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ if (ap->ioaddr.bmdma_addr)
ata_bmdma_stop(qc);
+
+ spin_unlock_irqrestore(ap->lock, flags);
}
+EXPORT_SYMBOL_GPL(ata_sff_post_internal_cmd);
/**
* ata_sff_port_start - Set port up for dma.
return ata_port_start(ap);
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_port_start);
/**
- * ata_std_ports - initialize ioaddr with standard port offsets.
+ * ata_sff_std_ports - initialize ioaddr with standard port offsets.
* @ioaddr: IO address structure to be initialized
*
* Utility function which initializes data_addr, error_addr,
*
* Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr.
*/
-void ata_std_ports(struct ata_ioports *ioaddr)
+void ata_sff_std_ports(struct ata_ioports *ioaddr)
{
ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR;
ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS;
ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
}
+EXPORT_SYMBOL_GPL(ata_sff_std_ports);
+
+unsigned long ata_bmdma_mode_filter(struct ata_device *adev,
+ unsigned long xfer_mask)
+{
+ /* Filter out DMA modes if the device has been configured by
+ the BIOS as PIO only */
+
+ if (adev->link->ap->ioaddr.bmdma_addr == NULL)
+ xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+ return xfer_mask;
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_mode_filter);
/**
* ata_bmdma_setup - Set up PCI IDE BMDMA transaction
iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
/* issue r/w command */
- ap->ops->exec_command(ap, &qc->tf);
+ ap->ops->sff_exec_command(ap, &qc->tf);
}
+EXPORT_SYMBOL_GPL(ata_bmdma_setup);
/**
* ata_bmdma_start - Start a PCI IDE BMDMA transaction
* unneccessarily delayed for MMIO
*/
}
+EXPORT_SYMBOL_GPL(ata_bmdma_start);
/**
* ata_bmdma_stop - Stop PCI IDE BMDMA transfer
mmio + ATA_DMA_CMD);
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
- ata_altstatus(ap); /* dummy read */
+ ata_sff_dma_pause(ap);
}
+EXPORT_SYMBOL_GPL(ata_bmdma_stop);
/**
* ata_bmdma_status - Read PCI IDE BMDMA status
{
return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
}
+EXPORT_SYMBOL_GPL(ata_bmdma_status);
/**
* ata_bus_reset - reset host port and associated ATA channel
devmask |= (1 << 1);
/* select device 0 again */
- ap->ops->dev_select(ap, 0);
+ ap->ops->sff_dev_select(ap, 0);
/* issue bus reset */
if (ap->flags & ATA_FLAG_SRST) {
- rc = ata_bus_softreset(ap, devmask, jiffies + 40 * HZ);
+ rc = ata_bus_softreset(ap, devmask,
+ ata_deadline(jiffies, 40000));
if (rc && rc != -ENODEV)
goto err_out;
}
/*
* determine by signature whether we have ATA or ATAPI devices
*/
- device[0].class = ata_dev_try_classify(&device[0], dev0, &err);
+ device[0].class = ata_sff_dev_classify(&device[0], dev0, &err);
if ((slave_possible) && (err != 0x81))
- device[1].class = ata_dev_try_classify(&device[1], dev1, &err);
+ device[1].class = ata_sff_dev_classify(&device[1], dev1, &err);
/* is double-select really necessary? */
if (device[1].class != ATA_DEV_NONE)
- ap->ops->dev_select(ap, 1);
+ ap->ops->sff_dev_select(ap, 1);
if (device[0].class != ATA_DEV_NONE)
- ap->ops->dev_select(ap, 0);
+ ap->ops->sff_dev_select(ap, 0);
/* if no devices were detected, disable this port */
if ((device[0].class == ATA_DEV_NONE) &&
DPRINTK("EXIT\n");
}
+EXPORT_SYMBOL_GPL(ata_bus_reset);
#ifdef CONFIG_PCI
/**
- * ata_pci_clear_simplex - attempt to kick device out of simplex
+ * ata_pci_bmdma_clear_simplex - attempt to kick device out of simplex
* @pdev: PCI device
*
* Some PCI ATA devices report simplex mode but in fact can be told to
* perform the task on such devices. Calling it on other devices will
* have -undefined- behaviour.
*/
-int ata_pci_clear_simplex(struct pci_dev *pdev)
+int ata_pci_bmdma_clear_simplex(struct pci_dev *pdev)
{
unsigned long bmdma = pci_resource_start(pdev, 4);
u8 simplex;
return -EOPNOTSUPP;
return 0;
}
-
-unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer_mask)
-{
- /* Filter out DMA modes if the device has been configured by
- the BIOS as PIO only */
-
- if (adev->link->ap->ioaddr.bmdma_addr == NULL)
- xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
- return xfer_mask;
-}
+EXPORT_SYMBOL_GPL(ata_pci_bmdma_clear_simplex);
/**
- * ata_pci_init_bmdma - acquire PCI BMDMA resources and init ATA host
+ * ata_pci_bmdma_init - acquire PCI BMDMA resources and init ATA host
* @host: target ATA host
*
* Acquire PCI BMDMA resources and initialize @host accordingly.
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_pci_init_bmdma(struct ata_host *host)
+int ata_pci_bmdma_init(struct ata_host *host)
{
struct device *gdev = host->dev;
struct pci_dev *pdev = to_pci_dev(gdev);
host->flags |= ATA_HOST_SIMPLEX;
ata_port_desc(ap, "bmdma 0x%llx",
- (unsigned long long)pci_resource_start(pdev, 4) + 8 * i);
+ (unsigned long long)pci_resource_start(pdev, 4) + 8 * i);
}
return 0;
}
+EXPORT_SYMBOL_GPL(ata_pci_bmdma_init);
static int ata_resources_present(struct pci_dev *pdev, int port)
{
/* Check the PCI resources for this channel are enabled */
port = port * 2;
- for (i = 0; i < 2; i ++) {
+ for (i = 0; i < 2; i++) {
if (pci_resource_start(pdev, port + i) == 0 ||
pci_resource_len(pdev, port + i) == 0)
return 0;
}
/**
- * ata_pci_init_sff_host - acquire native PCI ATA resources and init host
+ * ata_pci_sff_init_host - acquire native PCI ATA resources and init host
* @host: target ATA host
*
* Acquire native PCI ATA resources for @host and initialize the
* 0 if at least one port is initialized, -ENODEV if no port is
* available.
*/
-int ata_pci_init_sff_host(struct ata_host *host)
+int ata_pci_sff_init_host(struct ata_host *host)
{
struct device *gdev = host->dev;
struct pci_dev *pdev = to_pci_dev(gdev);
ap->ioaddr.altstatus_addr =
ap->ioaddr.ctl_addr = (void __iomem *)
((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS);
- ata_std_ports(&ap->ioaddr);
+ ata_sff_std_ports(&ap->ioaddr);
ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
(unsigned long long)pci_resource_start(pdev, base),
return 0;
}
+EXPORT_SYMBOL_GPL(ata_pci_sff_init_host);
/**
- * ata_pci_prepare_sff_host - helper to prepare native PCI ATA host
+ * ata_pci_sff_prepare_host - helper to prepare native PCI ATA host
* @pdev: target PCI device
* @ppi: array of port_info, must be enough for two ports
* @r_host: out argument for the initialized ATA host
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_pci_prepare_sff_host(struct pci_dev *pdev,
- const struct ata_port_info * const * ppi,
+int ata_pci_sff_prepare_host(struct pci_dev *pdev,
+ const struct ata_port_info * const *ppi,
struct ata_host **r_host)
{
struct ata_host *host;
goto err_out;
}
- rc = ata_pci_init_sff_host(host);
+ rc = ata_pci_sff_init_host(host);
if (rc)
goto err_out;
/* init DMA related stuff */
- rc = ata_pci_init_bmdma(host);
+ rc = ata_pci_bmdma_init(host);
if (rc)
goto err_bmdma;
*r_host = host;
return 0;
- err_bmdma:
+err_bmdma:
/* This is necessary because PCI and iomap resources are
* merged and releasing the top group won't release the
* acquired resources if some of those have been acquired
* before entering this function.
*/
pcim_iounmap_regions(pdev, 0xf);
- err_out:
+err_out:
devres_release_group(&pdev->dev, NULL);
return rc;
}
+EXPORT_SYMBOL_GPL(ata_pci_sff_prepare_host);
/**
- * ata_pci_activate_sff_host - start SFF host, request IRQ and register it
+ * ata_pci_sff_activate_host - start SFF host, request IRQ and register it
* @host: target SFF ATA host
* @irq_handler: irq_handler used when requesting IRQ(s)
* @sht: scsi_host_template to use when registering the host
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_pci_activate_sff_host(struct ata_host *host,
+int ata_pci_sff_activate_host(struct ata_host *host,
irq_handler_t irq_handler,
struct scsi_host_template *sht)
{
}
rc = ata_host_register(host, sht);
- out:
+out:
if (rc == 0)
devres_remove_group(dev, NULL);
else
return rc;
}
+EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
/**
- * ata_pci_init_one - Initialize/register PCI IDE host controller
+ * ata_pci_sff_init_one - Initialize/register PCI IDE host controller
* @pdev: Controller to be initialized
* @ppi: array of port_info, must be enough for two ports
* @sht: scsi_host_template to use when registering the host
* RETURNS:
* Zero on success, negative on errno-based value on error.
*/
-int ata_pci_init_one(struct pci_dev *pdev,
- const struct ata_port_info * const * ppi,
- struct scsi_host_template *sht, void *host_priv)
+int ata_pci_sff_init_one(struct pci_dev *pdev,
+ const struct ata_port_info * const *ppi,
+ struct scsi_host_template *sht, void *host_priv)
{
struct device *dev = &pdev->dev;
const struct ata_port_info *pi = NULL;
goto out;
/* prepare and activate SFF host */
- rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
+ rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
if (rc)
goto out;
host->private_data = host_priv;
pci_set_master(pdev);
- rc = ata_pci_activate_sff_host(host, ata_interrupt, sht);
- out:
+ rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht);
+out:
if (rc == 0)
devres_remove_group(&pdev->dev, NULL);
else
return rc;
}
+EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
#endif /* CONFIG_PCI */
-EXPORT_SYMBOL_GPL(ata_sff_port_ops);
-EXPORT_SYMBOL_GPL(ata_bmdma_port_ops);
-EXPORT_SYMBOL_GPL(ata_qc_prep);
-EXPORT_SYMBOL_GPL(ata_dumb_qc_prep);
-EXPORT_SYMBOL_GPL(ata_std_dev_select);
-EXPORT_SYMBOL_GPL(ata_check_status);
-EXPORT_SYMBOL_GPL(ata_altstatus);
-EXPORT_SYMBOL_GPL(ata_busy_sleep);
-EXPORT_SYMBOL_GPL(ata_wait_ready);
-EXPORT_SYMBOL_GPL(ata_tf_load);
-EXPORT_SYMBOL_GPL(ata_tf_read);
-EXPORT_SYMBOL_GPL(ata_exec_command);
-EXPORT_SYMBOL_GPL(ata_data_xfer);
-EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
-EXPORT_SYMBOL_GPL(ata_irq_on);
-EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
-EXPORT_SYMBOL_GPL(ata_hsm_move);
-EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
-EXPORT_SYMBOL_GPL(ata_host_intr);
-EXPORT_SYMBOL_GPL(ata_interrupt);
-EXPORT_SYMBOL_GPL(ata_bmdma_freeze);
-EXPORT_SYMBOL_GPL(ata_bmdma_thaw);
-EXPORT_SYMBOL_GPL(ata_std_prereset);
-EXPORT_SYMBOL_GPL(ata_dev_try_classify);
-EXPORT_SYMBOL_GPL(ata_wait_after_reset);
-EXPORT_SYMBOL_GPL(ata_std_softreset);
-EXPORT_SYMBOL_GPL(sata_std_hardreset);
-EXPORT_SYMBOL_GPL(ata_std_postreset);
-EXPORT_SYMBOL_GPL(ata_bmdma_error_handler);
-EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
-EXPORT_SYMBOL_GPL(ata_sff_port_start);
-EXPORT_SYMBOL_GPL(ata_std_ports);
-EXPORT_SYMBOL_GPL(ata_bmdma_setup);
-EXPORT_SYMBOL_GPL(ata_bmdma_start);
-EXPORT_SYMBOL_GPL(ata_bmdma_stop);
-EXPORT_SYMBOL_GPL(ata_bmdma_status);
-EXPORT_SYMBOL_GPL(ata_bus_reset);
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
-EXPORT_SYMBOL_GPL(ata_pci_default_filter);
-EXPORT_SYMBOL_GPL(ata_pci_init_bmdma);
-EXPORT_SYMBOL_GPL(ata_pci_init_sff_host);
-EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host);
-EXPORT_SYMBOL_GPL(ata_pci_activate_sff_host);
-EXPORT_SYMBOL_GPL(ata_pci_init_one);
-#endif /* CONFIG_PCI */