Commit dee23837 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev

* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev: (29 commits)
  libata: implement EH fast drain
  libata: schedule probing after SError access failure during autopsy
  libata: clear HOTPLUG flag after a reset
  libata: reorganize ata_ehi_hotplugged()
  libata: improve SCSI scan failure handling
  libata: quickly trigger SATA SPD down after debouncing failed
  libata: improve SATA PHY speed down logic
  The SATA controller device ID is different according to
  ahci: implement SCR_NOTIFICATION r/w
  ahci: make NO_NCQ handling more consistent
  libata: make ->scr_read/write callbacks return error code
  libata: implement AC_ERR_NCQ
  libata: improve EH report formatting
  sata_sil24: separate out sil24_do_softreset()
  sata_sil24: separate out sil24_exec_polled_cmd()
  sata_sil24: replace sil24_update_tf() with sil24_read_tf()
  ahci: separate out ahci_do_softreset()
  ahci: separate out ahci_exec_polled_cmd()
  ahci: separate out ahci_kick_engine()
  ahci: use deadline instead of fixed timeout for 1st FIS for SRST
  ...
parents e609ccc3 5ddf24c5
This diff is collapsed.
...@@ -111,8 +111,9 @@ MODULE_VERSION(DRV_VERSION); ...@@ -111,8 +111,9 @@ MODULE_VERSION(DRV_VERSION);
/** /**
* ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
* @tf: Taskfile to convert * @tf: Taskfile to convert
* @fis: Buffer into which data will output
* @pmp: Port multiplier port * @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 * Converts a standard ATA taskfile to a Serial ATA
* FIS structure (Register - Host to Device). * FIS structure (Register - Host to Device).
...@@ -120,12 +121,13 @@ MODULE_VERSION(DRV_VERSION); ...@@ -120,12 +121,13 @@ MODULE_VERSION(DRV_VERSION);
* LOCKING: * LOCKING:
* Inherited from caller. * Inherited from caller.
*/ */
void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
{ {
fis[0] = 0x27; /* Register - Host to Device FIS */ fis[0] = 0x27; /* Register - Host to Device FIS */
fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number, fis[1] = pmp & 0xf; /* Port multiplier number*/
bit 7 indicates Command FIS */ if (is_cmd)
fis[1] |= (1 << 7); /* bit 7 indicates Command FIS */
fis[2] = tf->command; fis[2] = tf->command;
fis[3] = tf->feature; fis[3] = tf->feature;
...@@ -2387,21 +2389,35 @@ int sata_down_spd_limit(struct ata_port *ap) ...@@ -2387,21 +2389,35 @@ int sata_down_spd_limit(struct ata_port *ap)
u32 sstatus, spd, mask; u32 sstatus, spd, mask;
int rc, highbit; 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); rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
if (rc) if (rc == 0)
return rc; spd = (sstatus >> 4) & 0xf;
else
spd = ap->sata_spd;
mask = ap->sata_spd_limit; mask = ap->sata_spd_limit;
if (mask <= 1) if (mask <= 1)
return -EINVAL; return -EINVAL;
/* unconditionally mask off the highest bit */
highbit = fls(mask) - 1; highbit = fls(mask) - 1;
mask &= ~(1 << highbit); mask &= ~(1 << highbit);
spd = (sstatus >> 4) & 0xf; /* Mask off all speeds higher than or equal to the current
if (spd <= 1) * one. Force 1.5Gbps if current SPD is not available.
return -EINVAL; */
spd--; if (spd > 1)
mask &= (1 << spd) - 1; mask &= (1 << (spd - 1)) - 1;
else
mask &= 1;
/* were we already at the bottom? */
if (!mask) if (!mask)
return -EINVAL; return -EINVAL;
...@@ -3251,9 +3267,11 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, ...@@ -3251,9 +3267,11 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
last = cur; last = cur;
last_jiffies = jiffies; 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)) if (time_after(jiffies, deadline))
return -EBUSY; return -EPIPE;
} }
} }
...@@ -3769,6 +3787,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ...@@ -3769,6 +3787,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, }, { "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, },
{ "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, }, { "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, },
{ "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, }, { "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, },
{ "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, },
/* Devices with NCQ limits */ /* Devices with NCQ limits */
...@@ -5729,10 +5748,8 @@ int sata_scr_valid(struct ata_port *ap) ...@@ -5729,10 +5748,8 @@ int sata_scr_valid(struct ata_port *ap)
*/ */
int sata_scr_read(struct ata_port *ap, int reg, u32 *val) int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
{ {
if (sata_scr_valid(ap)) { if (sata_scr_valid(ap))
*val = ap->ops->scr_read(ap, reg); return ap->ops->scr_read(ap, reg, val);
return 0;
}
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -5754,10 +5771,8 @@ int sata_scr_read(struct ata_port *ap, int reg, u32 *val) ...@@ -5754,10 +5771,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) int sata_scr_write(struct ata_port *ap, int reg, u32 val)
{ {
if (sata_scr_valid(ap)) { if (sata_scr_valid(ap))
ap->ops->scr_write(ap, reg, val); return ap->ops->scr_write(ap, reg, val);
return 0;
}
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -5778,10 +5793,13 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val) ...@@ -5778,10 +5793,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 sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
{ {
int rc;
if (sata_scr_valid(ap)) { if (sata_scr_valid(ap)) {
ap->ops->scr_write(ap, reg, val); rc = ap->ops->scr_write(ap, reg, val);
ap->ops->scr_read(ap, reg); if (rc == 0)
return 0; rc = ap->ops->scr_read(ap, reg, &val);
return rc;
} }
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -5993,6 +6011,7 @@ void ata_dev_init(struct ata_device *dev) ...@@ -5993,6 +6011,7 @@ void ata_dev_init(struct ata_device *dev)
/* SATA spd limit is bound to the first device */ /* SATA spd limit is bound to the first device */
ap->sata_spd_limit = ap->hw_sata_spd_limit; ap->sata_spd_limit = ap->hw_sata_spd_limit;
ap->sata_spd = 0;
/* High bits of dev->flags are used to record warm plug /* High bits of dev->flags are used to record warm plug
* requests which occur asynchronously. Synchronize using * requests which occur asynchronously. Synchronize using
...@@ -6058,6 +6077,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ...@@ -6058,6 +6077,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
INIT_LIST_HEAD(&ap->eh_done_q); INIT_LIST_HEAD(&ap->eh_done_q);
init_waitqueue_head(&ap->eh_wait_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; ap->cbl = ATA_CBL_NONE;
...@@ -6434,7 +6456,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ...@@ -6434,7 +6456,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
for (i = 0; i < host->n_ports; i++) { for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i]; struct ata_port *ap = host->ports[i];
ata_scsi_scan_host(ap); ata_scsi_scan_host(ap, 1);
} }
return 0; return 0;
...@@ -6942,6 +6964,9 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter); ...@@ -6942,6 +6964,9 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */ #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_eng_timeout);
EXPORT_SYMBOL_GPL(ata_port_schedule_eh); EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
EXPORT_SYMBOL_GPL(ata_port_abort); EXPORT_SYMBOL_GPL(ata_port_abort);
......
...@@ -56,6 +56,7 @@ enum { ...@@ -56,6 +56,7 @@ enum {
*/ */
enum { enum {
ATA_EH_PRERESET_TIMEOUT = 10 * HZ, ATA_EH_PRERESET_TIMEOUT = 10 * HZ,
ATA_EH_FASTDRAIN_INTERVAL = 3 * HZ,
}; };
/* The following table determines how we sequence resets. Each entry /* The following table determines how we sequence resets. Each entry
...@@ -85,6 +86,71 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) ...@@ -85,6 +86,71 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
{ } { }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, const char *fmt,
va_list args)
{
ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len,
ATA_EH_DESC_LEN - ehi->desc_len,
fmt, args);
}
/**
* __ata_ehi_push_desc - push error description without adding separator
* @ehi: target EHI
* @fmt: printf format string
*
* Format string according to @fmt and append it to @ehi->desc.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
__ata_ehi_pushv_desc(ehi, fmt, args);
va_end(args);
}
/**
* ata_ehi_push_desc - push error description with separator
* @ehi: target EHI
* @fmt: printf format string
*
* Format string according to @fmt and append it to @ehi->desc.
* If @ehi->desc is not empty, ", " is added in-between.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
{
va_list args;
if (ehi->desc_len)
__ata_ehi_push_desc(ehi, ", ");
va_start(args, fmt);
__ata_ehi_pushv_desc(ehi, fmt, args);
va_end(args);
}
/**
* ata_ehi_clear_desc - clean error description
* @ehi: target EHI
*
* Clear @ehi->desc.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
void ata_ehi_clear_desc(struct ata_eh_info *ehi)
{
ehi->desc[0] = '\0';
ehi->desc_len = 0;
}
static void ata_ering_record(struct ata_ering *ering, int is_io, static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask) unsigned int err_mask)
{ {
...@@ -296,6 +362,9 @@ void ata_scsi_error(struct Scsi_Host *host) ...@@ -296,6 +362,9 @@ void ata_scsi_error(struct Scsi_Host *host)
repeat: repeat:
/* invoke error handler */ /* invoke error handler */
if (ap->ops->error_handler) { if (ap->ops->error_handler) {
/* kill fast drain timer */
del_timer_sync(&ap->fastdrain_timer);
/* process port resume request */ /* process port resume request */
ata_eh_handle_port_resume(ap); ata_eh_handle_port_resume(ap);
...@@ -511,6 +580,94 @@ void ata_eng_timeout(struct ata_port *ap) ...@@ -511,6 +580,94 @@ void ata_eng_timeout(struct ata_port *ap)
DPRINTK("EXIT\n"); DPRINTK("EXIT\n");
} }
static int ata_eh_nr_in_flight(struct ata_port *ap)
{
unsigned int tag;
int nr = 0;
/* count only non-internal commands */
for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++)
if (ata_qc_from_tag(ap, tag))
nr++;
return nr;
}
void ata_eh_fastdrain_timerfn(unsigned long arg)
{
struct ata_port *ap = (void *)arg;
unsigned long flags;
int cnt;
spin_lock_irqsave(ap->lock, flags);
cnt = ata_eh_nr_in_flight(ap);
/* are we done? */
if (!cnt)
goto out_unlock;
if (cnt == ap->fastdrain_cnt) {
unsigned int tag;
/* No progress during the last interval, tag all
* in-flight qcs as timed out and freeze the port.
*/
for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++) {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
if (qc)
qc->err_mask |= AC_ERR_TIMEOUT;
}
ata_port_freeze(ap);
} else {
/* some qcs have finished, give it another chance */
ap->fastdrain_cnt = cnt;
ap->fastdrain_timer.expires =
jiffies + ATA_EH_FASTDRAIN_INTERVAL;
add_timer(&ap->fastdrain_timer);
}
out_unlock:
spin_unlock_irqrestore(ap->lock, flags);
}
/**
* ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain
* @ap: target ATA port
* @fastdrain: activate fast drain
*
* Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain
* is non-zero and EH wasn't pending before. Fast drain ensures
* that EH kicks in in timely manner.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
{
int cnt;
/* already scheduled? */
if (ap->pflags & ATA_PFLAG_EH_PENDING)
return;
ap->pflags |= ATA_PFLAG_EH_PENDING;
if (!fastdrain)
return;
/* do we have in-flight qcs? */
cnt = ata_eh_nr_in_flight(ap);
if (!cnt)
return;
/* activate fast drain */
ap->fastdrain_cnt = cnt;
ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL;
add_timer(&ap->fastdrain_timer);
}
/** /**
* ata_qc_schedule_eh - schedule qc for error handling * ata_qc_schedule_eh - schedule qc for error handling
* @qc: command to schedule error handling for * @qc: command to schedule error handling for
...@@ -528,7 +685,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) ...@@ -528,7 +685,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
WARN_ON(!ap->ops->error_handler); WARN_ON(!ap->ops->error_handler);
qc->flags |= ATA_QCFLAG_FAILED; qc->flags |= ATA_QCFLAG_FAILED;
qc->ap->pflags |= ATA_PFLAG_EH_PENDING; ata_eh_set_pending(ap, 1);
/* The following will fail if timeout has already expired. /* The following will fail if timeout has already expired.
* ata_scsi_error() takes care of such scmds on EH entry. * ata_scsi_error() takes care of such scmds on EH entry.
...@@ -555,7 +712,7 @@ void ata_port_schedule_eh(struct ata_port *ap) ...@@ -555,7 +712,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
if (ap->pflags & ATA_PFLAG_INITIALIZING) if (ap->pflags & ATA_PFLAG_INITIALIZING)
return; return;
ap->pflags |= ATA_PFLAG_EH_PENDING; ata_eh_set_pending(ap, 1);
scsi_schedule_eh(ap->scsi_host); scsi_schedule_eh(ap->scsi_host);
DPRINTK("port EH scheduled\n"); DPRINTK("port EH scheduled\n");
...@@ -579,6 +736,9 @@ int ata_port_abort(struct ata_port *ap) ...@@ -579,6 +736,9 @@ int ata_port_abort(struct ata_port *ap)
WARN_ON(!ap->ops->error_handler); WARN_ON(!ap->ops->error_handler);
/* we're gonna abort all commands, no need for fast drain */
ata_eh_set_pending(ap, 0);
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
...@@ -1130,7 +1290,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) ...@@ -1130,7 +1290,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
/* we've got the perpetrator, condemn it */ /* we've got the perpetrator, condemn it */
qc = __ata_qc_from_tag(ap, tag); qc = __ata_qc_from_tag(ap, tag);
memcpy(&qc->result_tf, &tf, sizeof(tf)); memcpy(&qc->result_tf, &tf, sizeof(tf));
qc->err_mask |= AC_ERR_DEV; qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
ehc->i.err_mask &= ~AC_ERR_DEV; ehc->i.err_mask &= ~AC_ERR_DEV;
} }
...@@ -1413,8 +1573,12 @@ static void ata_eh_autopsy(struct ata_port *ap) ...@@ -1413,8 +1573,12 @@ static void ata_eh_autopsy(struct ata_port *ap)
if (rc == 0) { if (rc == 0) {
ehc->i.serror |= serror; ehc->i.serror |= serror;
ata_eh_analyze_serror(ap); ata_eh_analyze_serror(ap);
} else if (rc != -EOPNOTSUPP) } else if (rc != -EOPNOTSUPP) {
/* SError read failed, force hardreset and probing */
ata_ehi_schedule_probe(&ehc->i);
ehc->i.action |= ATA_EH_HARDRESET; ehc->i.action |= ATA_EH_HARDRESET;
ehc->i.err_mask |= AC_ERR_OTHER;
}
/* analyze NCQ failure */ /* analyze NCQ failure */
ata_eh_analyze_ncq_error(ap); ata_eh_analyze_ncq_error(ap);
...@@ -1524,14 +1688,14 @@ static void ata_eh_report(struct ata_port *ap) ...@@ -1524,14 +1688,14 @@ static void ata_eh_report(struct ata_port *ap)
ehc->i.err_mask, ap->sactive, ehc->i.serror, ehc->i.err_mask, ap->sactive, ehc->i.serror,
ehc->i.action, frozen); ehc->i.action, frozen);
if (desc) if (desc)
ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc); ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
} else { } else {
ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x " ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
"SAct 0x%x SErr 0x%x action 0x%x%s\n", "SAct 0x%x SErr 0x%x action 0x%x%s\n",
ehc->i.err_mask, ap->sactive, ehc->i.serror, ehc->i.err_mask, ap->sactive, ehc->i.serror,
ehc->i.action, frozen); ehc->i.action, frozen);
if (desc) if (desc)
ata_port_printk(ap, KERN_ERR, "(%s)\n", desc); ata_port_printk(ap, KERN_ERR, "%s\n", desc);
} }
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
...@@ -1551,7 +1715,7 @@ static void ata_eh_report(struct ata_port *ap) ...@@ -1551,7 +1715,7 @@ static void ata_eh_report(struct ata_port *ap)
"cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
"tag %d cdb 0x%x data %u %s\n " "tag %d cdb 0x%x data %u %s\n "
"res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
"Emask 0x%x (%s)\n", "Emask 0x%x (%s)%s\n",
cmd->command, cmd->feature, cmd->nsect, cmd->command, cmd->feature, cmd->nsect,
cmd->lbal, cmd->lbam, cmd->lbah, cmd->lbal, cmd->lbam, cmd->lbah,
cmd->hob_feature, cmd->hob_nsect, cmd->hob_feature, cmd->hob_nsect,
...@@ -1562,7 +1726,8 @@ static void ata_eh_report(struct ata_port *ap) ...@@ -1562,7 +1726,8 @@ static void ata_eh_report(struct ata_port *ap)
res->lbal, res->lbam, res->lbah, res->lbal, res->lbam, res->lbah,
res->hob_feature, res->hob_nsect, res->hob_feature, res->hob_nsect,
res->hob_lbal, res->hob_lbam, res->hob_lbah, res->hob_lbal, res->hob_lbam, res->hob_lbah,
res->device, qc->err_mask, ata_err_string(qc->err_mask)); res->device, qc->err_mask, ata_err_string(qc->err_mask),
qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
} }
} }
...@@ -1648,7 +1813,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ...@@ -1648,7 +1813,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
} else } else
ata_port_printk(ap, KERN_ERR, ata_port_printk(ap, KERN_ERR,
"prereset failed (errno=%d)\n", rc); "prereset failed (errno=%d)\n", rc);
return rc; goto out;
} }
} }
...@@ -1661,7 +1826,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ...@@ -1661,7 +1826,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
/* prereset told us not to reset, bang classes and return */ /* prereset told us not to reset, bang classes and return */
for (i = 0; i < ATA_MAX_DEVICES; i++) for (i = 0; i < ATA_MAX_DEVICES; i++)
classes[i] = ATA_DEV_NONE; classes[i] = ATA_DEV_NONE;
return 0; rc = 0;
goto out;
} }
/* did prereset() screw up? if so, fix up to avoid oopsing */ /* did prereset() screw up? if so, fix up to avoid oopsing */
...@@ -1697,7 +1863,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ...@@ -1697,7 +1863,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_port_printk(ap, KERN_ERR, ata_port_printk(ap, KERN_ERR,
"follow-up softreset required " "follow-up softreset required "
"but no softreset avaliable\n"); "but no softreset avaliable\n");
return -EINVAL; rc = -EINVAL;
goto out;
} }
ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
...@@ -1707,7 +1874,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ...@@ -1707,7 +1874,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
classes[0] == ATA_DEV_UNKNOWN) { classes[0] == ATA_DEV_UNKNOWN) {
ata_port_printk(ap, KERN_ERR, ata_port_printk(ap, KERN_ERR,
"classification failed\n"); "classification failed\n");
return -EINVAL; rc = -EINVAL;
goto out;
} }
} }
...@@ -1724,7 +1892,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ...@@ -1724,7 +1892,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
schedule_timeout_uninterruptible(delta); schedule_timeout_uninterruptible(delta);
} }
if (reset == hardreset && if (rc == -EPIPE ||
try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1) try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
sata_down_spd_limit(ap); sata_down_spd_limit(ap);
if (hardreset) if (hardreset)
...@@ -1733,12 +1901,18 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ...@@ -1733,12 +1901,18 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
} }
if (rc == 0) { if (rc == 0) {
u32 sstatus;
/* After the reset, the device state is PIO 0 and the /* After the reset, the device state is PIO 0 and the
* controller state is undefined. Record the mode. * controller state is undefined. Record the mode.
*/ */
for (i = 0; i < ATA_MAX_DEVICES; i++) for (i = 0; i < ATA_MAX_DEVICES; i++)
ap->device[i].pio_mode = XFER_PIO_0; ap->device[i].pio_mode = XFER_PIO_0;
/* record current link speed */
if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0)
ap->sata_spd = (sstatus >> 4) & 0xf;
if (postreset) if (postreset)
postreset(ap, classes); postreset(ap, classes);
...@@ -1746,7 +1920,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ...@@ -1746,7 +1920,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
ehc->i.action |= ATA_EH_REVALIDATE; ehc->i.action |= ATA_EH_REVALIDATE;
} }
out:
/* clear hotplug flag */
ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
return rc; return rc;
} }
......
...@@ -2947,17 +2947,22 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) ...@@ -2947,17 +2947,22 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
return rc; return rc;
} }
void ata_scsi_scan_host(struct ata_port *ap) void ata_scsi_scan_host(struct ata_port *ap, int sync)
{ {
int tries = 5;
struct ata_device *last_failed_dev = NULL;
struct ata_device *dev;
unsigned int i; unsigned int i;
if (ap->flags & ATA_FLAG_DISABLED) if (ap->flags & ATA_FLAG_DISABLED)
return; return;
repeat:
for (i = 0; i < ATA_MAX_DEVICES; i++) { for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
struct scsi_device *sdev; struct scsi_device *sdev;
dev = &ap->device[i];
if (!ata_dev_enabled(dev) || dev->sdev) if (!ata_dev_enabled(dev) || dev->sdev)
continue; continue;
...@@ -2967,6 +2972,45 @@ void ata_scsi_scan_host(struct ata_port *ap) ...@@ -2967,6 +2972,45 @@ void ata_scsi_scan_host(struct ata_port *ap)
scsi_device_put(sdev); scsi_device_put(sdev);
} }
} }
/* If we scanned while EH was in progress or allocation
* failure occurred, scan would have failed silently. Check
* whether all devices are attached.
*/
for (i = 0; i < ATA_MAX_DEVICES; i++) {
dev = &ap->device[i];
if (ata_dev_enabled(dev) && !dev->sdev)
break;
}
if (i == ATA_MAX_DEVICES)
return;
/* we're missing some SCSI devices */
if (sync) {
/* If caller requested synchrnous scan && we've made
* any progress, sleep briefly and repeat.
*/
if (dev != last_failed_dev) {
msleep(100);
last_failed_dev = dev;
goto repeat;
}
/* We might be failing to detect boot device, give it
* a few more chances.
*/
if (--tries) {
msleep(100);
goto repeat;
}
ata_port_printk(ap, KERN_ERR, "WARNING: synchronous SCSI scan "
"failed without making any progress,\n"
" switching to async\n");
}
queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
round_jiffies_relative(HZ));
} }
/** /**
...@@ -3093,20 +3137,7 @@ void ata_scsi_hotplug(struct work_struct *work) ...@@ -3093,20 +3137,7 @@ void ata_scsi_hotplug(struct work_struct *work)
} }
/* scan for new ones */ /* scan for new ones */
ata_scsi_scan_host(ap); ata_scsi_scan_host(ap, 0);
/* If we scanned while EH was in progress, scan would have
* failed silently. Requeue if there are enabled but
* unattached devices.
*/
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
if (ata_dev_enabled(dev) && !dev->sdev) {
queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
round_jiffies_relative(HZ));
break;
}
}
DPRINTK("EXIT\n"); DPRINTK("EXIT\n");
} }
......
/* /*
* libata-bmdma.c - helper library for PCI IDE BMDMA * libata-sff.c - helper library for PCI IDE BMDMA
* *
* Maintained by: Jeff Garzik <jgarzik@pobox.com> * Maintained by: Jeff Garzik <jgarzik@pobox.com>
* Please ALWAYS copy linux-ide@vger.kernel.org * Please ALWAYS copy linux-ide@vger.kernel.org
...@@ -211,6 +211,8 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) ...@@ -211,6 +211,8 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
tf->hob_lbal = ioread8(ioaddr->lbal_addr); tf->hob_lbal = ioread8(ioaddr->lbal_addr);
tf->hob_lbam = ioread8(ioaddr->lbam_addr); tf->hob_lbam = ioread8(ioaddr->lbam_addr);
tf->hob_lbah = ioread8(ioaddr->lbah_addr); tf->hob_lbah = ioread8(ioaddr->lbah_addr);
iowrite8(tf->ctl, ioaddr->ctl_addr);
ap->last_ctl = tf->ctl;
} }
} }
......
...@@ -112,7 +112,7 @@ static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; } ...@@ -112,7 +112,7 @@ static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; }
/* libata-scsi.c */ /* libata-scsi.c */
extern int ata_scsi_add_hosts(struct ata_host *host, extern int ata_scsi_add_hosts(struct ata_host *host,
struct scsi_host_template *sht); struct scsi_host_template *sht);
extern void ata_scsi_scan_host(struct ata_port *ap); extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev); extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work); extern void ata_scsi_hotplug(struct work_struct *work);
extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
...@@ -151,6 +151,7 @@ extern int ata_bus_probe(struct ata_port *ap); ...@@ -151,6 +151,7 @@ extern int ata_bus_probe(struct ata_port *ap);
extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
extern void ata_scsi_error(struct Scsi_Host *host); extern void ata_scsi_error(struct Scsi_Host *host);
extern void ata_port_wait_eh(struct ata_port *ap); extern void ata_port_wait_eh(struct ata_port *ap);
extern void ata_eh_fastdrain_timerfn(unsigned long arg);
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
/* libata-sff.c */ /* libata-sff.c */
......
...@@ -213,8 +213,9 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) ...@@ -213,8 +213,9 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
pata_platform_setup_port(&ap->ioaddr, pp_info); pata_platform_setup_port(&ap->ioaddr, pp_info);
/* activate */ /* activate */
return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt, return ata_host_activate(host, platform_get_irq(pdev, 0),
pp_info->irq_flags, &pata_platform_sht); ata_interrupt, pp_info ? pp_info->irq_flags
: 0, &pata_platform_sht);
} }
/** /**
......
...@@ -238,12 +238,6 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev) ...@@ -238,12 +238,6 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
else else
offset = 0; /* 100MHz */ offset = 0; /* 100MHz */
/* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
if (adev->class == ATA_DEV_ATAPI && speed > XFER_UDMA_4) {
printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
speed = XFER_UDMA_4;
}
if (speed >= XFER_UDMA_0) if (speed >= XFER_UDMA_0)
idx = speed - XFER_UDMA_0; idx = speed - XFER_UDMA_0;
else else
...@@ -264,6 +258,17 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev) ...@@ -264,6 +258,17 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]); JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]);
} }
unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask)
{
/* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
if (adev->class == ATA_DEV_ATAPI &&
(mask & (0xE0 << ATA_SHIFT_UDMA))) {
printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
mask &= ~(0xE0 << ATA_SHIFT_UDMA);
}
return ata_pci_default_filter(adev, mask);
}
/** /**
* scc_tf_load - send taskfile registers to host controller * scc_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent * @ap: Port to which output is sent
...@@ -358,6 +363,8 @@ static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf) ...@@ -358,6 +363,8 @@ static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf)
tf->hob_lbal = in_be32(ioaddr->lbal_addr); tf->hob_lbal = in_be32(ioaddr->lbal_addr);
tf->hob_lbam = in_be32(ioaddr->lbam_addr); tf->hob_lbam = in_be32(ioaddr->lbam_addr);
tf->hob_lbah = in_be32(ioaddr->lbah_addr); tf->hob_lbah = in_be32(ioaddr->lbah_addr);
out_be32(ioaddr->ctl_addr, tf->ctl);
ap->last_ctl = tf->ctl;
} }
} }
...@@ -741,7 +748,7 @@ static u8 scc_bmdma_status (struct ata_port *ap) ...@@ -741,7 +748,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
return host_stat; return host_stat;
/* errata A252,A308 workaround: Step4 */ /* errata A252,A308 workaround: Step4 */
if (ata_altstatus(ap) & ATA_ERR && int_status & INTSTS_INTRQ) if ((ata_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))
return (host_stat | ATA_DMA_INTR); return (host_stat | ATA_DMA_INTR);
/* errata A308 workaround Step5 */ /* errata A308 workaround Step5 */
...@@ -752,11 +759,11 @@ static u8 scc_bmdma_status (struct ata_port *ap) ...@@ -752,11 +759,11 @@ static u8 scc_bmdma_status (struct ata_port *ap)
if ((qc->tf.protocol == ATA_PROT_DMA && if ((qc->tf.protocol == ATA_PROT_DMA &&
qc->dev->xfer_mode > XFER_UDMA_4)) { qc->dev->xfer_mode > XFER_UDMA_4)) {
if (!(int_status & INTSTS_ACTEINT)) { if (!(int_status & INTSTS_ACTEINT)) {
printk(KERN_WARNING "ata%u: data lost occurred. (ACTEINT==0, retry:%d)\n", printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n",
ap->print_id, retry); ap->print_id);
host_stat |= ATA_DMA_ERR; host_stat |= ATA_DMA_ERR;
if (retry++) if (retry++)
ap->udma_mask >>= 1; ap->udma_mask &= ~(1 << qc->dev->xfer_mode);
} else } else
retry = 0; retry = 0;
} }
...@@ -1016,7 +1023,7 @@ static const struct ata_port_operations scc_pata_ops = { ...@@ -1016,7 +1023,7 @@ static const struct ata_port_operations scc_pata_ops = {
.port_disable = ata_port_disable, .port_disable = ata_port_disable,
.set_piomode = scc_set_piomode, .set_piomode = scc_set_piomode,
.set_dmamode = scc_set_dmamode, .set_dmamode = scc_set_dmamode,
.mode_filter = ata_pci_default_filter, .mode_filter = scc_mode_filter,
.tf_load = scc_tf_load, .tf_load = scc_tf_load,
.tf_read = scc_tf_read, .tf_read = scc_tf_read,
......
...@@ -190,34 +190,34 @@ static void inic_reset_port(void __iomem *port_base) ...@@ -190,34 +190,34 @@ static void inic_reset_port(void __iomem *port_base)
writew(ctl, idma_ctl); writew(ctl, idma_ctl);
} }
static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg) static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{ {
void __iomem *scr_addr = ap->ioaddr.scr_addr; void __iomem *scr_addr = ap->ioaddr.scr_addr;
void __iomem *addr; void __iomem *addr;
u32 val;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
return 0xffffffffU; return -EINVAL;
addr = scr_addr + scr_map[sc_reg] * 4; addr = scr_addr + scr_map[sc_reg] * 4;
val = readl(scr_addr + scr_map[sc_reg] * 4); *val = readl(scr_addr + scr_map[sc_reg] * 4);
/* this controller has stuck DIAG.N, ignore it */ /* this controller has stuck DIAG.N, ignore it */
if (sc_reg == SCR_ERROR) if (sc_reg == SCR_ERROR)
val &= ~SERR_PHYRDY_CHG; *val &= ~SERR_PHYRDY_CHG;
return val; return 0;
} }
static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{ {
void __iomem *scr_addr = ap->ioaddr.scr_addr; void __iomem *scr_addr = ap->ioaddr.scr_addr;
void __iomem *addr; void __iomem *addr;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
return; return -EINVAL;
addr = scr_addr + scr_map[sc_reg] * 4; addr = scr_addr + scr_map[sc_reg] * 4;
writel(val, scr_addr + scr_map[sc_reg] * 4); writel(val, scr_addr + scr_map[sc_reg] * 4);
return 0;
} }
/* /*
......
This diff is collapsed.
...@@ -236,8 +236,8 @@ static void nv_ck804_host_stop(struct ata_host *host); ...@@ -236,8 +236,8 @@ static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance); static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance); static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance); static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg); static int nv_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void nv_nf2_freeze(struct ata_port *ap); static void nv_nf2_freeze(struct ata_port *ap);
static void nv_nf2_thaw(struct ata_port *ap); static void nv_nf2_thaw(struct ata_port *ap);
...@@ -715,19 +715,20 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) ...@@ -715,19 +715,20 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
int freeze = 0; int freeze = 0;
ata_ehi_clear_desc(ehi); ata_ehi_clear_desc(ehi);
ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags ); __ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags );
if (flags & NV_CPB_RESP_ATA_ERR) { if (flags & NV_CPB_RESP_ATA_ERR) {
ata_ehi_push_desc(ehi, ": ATA error"); ata_ehi_push_desc(ehi, "ATA error");
ehi->err_mask |= AC_ERR_DEV; ehi->err_mask |= AC_ERR_DEV;
} else if (flags & NV_CPB_RESP_CMD_ERR) { } else if (flags & NV_CPB_RESP_CMD_ERR) {
ata_ehi_push_desc(ehi, ": CMD error"); ata_ehi_push_desc(ehi, "CMD error");
ehi->err_mask |= AC_ERR_DEV; ehi->err_mask |= AC_ERR_DEV;
} else if (flags & NV_CPB_RESP_CPB_ERR) { } else if (flags & NV_CPB_RESP_CPB_ERR) {
ata_ehi_push_desc(ehi, ": CPB error"); ata_ehi_push_desc(ehi, "CPB error");
ehi->err_mask |= AC_ERR_SYSTEM; ehi->err_mask |= AC_ERR_SYSTEM;
freeze = 1; freeze = 1;
} else { } else {
/* notifier error, but no error in CPB flags? */ /* notifier error, but no error in CPB flags? */
ata_ehi_push_desc(ehi, "unknown");
ehi->err_mask |= AC_ERR_OTHER; ehi->err_mask |= AC_ERR_OTHER;
freeze = 1; freeze = 1;
} }
...@@ -854,20 +855,21 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) ...@@ -854,20 +855,21 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
struct ata_eh_info *ehi = &ap->eh_info; struct ata_eh_info *ehi = &ap->eh_info;
ata_ehi_clear_desc(ehi); ata_ehi_clear_desc(ehi);
ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status ); __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status );
if (status & NV_ADMA_STAT_TIMEOUT) { if (status & NV_ADMA_STAT_TIMEOUT) {
ehi->err_mask |= AC_ERR_SYSTEM; ehi->err_mask |= AC_ERR_SYSTEM;
ata_ehi_push_desc(ehi, ": timeout"); ata_ehi_push_desc(ehi, "timeout");
} else if (status & NV_ADMA_STAT_HOTPLUG) { } else if (status & NV_ADMA_STAT_HOTPLUG) {
ata_ehi_hotplugged(ehi); ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, ": hotplug"); ata_ehi_push_desc(ehi, "hotplug");
} else if (status & NV_ADMA_STAT_HOTUNPLUG) { } else if (status & NV_ADMA_STAT_HOTUNPLUG) {
ata_ehi_hotplugged(ehi); ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, ": hot unplug"); ata_ehi_push_desc(ehi, "hot unplug");
} else if (status & NV_ADMA_STAT_SERROR) { } else if (status & NV_ADMA_STAT_SERROR) {
/* let libata analyze SError and figure out the cause */ /* let libata analyze SError and figure out the cause */
ata_ehi_push_desc(ehi, ": SError"); ata_ehi_push_desc(ehi, "SError");
} } else
ata_ehi_push_desc(ehi, "unknown");
ata_port_freeze(ap); ata_port_freeze(ap);
continue; continue;
} }
...@@ -1391,20 +1393,22 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance) ...@@ -1391,20 +1393,22 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
return ret; return ret;
} }
static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return 0xffffffffU; return -EINVAL;
return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
} }
static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return; return -EINVAL;
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
} }
static void nv_nf2_freeze(struct ata_port *ap) static void nv_nf2_freeze(struct ata_port *ap)
......
...@@ -128,8 +128,8 @@ struct pdc_port_priv { ...@@ -128,8 +128,8 @@ struct pdc_port_priv {
dma_addr_t pkt_dma; dma_addr_t pkt_dma;
}; };
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int pdc_common_port_start(struct ata_port *ap); static int pdc_common_port_start(struct ata_port *ap);
static int pdc_sata_port_start(struct ata_port *ap); static int pdc_sata_port_start(struct ata_port *ap);
...@@ -427,19 +427,20 @@ static int pdc_sata_cable_detect(struct ata_port *ap) ...@@ -427,19 +427,20 @@ static int pdc_sata_cable_detect(struct ata_port *ap)
return ATA_CBL_SATA; return ATA_CBL_SATA;
} }
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return 0xffffffffU; return -EINVAL;
return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
} }
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return; return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
} }
static void pdc_atapi_pkt(struct ata_queued_cmd *qc) static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
...@@ -642,8 +643,12 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc, ...@@ -642,8 +643,12 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
| PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR)) | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
ac_err_mask |= AC_ERR_HOST_BUS; ac_err_mask |= AC_ERR_HOST_BUS;
if (sata_scr_valid(ap)) if (sata_scr_valid(ap)) {
ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR); u32 serror;
pdc_sata_scr_read(ap, SCR_ERROR, &serror);
ehi->serror |= serror;
}
qc->err_mask |= ac_err_mask; qc->err_mask |= ac_err_mask;
......
...@@ -111,8 +111,8 @@ struct qs_port_priv { ...@@ -111,8 +111,8 @@ struct qs_port_priv {
qs_state_t state; qs_state_t state;
}; };
static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg); static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int qs_port_start(struct ata_port *ap); static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host); static void qs_host_stop(struct ata_host *host);
...@@ -255,18 +255,20 @@ static void qs_eng_timeout(struct ata_port *ap) ...@@ -255,18 +255,20 @@ static void qs_eng_timeout(struct ata_port *ap)
ata_eng_timeout(ap); ata_eng_timeout(ap);
} }
static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg) static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return ~0U; return -EINVAL;
return readl(ap->ioaddr.scr_addr + (sc_reg * 8)); *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8));
return 0;
} }
static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return; return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 8)); writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
return 0;
} }
static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
...@@ -337,7 +339,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc) ...@@ -337,7 +339,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
buf[28] = dflags; buf[28] = dflags;
/* frame information structure (FIS) */ /* frame information structure (FIS) */
ata_tf_to_fis(&qc->tf, &buf[32], 0); ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
} }
static inline void qs_packet_start(struct ata_queued_cmd *qc) static inline void qs_packet_start(struct ata_queued_cmd *qc)
......
...@@ -115,8 +115,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); ...@@ -115,8 +115,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int sil_pci_device_resume(struct pci_dev *pdev); static int sil_pci_device_resume(struct pci_dev *pdev);
#endif #endif
static void sil_dev_config(struct ata_device *dev); static void sil_dev_config(struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed); static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
static void sil_freeze(struct ata_port *ap); static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap); static void sil_thaw(struct ata_port *ap);
...@@ -350,19 +350,26 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_re ...@@ -350,19 +350,26 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_re
return NULL; return NULL;
} }
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{ {
void __iomem *mmio = sil_scr_addr(ap, sc_reg); void __iomem *mmio = sil_scr_addr(ap, sc_reg);
if (mmio)
return readl(mmio); if (mmio) {
return 0xffffffffU; *val = readl(mmio);
return 0;
}
return -EINVAL;
} }
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{ {
void __iomem *mmio = sil_scr_addr(ap, sc_reg); void __iomem *mmio = sil_scr_addr(ap, sc_reg);
if (mmio)
if (mmio) {
writel(val, mmio); writel(val, mmio);
return 0;
}
return -EINVAL;
} }
static void sil_host_intr(struct ata_port *ap, u32 bmdma2) static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
...@@ -378,7 +385,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) ...@@ -378,7 +385,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* controllers continue to assert IRQ as long as * controllers continue to assert IRQ as long as
* SError bits are pending. Clear SError immediately. * SError bits are pending. Clear SError immediately.
*/ */
serror = sil_scr_read(ap, SCR_ERROR); sil_scr_read(ap, SCR_ERROR, &serror);
sil_scr_write(ap, SCR_ERROR, serror); sil_scr_write(ap, SCR_ERROR, serror);
/* Trigger hotplug and accumulate SError only if the /* Trigger hotplug and accumulate SError only if the
......
...@@ -326,8 +326,8 @@ struct sil24_port_priv { ...@@ -326,8 +326,8 @@ struct sil24_port_priv {
static void sil24_dev_config(struct ata_device *dev); static void sil24_dev_config(struct ata_device *dev);
static u8 sil24_check_status(struct ata_port *ap); static u8 sil24_check_status(struct ata_port *ap);
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
static void sil24_qc_prep(struct ata_queued_cmd *qc); static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
...@@ -464,15 +464,15 @@ static void sil24_dev_config(struct ata_device *dev) ...@@ -464,15 +464,15 @@ static void sil24_dev_config(struct ata_device *dev)
writel(PORT_CS_CDB16, port + PORT_CTRL_CLR); writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
} }
static inline void sil24_update_tf(struct ata_port *ap) static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf)
{ {
struct sil24_port_priv *pp = ap->private_data;
void __iomem *port = ap->ioaddr.cmd_addr; void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_prb __iomem *prb = port; struct sil24_prb __iomem *prb;
u8 fis[6 * 4]; u8 fis[6 * 4];
memcpy_fromio(fis, prb->fis, 6 * 4); prb = port + PORT_LRAM + sil24_tag(tag) * PORT_LRAM_SLOT_SZ;
ata_tf_from_fis(fis, &pp->tf); memcpy_fromio(fis, prb->fis, sizeof(fis));
ata_tf_from_fis(fis, tf);
} }
static u8 sil24_check_status(struct ata_port *ap) static u8 sil24_check_status(struct ata_port *ap)
...@@ -488,25 +488,30 @@ static int sil24_scr_map[] = { ...@@ -488,25 +488,30 @@ static int sil24_scr_map[] = {
[SCR_ACTIVE] = 3, [SCR_ACTIVE] = 3,
}; };
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg) static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{ {
void __iomem *scr_addr = ap->ioaddr.scr_addr; void __iomem *scr_addr = ap->ioaddr.scr_addr;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr; void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4; addr = scr_addr + sil24_scr_map[sc_reg] * 4;
return readl(scr_addr + sil24_scr_map[sc_reg] * 4); *val = readl(scr_addr + sil24_scr_map[sc_reg] * 4);
return 0;
} }
return 0xffffffffU; return -EINVAL;
} }
static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{ {
void __iomem *scr_addr = ap->ioaddr.scr_addr; void __iomem *scr_addr = ap->ioaddr.scr_addr;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr; void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4; addr = scr_addr + sil24_scr_map[sc_reg] * 4;
writel(val, scr_addr + sil24_scr_map[sc_reg] * 4); writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
return 0;
} }
return -EINVAL;
} }
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
...@@ -531,15 +536,60 @@ static int sil24_init_port(struct ata_port *ap) ...@@ -531,15 +536,60 @@ static int sil24_init_port(struct ata_port *ap)
return 0; return 0;
} }
static int sil24_softreset(struct ata_port *ap, unsigned int *class, static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
unsigned long deadline) const struct ata_taskfile *tf,
int is_cmd, u32 ctrl,
unsigned long timeout_msec)
{ {
void __iomem *port = ap->ioaddr.cmd_addr; void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data; struct sil24_port_priv *pp = ap->private_data;
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb; struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
dma_addr_t paddr = pp->cmd_block_dma; dma_addr_t paddr = pp->cmd_block_dma;
u32 mask, irq_stat; u32 irq_enabled, irq_mask, irq_stat;
int rc;
prb->ctrl = cpu_to_le16(ctrl);
ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);
/* temporarily plug completion and error interrupts */
irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
writel((u32)paddr, port + PORT_CMD_ACTIVATE);
writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
10, timeout_msec);
writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
irq_stat >>= PORT_IRQ_RAW_SHIFT;
if (irq_stat & PORT_IRQ_COMPLETE)
rc = 0;
else {
/* force port into known state */
sil24_init_port(ap);
if (irq_stat & PORT_IRQ_ERROR)
rc = -EIO;
else
rc = -EBUSY;
}
/* restore IRQ enabled */
writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);
return rc;
}
static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
int pmp, unsigned long deadline)
{
unsigned long timeout_msec = 0;
struct ata_taskfile tf;
const char *reason; const char *reason;
int rc;
DPRINTK("ENTER\n"); DPRINTK("ENTER\n");
...@@ -556,29 +606,22 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class, ...@@ -556,29 +606,22 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
} }
/* do SRST */ /* do SRST */
prb->ctrl = cpu_to_le16(PRB_CTRL_SRST); if (time_after(deadline, jiffies))
prb->fis[1] = 0; /* no PMP yet */ timeout_msec = jiffies_to_msecs(deadline - jiffies);
writel((u32)paddr, port + PORT_CMD_ACTIVATE); ata_tf_init(ap->device, &tf); /* doesn't really matter */
writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4); rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
timeout_msec);
mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT; if (rc == -EBUSY) {
irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0, reason = "timeout";
100, jiffies_to_msecs(deadline - jiffies)); goto err;
} else if (rc) {
writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */ reason = "SRST command error";
irq_stat >>= PORT_IRQ_RAW_SHIFT;
if (!(irq_stat & PORT_IRQ_COMPLETE)) {
if (irq_stat & PORT_IRQ_ERROR)
reason = "SRST command error";
else
reason = "timeout";
goto err; goto err;
} }
sil24_update_tf(ap); sil24_read_tf(ap, 0, &tf);
*class = ata_dev_classify(&pp->tf); *class = ata_dev_classify(&tf);
if (*class == ATA_DEV_UNKNOWN) if (*class == ATA_DEV_UNKNOWN)
*class = ATA_DEV_NONE; *class = ATA_DEV_NONE;
...@@ -592,6 +635,12 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class, ...@@ -592,6 +635,12 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
return -EIO; return -EIO;
} }
static int sil24_softreset(struct ata_port *ap, unsigned int *class,
unsigned long deadline)
{
return sil24_do_softreset(ap, class, 0, deadline);
}
static int sil24_hardreset(struct ata_port *ap, unsigned int *class, static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
unsigned long deadline) unsigned long deadline)
{ {
...@@ -699,7 +748,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) ...@@ -699,7 +748,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
} }
prb->ctrl = cpu_to_le16(ctrl); prb->ctrl = cpu_to_le16(ctrl);
ata_tf_to_fis(&qc->tf, prb->fis, 0); ata_tf_to_fis(&qc->tf, 0, 1, prb->fis);
if (qc->flags & ATA_QCFLAG_DMAMAP) if (qc->flags & ATA_QCFLAG_DMAMAP)
sil24_fill_sg(qc, sge); sil24_fill_sg(qc, sge);
...@@ -754,6 +803,7 @@ static void sil24_thaw(struct ata_port *ap) ...@@ -754,6 +803,7 @@ static void sil24_thaw(struct ata_port *ap)
static void sil24_error_intr(struct ata_port *ap) static void sil24_error_intr(struct ata_port *ap)
{ {
void __iomem *port = ap->ioaddr.cmd_addr; void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
struct ata_eh_info *ehi = &ap->eh_info; struct ata_eh_info *ehi = &ap->eh_info;
int freeze = 0; int freeze = 0;
u32 irq_stat; u32 irq_stat;
...@@ -769,16 +819,16 @@ static void sil24_error_intr(struct ata_port *ap) ...@@ -769,16 +819,16 @@ static void sil24_error_intr(struct ata_port *ap)
if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) { if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
ata_ehi_hotplugged(ehi); ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, ", %s", ata_ehi_push_desc(ehi, "%s",
irq_stat & PORT_IRQ_PHYRDY_CHG ? irq_stat & PORT_IRQ_PHYRDY_CHG ?
"PHY RDY changed" : "device exchanged"); "PHY RDY changed" : "device exchanged");
freeze = 1; freeze = 1;
} }
if (irq_stat & PORT_IRQ_UNK_FIS) { if (irq_stat & PORT_IRQ_UNK_FIS) {
ehi->err_mask |= AC_ERR_HSM; ehi->err_mask |= AC_ERR_HSM;
ehi->action |= ATA_EH_SOFTRESET; ehi->action |= ATA_EH_SOFTRESET;
ata_ehi_push_desc(ehi , ", unknown FIS"); ata_ehi_push_desc(ehi, "unknown FIS");
freeze = 1; freeze = 1;
} }
...@@ -797,18 +847,18 @@ static void sil24_error_intr(struct ata_port *ap) ...@@ -797,18 +847,18 @@ static void sil24_error_intr(struct ata_port *ap)
if (ci && ci->desc) { if (ci && ci->desc) {
err_mask |= ci->err_mask; err_mask |= ci->err_mask;
action |= ci->action; action |= ci->action;
ata_ehi_push_desc(ehi, ", %s", ci->desc); ata_ehi_push_desc(ehi, "%s", ci->desc);
} else { } else {
err_mask |= AC_ERR_OTHER; err_mask |= AC_ERR_OTHER;
action |= ATA_EH_SOFTRESET; action |= ATA_EH_SOFTRESET;
ata_ehi_push_desc(ehi, ", unknown command error %d", ata_ehi_push_desc(ehi, "unknown command error %d",
cerr); cerr);
} }
/* record error info */ /* record error info */
qc = ata_qc_from_tag(ap, ap->active_tag); qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc) { if (qc) {
sil24_update_tf(ap); sil24_read_tf(ap, qc->tag, &pp->tf);
qc->err_mask |= err_mask; qc->err_mask |= err_mask;
} else } else
ehi->err_mask |= err_mask; ehi->err_mask |= err_mask;
...@@ -825,8 +875,11 @@ static void sil24_error_intr(struct ata_port *ap) ...@@ -825,8 +875,11 @@ static void sil24_error_intr(struct ata_port *ap)
static void sil24_finish_qc(struct ata_queued_cmd *qc) static void sil24_finish_qc(struct ata_queued_cmd *qc)
{ {
struct ata_port *ap = qc->ap;
struct sil24_port_priv *pp = ap->private_data;
if (qc->flags & ATA_QCFLAG_RESULT_TF) if (qc->flags & ATA_QCFLAG_RESULT_TF)
sil24_update_tf(qc->ap); sil24_read_tf(ap, qc->tag, &pp->tf);
} }
static inline void sil24_host_intr(struct ata_port *ap) static inline void sil24_host_intr(struct ata_port *ap)
......
...@@ -64,8 +64,8 @@ enum { ...@@ -64,8 +64,8 @@ enum {
}; };
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg); static int sis_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id sis_pci_tbl[] = { static const struct pci_device_id sis_pci_tbl[] = {
{ PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */ { PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
...@@ -207,36 +207,37 @@ static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val ...@@ -207,36 +207,37 @@ static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val
pci_write_config_dword(pdev, cfg_addr+0x10, val); pci_write_config_dword(pdev, cfg_addr+0x10, val);
} }
static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg) static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{ {
struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 val, val2 = 0;
u8 pmr; u8 pmr;
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return 0xffffffffU; return -EINVAL;
if (ap->flags & SIS_FLAG_CFGSCR) if (ap->flags & SIS_FLAG_CFGSCR)
return sis_scr_cfg_read(ap, sc_reg); return sis_scr_cfg_read(ap, sc_reg);
pci_read_config_byte(pdev, SIS_PMR, &pmr); pci_read_config_byte(pdev, SIS_PMR, &pmr);
val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); *val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
*val &= 0xfffffffb;
return (val | val2) & 0xfffffffb; return 0;
} }
static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{ {
struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 pmr; u8 pmr;
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return; return -EINVAL;
pci_read_config_byte(pdev, SIS_PMR, &pmr); pci_read_config_byte(pdev, SIS_PMR, &pmr);
...@@ -248,6 +249,7 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) ...@@ -248,6 +249,7 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10); iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
} }
return 0;
} }
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
......
...@@ -103,20 +103,21 @@ static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc) ...@@ -103,20 +103,21 @@ static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
return 0; return 0;
} }
static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return 0xffffffffU; return -EINVAL;
return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
} }
static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return; return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
} }
......
...@@ -57,8 +57,8 @@ struct uli_priv { ...@@ -57,8 +57,8 @@ struct uli_priv {
}; };
static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg); static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id uli_pci_tbl[] = { static const struct pci_device_id uli_pci_tbl[] = {
{ PCI_VDEVICE(AL, 0x5289), uli_5289 }, { PCI_VDEVICE(AL, 0x5289), uli_5289 },
...@@ -164,20 +164,22 @@ static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) ...@@ -164,20 +164,22 @@ static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
pci_write_config_dword(pdev, cfg_addr, val); pci_write_config_dword(pdev, cfg_addr, val);
} }
static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg) static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return 0xffffffffU; return -EINVAL;
return uli_scr_cfg_read(ap, sc_reg); *val = uli_scr_cfg_read(ap, sc_reg);
return 0;
} }
static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{ {
if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0 if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
return; return -EINVAL;
uli_scr_cfg_write(ap, sc_reg, val); uli_scr_cfg_write(ap, sc_reg, val);
return 0;
} }
static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
......
...@@ -72,8 +72,8 @@ enum { ...@@ -72,8 +72,8 @@ enum {
}; };
static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg); static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static void svia_noop_freeze(struct ata_port *ap); static void svia_noop_freeze(struct ata_port *ap);
static void vt6420_error_handler(struct ata_port *ap); static void vt6420_error_handler(struct ata_port *ap);
static int vt6421_pata_cable_detect(struct ata_port *ap); static int vt6421_pata_cable_detect(struct ata_port *ap);
...@@ -249,18 +249,20 @@ MODULE_LICENSE("GPL"); ...@@ -249,18 +249,20 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, svia_pci_tbl); MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
MODULE_VERSION(DRV_VERSION); MODULE_VERSION(DRV_VERSION);
static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg) static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return 0xffffffffU; return -EINVAL;
return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg)); *val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
return 0;
} }
static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return; return -EINVAL;
iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg)); iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
return 0;
} }
static void svia_noop_freeze(struct ata_port *ap) static void svia_noop_freeze(struct ata_port *ap)
...@@ -305,18 +307,19 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) ...@@ -305,18 +307,19 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
/* Resume phy. This is the old SATA resume sequence */ /* Resume phy. This is the old SATA resume sequence */
svia_scr_write(ap, SCR_CONTROL, 0x300); svia_scr_write(ap, SCR_CONTROL, 0x300);
svia_scr_read(ap, SCR_CONTROL); /* flush */ svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
/* wait for phy to become ready, if necessary */ /* wait for phy to become ready, if necessary */
do { do {
msleep(200); msleep(200);
if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1) svia_scr_read(ap, SCR_STATUS, &sstatus);
if ((sstatus & 0xf) != 1)
break; break;
} while (time_before(jiffies, timeout)); } while (time_before(jiffies, timeout));
/* open code sata_print_link_status() */ /* open code sata_print_link_status() */
sstatus = svia_scr_read(ap, SCR_STATUS); svia_scr_read(ap, SCR_STATUS, &sstatus);
scontrol = svia_scr_read(ap, SCR_CONTROL); svia_scr_read(ap, SCR_CONTROL, &scontrol);
online = (sstatus & 0xf) == 0x3; online = (sstatus & 0xf) == 0x3;
...@@ -325,7 +328,7 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) ...@@ -325,7 +328,7 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
online ? "up" : "down", sstatus, scontrol); online ? "up" : "down", sstatus, scontrol);
/* SStatus is read one more time */ /* SStatus is read one more time */
svia_scr_read(ap, SCR_STATUS); svia_scr_read(ap, SCR_STATUS, &sstatus);
if (!online) { if (!online) {
/* tell EH to bail */ /* tell EH to bail */
......
...@@ -98,20 +98,21 @@ enum { ...@@ -98,20 +98,21 @@ enum {
VSC_SATA_INT_PHY_CHANGE), VSC_SATA_INT_PHY_CHANGE),
}; };
static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return 0xffffffffU; return -EINVAL;
return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
} }
static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return; return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
} }
......
...@@ -323,6 +323,7 @@ enum ata_completion_errors { ...@@ -323,6 +323,7 @@ enum ata_completion_errors {
AC_ERR_INVALID = (1 << 7), /* invalid argument */ AC_ERR_INVALID = (1 << 7), /* invalid argument */
AC_ERR_OTHER = (1 << 8), /* unknown */ AC_ERR_OTHER = (1 << 8), /* unknown */
AC_ERR_NODEV_HINT = (1 << 9), /* polling device detection hint */ AC_ERR_NODEV_HINT = (1 << 9), /* polling device detection hint */
AC_ERR_NCQ = (1 << 10), /* marker for offending NCQ qc */
}; };
/* forward declarations */ /* forward declarations */
...@@ -530,6 +531,7 @@ struct ata_port { ...@@ -530,6 +531,7 @@ struct ata_port {
unsigned int cbl; /* cable type; ATA_CBL_xxx */ unsigned int cbl; /* cable type; ATA_CBL_xxx */
unsigned int hw_sata_spd_limit; unsigned int hw_sata_spd_limit;
unsigned int sata_spd_limit; /* SATA PHY speed limit */ unsigned int sata_spd_limit; /* SATA PHY speed limit */
unsigned int sata_spd; /* current SATA PHY speed */
/* record runtime error info, protected by host lock */ /* record runtime error info, protected by host lock */
struct ata_eh_info eh_info; struct ata_eh_info eh_info;
...@@ -563,6 +565,9 @@ struct ata_port { ...@@ -563,6 +565,9 @@ struct ata_port {
pm_message_t pm_mesg; pm_message_t pm_mesg;
int *pm_result; int *pm_result;
struct timer_list fastdrain_timer;
unsigned long fastdrain_cnt;
void *private_data; void *private_data;
#ifdef CONFIG_ATA_ACPI #ifdef CONFIG_ATA_ACPI
...@@ -619,9 +624,8 @@ struct ata_port_operations { ...@@ -619,9 +624,8 @@ struct ata_port_operations {
u8 (*irq_on) (struct ata_port *); u8 (*irq_on) (struct ata_port *);
u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq); u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq);
u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg); int (*scr_read) (struct ata_port *ap, unsigned int sc_reg, u32 *val);
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg, int (*scr_write) (struct ata_port *ap, unsigned int sc_reg, u32 val);
u32 val);
int (*port_suspend) (struct ata_port *ap, pm_message_t mesg); int (*port_suspend) (struct ata_port *ap, pm_message_t mesg);
int (*port_resume) (struct ata_port *ap); int (*port_resume) (struct ata_port *ap);
...@@ -764,7 +768,8 @@ extern unsigned int ata_dev_try_classify(struct ata_port *, unsigned int, u8 *); ...@@ -764,7 +768,8 @@ extern unsigned int ata_dev_try_classify(struct ata_port *, unsigned int, u8 *);
*/ */
extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp); extern void ata_tf_to_fis(const struct ata_taskfile *tf,
u8 pmp, int is_cmd, u8 *fis);
extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf); extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device); extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
extern void ata_std_dev_select (struct ata_port *ap, unsigned int device); extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
...@@ -909,27 +914,21 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -909,27 +914,21 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
/* /*
* ata_eh_info helpers * ata_eh_info helpers
*/ */
#define ata_ehi_push_desc(ehi, fmt, args...) do { \ extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
(ehi)->desc_len += scnprintf((ehi)->desc + (ehi)->desc_len, \ extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
ATA_EH_DESC_LEN - (ehi)->desc_len, \ extern void ata_ehi_clear_desc(struct ata_eh_info *ehi);
fmt , ##args); \
} while (0) static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi)
#define ata_ehi_clear_desc(ehi) do { \
(ehi)->desc[0] = '\0'; \
(ehi)->desc_len = 0; \
} while (0)
static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
{ {
ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK; ehi->flags |= ATA_EHI_RESUME_LINK;
ehi->action |= ATA_EH_SOFTRESET; ehi->action |= ATA_EH_SOFTRESET;
ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
} }
static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
{ {
__ata_ehi_hotplugged(ehi); ata_ehi_schedule_probe(ehi);
ehi->flags |= ATA_EHI_HOTPLUGGED;
ehi->err_mask |= AC_ERR_ATA_BUS; ehi->err_mask |= AC_ERR_ATA_BUS;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment