Commit 6adc74b7 authored by Linus Torvalds's avatar Linus Torvalds

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

* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev:
  [libata] ata_piix: Enable parallel scan
  sata_nv: use hardreset only for post-boot probing
  [libata] ahci: Restore SB600 SATA controller 64 bit DMA
  ata_piix: Remove stale comment
  ata_piix: Turn on hotplugging support for older chips
  ahci: misc cleanups for EM stuff
  [libata] get rid of ATA_MAX_QUEUE loop in ata_qc_complete_multiple() v2
  sata_sil: enable 32-bit PIO
  sata_sx4: speed up ECC initialization
  libata-sff: avoid byte swapping in ata_sff_data_xfer()
  [libata] ahci: use less error-prone array initializers
parents c9059598 517d3cc1
...@@ -77,8 +77,6 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, ...@@ -77,8 +77,6 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
size_t size); size_t size);
static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
ssize_t size); ssize_t size);
#define MAX_SLOTS 8
#define MAX_RETRY 15
enum { enum {
AHCI_PCI_BAR = 5, AHCI_PCI_BAR = 5,
...@@ -231,6 +229,10 @@ enum { ...@@ -231,6 +229,10 @@ enum {
ICH_MAP = 0x90, /* ICH MAP register */ ICH_MAP = 0x90, /* ICH MAP register */
/* em constants */
EM_MAX_SLOTS = 8,
EM_MAX_RETRY = 5,
/* em_ctl bits */ /* em_ctl bits */
EM_CTL_RST = (1 << 9), /* Reset */ EM_CTL_RST = (1 << 9), /* Reset */
EM_CTL_TM = (1 << 8), /* Transmit Message */ EM_CTL_TM = (1 << 8), /* Transmit Message */
...@@ -282,8 +284,8 @@ struct ahci_port_priv { ...@@ -282,8 +284,8 @@ struct ahci_port_priv {
unsigned int ncq_saw_dmas:1; unsigned int ncq_saw_dmas:1;
unsigned int ncq_saw_sdb:1; unsigned int ncq_saw_sdb:1;
u32 intr_mask; /* interrupts to enable */ u32 intr_mask; /* interrupts to enable */
struct ahci_em_priv em_priv[MAX_SLOTS];/* enclosure management info /* enclosure management info per PM slot */
* per PM slot */ struct ahci_em_priv em_priv[EM_MAX_SLOTS];
}; };
static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
...@@ -313,7 +315,6 @@ static void ahci_error_handler(struct ata_port *ap); ...@@ -313,7 +315,6 @@ static void ahci_error_handler(struct ata_port *ap);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
static int ahci_port_resume(struct ata_port *ap); static int ahci_port_resume(struct ata_port *ap);
static void ahci_dev_config(struct ata_device *dev); static void ahci_dev_config(struct ata_device *dev);
static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
u32 opts); u32 opts);
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -404,14 +405,14 @@ static struct ata_port_operations ahci_sb600_ops = { ...@@ -404,14 +405,14 @@ static struct ata_port_operations ahci_sb600_ops = {
#define AHCI_HFLAGS(flags) .private_data = (void *)(flags) #define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
static const struct ata_port_info ahci_port_info[] = { static const struct ata_port_info ahci_port_info[] = {
/* board_ahci */ [board_ahci] =
{ {
.flags = AHCI_FLAG_COMMON, .flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops, .port_ops = &ahci_ops,
}, },
/* board_ahci_vt8251 */ [board_ahci_vt8251] =
{ {
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
.flags = AHCI_FLAG_COMMON, .flags = AHCI_FLAG_COMMON,
...@@ -419,7 +420,7 @@ static const struct ata_port_info ahci_port_info[] = { ...@@ -419,7 +420,7 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &ahci_vt8251_ops, .port_ops = &ahci_vt8251_ops,
}, },
/* board_ahci_ign_iferr */ [board_ahci_ign_iferr] =
{ {
AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR),
.flags = AHCI_FLAG_COMMON, .flags = AHCI_FLAG_COMMON,
...@@ -427,17 +428,16 @@ static const struct ata_port_info ahci_port_info[] = { ...@@ -427,17 +428,16 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops, .port_ops = &ahci_ops,
}, },
/* board_ahci_sb600 */ [board_ahci_sb600] =
{ {
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255),
AHCI_HFLAG_SECT255),
.flags = AHCI_FLAG_COMMON, .flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &ahci_sb600_ops, .port_ops = &ahci_sb600_ops,
}, },
/* board_ahci_mv */ [board_ahci_mv] =
{ {
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP), AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
...@@ -447,7 +447,7 @@ static const struct ata_port_info ahci_port_info[] = { ...@@ -447,7 +447,7 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops, .port_ops = &ahci_ops,
}, },
/* board_ahci_sb700, for SB700 and SB800 */ [board_ahci_sb700] = /* for SB700 and SB800 */
{ {
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL), AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL),
.flags = AHCI_FLAG_COMMON, .flags = AHCI_FLAG_COMMON,
...@@ -455,7 +455,7 @@ static const struct ata_port_info ahci_port_info[] = { ...@@ -455,7 +455,7 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &ahci_sb600_ops, .port_ops = &ahci_sb600_ops,
}, },
/* board_ahci_mcp65 */ [board_ahci_mcp65] =
{ {
AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ), AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ),
.flags = AHCI_FLAG_COMMON, .flags = AHCI_FLAG_COMMON,
...@@ -463,7 +463,7 @@ static const struct ata_port_info ahci_port_info[] = { ...@@ -463,7 +463,7 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops, .port_ops = &ahci_ops,
}, },
/* board_ahci_nopmp */ [board_ahci_nopmp] =
{ {
AHCI_HFLAGS (AHCI_HFLAG_NO_PMP), AHCI_HFLAGS (AHCI_HFLAG_NO_PMP),
.flags = AHCI_FLAG_COMMON, .flags = AHCI_FLAG_COMMON,
...@@ -1141,12 +1141,12 @@ static void ahci_start_port(struct ata_port *ap) ...@@ -1141,12 +1141,12 @@ static void ahci_start_port(struct ata_port *ap)
emp = &pp->em_priv[link->pmp]; emp = &pp->em_priv[link->pmp];
/* EM Transmit bit maybe busy during init */ /* EM Transmit bit maybe busy during init */
for (i = 0; i < MAX_RETRY; i++) { for (i = 0; i < EM_MAX_RETRY; i++) {
rc = ahci_transmit_led_message(ap, rc = ahci_transmit_led_message(ap,
emp->led_state, emp->led_state,
4); 4);
if (rc == -EBUSY) if (rc == -EBUSY)
udelay(100); msleep(1);
else else
break; break;
} }
...@@ -1340,7 +1340,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, ...@@ -1340,7 +1340,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
/* get the slot number from the message */ /* get the slot number from the message */
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
if (pmp < MAX_SLOTS) if (pmp < EM_MAX_SLOTS)
emp = &pp->em_priv[pmp]; emp = &pp->em_priv[pmp];
else else
return -EINVAL; return -EINVAL;
...@@ -1408,7 +1408,7 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, ...@@ -1408,7 +1408,7 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
/* get the slot number from the message */ /* get the slot number from the message */
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
if (pmp < MAX_SLOTS) if (pmp < EM_MAX_SLOTS)
emp = &pp->em_priv[pmp]; emp = &pp->em_priv[pmp];
else else
return -EINVAL; return -EINVAL;
...@@ -2584,6 +2584,51 @@ static void ahci_p5wdh_workaround(struct ata_host *host) ...@@ -2584,6 +2584,51 @@ static void ahci_p5wdh_workaround(struct ata_host *host)
} }
} }
/*
* SB600 ahci controller on ASUS M2A-VM can't do 64bit DMA with older
* BIOS. The oldest version known to be broken is 0901 and working is
* 1501 which was released on 2007-10-26. Force 32bit DMA on anything
* older than 1501. Please read bko#9412 for more info.
*/
static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev)
{
static const struct dmi_system_id sysids[] = {
{
.ident = "ASUS M2A-VM",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR,
"ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
},
},
{ }
};
const char *cutoff_mmdd = "10/26";
const char *date;
int year;
if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
!dmi_check_system(sysids))
return false;
/*
* Argh.... both version and date are free form strings.
* Let's hope they're using the same date format across
* different versions.
*/
date = dmi_get_system_info(DMI_BIOS_DATE);
year = dmi_get_year(DMI_BIOS_DATE);
if (date && strlen(date) >= 10 && date[2] == '/' && date[5] == '/' &&
(year > 2007 ||
(year == 2007 && strncmp(date, cutoff_mmdd, 5) >= 0)))
return false;
dev_printk(KERN_WARNING, &pdev->dev, "ASUS M2A-VM: BIOS too old, "
"forcing 32bit DMA, update BIOS\n");
return true;
}
static bool ahci_broken_system_poweroff(struct pci_dev *pdev) static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
{ {
static const struct dmi_system_id broken_systems[] = { static const struct dmi_system_id broken_systems[] = {
...@@ -2744,6 +2789,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2744,6 +2789,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (board_id == board_ahci_sb700 && pdev->revision >= 0x40) if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL; hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
/* apply ASUS M2A_VM quirk */
if (ahci_asus_m2a_vm_32bit_only(pdev))
hpriv->flags |= AHCI_HFLAG_32BIT_ONLY;
if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
pci_enable_msi(pdev); pci_enable_msi(pdev);
......
...@@ -223,10 +223,8 @@ static const struct pci_device_id piix_pci_tbl[] = { ...@@ -223,10 +223,8 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* ICH8 Mobile PATA Controller */ /* ICH8 Mobile PATA Controller */
{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* NOTE: The following PCI ids must be kept in sync with the /* SATA ports */
* list in drivers/pci/quirks.c.
*/
/* 82801EB (ICH5) */ /* 82801EB (ICH5) */
{ 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
/* 82801EB (ICH5) */ /* 82801EB (ICH5) */
...@@ -1509,8 +1507,8 @@ static int __devinit piix_init_one(struct pci_dev *pdev, ...@@ -1509,8 +1507,8 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
dev_printk(KERN_DEBUG, &pdev->dev, dev_printk(KERN_DEBUG, &pdev->dev,
"version " DRV_VERSION "\n"); "version " DRV_VERSION "\n");
/* no hotplugging support (FIXME) */ /* no hotplugging support for later devices (FIXME) */
if (!in_module_init) if (!in_module_init && ent->driver_data >= ich5_sata)
return -ENODEV; return -ENODEV;
if (piix_broken_system_poweroff(pdev)) { if (piix_broken_system_poweroff(pdev)) {
...@@ -1591,6 +1589,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, ...@@ -1591,6 +1589,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
host->ports[1]->mwdma_mask = 0; host->ports[1]->mwdma_mask = 0;
host->ports[1]->udma_mask = 0; host->ports[1]->udma_mask = 0;
} }
host->flags |= ATA_HOST_PARALLEL_SCAN;
pci_set_master(pdev); pci_set_master(pdev);
return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht); return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht);
......
...@@ -5031,7 +5031,6 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active) ...@@ -5031,7 +5031,6 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)
{ {
int nr_done = 0; int nr_done = 0;
u32 done_mask; u32 done_mask;
int i;
done_mask = ap->qc_active ^ qc_active; done_mask = ap->qc_active ^ qc_active;
...@@ -5041,16 +5040,16 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active) ...@@ -5041,16 +5040,16 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < ATA_MAX_QUEUE; i++) { while (done_mask) {
struct ata_queued_cmd *qc; struct ata_queued_cmd *qc;
unsigned int tag = __ffs(done_mask);
if (!(done_mask & (1 << i))) qc = ata_qc_from_tag(ap, tag);
continue; if (qc) {
if ((qc = ata_qc_from_tag(ap, i))) {
ata_qc_complete(qc); ata_qc_complete(qc);
nr_done++; nr_done++;
} }
done_mask &= ~(1 << tag);
} }
return nr_done; return nr_done;
......
...@@ -727,17 +727,23 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf, ...@@ -727,17 +727,23 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf,
else else
iowrite16_rep(data_addr, buf, words); iowrite16_rep(data_addr, buf, words);
/* Transfer trailing 1 byte, if any. */ /* Transfer trailing byte, if any. */
if (unlikely(buflen & 0x01)) { if (unlikely(buflen & 0x01)) {
__le16 align_buf[1] = { 0 }; unsigned char pad[2];
unsigned char *trailing_buf = buf + buflen - 1;
/* Point buf to the tail of buffer */
buf += buflen - 1;
/*
* Use io*16_rep() accessors here as well to avoid pointlessly
* swapping bytes to and fro on the big endian machines...
*/
if (rw == READ) { if (rw == READ) {
align_buf[0] = cpu_to_le16(ioread16(data_addr)); ioread16_rep(data_addr, pad, 1);
memcpy(trailing_buf, align_buf, 1); *buf = pad[0];
} else { } else {
memcpy(align_buf, trailing_buf, 1); pad[0] = *buf;
iowrite16(le16_to_cpu(align_buf[0]), data_addr); iowrite16_rep(data_addr, pad, 1);
} }
words++; words++;
} }
......
...@@ -305,8 +305,8 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance); ...@@ -305,8 +305,8 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, static int nv_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline); unsigned long deadline);
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);
static void nv_ck804_freeze(struct ata_port *ap); static void nv_ck804_freeze(struct ata_port *ap);
...@@ -406,49 +406,82 @@ static struct scsi_host_template nv_swncq_sht = { ...@@ -406,49 +406,82 @@ static struct scsi_host_template nv_swncq_sht = {
.slave_configure = nv_swncq_slave_config, .slave_configure = nv_swncq_slave_config,
}; };
static struct ata_port_operations nv_common_ops = { /*
* NV SATA controllers have various different problems with hardreset
* protocol depending on the specific controller and device.
*
* GENERIC:
*
* bko11195 reports that link doesn't come online after hardreset on
* generic nv's and there have been several other similar reports on
* linux-ide.
*
* bko12351#c23 reports that warmplug on MCP61 doesn't work with
* softreset.
*
* NF2/3:
*
* bko3352 reports nf2/3 controllers can't determine device signature
* reliably after hardreset. The following thread reports detection
* failure on cold boot with the standard debouncing timing.
*
* http://thread.gmane.org/gmane.linux.ide/34098
*
* bko12176 reports that hardreset fails to bring up the link during
* boot on nf2.
*
* CK804:
*
* For initial probing after boot and hot plugging, hardreset mostly
* works fine on CK804 but curiously, reprobing on the initial port
* by rescanning or rmmod/insmod fails to acquire the initial D2H Reg
* FIS in somewhat undeterministic way.
*
* SWNCQ:
*
* bko12351 reports that when SWNCQ is enabled, for hotplug to work,
* hardreset should be used and hardreset can't report proper
* signature, which suggests that mcp5x is closer to nf2 as long as
* reset quirkiness is concerned.
*
* bko12703 reports that boot probing fails for intel SSD with
* hardreset. Link fails to come online. Softreset works fine.
*
* The failures are varied but the following patterns seem true for
* all flavors.
*
* - Softreset during boot always works.
*
* - Hardreset during boot sometimes fails to bring up the link on
* certain comibnations and device signature acquisition is
* unreliable.
*
* - Hardreset is often necessary after hotplug.
*
* So, preferring softreset for boot probing and error handling (as
* hardreset might bring down the link) but using hardreset for
* post-boot probing should work around the above issues in most
* cases. Define nv_hardreset() which only kicks in for post-boot
* probing and use it for all variants.
*/
static struct ata_port_operations nv_generic_ops = {
.inherits = &ata_bmdma_port_ops, .inherits = &ata_bmdma_port_ops,
.lost_interrupt = ATA_OP_NULL, .lost_interrupt = ATA_OP_NULL,
.scr_read = nv_scr_read, .scr_read = nv_scr_read,
.scr_write = nv_scr_write, .scr_write = nv_scr_write,
.hardreset = nv_hardreset,
}; };
/* OSDL bz11195 reports that link doesn't come online after hardreset
* on generic nv's and there have been several other similar reports
* on linux-ide. Disable hardreset for generic nv's.
*/
static struct ata_port_operations nv_generic_ops = {
.inherits = &nv_common_ops,
.hardreset = ATA_OP_NULL,
};
/* nf2 is ripe with hardreset related problems.
*
* kernel bz#3352 reports nf2/3 controllers can't determine device
* signature reliably. The following thread reports detection failure
* on cold boot with the standard debouncing timing.
*
* http://thread.gmane.org/gmane.linux.ide/34098
*
* And bz#12176 reports that hardreset simply doesn't work on nf2.
* Give up on it and just don't do hardreset.
*/
static struct ata_port_operations nv_nf2_ops = { static struct ata_port_operations nv_nf2_ops = {
.inherits = &nv_generic_ops, .inherits = &nv_generic_ops,
.freeze = nv_nf2_freeze, .freeze = nv_nf2_freeze,
.thaw = nv_nf2_thaw, .thaw = nv_nf2_thaw,
}; };
/* For initial probing after boot and hot plugging, hardreset mostly
* works fine on CK804 but curiously, reprobing on the initial port by
* rescanning or rmmod/insmod fails to acquire the initial D2H Reg FIS
* in somewhat undeterministic way. Use noclassify hardreset.
*/
static struct ata_port_operations nv_ck804_ops = { static struct ata_port_operations nv_ck804_ops = {
.inherits = &nv_common_ops, .inherits = &nv_generic_ops,
.freeze = nv_ck804_freeze, .freeze = nv_ck804_freeze,
.thaw = nv_ck804_thaw, .thaw = nv_ck804_thaw,
.hardreset = nv_noclassify_hardreset,
.host_stop = nv_ck804_host_stop, .host_stop = nv_ck804_host_stop,
}; };
...@@ -476,19 +509,8 @@ static struct ata_port_operations nv_adma_ops = { ...@@ -476,19 +509,8 @@ static struct ata_port_operations nv_adma_ops = {
.host_stop = nv_adma_host_stop, .host_stop = nv_adma_host_stop,
}; };
/* Kernel bz#12351 reports that when SWNCQ is enabled, for hotplug to
* work, hardreset should be used and hardreset can't report proper
* signature, which suggests that mcp5x is closer to nf2 as long as
* reset quirkiness is concerned. Define separate ops for mcp5x with
* nv_noclassify_hardreset().
*/
static struct ata_port_operations nv_mcp5x_ops = {
.inherits = &nv_common_ops,
.hardreset = nv_noclassify_hardreset,
};
static struct ata_port_operations nv_swncq_ops = { static struct ata_port_operations nv_swncq_ops = {
.inherits = &nv_mcp5x_ops, .inherits = &nv_generic_ops,
.qc_defer = ata_std_qc_defer, .qc_defer = ata_std_qc_defer,
.qc_prep = nv_swncq_qc_prep, .qc_prep = nv_swncq_qc_prep,
...@@ -557,7 +579,7 @@ static const struct ata_port_info nv_port_info[] = { ...@@ -557,7 +579,7 @@ static const struct ata_port_info nv_port_info[] = {
.pio_mask = NV_PIO_MASK, .pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK, .mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK, .udma_mask = NV_UDMA_MASK,
.port_ops = &nv_mcp5x_ops, .port_ops = &nv_generic_ops,
.private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht), .private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht),
}, },
/* SWNCQ */ /* SWNCQ */
...@@ -1559,15 +1581,24 @@ static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) ...@@ -1559,15 +1581,24 @@ static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
return 0; return 0;
} }
static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, static int nv_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline) unsigned long deadline)
{ {
bool online; struct ata_eh_context *ehc = &link->eh_context;
int rc;
rc = sata_link_hardreset(link, sata_deb_timing_hotplug, deadline, /* Do hardreset iff it's post-boot probing, please read the
&online, NULL); * comment above port ops for details.
return online ? -EAGAIN : rc; */
if (!(link->ap->pflags & ATA_PFLAG_LOADING) &&
!ata_dev_enabled(link->device))
sata_link_hardreset(link, sata_deb_timing_hotplug, deadline,
NULL, NULL);
else if (!(ehc->i.flags & ATA_EHI_QUIET))
ata_link_printk(link, KERN_INFO,
"nv: skipping hardreset on occupied port\n");
/* device signature acquisition is unreliable */
return -EAGAIN;
} }
static void nv_nf2_freeze(struct ata_port *ap) static void nv_nf2_freeze(struct ata_port *ap)
......
...@@ -183,7 +183,7 @@ static struct scsi_host_template sil_sht = { ...@@ -183,7 +183,7 @@ static struct scsi_host_template sil_sht = {
}; };
static struct ata_port_operations sil_ops = { static struct ata_port_operations sil_ops = {
.inherits = &ata_bmdma_port_ops, .inherits = &ata_bmdma32_port_ops,
.dev_config = sil_dev_config, .dev_config = sil_dev_config,
.set_mode = sil_set_mode, .set_mode = sil_set_mode,
.bmdma_setup = sil_bmdma_setup, .bmdma_setup = sil_bmdma_setup,
......
...@@ -193,6 +193,7 @@ enum { ...@@ -193,6 +193,7 @@ enum {
PDC_TIMER_MASK_INT, PDC_TIMER_MASK_INT,
}; };
#define ECC_ERASE_BUF_SZ (128 * 1024)
struct pdc_port_priv { struct pdc_port_priv {
u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512]; u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
...@@ -1280,7 +1281,6 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) ...@@ -1280,7 +1281,6 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
{ {
int speed, size, length; int speed, size, length;
u32 addr, spd0, pci_status; u32 addr, spd0, pci_status;
u32 tmp = 0;
u32 time_period = 0; u32 time_period = 0;
u32 tcount = 0; u32 tcount = 0;
u32 ticks = 0; u32 ticks = 0;
...@@ -1395,14 +1395,17 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) ...@@ -1395,14 +1395,17 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_TYPE, &spd0); PDC_DIMM_SPD_TYPE, &spd0);
if (spd0 == 0x02) { if (spd0 == 0x02) {
void *buf;
VPRINTK("Start ECC initialization\n"); VPRINTK("Start ECC initialization\n");
addr = 0; addr = 0;
length = size * 1024 * 1024; length = size * 1024 * 1024;
buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL);
while (addr < length) { while (addr < length) {
pdc20621_put_to_dimm(host, (void *) &tmp, addr, pdc20621_put_to_dimm(host, buf, addr,
sizeof(u32)); ECC_ERASE_BUF_SZ);
addr += sizeof(u32); addr += ECC_ERASE_BUF_SZ;
} }
kfree(buf);
VPRINTK("Finish ECC initialization\n"); VPRINTK("Finish ECC initialization\n");
} }
return 0; return 0;
......
...@@ -596,6 +596,7 @@ int dmi_get_year(int field) ...@@ -596,6 +596,7 @@ int dmi_get_year(int field)
return year; return year;
} }
EXPORT_SYMBOL(dmi_get_year);
/** /**
* dmi_walk - Walk the DMI table and get called back for every record * dmi_walk - Walk the DMI table and get called back for every record
......
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