提交 e10117d3 编写于 作者: L 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: (26 commits)
  include/linux/libata.h: fix typo
  pata_bf54x: fix return type of bfin_set_devctl
  Drivers: ata: Makefile: replace the use of <module>-objs with <module>-y
  libahci: fix result_tf handling after an ATA PIO data-in command
  pata_sl82c105: implement sff_irq_check() method
  pata_sil680: implement sff_irq_check() method
  pata_pdc202xx_old: implement sff_irq_check() method
  pata_cmd640: implement sff_irq_check() method
  ata_piix: Add device ID for ICH4-L
  pata_sil680: make sil680_sff_exec_command() 'static'
  ata: Intel IDE-R support
  libata: reorder ata_queued_cmd to remove alignment padding on 64 bit builds
  libata: Signal that our SATL supports WRITE SAME(16) with UNMAP
  ata_piix: remove SIDPR locking
  libata: implement cross-port EH exclusion
  libata: add @ap to ata_wait_register() and introduce ata_msleep()
  ata_piix: implement LPM support
  libata: implement LPM support for port multipliers
  libata: reimplement link power management
  libata: implement sata_link_scr_lpm() and make ata_dev_set_feature() global
  ...
What: /sys/class/ata_...
Date: August 2008
Contact: Gwendal Grignou<gwendal@google.com>
Description:
Provide a place in sysfs for storing the ATA topology of the system. This allows
retrieving various information about ATA objects.
Files under /sys/class/ata_port
-------------------------------
For each port, a directory ataX is created where X is the ata_port_id of
the port. The device parent is the ata host device.
idle_irq (read)
Number of IRQ received by the port while idle [some ata HBA only].
nr_pmp_links (read)
If a SATA Port Multiplier (PM) is connected, number of link behind it.
Files under /sys/class/ata_link
-------------------------------
Behind each port, there is a ata_link. If there is a SATA PM in the
topology, 15 ata_link objects are created.
If a link is behind a port, the directory name is linkX, where X is
ata_port_id of the port.
If a link is behind a PM, its name is linkX.Y where X is ata_port_id
of the parent port and Y the PM port.
hw_sata_spd_limit
Maximum speed supported by the connected SATA device.
sata_spd_limit
Maximum speed imposed by libata.
sata_spd
Current speed of the link [1.5, 3Gps,...].
Files under /sys/class/ata_device
---------------------------------
Behind each link, up to two ata device are created.
The name of the directory is devX[.Y].Z where:
- X is ata_port_id of the port where the device is connected,
- Y the port of the PM if any, and
- Z the device id: for PATA, there is usually 2 devices [0,1],
only 1 for SATA.
class
Device class. Can be "ata" for disk, "atapi" for packet device,
"pmp" for PM, or "none" if no device was found behind the link.
dma_mode
Transfer modes supported by the device when in DMA mode.
Mostly used by PATA device.
pio_mode
Transfer modes supported by the device when in PIO mode.
Mostly used by PATA device.
xfer_mode
Current transfer mode.
id
Cached result of IDENTIFY command, as described in ATA8 7.16 and 7.17.
Only valid if the device is not a PM.
gscr
Cached result of the dump of PM GSCR register.
Valid registers are:
0: SATA_PMP_GSCR_PROD_ID,
1: SATA_PMP_GSCR_REV,
2: SATA_PMP_GSCR_PORT_INFO,
32: SATA_PMP_GSCR_ERROR,
33: SATA_PMP_GSCR_ERROR_EN,
64: SATA_PMP_GSCR_FEAT,
96: SATA_PMP_GSCR_FEAT_EN,
130: SATA_PMP_GSCR_SII_GPIO
Only valid if the device is a PM.
spdn_cnt
Number of time libata decided to lower the speed of link due to errors.
ering
Formatted output of the error ring of the device.
...@@ -99,7 +99,7 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o ...@@ -99,7 +99,7 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
# Should be last libata driver # Should be last libata driver
obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o
libata-objs := libata-core.o libata-scsi.o libata-eh.o libata-y := libata-core.o libata-scsi.o libata-eh.o libata-transport.o
libata-$(CONFIG_ATA_SFF) += libata-sff.o libata-$(CONFIG_ATA_SFF) += libata-sff.o
libata-$(CONFIG_SATA_PMP) += libata-pmp.o libata-$(CONFIG_SATA_PMP) += libata-pmp.o
libata-$(CONFIG_ATA_ACPI) += libata-acpi.o libata-$(CONFIG_ATA_ACPI) += libata-acpi.o
...@@ -1208,9 +1208,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1208,9 +1208,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
ata_port_pbar_desc(ap, AHCI_PCI_BAR, ata_port_pbar_desc(ap, AHCI_PCI_BAR,
0x100 + ap->port_no * 0x80, "port"); 0x100 + ap->port_no * 0x80, "port");
/* set initial link pm policy */
ap->pm_policy = NOT_AVAILABLE;
/* set enclosure management message type */ /* set enclosure management message type */
if (ap->flags & ATA_FLAG_EM) if (ap->flags & ATA_FLAG_EM)
ap->em_message_type = hpriv->em_msg_type; ap->em_message_type = hpriv->em_msg_type;
......
...@@ -72,6 +72,7 @@ enum { ...@@ -72,6 +72,7 @@ enum {
AHCI_CMD_RESET = (1 << 8), AHCI_CMD_RESET = (1 << 8),
AHCI_CMD_CLR_BUSY = (1 << 10), AHCI_CMD_CLR_BUSY = (1 << 10),
RX_FIS_PIO_SETUP = 0x20, /* offset of PIO Setup FIS data */
RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ RX_FIS_SDB = 0x58, /* offset of SDB FIS data */
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
...@@ -201,7 +202,6 @@ enum { ...@@ -201,7 +202,6 @@ enum {
AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */
AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */
AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */
AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */
AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */
AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */
AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */
...@@ -216,7 +216,7 @@ enum { ...@@ -216,7 +216,7 @@ enum {
AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
ATA_FLAG_ACPI_SATA | ATA_FLAG_AN | ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
ATA_FLAG_IPM, ATA_FLAG_LPM,
ICH_MAP = 0x90, /* ICH MAP register */ ICH_MAP = 0x90, /* ICH MAP register */
......
...@@ -129,9 +129,6 @@ static int __init ahci_probe(struct platform_device *pdev) ...@@ -129,9 +129,6 @@ static int __init ahci_probe(struct platform_device *pdev)
ata_port_desc(ap, "mmio %pR", mem); ata_port_desc(ap, "mmio %pR", mem);
ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
/* set initial link pm policy */
ap->pm_policy = NOT_AVAILABLE;
/* set enclosure management message type */ /* set enclosure management message type */
if (ap->flags & ATA_FLAG_EM) if (ap->flags & ATA_FLAG_EM)
ap->em_message_type = hpriv->em_msg_type; ap->em_message_type = hpriv->em_msg_type;
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
enum { enum {
ATA_GEN_CLASS_MATCH = (1 << 0), ATA_GEN_CLASS_MATCH = (1 << 0),
ATA_GEN_FORCE_DMA = (1 << 1), ATA_GEN_FORCE_DMA = (1 << 1),
ATA_GEN_INTEL_IDER = (1 << 2),
}; };
/** /**
...@@ -108,6 +109,49 @@ static struct ata_port_operations generic_port_ops = { ...@@ -108,6 +109,49 @@ static struct ata_port_operations generic_port_ops = {
static int all_generic_ide; /* Set to claim all devices */ static int all_generic_ide; /* Set to claim all devices */
/**
* is_intel_ider - identify intel IDE-R devices
* @dev: PCI device
*
* Distinguish Intel IDE-R controller devices from other Intel IDE
* devices. IDE-R devices have no timing registers and are in
* most respects virtual. They should be driven by the ata_generic
* driver.
*
* IDE-R devices have PCI offset 0xF8.L as zero, later Intel ATA has
* it non zero. All Intel ATA has 0x40 writable (timing), but it is
* not writable on IDE-R devices (this is guaranteed).
*/
static int is_intel_ider(struct pci_dev *dev)
{
/* For Intel IDE the value at 0xF8 is only zero on IDE-R
interfaces */
u32 r;
u16 t;
/* Check the manufacturing ID, it will be zero for IDE-R */
pci_read_config_dword(dev, 0xF8, &r);
/* Not IDE-R: punt so that ata_(old)piix gets it */
if (r != 0)
return 0;
/* 0xF8 will also be zero on some early Intel IDE devices
but they will have a sane timing register */
pci_read_config_word(dev, 0x40, &t);
if (t != 0)
return 0;
/* Finally check if the timing register is writable so that
we eliminate any early devices hot-docked in a docking
station */
pci_write_config_word(dev, 0x40, 1);
pci_read_config_word(dev, 0x40, &t);
if (t) {
pci_write_config_word(dev, 0x40, 0);
return 0;
}
return 1;
}
/** /**
* ata_generic_init - attach generic IDE * ata_generic_init - attach generic IDE
* @dev: PCI device found * @dev: PCI device found
...@@ -134,6 +178,10 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id ...@@ -134,6 +178,10 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
if ((id->driver_data & ATA_GEN_CLASS_MATCH) && all_generic_ide == 0) if ((id->driver_data & ATA_GEN_CLASS_MATCH) && all_generic_ide == 0)
return -ENODEV; return -ENODEV;
if (id->driver_data & ATA_GEN_INTEL_IDER)
if (!is_intel_ider(dev))
return -ENODEV;
/* Devices that need care */ /* Devices that need care */
if (dev->vendor == PCI_VENDOR_ID_UMC && if (dev->vendor == PCI_VENDOR_ID_UMC &&
dev->device == PCI_DEVICE_ID_UMC_UM8886A && dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
...@@ -187,6 +235,10 @@ static struct pci_device_id ata_generic[] = { ...@@ -187,6 +235,10 @@ static struct pci_device_id ata_generic[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), },
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_5), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_5), },
#endif #endif
/* Intel, IDE class device */
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL,
.driver_data = ATA_GEN_INTEL_IDER },
/* Must come last. If you add entries adjust this table appropriately */ /* Must come last. If you add entries adjust this table appropriately */
{ PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL), { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL),
.driver_data = ATA_GEN_CLASS_MATCH }, .driver_data = ATA_GEN_CLASS_MATCH },
......
...@@ -158,7 +158,6 @@ struct piix_map_db { ...@@ -158,7 +158,6 @@ struct piix_map_db {
struct piix_host_priv { struct piix_host_priv {
const int *map; const int *map;
u32 saved_iocfg; u32 saved_iocfg;
spinlock_t sidpr_lock; /* FIXME: remove once locking in EH is fixed */
void __iomem *sidpr; void __iomem *sidpr;
}; };
...@@ -175,6 +174,8 @@ static int piix_sidpr_scr_read(struct ata_link *link, ...@@ -175,6 +174,8 @@ static int piix_sidpr_scr_read(struct ata_link *link,
unsigned int reg, u32 *val); unsigned int reg, u32 *val);
static int piix_sidpr_scr_write(struct ata_link *link, static int piix_sidpr_scr_write(struct ata_link *link,
unsigned int reg, u32 val); unsigned int reg, u32 val);
static int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
unsigned hints);
static bool piix_irq_check(struct ata_port *ap); static bool piix_irq_check(struct ata_port *ap);
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
...@@ -209,6 +210,8 @@ static const struct pci_device_id piix_pci_tbl[] = { ...@@ -209,6 +210,8 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* Intel ICH3 (E7500/1) UDMA 100 */ /* Intel ICH3 (E7500/1) UDMA 100 */
{ 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* Intel ICH4-L */
{ 0x8086, 0x24C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */ /* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */
{ 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
{ 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
...@@ -348,11 +351,22 @@ static struct ata_port_operations ich_pata_ops = { ...@@ -348,11 +351,22 @@ static struct ata_port_operations ich_pata_ops = {
.set_dmamode = ich_set_dmamode, .set_dmamode = ich_set_dmamode,
}; };
static struct device_attribute *piix_sidpr_shost_attrs[] = {
&dev_attr_link_power_management_policy,
NULL
};
static struct scsi_host_template piix_sidpr_sht = {
ATA_BMDMA_SHT(DRV_NAME),
.shost_attrs = piix_sidpr_shost_attrs,
};
static struct ata_port_operations piix_sidpr_sata_ops = { static struct ata_port_operations piix_sidpr_sata_ops = {
.inherits = &piix_sata_ops, .inherits = &piix_sata_ops,
.hardreset = sata_std_hardreset, .hardreset = sata_std_hardreset,
.scr_read = piix_sidpr_scr_read, .scr_read = piix_sidpr_scr_read,
.scr_write = piix_sidpr_scr_write, .scr_write = piix_sidpr_scr_write,
.set_lpm = piix_sidpr_set_lpm,
}; };
static const struct piix_map_db ich5_map_db = { static const struct piix_map_db ich5_map_db = {
...@@ -956,15 +970,12 @@ static int piix_sidpr_scr_read(struct ata_link *link, ...@@ -956,15 +970,12 @@ static int piix_sidpr_scr_read(struct ata_link *link,
unsigned int reg, u32 *val) unsigned int reg, u32 *val)
{ {
struct piix_host_priv *hpriv = link->ap->host->private_data; struct piix_host_priv *hpriv = link->ap->host->private_data;
unsigned long flags;
if (reg >= ARRAY_SIZE(piix_sidx_map)) if (reg >= ARRAY_SIZE(piix_sidx_map))
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&hpriv->sidpr_lock, flags);
piix_sidpr_sel(link, reg); piix_sidpr_sel(link, reg);
*val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA); *val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
return 0; return 0;
} }
...@@ -972,18 +983,21 @@ static int piix_sidpr_scr_write(struct ata_link *link, ...@@ -972,18 +983,21 @@ static int piix_sidpr_scr_write(struct ata_link *link,
unsigned int reg, u32 val) unsigned int reg, u32 val)
{ {
struct piix_host_priv *hpriv = link->ap->host->private_data; struct piix_host_priv *hpriv = link->ap->host->private_data;
unsigned long flags;
if (reg >= ARRAY_SIZE(piix_sidx_map)) if (reg >= ARRAY_SIZE(piix_sidx_map))
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&hpriv->sidpr_lock, flags);
piix_sidpr_sel(link, reg); piix_sidpr_sel(link, reg);
iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA); iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
return 0; return 0;
} }
static int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
unsigned hints)
{
return sata_link_scr_lpm(link, policy, false);
}
static bool piix_irq_check(struct ata_port *ap) static bool piix_irq_check(struct ata_port *ap)
{ {
if (unlikely(!ap->ioaddr.bmdma_addr)) if (unlikely(!ap->ioaddr.bmdma_addr))
...@@ -1543,6 +1557,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, ...@@ -1543,6 +1557,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct ata_port_info port_info[2]; struct ata_port_info port_info[2];
const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] }; const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };
struct scsi_host_template *sht = &piix_sht;
unsigned long port_flags; unsigned long port_flags;
struct ata_host *host; struct ata_host *host;
struct piix_host_priv *hpriv; struct piix_host_priv *hpriv;
...@@ -1577,7 +1592,6 @@ static int __devinit piix_init_one(struct pci_dev *pdev, ...@@ -1577,7 +1592,6 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv) if (!hpriv)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&hpriv->sidpr_lock);
/* Save IOCFG, this will be used for cable detection, quirk /* Save IOCFG, this will be used for cable detection, quirk
* detection and restoration on detach. This is necessary * detection and restoration on detach. This is necessary
...@@ -1612,6 +1626,8 @@ static int __devinit piix_init_one(struct pci_dev *pdev, ...@@ -1612,6 +1626,8 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
rc = piix_init_sidpr(host); rc = piix_init_sidpr(host);
if (rc) if (rc)
return rc; return rc;
if (host->ports[0]->ops == &piix_sidpr_sata_ops)
sht = &piix_sidpr_sht;
} }
/* apply IOCFG bit18 quirk */ /* apply IOCFG bit18 quirk */
...@@ -1638,7 +1654,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, ...@@ -1638,7 +1654,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
host->flags |= ATA_HOST_PARALLEL_SCAN; host->flags |= ATA_HOST_PARALLEL_SCAN;
pci_set_master(pdev); pci_set_master(pdev);
return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, &piix_sht); return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
} }
static void piix_remove_one(struct pci_dev *pdev) static void piix_remove_one(struct pci_dev *pdev)
......
...@@ -56,9 +56,8 @@ MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip) ...@@ -56,9 +56,8 @@ MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)
module_param_named(ignore_sss, ahci_ignore_sss, int, 0444); module_param_named(ignore_sss, ahci_ignore_sss, int, 0444);
MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)"); MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
static int ahci_enable_alpm(struct ata_port *ap, static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
enum link_pm policy); unsigned hints);
static void ahci_disable_alpm(struct ata_port *ap);
static ssize_t ahci_led_show(struct ata_port *ap, char *buf); static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
size_t size); size_t size);
...@@ -164,8 +163,7 @@ struct ata_port_operations ahci_ops = { ...@@ -164,8 +163,7 @@ struct ata_port_operations ahci_ops = {
.pmp_attach = ahci_pmp_attach, .pmp_attach = ahci_pmp_attach,
.pmp_detach = ahci_pmp_detach, .pmp_detach = ahci_pmp_detach,
.enable_pm = ahci_enable_alpm, .set_lpm = ahci_set_lpm,
.disable_pm = ahci_disable_alpm,
.em_show = ahci_led_show, .em_show = ahci_led_show,
.em_store = ahci_led_store, .em_store = ahci_led_store,
.sw_activity_show = ahci_activity_show, .sw_activity_show = ahci_activity_show,
...@@ -569,7 +567,7 @@ int ahci_stop_engine(struct ata_port *ap) ...@@ -569,7 +567,7 @@ int ahci_stop_engine(struct ata_port *ap)
writel(tmp, port_mmio + PORT_CMD); writel(tmp, port_mmio + PORT_CMD);
/* wait for engine to stop. This could be as long as 500 msec */ /* wait for engine to stop. This could be as long as 500 msec */
tmp = ata_wait_register(port_mmio + PORT_CMD, tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
if (tmp & PORT_CMD_LIST_ON) if (tmp & PORT_CMD_LIST_ON)
return -EIO; return -EIO;
...@@ -616,7 +614,7 @@ static int ahci_stop_fis_rx(struct ata_port *ap) ...@@ -616,7 +614,7 @@ static int ahci_stop_fis_rx(struct ata_port *ap)
writel(tmp, port_mmio + PORT_CMD); writel(tmp, port_mmio + PORT_CMD);
/* wait for completion, spec says 500ms, give it 1000 */ /* wait for completion, spec says 500ms, give it 1000 */
tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, tmp = ata_wait_register(ap, port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
PORT_CMD_FIS_ON, 10, 1000); PORT_CMD_FIS_ON, 10, 1000);
if (tmp & PORT_CMD_FIS_ON) if (tmp & PORT_CMD_FIS_ON)
return -EBUSY; return -EBUSY;
...@@ -642,127 +640,56 @@ static void ahci_power_up(struct ata_port *ap) ...@@ -642,127 +640,56 @@ static void ahci_power_up(struct ata_port *ap)
writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
} }
static void ahci_disable_alpm(struct ata_port *ap) static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
unsigned int hints)
{ {
struct ata_port *ap = link->ap;
struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 cmd;
struct ahci_port_priv *pp = ap->private_data; struct ahci_port_priv *pp = ap->private_data;
/* IPM bits should be disabled by libata-core */
/* get the existing command bits */
cmd = readl(port_mmio + PORT_CMD);
/* disable ALPM and ASP */
cmd &= ~PORT_CMD_ASP;
cmd &= ~PORT_CMD_ALPE;
/* force the interface back to active */
cmd |= PORT_CMD_ICC_ACTIVE;
/* write out new cmd value */
writel(cmd, port_mmio + PORT_CMD);
cmd = readl(port_mmio + PORT_CMD);
/* wait 10ms to be sure we've come out of any low power state */
msleep(10);
/* clear out any PhyRdy stuff from interrupt status */
writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
/* go ahead and clean out PhyRdy Change from Serror too */
ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
/*
* Clear flag to indicate that we should ignore all PhyRdy
* state changes
*/
hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
/*
* Enable interrupts on Phy Ready.
*/
pp->intr_mask |= PORT_IRQ_PHYRDY;
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
/*
* don't change the link pm policy - we can be called
* just to turn of link pm temporarily
*/
}
static int ahci_enable_alpm(struct ata_port *ap,
enum link_pm policy)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *port_mmio = ahci_port_base(ap); void __iomem *port_mmio = ahci_port_base(ap);
u32 cmd;
struct ahci_port_priv *pp = ap->private_data;
u32 asp;
/* Make sure the host is capable of link power management */
if (!(hpriv->cap & HOST_CAP_ALPM))
return -EINVAL;
switch (policy) {
case MAX_PERFORMANCE:
case NOT_AVAILABLE:
/*
* if we came here with NOT_AVAILABLE,
* it just means this is the first time we
* have tried to enable - default to max performance,
* and let the user go to lower power modes on request.
*/
ahci_disable_alpm(ap);
return 0;
case MIN_POWER:
/* configure HBA to enter SLUMBER */
asp = PORT_CMD_ASP;
break;
case MEDIUM_POWER:
/* configure HBA to enter PARTIAL */
asp = 0;
break;
default:
return -EINVAL;
}
if (policy != ATA_LPM_MAX_POWER) {
/* /*
* Disable interrupts on Phy Ready. This keeps us from * Disable interrupts on Phy Ready. This keeps us from
* getting woken up due to spurious phy ready interrupts * getting woken up due to spurious phy ready
* TBD - Hot plug should be done via polling now, is * interrupts.
* that even supported?
*/ */
pp->intr_mask &= ~PORT_IRQ_PHYRDY; pp->intr_mask &= ~PORT_IRQ_PHYRDY;
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
/* sata_link_scr_lpm(link, policy, false);
* Set a flag to indicate that we should ignore all PhyRdy }
* state changes since these can happen now whenever we
* change link state
*/
hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
/* get the existing command bits */ if (hpriv->cap & HOST_CAP_ALPM) {
cmd = readl(port_mmio + PORT_CMD); u32 cmd = readl(port_mmio + PORT_CMD);
/* if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
* Set ASP based on Policy cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
*/ cmd |= PORT_CMD_ICC_ACTIVE;
cmd |= asp;
/* writel(cmd, port_mmio + PORT_CMD);
* Setting this bit will instruct the HBA to aggressively readl(port_mmio + PORT_CMD);
* enter a lower power link state when it's appropriate and
* based on the value set above for ASP /* wait 10ms to be sure we've come out of LPM state */
*/ ata_msleep(ap, 10);
} else {
cmd |= PORT_CMD_ALPE; cmd |= PORT_CMD_ALPE;
if (policy == ATA_LPM_MIN_POWER)
cmd |= PORT_CMD_ASP;
/* write out new cmd value */ /* write out new cmd value */
writel(cmd, port_mmio + PORT_CMD); writel(cmd, port_mmio + PORT_CMD);
cmd = readl(port_mmio + PORT_CMD); }
}
if (policy == ATA_LPM_MAX_POWER) {
sata_link_scr_lpm(link, policy, false);
/* turn PHYRDY IRQ back on */
pp->intr_mask |= PORT_IRQ_PHYRDY;
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
/* IPM bits should be set by libata-core */
return 0; return 0;
} }
...@@ -813,7 +740,7 @@ static void ahci_start_port(struct ata_port *ap) ...@@ -813,7 +740,7 @@ static void ahci_start_port(struct ata_port *ap)
emp->led_state, emp->led_state,
4); 4);
if (rc == -EBUSY) if (rc == -EBUSY)
msleep(1); ata_msleep(ap, 1);
else else
break; break;
} }
...@@ -872,7 +799,7 @@ int ahci_reset_controller(struct ata_host *host) ...@@ -872,7 +799,7 @@ int ahci_reset_controller(struct ata_host *host)
* reset must complete within 1 second, or * reset must complete within 1 second, or
* the hardware should be considered fried. * the hardware should be considered fried.
*/ */
tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET, tmp = ata_wait_register(NULL, mmio + HOST_CTL, HOST_RESET,
HOST_RESET, 10, 1000); HOST_RESET, 10, 1000);
if (tmp & HOST_RESET) { if (tmp & HOST_RESET) {
...@@ -1252,7 +1179,7 @@ int ahci_kick_engine(struct ata_port *ap) ...@@ -1252,7 +1179,7 @@ int ahci_kick_engine(struct ata_port *ap)
writel(tmp, port_mmio + PORT_CMD); writel(tmp, port_mmio + PORT_CMD);
rc = 0; rc = 0;
tmp = ata_wait_register(port_mmio + PORT_CMD, tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
if (tmp & PORT_CMD_CLO) if (tmp & PORT_CMD_CLO)
rc = -EIO; rc = -EIO;
...@@ -1282,8 +1209,8 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, ...@@ -1282,8 +1209,8 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
writel(1, port_mmio + PORT_CMD_ISSUE); writel(1, port_mmio + PORT_CMD_ISSUE);
if (timeout_msec) { if (timeout_msec) {
tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, tmp = ata_wait_register(ap, port_mmio + PORT_CMD_ISSUE,
1, timeout_msec); 0x1, 0x1, 1, timeout_msec);
if (tmp & 0x1) { if (tmp & 0x1) {
ahci_kick_engine(ap); ahci_kick_engine(ap);
return -EBUSY; return -EBUSY;
...@@ -1330,7 +1257,7 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class, ...@@ -1330,7 +1257,7 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
} }
/* spec says at least 5us, but be generous and sleep for 1ms */ /* spec says at least 5us, but be generous and sleep for 1ms */
msleep(1); ata_msleep(ap, 1);
/* issue the second D2H Register FIS */ /* issue the second D2H Register FIS */
tf.ctl &= ~ATA_SRST; tf.ctl &= ~ATA_SRST;
...@@ -1660,15 +1587,10 @@ static void ahci_port_intr(struct ata_port *ap) ...@@ -1660,15 +1587,10 @@ static void ahci_port_intr(struct ata_port *ap)
if (unlikely(resetting)) if (unlikely(resetting))
status &= ~PORT_IRQ_BAD_PMP; status &= ~PORT_IRQ_BAD_PMP;
/* If we are getting PhyRdy, this is /* if LPM is enabled, PHYRDY doesn't mean anything */
* just a power state change, we should if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) {
* clear out this, plus the PhyRdy/Comm
* Wake bits from Serror
*/
if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
(status & PORT_IRQ_PHYRDY)) {
status &= ~PORT_IRQ_PHYRDY; status &= ~PORT_IRQ_PHYRDY;
ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18))); ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG);
} }
if (unlikely(status & PORT_IRQ_ERROR)) { if (unlikely(status & PORT_IRQ_ERROR)) {
...@@ -1830,12 +1752,24 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) ...@@ -1830,12 +1752,24 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
{ {
struct ahci_port_priv *pp = qc->ap->private_data; struct ahci_port_priv *pp = qc->ap->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; u8 *rx_fis = pp->rx_fis;
if (pp->fbs_enabled) if (pp->fbs_enabled)
d2h_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ; rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
/*
* After a successful execution of an ATA PIO data-in command,
* the device doesn't send D2H Reg FIS to update the TF and
* the host should take TF and E_Status from the preceding PIO
* Setup FIS.
*/
if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
!(qc->flags & ATA_QCFLAG_FAILED)) {
ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15];
} else
ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
ata_tf_from_fis(d2h_fis, &qc->result_tf);
return true; return true;
} }
......
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include "libata.h" #include "libata.h"
#include "libata-transport.h"
/* debounce timing parameters in msecs { interval, duration, timeout } */ /* debounce timing parameters in msecs { interval, duration, timeout } */
const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 }; const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
...@@ -91,8 +91,6 @@ const struct ata_port_operations sata_port_ops = { ...@@ -91,8 +91,6 @@ const struct ata_port_operations sata_port_ops = {
static unsigned int ata_dev_init_params(struct ata_device *dev, static unsigned int ata_dev_init_params(struct ata_device *dev,
u16 heads, u16 sectors); u16 heads, u16 sectors);
static unsigned int ata_dev_set_xfermode(struct ata_device *dev); static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
static unsigned int ata_dev_set_feature(struct ata_device *dev,
u8 enable, u8 feature);
static void ata_dev_xfermask(struct ata_device *dev); static void ata_dev_xfermask(struct ata_device *dev);
static unsigned long ata_dev_blacklisted(const struct ata_device *dev); static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
...@@ -1017,7 +1015,7 @@ const char *ata_mode_string(unsigned long xfer_mask) ...@@ -1017,7 +1015,7 @@ const char *ata_mode_string(unsigned long xfer_mask)
return "<n/a>"; return "<n/a>";
} }
static const char *sata_spd_string(unsigned int spd) const char *sata_spd_string(unsigned int spd)
{ {
static const char * const spd_str[] = { static const char * const spd_str[] = {
"1.5 Gbps", "1.5 Gbps",
...@@ -1030,182 +1028,6 @@ static const char *sata_spd_string(unsigned int spd) ...@@ -1030,182 +1028,6 @@ static const char *sata_spd_string(unsigned int spd)
return spd_str[spd - 1]; return spd_str[spd - 1];
} }
static int ata_dev_set_dipm(struct ata_device *dev, enum link_pm policy)
{
struct ata_link *link = dev->link;
struct ata_port *ap = link->ap;
u32 scontrol;
unsigned int err_mask;
int rc;
/*
* disallow DIPM for drivers which haven't set
* ATA_FLAG_IPM. This is because when DIPM is enabled,
* phy ready will be set in the interrupt status on
* state changes, which will cause some drivers to
* think there are errors - additionally drivers will
* need to disable hot plug.
*/
if (!(ap->flags & ATA_FLAG_IPM) || !ata_dev_enabled(dev)) {
ap->pm_policy = NOT_AVAILABLE;
return -EINVAL;
}
/*
* For DIPM, we will only enable it for the
* min_power setting.
*
* Why? Because Disks are too stupid to know that
* If the host rejects a request to go to SLUMBER
* they should retry at PARTIAL, and instead it
* just would give up. So, for medium_power to
* work at all, we need to only allow HIPM.
*/
rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
if (rc)
return rc;
switch (policy) {
case MIN_POWER:
/* no restrictions on IPM transitions */
scontrol &= ~(0x3 << 8);
rc = sata_scr_write(link, SCR_CONTROL, scontrol);
if (rc)
return rc;
/* enable DIPM */
if (dev->flags & ATA_DFLAG_DIPM)
err_mask = ata_dev_set_feature(dev,
SETFEATURES_SATA_ENABLE, SATA_DIPM);
break;
case MEDIUM_POWER:
/* allow IPM to PARTIAL */
scontrol &= ~(0x1 << 8);
scontrol |= (0x2 << 8);
rc = sata_scr_write(link, SCR_CONTROL, scontrol);
if (rc)
return rc;
/*
* we don't have to disable DIPM since IPM flags
* disallow transitions to SLUMBER, which effectively
* disable DIPM if it does not support PARTIAL
*/
break;
case NOT_AVAILABLE:
case MAX_PERFORMANCE:
/* disable all IPM transitions */
scontrol |= (0x3 << 8);
rc = sata_scr_write(link, SCR_CONTROL, scontrol);
if (rc)
return rc;
/*
* we don't have to disable DIPM since IPM flags
* disallow all transitions which effectively
* disable DIPM anyway.
*/
break;
}
/* FIXME: handle SET FEATURES failure */
(void) err_mask;
return 0;
}
/**
* ata_dev_enable_pm - enable SATA interface power management
* @dev: device to enable power management
* @policy: the link power management policy
*
* Enable SATA Interface power management. This will enable
* Device Interface Power Management (DIPM) for min_power
* policy, and then call driver specific callbacks for
* enabling Host Initiated Power management.
*
* Locking: Caller.
* Returns: -EINVAL if IPM is not supported, 0 otherwise.
*/
void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy)
{
int rc = 0;
struct ata_port *ap = dev->link->ap;
/* set HIPM first, then DIPM */
if (ap->ops->enable_pm)
rc = ap->ops->enable_pm(ap, policy);
if (rc)
goto enable_pm_out;
rc = ata_dev_set_dipm(dev, policy);
enable_pm_out:
if (rc)
ap->pm_policy = MAX_PERFORMANCE;
else
ap->pm_policy = policy;
return /* rc */; /* hopefully we can use 'rc' eventually */
}
#ifdef CONFIG_PM
/**
* ata_dev_disable_pm - disable SATA interface power management
* @dev: device to disable power management
*
* Disable SATA Interface power management. This will disable
* Device Interface Power Management (DIPM) without changing
* policy, call driver specific callbacks for disabling Host
* Initiated Power management.
*
* Locking: Caller.
* Returns: void
*/
static void ata_dev_disable_pm(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
ata_dev_set_dipm(dev, MAX_PERFORMANCE);
if (ap->ops->disable_pm)
ap->ops->disable_pm(ap);
}
#endif /* CONFIG_PM */
void ata_lpm_schedule(struct ata_port *ap, enum link_pm policy)
{
ap->pm_policy = policy;
ap->link.eh_info.action |= ATA_EH_LPM;
ap->link.eh_info.flags |= ATA_EHI_NO_AUTOPSY;
ata_port_schedule_eh(ap);
}
#ifdef CONFIG_PM
static void ata_lpm_enable(struct ata_host *host)
{
struct ata_link *link;
struct ata_port *ap;
struct ata_device *dev;
int i;
for (i = 0; i < host->n_ports; i++) {
ap = host->ports[i];
ata_for_each_link(link, ap, EDGE) {
ata_for_each_dev(dev, link, ALL)
ata_dev_disable_pm(dev);
}
}
}
static void ata_lpm_disable(struct ata_host *host)
{
int i;
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
ata_lpm_schedule(ap, ap->pm_policy);
}
}
#endif /* CONFIG_PM */
/** /**
* ata_dev_classify - determine device type based on ATA-spec signature * ata_dev_classify - determine device type based on ATA-spec signature
* @tf: ATA taskfile register set for device to be identified * @tf: ATA taskfile register set for device to be identified
...@@ -1806,8 +1628,14 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, ...@@ -1806,8 +1628,14 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
} }
} }
if (ap->ops->error_handler)
ata_eh_release(ap);
rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout)); rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout));
if (ap->ops->error_handler)
ata_eh_acquire(ap);
ata_sff_flush_pio_task(ap); ata_sff_flush_pio_task(ap);
if (!rc) { if (!rc) {
...@@ -2564,13 +2392,6 @@ int ata_dev_configure(struct ata_device *dev) ...@@ -2564,13 +2392,6 @@ int ata_dev_configure(struct ata_device *dev)
if (dev->flags & ATA_DFLAG_LBA48) if (dev->flags & ATA_DFLAG_LBA48)
dev->max_sectors = ATA_MAX_SECTORS_LBA48; dev->max_sectors = ATA_MAX_SECTORS_LBA48;
if (!(dev->horkage & ATA_HORKAGE_IPM)) {
if (ata_id_has_hipm(dev->id))
dev->flags |= ATA_DFLAG_HIPM;
if (ata_id_has_dipm(dev->id))
dev->flags |= ATA_DFLAG_DIPM;
}
/* Limit PATA drive on SATA cable bridge transfers to udma5, /* Limit PATA drive on SATA cable bridge transfers to udma5,
200 sectors */ 200 sectors */
if (ata_dev_knobble(dev)) { if (ata_dev_knobble(dev)) {
...@@ -2591,13 +2412,6 @@ int ata_dev_configure(struct ata_device *dev) ...@@ -2591,13 +2412,6 @@ int ata_dev_configure(struct ata_device *dev)
dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128, dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
dev->max_sectors); dev->max_sectors);
if (ata_dev_blacklisted(dev) & ATA_HORKAGE_IPM) {
dev->horkage |= ATA_HORKAGE_IPM;
/* reset link pm_policy for this port to no pm */
ap->pm_policy = MAX_PERFORMANCE;
}
if (ap->ops->dev_config) if (ap->ops->dev_config)
ap->ops->dev_config(dev); ap->ops->dev_config(dev);
...@@ -3596,7 +3410,7 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline, ...@@ -3596,7 +3410,7 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
warned = 1; warned = 1;
} }
msleep(50); ata_msleep(link->ap, 50);
} }
} }
...@@ -3617,7 +3431,7 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline, ...@@ -3617,7 +3431,7 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
int ata_wait_after_reset(struct ata_link *link, unsigned long deadline, int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
int (*check_ready)(struct ata_link *link)) int (*check_ready)(struct ata_link *link))
{ {
msleep(ATA_WAIT_AFTER_RESET); ata_msleep(link->ap, ATA_WAIT_AFTER_RESET);
return ata_wait_ready(link, deadline, check_ready); return ata_wait_ready(link, deadline, check_ready);
} }
...@@ -3628,7 +3442,7 @@ int ata_wait_after_reset(struct ata_link *link, unsigned long deadline, ...@@ -3628,7 +3442,7 @@ int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
* @params: timing parameters { interval, duratinon, timeout } in msec * @params: timing parameters { interval, duratinon, timeout } in msec
* @deadline: deadline jiffies for the operation * @deadline: deadline jiffies for the operation
* *
* Make sure SStatus of @link reaches stable state, determined by * Make sure SStatus of @link reaches stable state, determined by
* holding the same value where DET is not 1 for @duration polled * holding the same value where DET is not 1 for @duration polled
* every @interval, before @timeout. Timeout constraints the * every @interval, before @timeout. Timeout constraints the
* beginning of the stable state. Because DET gets stuck at 1 on * beginning of the stable state. Because DET gets stuck at 1 on
...@@ -3665,7 +3479,7 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params, ...@@ -3665,7 +3479,7 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params,
last_jiffies = jiffies; last_jiffies = jiffies;
while (1) { while (1) {
msleep(interval); ata_msleep(link->ap, interval);
if ((rc = sata_scr_read(link, SCR_STATUS, &cur))) if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
return rc; return rc;
cur &= 0xf; cur &= 0xf;
...@@ -3730,7 +3544,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, ...@@ -3730,7 +3544,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
* immediately after resuming. Delay 200ms before * immediately after resuming. Delay 200ms before
* debouncing. * debouncing.
*/ */
msleep(200); ata_msleep(link->ap, 200);
/* is SControl restored correctly? */ /* is SControl restored correctly? */
if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
...@@ -3759,6 +3573,72 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, ...@@ -3759,6 +3573,72 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
return rc != -EINVAL ? rc : 0; return rc != -EINVAL ? rc : 0;
} }
/**
* sata_link_scr_lpm - manipulate SControl IPM and SPM fields
* @link: ATA link to manipulate SControl for
* @policy: LPM policy to configure
* @spm_wakeup: initiate LPM transition to active state
*
* Manipulate the IPM field of the SControl register of @link
* according to @policy. If @policy is ATA_LPM_MAX_POWER and
* @spm_wakeup is %true, the SPM field is manipulated to wake up
* the link. This function also clears PHYRDY_CHG before
* returning.
*
* LOCKING:
* EH context.
*
* RETURNS:
* 0 on succes, -errno otherwise.
*/
int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
bool spm_wakeup)
{
struct ata_eh_context *ehc = &link->eh_context;
bool woken_up = false;
u32 scontrol;
int rc;
rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
if (rc)
return rc;
switch (policy) {
case ATA_LPM_MAX_POWER:
/* disable all LPM transitions */
scontrol |= (0x3 << 8);
/* initiate transition to active state */
if (spm_wakeup) {
scontrol |= (0x4 << 12);
woken_up = true;
}
break;
case ATA_LPM_MED_POWER:
/* allow LPM to PARTIAL */
scontrol &= ~(0x1 << 8);
scontrol |= (0x2 << 8);
break;
case ATA_LPM_MIN_POWER:
/* no restrictions on LPM transitions */
scontrol &= ~(0x3 << 8);
break;
default:
WARN_ON(1);
}
rc = sata_scr_write(link, SCR_CONTROL, scontrol);
if (rc)
return rc;
/* give the link time to transit out of LPM state */
if (woken_up)
msleep(10);
/* clear PHYRDY_CHG from SError */
ehc->i.serror &= ~SERR_PHYRDY_CHG;
return sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
}
/** /**
* ata_std_prereset - prepare for reset * ata_std_prereset - prepare for reset
* @link: ATA link to be reset * @link: ATA link to be reset
...@@ -3868,7 +3748,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, ...@@ -3868,7 +3748,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
/* Couldn't find anything in SATA I/II specs, but AHCI-1.1 /* Couldn't find anything in SATA I/II specs, but AHCI-1.1
* 10.4.2 says at least 1 ms. * 10.4.2 says at least 1 ms.
*/ */
msleep(1); ata_msleep(link->ap, 1);
/* bring link back */ /* bring link back */
rc = sata_link_resume(link, timing, deadline); rc = sata_link_resume(link, timing, deadline);
...@@ -4551,6 +4431,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) ...@@ -4551,6 +4431,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
DPRINTK("EXIT, err_mask=%x\n", err_mask); DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask; return err_mask;
} }
/** /**
* ata_dev_set_feature - Issue SET FEATURES - SATA FEATURES * ata_dev_set_feature - Issue SET FEATURES - SATA FEATURES
* @dev: Device to which command will be sent * @dev: Device to which command will be sent
...@@ -4566,8 +4447,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) ...@@ -4566,8 +4447,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
* RETURNS: * RETURNS:
* 0 on success, AC_ERR_* mask otherwise. * 0 on success, AC_ERR_* mask otherwise.
*/ */
static unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature)
u8 feature)
{ {
struct ata_taskfile tf; struct ata_taskfile tf;
unsigned int err_mask; unsigned int err_mask;
...@@ -4943,8 +4823,13 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc) ...@@ -4943,8 +4823,13 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc)
* ata_qc_complete - Complete an active ATA command * ata_qc_complete - Complete an active ATA command
* @qc: Command to complete * @qc: Command to complete
* *
* Indicate to the mid and upper layers that an ATA * Indicate to the mid and upper layers that an ATA command has
* command has completed, with either an ok or not-ok status. * completed, with either an ok or not-ok status.
*
* Refrain from calling this function multiple times when
* successfully completing multiple NCQ commands.
* ata_qc_complete_multiple() should be used instead, which will
* properly update IRQ expect state.
* *
* LOCKING: * LOCKING:
* spin_lock_irqsave(host lock) * spin_lock_irqsave(host lock)
...@@ -5037,6 +4922,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc) ...@@ -5037,6 +4922,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
* requests normally. ap->qc_active and @qc_active is compared * requests normally. ap->qc_active and @qc_active is compared
* and commands are completed accordingly. * and commands are completed accordingly.
* *
* Always use this function when completing multiple NCQ commands
* from IRQ handlers instead of calling ata_qc_complete()
* multiple times to keep IRQ expect status properly in sync.
*
* LOCKING: * LOCKING:
* spin_lock_irqsave(host lock) * spin_lock_irqsave(host lock)
* *
...@@ -5421,12 +5310,6 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg) ...@@ -5421,12 +5310,6 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
unsigned int ehi_flags = ATA_EHI_QUIET; unsigned int ehi_flags = ATA_EHI_QUIET;
int rc; int rc;
/*
* disable link pm on all ports before requesting
* any pm activity
*/
ata_lpm_enable(host);
/* /*
* On some hardware, device fails to respond after spun down * On some hardware, device fails to respond after spun down
* for suspend. As the device won't be used before being * for suspend. As the device won't be used before being
...@@ -5460,9 +5343,6 @@ void ata_host_resume(struct ata_host *host) ...@@ -5460,9 +5343,6 @@ void ata_host_resume(struct ata_host *host)
ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET, ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET,
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0); ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
host->dev->power.power_state = PMSG_ON; host->dev->power.power_state = PMSG_ON;
/* reenable link pm */
ata_lpm_disable(host);
} }
#endif #endif
...@@ -5517,7 +5397,8 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) ...@@ -5517,7 +5397,8 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
int i; int i;
/* clear everything except for devices */ /* clear everything except for devices */
memset(link, 0, offsetof(struct ata_link, device[0])); memset((void *)link + ATA_LINK_CLEAR_BEGIN, 0,
ATA_LINK_CLEAR_END - ATA_LINK_CLEAR_BEGIN);
link->ap = ap; link->ap = ap;
link->pmp = pmp; link->pmp = pmp;
...@@ -5695,6 +5576,7 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports) ...@@ -5695,6 +5576,7 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
dev_set_drvdata(dev, host); dev_set_drvdata(dev, host);
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
mutex_init(&host->eh_mutex);
host->dev = dev; host->dev = dev;
host->n_ports = max_ports; host->n_ports = max_ports;
...@@ -5992,6 +5874,7 @@ void ata_host_init(struct ata_host *host, struct device *dev, ...@@ -5992,6 +5874,7 @@ void ata_host_init(struct ata_host *host, struct device *dev,
unsigned long flags, struct ata_port_operations *ops) unsigned long flags, struct ata_port_operations *ops)
{ {
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
mutex_init(&host->eh_mutex);
host->dev = dev; host->dev = dev;
host->flags = flags; host->flags = flags;
host->ops = ops; host->ops = ops;
...@@ -6022,7 +5905,7 @@ static void async_port_probe(void *data, async_cookie_t cookie) ...@@ -6022,7 +5905,7 @@ static void async_port_probe(void *data, async_cookie_t cookie)
spin_lock_irqsave(ap->lock, flags); spin_lock_irqsave(ap->lock, flags);
ehi->probe_mask |= ATA_ALL_DEVICES; ehi->probe_mask |= ATA_ALL_DEVICES;
ehi->action |= ATA_EH_RESET | ATA_EH_LPM; ehi->action |= ATA_EH_RESET;
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
ap->pflags &= ~ATA_PFLAG_INITIALIZING; ap->pflags &= ~ATA_PFLAG_INITIALIZING;
...@@ -6093,9 +5976,18 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ...@@ -6093,9 +5976,18 @@ 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++)
host->ports[i]->print_id = ata_print_id++; host->ports[i]->print_id = ata_print_id++;
/* Create associated sysfs transport objects */
for (i = 0; i < host->n_ports; i++) {
rc = ata_tport_add(host->dev,host->ports[i]);
if (rc) {
goto err_tadd;
}
}
rc = ata_scsi_add_hosts(host, sht); rc = ata_scsi_add_hosts(host, sht);
if (rc) if (rc)
return rc; goto err_tadd;
/* associate with ACPI nodes */ /* associate with ACPI nodes */
ata_acpi_associate(host); ata_acpi_associate(host);
...@@ -6136,6 +6028,13 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ...@@ -6136,6 +6028,13 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
} }
return 0; return 0;
err_tadd:
while (--i >= 0) {
ata_tport_delete(host->ports[i]);
}
return rc;
} }
/** /**
...@@ -6226,6 +6125,13 @@ static void ata_port_detach(struct ata_port *ap) ...@@ -6226,6 +6125,13 @@ static void ata_port_detach(struct ata_port *ap)
cancel_rearming_delayed_work(&ap->hotplug_task); cancel_rearming_delayed_work(&ap->hotplug_task);
skip_eh: skip_eh:
if (ap->pmp_link) {
int i;
for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
ata_tlink_delete(&ap->pmp_link[i]);
}
ata_tport_delete(ap);
/* remove the associated SCSI host */ /* remove the associated SCSI host */
scsi_remove_host(ap->scsi_host); scsi_remove_host(ap->scsi_host);
} }
...@@ -6542,7 +6448,7 @@ static void __init ata_parse_force_param(void) ...@@ -6542,7 +6448,7 @@ static void __init ata_parse_force_param(void)
static int __init ata_init(void) static int __init ata_init(void)
{ {
int rc = -ENOMEM; int rc;
ata_parse_force_param(); ata_parse_force_param();
...@@ -6552,12 +6458,25 @@ static int __init ata_init(void) ...@@ -6552,12 +6458,25 @@ static int __init ata_init(void)
return rc; return rc;
} }
libata_transport_init();
ata_scsi_transport_template = ata_attach_transport();
if (!ata_scsi_transport_template) {
ata_sff_exit();
rc = -ENOMEM;
goto err_out;
}
printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n"); printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
return 0; return 0;
err_out:
return rc;
} }
static void __exit ata_exit(void) static void __exit ata_exit(void)
{ {
ata_release_transport(ata_scsi_transport_template);
libata_transport_exit();
ata_sff_exit(); ata_sff_exit();
kfree(ata_force_tbl); kfree(ata_force_tbl);
} }
...@@ -6572,8 +6491,36 @@ int ata_ratelimit(void) ...@@ -6572,8 +6491,36 @@ int ata_ratelimit(void)
return __ratelimit(&ratelimit); return __ratelimit(&ratelimit);
} }
/**
* ata_msleep - ATA EH owner aware msleep
* @ap: ATA port to attribute the sleep to
* @msecs: duration to sleep in milliseconds
*
* Sleeps @msecs. If the current task is owner of @ap's EH, the
* ownership is released before going to sleep and reacquired
* after the sleep is complete. IOW, other ports sharing the
* @ap->host will be allowed to own the EH while this task is
* sleeping.
*
* LOCKING:
* Might sleep.
*/
void ata_msleep(struct ata_port *ap, unsigned int msecs)
{
bool owns_eh = ap && ap->host->eh_owner == current;
if (owns_eh)
ata_eh_release(ap);
msleep(msecs);
if (owns_eh)
ata_eh_acquire(ap);
}
/** /**
* ata_wait_register - wait until register value changes * ata_wait_register - wait until register value changes
* @ap: ATA port to wait register for, can be NULL
* @reg: IO-mapped register * @reg: IO-mapped register
* @mask: Mask to apply to read register value * @mask: Mask to apply to read register value
* @val: Wait condition * @val: Wait condition
...@@ -6595,7 +6542,7 @@ int ata_ratelimit(void) ...@@ -6595,7 +6542,7 @@ int ata_ratelimit(void)
* RETURNS: * RETURNS:
* The final register value. * The final register value.
*/ */
u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val,
unsigned long interval, unsigned long timeout) unsigned long interval, unsigned long timeout)
{ {
unsigned long deadline; unsigned long deadline;
...@@ -6610,7 +6557,7 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, ...@@ -6610,7 +6557,7 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
deadline = ata_deadline(jiffies, timeout); deadline = ata_deadline(jiffies, timeout);
while ((tmp & mask) == val && time_before(jiffies, deadline)) { while ((tmp & mask) == val && time_before(jiffies, deadline)) {
msleep(interval); ata_msleep(ap, interval);
tmp = ioread32(reg); tmp = ioread32(reg);
} }
...@@ -6686,6 +6633,7 @@ EXPORT_SYMBOL_GPL(sata_set_spd); ...@@ -6686,6 +6633,7 @@ EXPORT_SYMBOL_GPL(sata_set_spd);
EXPORT_SYMBOL_GPL(ata_wait_after_reset); EXPORT_SYMBOL_GPL(ata_wait_after_reset);
EXPORT_SYMBOL_GPL(sata_link_debounce); EXPORT_SYMBOL_GPL(sata_link_debounce);
EXPORT_SYMBOL_GPL(sata_link_resume); EXPORT_SYMBOL_GPL(sata_link_resume);
EXPORT_SYMBOL_GPL(sata_link_scr_lpm);
EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_prereset);
EXPORT_SYMBOL_GPL(sata_link_hardreset); EXPORT_SYMBOL_GPL(sata_link_hardreset);
EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(sata_std_hardreset);
...@@ -6693,6 +6641,7 @@ EXPORT_SYMBOL_GPL(ata_std_postreset); ...@@ -6693,6 +6641,7 @@ EXPORT_SYMBOL_GPL(ata_std_postreset);
EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_classify);
EXPORT_SYMBOL_GPL(ata_dev_pair); EXPORT_SYMBOL_GPL(ata_dev_pair);
EXPORT_SYMBOL_GPL(ata_ratelimit); EXPORT_SYMBOL_GPL(ata_ratelimit);
EXPORT_SYMBOL_GPL(ata_msleep);
EXPORT_SYMBOL_GPL(ata_wait_register); EXPORT_SYMBOL_GPL(ata_wait_register);
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
......
...@@ -57,6 +57,7 @@ enum { ...@@ -57,6 +57,7 @@ enum {
/* error flags */ /* error flags */
ATA_EFLAG_IS_IO = (1 << 0), ATA_EFLAG_IS_IO = (1 << 0),
ATA_EFLAG_DUBIOUS_XFER = (1 << 1), ATA_EFLAG_DUBIOUS_XFER = (1 << 1),
ATA_EFLAG_OLD_ER = (1 << 31),
/* error categories */ /* error categories */
ATA_ECAT_NONE = 0, ATA_ECAT_NONE = 0,
...@@ -396,12 +397,7 @@ static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering) ...@@ -396,12 +397,7 @@ static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering)
return NULL; return NULL;
} }
static void ata_ering_clear(struct ata_ering *ering) int ata_ering_map(struct ata_ering *ering,
{
memset(ering, 0, sizeof(*ering));
}
static int ata_ering_map(struct ata_ering *ering,
int (*map_fn)(struct ata_ering_entry *, void *), int (*map_fn)(struct ata_ering_entry *, void *),
void *arg) void *arg)
{ {
...@@ -422,6 +418,17 @@ static int ata_ering_map(struct ata_ering *ering, ...@@ -422,6 +418,17 @@ static int ata_ering_map(struct ata_ering *ering,
return rc; return rc;
} }
int ata_ering_clear_cb(struct ata_ering_entry *ent, void *void_arg)
{
ent->eflags |= ATA_EFLAG_OLD_ER;
return 0;
}
static void ata_ering_clear(struct ata_ering *ering)
{
ata_ering_map(ering, ata_ering_clear_cb, NULL);
}
static unsigned int ata_eh_dev_action(struct ata_device *dev) static unsigned int ata_eh_dev_action(struct ata_device *dev)
{ {
struct ata_eh_context *ehc = &dev->link->eh_context; struct ata_eh_context *ehc = &dev->link->eh_context;
...@@ -455,6 +462,41 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev, ...@@ -455,6 +462,41 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
} }
} }
/**
* ata_eh_acquire - acquire EH ownership
* @ap: ATA port to acquire EH ownership for
*
* Acquire EH ownership for @ap. This is the basic exclusion
* mechanism for ports sharing a host. Only one port hanging off
* the same host can claim the ownership of EH.
*
* LOCKING:
* EH context.
*/
void ata_eh_acquire(struct ata_port *ap)
{
mutex_lock(&ap->host->eh_mutex);
WARN_ON_ONCE(ap->host->eh_owner);
ap->host->eh_owner = current;
}
/**
* ata_eh_release - release EH ownership
* @ap: ATA port to release EH ownership for
*
* Release EH ownership for @ap if the caller. The caller must
* have acquired EH ownership using ata_eh_acquire() previously.
*
* LOCKING:
* EH context.
*/
void ata_eh_release(struct ata_port *ap)
{
WARN_ON_ONCE(ap->host->eh_owner != current);
ap->host->eh_owner = NULL;
mutex_unlock(&ap->host->eh_mutex);
}
/** /**
* ata_scsi_timed_out - SCSI layer time out callback * ata_scsi_timed_out - SCSI layer time out callback
* @cmd: timed out SCSI command * @cmd: timed out SCSI command
...@@ -632,11 +674,13 @@ void ata_scsi_error(struct Scsi_Host *host) ...@@ -632,11 +674,13 @@ void ata_scsi_error(struct Scsi_Host *host)
/* If we timed raced normal completion and there is nothing to /* If we timed raced normal completion and there is nothing to
recover nr_timedout == 0 why exactly are we doing error recovery ? */ recover nr_timedout == 0 why exactly are we doing error recovery ? */
repeat:
/* invoke error handler */ /* invoke error handler */
if (ap->ops->error_handler) { if (ap->ops->error_handler) {
struct ata_link *link; struct ata_link *link;
/* acquire EH ownership */
ata_eh_acquire(ap);
repeat:
/* kill fast drain timer */ /* kill fast drain timer */
del_timer_sync(&ap->fastdrain_timer); del_timer_sync(&ap->fastdrain_timer);
...@@ -711,6 +755,7 @@ void ata_scsi_error(struct Scsi_Host *host) ...@@ -711,6 +755,7 @@ void ata_scsi_error(struct Scsi_Host *host)
host->host_eh_scheduled = 0; host->host_eh_scheduled = 0;
spin_unlock_irqrestore(ap->lock, flags); spin_unlock_irqrestore(ap->lock, flags);
ata_eh_release(ap);
} else { } else {
WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL); WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL);
ap->ops->eng_timeout(ap); ap->ops->eng_timeout(ap);
...@@ -772,7 +817,7 @@ void ata_port_wait_eh(struct ata_port *ap) ...@@ -772,7 +817,7 @@ void ata_port_wait_eh(struct ata_port *ap)
/* make sure SCSI EH is complete */ /* make sure SCSI EH is complete */
if (scsi_host_in_recovery(ap->scsi_host)) { if (scsi_host_in_recovery(ap->scsi_host)) {
msleep(10); ata_msleep(ap, 10);
goto retry; goto retry;
} }
} }
...@@ -1573,9 +1618,9 @@ static void ata_eh_analyze_serror(struct ata_link *link) ...@@ -1573,9 +1618,9 @@ static void ata_eh_analyze_serror(struct ata_link *link)
* host links. For disabled PMP links, only N bit is * host links. For disabled PMP links, only N bit is
* considered as X bit is left at 1 for link plugging. * considered as X bit is left at 1 for link plugging.
*/ */
hotplug_mask = 0; if (link->lpm_policy != ATA_LPM_MAX_POWER)
hotplug_mask = 0; /* hotplug doesn't work w/ LPM */
if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link)) else if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG; hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
else else
hotplug_mask = SERR_PHYRDY_CHG; hotplug_mask = SERR_PHYRDY_CHG;
...@@ -1755,7 +1800,7 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) ...@@ -1755,7 +1800,7 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
struct speed_down_verdict_arg *arg = void_arg; struct speed_down_verdict_arg *arg = void_arg;
int cat; int cat;
if (ent->timestamp < arg->since) if ((ent->eflags & ATA_EFLAG_OLD_ER) || (ent->timestamp < arg->since))
return -1; return -1;
cat = ata_eh_categorize_error(ent->eflags, ent->err_mask, cat = ata_eh_categorize_error(ent->eflags, ent->err_mask,
...@@ -2779,6 +2824,7 @@ int ata_eh_reset(struct ata_link *link, int classify, ...@@ -2779,6 +2824,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
ata_eh_done(slave, NULL, ATA_EH_RESET); ata_eh_done(slave, NULL, ATA_EH_RESET);
ehc->last_reset = jiffies; /* update to completion time */ ehc->last_reset = jiffies; /* update to completion time */
ehc->i.action |= ATA_EH_REVALIDATE; ehc->i.action |= ATA_EH_REVALIDATE;
link->lpm_policy = ATA_LPM_UNKNOWN; /* reset LPM state */
rc = 0; rc = 0;
out: out:
...@@ -2810,8 +2856,10 @@ int ata_eh_reset(struct ata_link *link, int classify, ...@@ -2810,8 +2856,10 @@ int ata_eh_reset(struct ata_link *link, int classify,
"reset failed (errno=%d), retrying in %u secs\n", "reset failed (errno=%d), retrying in %u secs\n",
rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000)); rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000));
ata_eh_release(ap);
while (delta) while (delta)
delta = schedule_timeout_uninterruptible(delta); delta = schedule_timeout_uninterruptible(delta);
ata_eh_acquire(ap);
} }
if (try == max_tries - 1) { if (try == max_tries - 1) {
...@@ -3204,6 +3252,124 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev) ...@@ -3204,6 +3252,124 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev)
return rc; return rc;
} }
/**
* ata_eh_set_lpm - configure SATA interface power management
* @link: link to configure power management
* @policy: the link power management policy
* @r_failed_dev: out parameter for failed device
*
* Enable SATA Interface power management. This will enable
* Device Interface Power Management (DIPM) for min_power
* policy, and then call driver specific callbacks for
* enabling Host Initiated Power management.
*
* LOCKING:
* EH context.
*
* RETURNS:
* 0 on success, -errno on failure.
*/
static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
struct ata_device **r_failed_dev)
{
struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL;
struct ata_eh_context *ehc = &link->eh_context;
struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
unsigned int err_mask;
int rc;
/* if the link or host doesn't do LPM, noop */
if ((link->flags & ATA_LFLAG_NO_LPM) || (ap && !ap->ops->set_lpm))
return 0;
/*
* DIPM is enabled only for MIN_POWER as some devices
* misbehave when the host NACKs transition to SLUMBER. Order
* device and link configurations such that the host always
* allows DIPM requests.
*/
ata_for_each_dev(dev, link, ENABLED) {
bool hipm = ata_id_has_hipm(dev->id);
bool dipm = ata_id_has_dipm(dev->id);
/* find the first enabled and LPM enabled devices */
if (!link_dev)
link_dev = dev;
if (!lpm_dev && (hipm || dipm))
lpm_dev = dev;
hints &= ~ATA_LPM_EMPTY;
if (!hipm)
hints &= ~ATA_LPM_HIPM;
/* disable DIPM before changing link config */
if (policy != ATA_LPM_MIN_POWER && dipm) {
err_mask = ata_dev_set_feature(dev,
SETFEATURES_SATA_DISABLE, SATA_DIPM);
if (err_mask && err_mask != AC_ERR_DEV) {
ata_dev_printk(dev, KERN_WARNING,
"failed to disable DIPM, Emask 0x%x\n",
err_mask);
rc = -EIO;
goto fail;
}
}
}
if (ap) {
rc = ap->ops->set_lpm(link, policy, hints);
if (!rc && ap->slave_link)
rc = ap->ops->set_lpm(ap->slave_link, policy, hints);
} else
rc = sata_pmp_set_lpm(link, policy, hints);
/*
* Attribute link config failure to the first (LPM) enabled
* device on the link.
*/
if (rc) {
if (rc == -EOPNOTSUPP) {
link->flags |= ATA_LFLAG_NO_LPM;
return 0;
}
dev = lpm_dev ? lpm_dev : link_dev;
goto fail;
}
/* host config updated, enable DIPM if transitioning to MIN_POWER */
ata_for_each_dev(dev, link, ENABLED) {
if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) {
err_mask = ata_dev_set_feature(dev,
SETFEATURES_SATA_ENABLE, SATA_DIPM);
if (err_mask && err_mask != AC_ERR_DEV) {
ata_dev_printk(dev, KERN_WARNING,
"failed to enable DIPM, Emask 0x%x\n",
err_mask);
rc = -EIO;
goto fail;
}
}
}
link->lpm_policy = policy;
if (ap && ap->slave_link)
ap->slave_link->lpm_policy = policy;
return 0;
fail:
/* if no device or only one more chance is left, disable LPM */
if (!dev || ehc->tries[dev->devno] <= 2) {
ata_link_printk(link, KERN_WARNING,
"disabling LPM on the link\n");
link->flags |= ATA_LFLAG_NO_LPM;
}
if (r_failed_dev)
*r_failed_dev = dev;
return rc;
}
static int ata_link_nr_enabled(struct ata_link *link) static int ata_link_nr_enabled(struct ata_link *link)
{ {
struct ata_device *dev; struct ata_device *dev;
...@@ -3288,6 +3454,16 @@ static int ata_eh_schedule_probe(struct ata_device *dev) ...@@ -3288,6 +3454,16 @@ static int ata_eh_schedule_probe(struct ata_device *dev)
ehc->saved_xfer_mode[dev->devno] = 0; ehc->saved_xfer_mode[dev->devno] = 0;
ehc->saved_ncq_enabled &= ~(1 << dev->devno); ehc->saved_ncq_enabled &= ~(1 << dev->devno);
/* the link maybe in a deep sleep, wake it up */
if (link->lpm_policy > ATA_LPM_MAX_POWER) {
if (ata_is_host_link(link))
link->ap->ops->set_lpm(link, ATA_LPM_MAX_POWER,
ATA_LPM_EMPTY);
else
sata_pmp_set_lpm(link, ATA_LPM_MAX_POWER,
ATA_LPM_EMPTY);
}
/* Record and count probe trials on the ering. The specific /* Record and count probe trials on the ering. The specific
* error mask used is irrelevant. Because a successful device * error mask used is irrelevant. Because a successful device
* detection clears the ering, this count accumulates only if * detection clears the ering, this count accumulates only if
...@@ -3389,8 +3565,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -3389,8 +3565,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
{ {
struct ata_link *link; struct ata_link *link;
struct ata_device *dev; struct ata_device *dev;
int nr_failed_devs; int rc, nr_fails;
int rc;
unsigned long flags, deadline; unsigned long flags, deadline;
DPRINTK("ENTER\n"); DPRINTK("ENTER\n");
...@@ -3431,7 +3606,6 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -3431,7 +3606,6 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
retry: retry:
rc = 0; rc = 0;
nr_failed_devs = 0;
/* if UNLOADING, finish immediately */ /* if UNLOADING, finish immediately */
if (ap->pflags & ATA_PFLAG_UNLOADING) if (ap->pflags & ATA_PFLAG_UNLOADING)
...@@ -3501,8 +3675,10 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -3501,8 +3675,10 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
if (time_before_eq(deadline, now)) if (time_before_eq(deadline, now))
break; break;
ata_eh_release(ap);
deadline = wait_for_completion_timeout(&ap->park_req_pending, deadline = wait_for_completion_timeout(&ap->park_req_pending,
deadline - now); deadline - now);
ata_eh_acquire(ap);
} while (deadline); } while (deadline);
ata_for_each_link(link, ap, EDGE) { ata_for_each_link(link, ap, EDGE) {
ata_for_each_dev(dev, link, ALL) { ata_for_each_dev(dev, link, ALL) {
...@@ -3516,13 +3692,17 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -3516,13 +3692,17 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
} }
/* the rest */ /* the rest */
ata_for_each_link(link, ap, EDGE) { nr_fails = 0;
ata_for_each_link(link, ap, PMP_FIRST) {
struct ata_eh_context *ehc = &link->eh_context; struct ata_eh_context *ehc = &link->eh_context;
if (sata_pmp_attached(ap) && ata_is_host_link(link))
goto config_lpm;
/* revalidate existing devices and attach new ones */ /* revalidate existing devices and attach new ones */
rc = ata_eh_revalidate_and_attach(link, &dev); rc = ata_eh_revalidate_and_attach(link, &dev);
if (rc) if (rc)
goto dev_fail; goto rest_fail;
/* if PMP got attached, return, pmp EH will take care of it */ /* if PMP got attached, return, pmp EH will take care of it */
if (link->device->class == ATA_DEV_PMP) { if (link->device->class == ATA_DEV_PMP) {
...@@ -3534,7 +3714,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -3534,7 +3714,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
if (ehc->i.flags & ATA_EHI_SETMODE) { if (ehc->i.flags & ATA_EHI_SETMODE) {
rc = ata_set_mode(link, &dev); rc = ata_set_mode(link, &dev);
if (rc) if (rc)
goto dev_fail; goto rest_fail;
ehc->i.flags &= ~ATA_EHI_SETMODE; ehc->i.flags &= ~ATA_EHI_SETMODE;
} }
...@@ -3547,7 +3727,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -3547,7 +3727,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
continue; continue;
rc = atapi_eh_clear_ua(dev); rc = atapi_eh_clear_ua(dev);
if (rc) if (rc)
goto dev_fail; goto rest_fail;
} }
} }
...@@ -3557,20 +3737,24 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -3557,20 +3737,24 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
continue; continue;
rc = ata_eh_maybe_retry_flush(dev); rc = ata_eh_maybe_retry_flush(dev);
if (rc) if (rc)
goto dev_fail; goto rest_fail;
} }
config_lpm:
/* configure link power saving */ /* configure link power saving */
if (ehc->i.action & ATA_EH_LPM) if (link->lpm_policy != ap->target_lpm_policy) {
ata_for_each_dev(dev, link, ALL) rc = ata_eh_set_lpm(link, ap->target_lpm_policy, &dev);
ata_dev_enable_pm(dev, ap->pm_policy); if (rc)
goto rest_fail;
}
/* this link is okay now */ /* this link is okay now */
ehc->i.flags = 0; ehc->i.flags = 0;
continue; continue;
dev_fail: rest_fail:
nr_failed_devs++; nr_fails++;
if (dev)
ata_eh_handle_dev_fail(dev, rc); ata_eh_handle_dev_fail(dev, rc);
if (ap->pflags & ATA_PFLAG_FROZEN) { if (ap->pflags & ATA_PFLAG_FROZEN) {
...@@ -3583,7 +3767,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -3583,7 +3767,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
} }
} }
if (nr_failed_devs) if (nr_fails)
goto retry; goto retry;
out: out:
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/libata.h> #include <linux/libata.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "libata.h" #include "libata.h"
#include "libata-transport.h"
const struct ata_port_operations sata_pmp_port_ops = { const struct ata_port_operations sata_pmp_port_ops = {
.inherits = &sata_port_ops, .inherits = &sata_port_ops,
...@@ -184,6 +185,27 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) ...@@ -184,6 +185,27 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
return 0; return 0;
} }
/**
* sata_pmp_set_lpm - configure LPM for a PMP link
* @link: PMP link to configure LPM for
* @policy: target LPM policy
* @hints: LPM hints
*
* Configure LPM for @link. This function will contain any PMP
* specific workarounds if necessary.
*
* LOCKING:
* EH context.
*
* RETURNS:
* 0 on success, -errno on failure.
*/
int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
unsigned hints)
{
return sata_link_scr_lpm(link, policy, true);
}
/** /**
* sata_pmp_read_gscr - read GSCR block of SATA PMP * sata_pmp_read_gscr - read GSCR block of SATA PMP
* @dev: PMP device * @dev: PMP device
...@@ -312,10 +334,10 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) ...@@ -312,10 +334,10 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info)
return rc; return rc;
} }
static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) static int sata_pmp_init_links (struct ata_port *ap, int nr_ports)
{ {
struct ata_link *pmp_link = ap->pmp_link; struct ata_link *pmp_link = ap->pmp_link;
int i; int i, err;
if (!pmp_link) { if (!pmp_link) {
pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS, pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS,
...@@ -327,6 +349,13 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) ...@@ -327,6 +349,13 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
ata_link_init(ap, &pmp_link[i], i); ata_link_init(ap, &pmp_link[i], i);
ap->pmp_link = pmp_link; ap->pmp_link = pmp_link;
for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
err = ata_tlink_add(&pmp_link[i]);
if (err) {
goto err_tlink;
}
}
} }
for (i = 0; i < nr_ports; i++) { for (i = 0; i < nr_ports; i++) {
...@@ -339,6 +368,12 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) ...@@ -339,6 +368,12 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
} }
return 0; return 0;
err_tlink:
while (--i >= 0)
ata_tlink_delete(&pmp_link[i]);
kfree(pmp_link);
ap->pmp_link = NULL;
return err;
} }
static void sata_pmp_quirks(struct ata_port *ap) static void sata_pmp_quirks(struct ata_port *ap)
...@@ -351,6 +386,9 @@ static void sata_pmp_quirks(struct ata_port *ap) ...@@ -351,6 +386,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
if (vendor == 0x1095 && devid == 0x3726) { if (vendor == 0x1095 && devid == 0x3726) {
/* sil3726 quirks */ /* sil3726 quirks */
ata_for_each_link(link, ap, EDGE) { ata_for_each_link(link, ap, EDGE) {
/* link reports offline after LPM */
link->flags |= ATA_LFLAG_NO_LPM;
/* Class code report is unreliable and SRST /* Class code report is unreliable and SRST
* times out under certain configurations. * times out under certain configurations.
*/ */
...@@ -366,6 +404,9 @@ static void sata_pmp_quirks(struct ata_port *ap) ...@@ -366,6 +404,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
} else if (vendor == 0x1095 && devid == 0x4723) { } else if (vendor == 0x1095 && devid == 0x4723) {
/* sil4723 quirks */ /* sil4723 quirks */
ata_for_each_link(link, ap, EDGE) { ata_for_each_link(link, ap, EDGE) {
/* link reports offline after LPM */
link->flags |= ATA_LFLAG_NO_LPM;
/* class code report is unreliable */ /* class code report is unreliable */
if (link->pmp < 2) if (link->pmp < 2)
link->flags |= ATA_LFLAG_ASSUME_ATA; link->flags |= ATA_LFLAG_ASSUME_ATA;
...@@ -378,6 +419,9 @@ static void sata_pmp_quirks(struct ata_port *ap) ...@@ -378,6 +419,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
} else if (vendor == 0x1095 && devid == 0x4726) { } else if (vendor == 0x1095 && devid == 0x4726) {
/* sil4726 quirks */ /* sil4726 quirks */
ata_for_each_link(link, ap, EDGE) { ata_for_each_link(link, ap, EDGE) {
/* link reports offline after LPM */
link->flags |= ATA_LFLAG_NO_LPM;
/* Class code report is unreliable and SRST /* Class code report is unreliable and SRST
* times out under certain configurations. * times out under certain configurations.
* Config device can be at port 0 or 5 and * Config device can be at port 0 or 5 and
...@@ -938,15 +982,25 @@ static int sata_pmp_eh_recover(struct ata_port *ap) ...@@ -938,15 +982,25 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
if (rc) if (rc)
goto link_fail; goto link_fail;
/* Connection status might have changed while resetting other
* links, check SATA_PMP_GSCR_ERROR before returning.
*/
/* clear SNotification */ /* clear SNotification */
rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
if (rc == 0) if (rc == 0)
sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
/*
* If LPM is active on any fan-out port, hotplug wouldn't
* work. Return w/ PHY event notification disabled.
*/
ata_for_each_link(link, ap, EDGE)
if (link->lpm_policy > ATA_LPM_MAX_POWER)
return 0;
/*
* Connection status might have changed while resetting other
* links, enable notification and check SATA_PMP_GSCR_ERROR
* before returning.
*/
/* enable notification */ /* enable notification */
if (pmp_dev->flags & ATA_DFLAG_AN) { if (pmp_dev->flags & ATA_DFLAG_AN) {
gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
......
...@@ -51,8 +51,8 @@ ...@@ -51,8 +51,8 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "libata.h" #include "libata.h"
#include "libata-transport.h"
#define SECTOR_SIZE 512
#define ATA_SCSI_RBUF_SIZE 4096 #define ATA_SCSI_RBUF_SIZE 4096
static DEFINE_SPINLOCK(ata_scsi_rbuf_lock); static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
...@@ -64,9 +64,6 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, ...@@ -64,9 +64,6 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev); const struct scsi_device *scsidev);
static struct ata_device *ata_scsi_find_dev(struct ata_port *ap, static struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev); const struct scsi_device *scsidev);
static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun);
#define RW_RECOVERY_MPAGE 0x1 #define RW_RECOVERY_MPAGE 0x1
#define RW_RECOVERY_MPAGE_LEN 12 #define RW_RECOVERY_MPAGE_LEN 12
...@@ -106,83 +103,55 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = { ...@@ -106,83 +103,55 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
0, 30 /* extended self test time, see 05-359r1 */ 0, 30 /* extended self test time, see 05-359r1 */
}; };
/* static const char *ata_lpm_policy_names[] = {
* libata transport template. libata doesn't do real transport stuff. [ATA_LPM_UNKNOWN] = "max_performance",
* It just needs the eh_timed_out hook. [ATA_LPM_MAX_POWER] = "max_performance",
*/ [ATA_LPM_MED_POWER] = "medium_power",
static struct scsi_transport_template ata_scsi_transport_template = { [ATA_LPM_MIN_POWER] = "min_power",
.eh_strategy_handler = ata_scsi_error,
.eh_timed_out = ata_scsi_timed_out,
.user_scan = ata_scsi_user_scan,
};
static const struct {
enum link_pm value;
const char *name;
} link_pm_policy[] = {
{ NOT_AVAILABLE, "max_performance" },
{ MIN_POWER, "min_power" },
{ MAX_PERFORMANCE, "max_performance" },
{ MEDIUM_POWER, "medium_power" },
}; };
static const char *ata_scsi_lpm_get(enum link_pm policy) static ssize_t ata_scsi_lpm_store(struct device *dev,
{
int i;
for (i = 0; i < ARRAY_SIZE(link_pm_policy); i++)
if (link_pm_policy[i].value == policy)
return link_pm_policy[i].name;
return NULL;
}
static ssize_t ata_scsi_lpm_put(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct Scsi_Host *shost = class_to_shost(dev); struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost); struct ata_port *ap = ata_shost_to_port(shost);
enum link_pm policy = 0; enum ata_lpm_policy policy;
int i; unsigned long flags;
/* /* UNKNOWN is internal state, iterate from MAX_POWER */
* we are skipping array location 0 on purpose - this for (policy = ATA_LPM_MAX_POWER;
* is because a value of NOT_AVAILABLE is displayed policy < ARRAY_SIZE(ata_lpm_policy_names); policy++) {
* to the user as max_performance, but when the user const char *name = ata_lpm_policy_names[policy];
* writes "max_performance", they actually want the
* value to match MAX_PERFORMANCE. if (strncmp(name, buf, strlen(name)) == 0)
*/
for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) {
const int len = strlen(link_pm_policy[i].name);
if (strncmp(link_pm_policy[i].name, buf, len) == 0) {
policy = link_pm_policy[i].value;
break; break;
} }
} if (policy == ARRAY_SIZE(ata_lpm_policy_names))
if (!policy)
return -EINVAL; return -EINVAL;
ata_lpm_schedule(ap, policy); spin_lock_irqsave(ap->lock, flags);
ap->target_lpm_policy = policy;
ata_port_schedule_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
return count; return count;
} }
static ssize_t static ssize_t ata_scsi_lpm_show(struct device *dev,
ata_scsi_lpm_show(struct device *dev, struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct Scsi_Host *shost = class_to_shost(dev); struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost); struct ata_port *ap = ata_shost_to_port(shost);
const char *policy =
ata_scsi_lpm_get(ap->pm_policy);
if (!policy) if (ap->target_lpm_policy >= ARRAY_SIZE(ata_lpm_policy_names))
return -EINVAL; return -EINVAL;
return snprintf(buf, 23, "%s\n", policy); return snprintf(buf, PAGE_SIZE, "%s\n",
ata_lpm_policy_names[ap->target_lpm_policy]);
} }
DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
ata_scsi_lpm_show, ata_scsi_lpm_put); ata_scsi_lpm_show, ata_scsi_lpm_store);
EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
static ssize_t ata_scsi_park_show(struct device *device, static ssize_t ata_scsi_park_show(struct device *device,
...@@ -516,7 +485,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) ...@@ -516,7 +485,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
memset(scsi_cmd, 0, sizeof(scsi_cmd)); memset(scsi_cmd, 0, sizeof(scsi_cmd));
if (args[3]) { if (args[3]) {
argsize = SECTOR_SIZE * args[3]; argsize = ATA_SECT_SIZE * args[3];
argbuf = kmalloc(argsize, GFP_KERNEL); argbuf = kmalloc(argsize, GFP_KERNEL);
if (argbuf == NULL) { if (argbuf == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
...@@ -1150,8 +1119,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, ...@@ -1150,8 +1119,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN); blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
} else { } else {
/* ATA devices must be sector aligned */ /* ATA devices must be sector aligned */
sdev->sector_size = ata_id_logical_sector_size(dev->id);
blk_queue_update_dma_alignment(sdev->request_queue, blk_queue_update_dma_alignment(sdev->request_queue,
ATA_SECT_SIZE - 1); sdev->sector_size - 1);
sdev->manage_start_stop = 1; sdev->manage_start_stop = 1;
} }
...@@ -1166,6 +1136,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, ...@@ -1166,6 +1136,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth); scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
} }
dev->sdev = sdev;
return 0; return 0;
} }
...@@ -1696,7 +1667,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) ...@@ -1696,7 +1667,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
goto nothing_to_do; goto nothing_to_do;
qc->flags |= ATA_QCFLAG_IO; qc->flags |= ATA_QCFLAG_IO;
qc->nbytes = n_block * ATA_SECT_SIZE; qc->nbytes = n_block * scmd->device->sector_size;
rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags, rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
qc->tag); qc->tag);
...@@ -2001,6 +1972,7 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) ...@@ -2001,6 +1972,7 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)
0x89, /* page 0x89, ata info page */ 0x89, /* page 0x89, ata info page */
0xb0, /* page 0xb0, block limits page */ 0xb0, /* page 0xb0, block limits page */
0xb1, /* page 0xb1, block device characteristics page */ 0xb1, /* page 0xb1, block device characteristics page */
0xb2, /* page 0xb2, thin provisioning page */
}; };
rbuf[3] = sizeof(pages); /* number of supported VPD pages */ rbuf[3] = sizeof(pages); /* number of supported VPD pages */
...@@ -2123,7 +2095,7 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf) ...@@ -2123,7 +2095,7 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
{ {
u32 min_io_sectors; u16 min_io_sectors;
rbuf[1] = 0xb0; rbuf[1] = 0xb0;
rbuf[3] = 0x3c; /* required VPD size with unmap support */ rbuf[3] = 0x3c; /* required VPD size with unmap support */
...@@ -2135,10 +2107,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) ...@@ -2135,10 +2107,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
* logical than physical sector size we need to figure out what the * logical than physical sector size we need to figure out what the
* latter is. * latter is.
*/ */
if (ata_id_has_large_logical_sectors(args->id)) min_io_sectors = 1 << ata_id_log2_per_physical_sector(args->id);
min_io_sectors = ata_id_logical_per_physical_sectors(args->id);
else
min_io_sectors = 1;
put_unaligned_be16(min_io_sectors, &rbuf[6]); put_unaligned_be16(min_io_sectors, &rbuf[6]);
/* /*
...@@ -2172,6 +2141,16 @@ static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf) ...@@ -2172,6 +2141,16 @@ static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf)
return 0; return 0;
} }
static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf)
{
/* SCSI Thin Provisioning VPD page: SBC-3 rev 22 or later */
rbuf[1] = 0xb2;
rbuf[3] = 0x4;
rbuf[5] = 1 << 6; /* TPWS */
return 0;
}
/** /**
* ata_scsiop_noop - Command handler that simply returns success. * ata_scsiop_noop - Command handler that simply returns success.
* @args: device IDENTIFY data / SCSI command of interest. * @args: device IDENTIFY data / SCSI command of interest.
...@@ -2397,21 +2376,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) ...@@ -2397,21 +2376,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
{ {
struct ata_device *dev = args->dev; struct ata_device *dev = args->dev;
u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */ u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */
u8 log_per_phys = 0; u32 sector_size; /* physical sector size in bytes */
u16 lowest_aligned = 0; u8 log2_per_phys;
u16 word_106 = dev->id[106]; u16 lowest_aligned;
u16 word_209 = dev->id[209];
if ((word_106 & 0xc000) == 0x4000) { sector_size = ata_id_logical_sector_size(dev->id);
/* Number and offset of logical sectors per physical sector */ log2_per_phys = ata_id_log2_per_physical_sector(dev->id);
if (word_106 & (1 << 13)) lowest_aligned = ata_id_logical_sector_offset(dev->id, log2_per_phys);
log_per_phys = word_106 & 0xf;
if ((word_209 & 0xc000) == 0x4000) {
u16 first = dev->id[209] & 0x3fff;
if (first > 0)
lowest_aligned = (1 << log_per_phys) - first;
}
}
VPRINTK("ENTER\n"); VPRINTK("ENTER\n");
...@@ -2426,8 +2397,10 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) ...@@ -2426,8 +2397,10 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
rbuf[3] = last_lba; rbuf[3] = last_lba;
/* sector size */ /* sector size */
rbuf[6] = ATA_SECT_SIZE >> 8; rbuf[4] = sector_size >> (8 * 3);
rbuf[7] = ATA_SECT_SIZE & 0xff; rbuf[5] = sector_size >> (8 * 2);
rbuf[6] = sector_size >> (8 * 1);
rbuf[7] = sector_size;
} else { } else {
/* sector count, 64-bit */ /* sector count, 64-bit */
rbuf[0] = last_lba >> (8 * 7); rbuf[0] = last_lba >> (8 * 7);
...@@ -2440,11 +2413,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) ...@@ -2440,11 +2413,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
rbuf[7] = last_lba; rbuf[7] = last_lba;
/* sector size */ /* sector size */
rbuf[10] = ATA_SECT_SIZE >> 8; rbuf[ 8] = sector_size >> (8 * 3);
rbuf[11] = ATA_SECT_SIZE & 0xff; rbuf[ 9] = sector_size >> (8 * 2);
rbuf[10] = sector_size >> (8 * 1);
rbuf[11] = sector_size;
rbuf[12] = 0; rbuf[12] = 0;
rbuf[13] = log_per_phys; rbuf[13] = log2_per_phys;
rbuf[14] = (lowest_aligned >> 8) & 0x3f; rbuf[14] = (lowest_aligned >> 8) & 0x3f;
rbuf[15] = lowest_aligned; rbuf[15] = lowest_aligned;
...@@ -2888,9 +2863,8 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) ...@@ -2888,9 +2863,8 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
tf->device = dev->devno ? tf->device = dev->devno ?
tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1; tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
/* READ/WRITE LONG use a non-standard sect_size */
qc->sect_size = ATA_SECT_SIZE;
switch (tf->command) { switch (tf->command) {
/* READ/WRITE LONG use a non-standard sect_size */
case ATA_CMD_READ_LONG: case ATA_CMD_READ_LONG:
case ATA_CMD_READ_LONG_ONCE: case ATA_CMD_READ_LONG_ONCE:
case ATA_CMD_WRITE_LONG: case ATA_CMD_WRITE_LONG:
...@@ -2898,6 +2872,45 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) ...@@ -2898,6 +2872,45 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
goto invalid_fld; goto invalid_fld;
qc->sect_size = scsi_bufflen(scmd); qc->sect_size = scsi_bufflen(scmd);
break;
/* commands using reported Logical Block size (e.g. 512 or 4K) */
case ATA_CMD_CFA_WRITE_NE:
case ATA_CMD_CFA_TRANS_SECT:
case ATA_CMD_CFA_WRITE_MULT_NE:
/* XXX: case ATA_CMD_CFA_WRITE_SECTORS_WITHOUT_ERASE: */
case ATA_CMD_READ:
case ATA_CMD_READ_EXT:
case ATA_CMD_READ_QUEUED:
/* XXX: case ATA_CMD_READ_QUEUED_EXT: */
case ATA_CMD_FPDMA_READ:
case ATA_CMD_READ_MULTI:
case ATA_CMD_READ_MULTI_EXT:
case ATA_CMD_PIO_READ:
case ATA_CMD_PIO_READ_EXT:
case ATA_CMD_READ_STREAM_DMA_EXT:
case ATA_CMD_READ_STREAM_EXT:
case ATA_CMD_VERIFY:
case ATA_CMD_VERIFY_EXT:
case ATA_CMD_WRITE:
case ATA_CMD_WRITE_EXT:
case ATA_CMD_WRITE_FUA_EXT:
case ATA_CMD_WRITE_QUEUED:
case ATA_CMD_WRITE_QUEUED_FUA_EXT:
case ATA_CMD_FPDMA_WRITE:
case ATA_CMD_WRITE_MULTI:
case ATA_CMD_WRITE_MULTI_EXT:
case ATA_CMD_WRITE_MULTI_FUA_EXT:
case ATA_CMD_PIO_WRITE:
case ATA_CMD_PIO_WRITE_EXT:
case ATA_CMD_WRITE_STREAM_DMA_EXT:
case ATA_CMD_WRITE_STREAM_EXT:
qc->sect_size = scmd->device->sector_size;
break;
/* Everything else uses 512 byte "sectors" */
default:
qc->sect_size = ATA_SECT_SIZE;
} }
/* /*
...@@ -3250,6 +3263,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, ...@@ -3250,6 +3263,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
case 0xb1: case 0xb1:
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1); ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1);
break; break;
case 0xb2:
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2);
break;
default: default:
ata_scsi_invalid_field(cmd, done); ata_scsi_invalid_field(cmd, done);
break; break;
...@@ -3334,7 +3350,7 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) ...@@ -3334,7 +3350,7 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
*(struct ata_port **)&shost->hostdata[0] = ap; *(struct ata_port **)&shost->hostdata[0] = ap;
ap->scsi_host = shost; ap->scsi_host = shost;
shost->transportt = &ata_scsi_transport_template; shost->transportt = ata_scsi_transport_template;
shost->unique_id = ap->print_id; shost->unique_id = ap->print_id;
shost->max_id = 16; shost->max_id = 16;
shost->max_lun = 1; shost->max_lun = 1;
...@@ -3393,6 +3409,8 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) ...@@ -3393,6 +3409,8 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
if (!IS_ERR(sdev)) { if (!IS_ERR(sdev)) {
dev->sdev = sdev; dev->sdev = sdev;
scsi_device_put(sdev); scsi_device_put(sdev);
} else {
dev->sdev = NULL;
} }
} }
} }
...@@ -3616,7 +3634,7 @@ void ata_scsi_hotplug(struct work_struct *work) ...@@ -3616,7 +3634,7 @@ void ata_scsi_hotplug(struct work_struct *work)
* RETURNS: * RETURNS:
* Zero. * Zero.
*/ */
static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun) unsigned int id, unsigned int lun)
{ {
struct ata_port *ap = ata_shost_to_port(shost); struct ata_port *ap = ata_shost_to_port(shost);
......
...@@ -222,7 +222,7 @@ int ata_sff_busy_sleep(struct ata_port *ap, ...@@ -222,7 +222,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
timeout = ata_deadline(timer_start, tmout_pat); timeout = ata_deadline(timer_start, tmout_pat);
while (status != 0xff && (status & ATA_BUSY) && while (status != 0xff && (status & ATA_BUSY) &&
time_before(jiffies, timeout)) { time_before(jiffies, timeout)) {
msleep(50); ata_msleep(ap, 50);
status = ata_sff_busy_wait(ap, ATA_BUSY, 3); status = ata_sff_busy_wait(ap, ATA_BUSY, 3);
} }
...@@ -234,7 +234,7 @@ int ata_sff_busy_sleep(struct ata_port *ap, ...@@ -234,7 +234,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
timeout = ata_deadline(timer_start, tmout); timeout = ata_deadline(timer_start, tmout);
while (status != 0xff && (status & ATA_BUSY) && while (status != 0xff && (status & ATA_BUSY) &&
time_before(jiffies, timeout)) { time_before(jiffies, timeout)) {
msleep(50); ata_msleep(ap, 50);
status = ap->ops->sff_check_status(ap); status = ap->ops->sff_check_status(ap);
} }
...@@ -360,7 +360,7 @@ static void ata_dev_select(struct ata_port *ap, unsigned int device, ...@@ -360,7 +360,7 @@ static void ata_dev_select(struct ata_port *ap, unsigned int device,
if (wait) { if (wait) {
if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI) if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
msleep(150); ata_msleep(ap, 150);
ata_wait_idle(ap); ata_wait_idle(ap);
} }
} }
...@@ -1356,7 +1356,7 @@ static void ata_sff_pio_task(struct work_struct *work) ...@@ -1356,7 +1356,7 @@ static void ata_sff_pio_task(struct work_struct *work)
*/ */
status = ata_sff_busy_wait(ap, ATA_BUSY, 5); status = ata_sff_busy_wait(ap, ATA_BUSY, 5);
if (status & ATA_BUSY) { if (status & ATA_BUSY) {
msleep(2); ata_msleep(ap, 2);
status = ata_sff_busy_wait(ap, ATA_BUSY, 10); status = ata_sff_busy_wait(ap, ATA_BUSY, 10);
if (status & ATA_BUSY) { if (status & ATA_BUSY) {
ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE); ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE);
...@@ -1937,7 +1937,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask, ...@@ -1937,7 +1937,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
unsigned int dev1 = devmask & (1 << 1); unsigned int dev1 = devmask & (1 << 1);
int rc, ret = 0; int rc, ret = 0;
msleep(ATA_WAIT_AFTER_RESET); ata_msleep(ap, ATA_WAIT_AFTER_RESET);
/* always check readiness of the master device */ /* always check readiness of the master device */
rc = ata_sff_wait_ready(link, deadline); rc = ata_sff_wait_ready(link, deadline);
...@@ -1966,7 +1966,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask, ...@@ -1966,7 +1966,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
lbal = ioread8(ioaddr->lbal_addr); lbal = ioread8(ioaddr->lbal_addr);
if ((nsect == 1) && (lbal == 1)) if ((nsect == 1) && (lbal == 1))
break; break;
msleep(50); /* give drive a breather */ ata_msleep(ap, 50); /* give drive a breather */
} }
rc = ata_sff_wait_ready(link, deadline); rc = ata_sff_wait_ready(link, deadline);
...@@ -3342,7 +3342,7 @@ int __init ata_sff_init(void) ...@@ -3342,7 +3342,7 @@ int __init ata_sff_init(void)
return 0; return 0;
} }
void __exit ata_sff_exit(void) void ata_sff_exit(void)
{ {
destroy_workqueue(ata_sff_wq); destroy_workqueue(ata_sff_wq);
} }
/*
* Copyright 2008 ioogle, Inc. All rights reserved.
* Released under GPL v2.
*
* Libata transport class.
*
* The ATA transport class contains common code to deal with ATA HBAs,
* an approximated representation of ATA topologies in the driver model,
* and various sysfs attributes to expose these topologies and management
* interfaces to user-space.
*
* There are 3 objects defined in in this class:
* - ata_port
* - ata_link
* - ata_device
* Each port has a link object. Each link can have up to two devices for PATA
* and generally one for SATA.
* If there is SATA port multiplier [PMP], 15 additional ata_link object are
* created.
*
* These objects are created when the ata host is initialized and when a PMP is
* found. They are removed only when the HBA is removed, cleaned before the
* error handler runs.
*/
#include <linux/kernel.h>
#include <linux/blkdev.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <scsi/scsi_transport.h>
#include <linux/libata.h>
#include <linux/hdreg.h>
#include <linux/uaccess.h>
#include "libata.h"
#include "libata-transport.h"
#define ATA_PORT_ATTRS 2
#define ATA_LINK_ATTRS 3
#define ATA_DEV_ATTRS 9
struct scsi_transport_template;
struct scsi_transport_template *ata_scsi_transport_template;
struct ata_internal {
struct scsi_transport_template t;
struct device_attribute private_port_attrs[ATA_PORT_ATTRS];
struct device_attribute private_link_attrs[ATA_LINK_ATTRS];
struct device_attribute private_dev_attrs[ATA_DEV_ATTRS];
struct transport_container link_attr_cont;
struct transport_container dev_attr_cont;
/*
* The array of null terminated pointers to attributes
* needed by scsi_sysfs.c
*/
struct device_attribute *link_attrs[ATA_LINK_ATTRS + 1];
struct device_attribute *port_attrs[ATA_PORT_ATTRS + 1];
struct device_attribute *dev_attrs[ATA_DEV_ATTRS + 1];
};
#define to_ata_internal(tmpl) container_of(tmpl, struct ata_internal, t)
#define tdev_to_device(d) \
container_of((d), struct ata_device, tdev)
#define transport_class_to_dev(dev) \
tdev_to_device((dev)->parent)
#define tdev_to_link(d) \
container_of((d), struct ata_link, tdev)
#define transport_class_to_link(dev) \
tdev_to_link((dev)->parent)
#define tdev_to_port(d) \
container_of((d), struct ata_port, tdev)
#define transport_class_to_port(dev) \
tdev_to_port((dev)->parent)
/* Device objects are always created whit link objects */
static int ata_tdev_add(struct ata_device *dev);
static void ata_tdev_delete(struct ata_device *dev);
/*
* Hack to allow attributes of the same name in different objects.
*/
#define ATA_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
struct device_attribute device_attr_##_prefix##_##_name = \
__ATTR(_name,_mode,_show,_store)
#define ata_bitfield_name_match(title, table) \
static ssize_t \
get_ata_##title##_names(u32 table_key, char *buf) \
{ \
char *prefix = ""; \
ssize_t len = 0; \
int i; \
\
for (i = 0; i < ARRAY_SIZE(table); i++) { \
if (table[i].value & table_key) { \
len += sprintf(buf + len, "%s%s", \
prefix, table[i].name); \
prefix = ", "; \
} \
} \
len += sprintf(buf + len, "\n"); \
return len; \
}
#define ata_bitfield_name_search(title, table) \
static ssize_t \
get_ata_##title##_names(u32 table_key, char *buf) \
{ \
ssize_t len = 0; \
int i; \
\
for (i = 0; i < ARRAY_SIZE(table); i++) { \
if (table[i].value == table_key) { \
len += sprintf(buf + len, "%s", \
table[i].name); \
break; \
} \
} \
len += sprintf(buf + len, "\n"); \
return len; \
}
static struct {
u32 value;
char *name;
} ata_class_names[] = {
{ ATA_DEV_UNKNOWN, "unknown" },
{ ATA_DEV_ATA, "ata" },
{ ATA_DEV_ATA_UNSUP, "ata" },
{ ATA_DEV_ATAPI, "atapi" },
{ ATA_DEV_ATAPI_UNSUP, "atapi" },
{ ATA_DEV_PMP, "pmp" },
{ ATA_DEV_PMP_UNSUP, "pmp" },
{ ATA_DEV_SEMB, "semb" },
{ ATA_DEV_SEMB_UNSUP, "semb" },
{ ATA_DEV_NONE, "none" }
};
ata_bitfield_name_search(class, ata_class_names)
static struct {
u32 value;
char *name;
} ata_err_names[] = {
{ AC_ERR_DEV, "DeviceError" },
{ AC_ERR_HSM, "HostStateMachineError" },
{ AC_ERR_TIMEOUT, "Timeout" },
{ AC_ERR_MEDIA, "MediaError" },
{ AC_ERR_ATA_BUS, "BusError" },
{ AC_ERR_HOST_BUS, "HostBusError" },
{ AC_ERR_SYSTEM, "SystemError" },
{ AC_ERR_INVALID, "InvalidArg" },
{ AC_ERR_OTHER, "Unknown" },
{ AC_ERR_NODEV_HINT, "NoDeviceHint" },
{ AC_ERR_NCQ, "NCQError" }
};
ata_bitfield_name_match(err, ata_err_names)
static struct {
u32 value;
char *name;
} ata_xfer_names[] = {
{ XFER_UDMA_7, "XFER_UDMA_7" },
{ XFER_UDMA_6, "XFER_UDMA_6" },
{ XFER_UDMA_5, "XFER_UDMA_5" },
{ XFER_UDMA_4, "XFER_UDMA_4" },
{ XFER_UDMA_3, "XFER_UDMA_3" },
{ XFER_UDMA_2, "XFER_UDMA_2" },
{ XFER_UDMA_1, "XFER_UDMA_1" },
{ XFER_UDMA_0, "XFER_UDMA_0" },
{ XFER_MW_DMA_4, "XFER_MW_DMA_4" },
{ XFER_MW_DMA_3, "XFER_MW_DMA_3" },
{ XFER_MW_DMA_2, "XFER_MW_DMA_2" },
{ XFER_MW_DMA_1, "XFER_MW_DMA_1" },
{ XFER_MW_DMA_0, "XFER_MW_DMA_0" },
{ XFER_SW_DMA_2, "XFER_SW_DMA_2" },
{ XFER_SW_DMA_1, "XFER_SW_DMA_1" },
{ XFER_SW_DMA_0, "XFER_SW_DMA_0" },
{ XFER_PIO_6, "XFER_PIO_6" },
{ XFER_PIO_5, "XFER_PIO_5" },
{ XFER_PIO_4, "XFER_PIO_4" },
{ XFER_PIO_3, "XFER_PIO_3" },
{ XFER_PIO_2, "XFER_PIO_2" },
{ XFER_PIO_1, "XFER_PIO_1" },
{ XFER_PIO_0, "XFER_PIO_0" },
{ XFER_PIO_SLOW, "XFER_PIO_SLOW" }
};
ata_bitfield_name_match(xfer,ata_xfer_names)
/*
* ATA Port attributes
*/
#define ata_port_show_simple(field, name, format_string, cast) \
static ssize_t \
show_ata_port_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct ata_port *ap = transport_class_to_port(dev); \
\
return snprintf(buf, 20, format_string, cast ap->field); \
}
#define ata_port_simple_attr(field, name, format_string, type) \
ata_port_show_simple(field, name, format_string, (type)) \
static DEVICE_ATTR(name, S_IRUGO, show_ata_port_##name, NULL)
ata_port_simple_attr(nr_pmp_links, nr_pmp_links, "%d\n", int);
ata_port_simple_attr(stats.idle_irq, idle_irq, "%ld\n", unsigned long);
static DECLARE_TRANSPORT_CLASS(ata_port_class,
"ata_port", NULL, NULL, NULL);
static void ata_tport_release(struct device *dev)
{
put_device(dev->parent);
}
/**
* ata_is_port -- check if a struct device represents a ATA port
* @dev: device to check
*
* Returns:
* %1 if the device represents a ATA Port, %0 else
*/
int ata_is_port(const struct device *dev)
{
return dev->release == ata_tport_release;
}
static int ata_tport_match(struct attribute_container *cont,
struct device *dev)
{
if (!ata_is_port(dev))
return 0;
return &ata_scsi_transport_template->host_attrs.ac == cont;
}
/**
* ata_tport_delete -- remove ATA PORT
* @port: ATA PORT to remove
*
* Removes the specified ATA PORT. Remove the associated link as well.
*/
void ata_tport_delete(struct ata_port *ap)
{
struct device *dev = &ap->tdev;
ata_tlink_delete(&ap->link);
transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
put_device(dev);
}
/** ata_tport_add - initialize a transport ATA port structure
*
* @parent: parent device
* @ap: existing ata_port structure
*
* Initialize a ATA port structure for sysfs. It will be added to the device
* tree below the device specified by @parent which could be a PCI device.
*
* Returns %0 on success
*/
int ata_tport_add(struct device *parent,
struct ata_port *ap)
{
int error;
struct device *dev = &ap->tdev;
device_initialize(dev);
dev->parent = get_device(parent);
dev->release = ata_tport_release;
dev_set_name(dev, "ata%d", ap->print_id);
transport_setup_device(dev);
error = device_add(dev);
if (error) {
goto tport_err;
}
transport_add_device(dev);
transport_configure_device(dev);
error = ata_tlink_add(&ap->link);
if (error) {
goto tport_link_err;
}
return 0;
tport_link_err:
transport_remove_device(dev);
device_del(dev);
tport_err:
transport_destroy_device(dev);
put_device(dev);
return error;
}
/*
* ATA link attributes
*/
#define ata_link_show_linkspeed(field) \
static ssize_t \
show_ata_link_##field(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct ata_link *link = transport_class_to_link(dev); \
\
return sprintf(buf,"%s\n", sata_spd_string(fls(link->field))); \
}
#define ata_link_linkspeed_attr(field) \
ata_link_show_linkspeed(field) \
static DEVICE_ATTR(field, S_IRUGO, show_ata_link_##field, NULL)
ata_link_linkspeed_attr(hw_sata_spd_limit);
ata_link_linkspeed_attr(sata_spd_limit);
ata_link_linkspeed_attr(sata_spd);
static DECLARE_TRANSPORT_CLASS(ata_link_class,
"ata_link", NULL, NULL, NULL);
static void ata_tlink_release(struct device *dev)
{
put_device(dev->parent);
}
/**
* ata_is_link -- check if a struct device represents a ATA link
* @dev: device to check
*
* Returns:
* %1 if the device represents a ATA link, %0 else
*/
int ata_is_link(const struct device *dev)
{
return dev->release == ata_tlink_release;
}
static int ata_tlink_match(struct attribute_container *cont,
struct device *dev)
{
struct ata_internal* i = to_ata_internal(ata_scsi_transport_template);
if (!ata_is_link(dev))
return 0;
return &i->link_attr_cont.ac == cont;
}
/**
* ata_tlink_delete -- remove ATA LINK
* @port: ATA LINK to remove
*
* Removes the specified ATA LINK. remove associated ATA device(s) as well.
*/
void ata_tlink_delete(struct ata_link *link)
{
struct device *dev = &link->tdev;
struct ata_device *ata_dev;
ata_for_each_dev(ata_dev, link, ALL) {
ata_tdev_delete(ata_dev);
}
transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
put_device(dev);
}
/**
* ata_tlink_add -- initialize a transport ATA link structure
* @link: allocated ata_link structure.
*
* Initialize an ATA LINK structure for sysfs. It will be added in the
* device tree below the ATA PORT it belongs to.
*
* Returns %0 on success
*/
int ata_tlink_add(struct ata_link *link)
{
struct device *dev = &link->tdev;
struct ata_port *ap = link->ap;
struct ata_device *ata_dev;
int error;
device_initialize(dev);
dev->parent = get_device(&ap->tdev);
dev->release = ata_tlink_release;
if (ata_is_host_link(link))
dev_set_name(dev, "link%d", ap->print_id);
else
dev_set_name(dev, "link%d.%d", ap->print_id, link->pmp);
transport_setup_device(dev);
error = device_add(dev);
if (error) {
goto tlink_err;
}
transport_add_device(dev);
transport_configure_device(dev);
ata_for_each_dev(ata_dev, link, ALL) {
error = ata_tdev_add(ata_dev);
if (error) {
goto tlink_dev_err;
}
}
return 0;
tlink_dev_err:
while (--ata_dev >= link->device) {
ata_tdev_delete(ata_dev);
}
transport_remove_device(dev);
device_del(dev);
tlink_err:
transport_destroy_device(dev);
put_device(dev);
return error;
}
/*
* ATA device attributes
*/
#define ata_dev_show_class(title, field) \
static ssize_t \
show_ata_dev_##field(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct ata_device *ata_dev = transport_class_to_dev(dev); \
\
return get_ata_##title##_names(ata_dev->field, buf); \
}
#define ata_dev_attr(title, field) \
ata_dev_show_class(title, field) \
static DEVICE_ATTR(field, S_IRUGO, show_ata_dev_##field, NULL)
ata_dev_attr(class, class);
ata_dev_attr(xfer, pio_mode);
ata_dev_attr(xfer, dma_mode);
ata_dev_attr(xfer, xfer_mode);
#define ata_dev_show_simple(field, format_string, cast) \
static ssize_t \
show_ata_dev_##field(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct ata_device *ata_dev = transport_class_to_dev(dev); \
\
return snprintf(buf, 20, format_string, cast ata_dev->field); \
}
#define ata_dev_simple_attr(field, format_string, type) \
ata_dev_show_simple(field, format_string, (type)) \
static DEVICE_ATTR(field, S_IRUGO, \
show_ata_dev_##field, NULL)
ata_dev_simple_attr(spdn_cnt, "%d\n", int);
struct ata_show_ering_arg {
char* buf;
int written;
};
static int ata_show_ering(struct ata_ering_entry *ent, void *void_arg)
{
struct ata_show_ering_arg* arg = void_arg;
struct timespec time;
jiffies_to_timespec(ent->timestamp,&time);
arg->written += sprintf(arg->buf + arg->written,
"[%5lu.%06lu]",
time.tv_sec, time.tv_nsec);
arg->written += get_ata_err_names(ent->err_mask,
arg->buf + arg->written);
return 0;
}
static ssize_t
show_ata_dev_ering(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ata_device *ata_dev = transport_class_to_dev(dev);
struct ata_show_ering_arg arg = { buf, 0 };
ata_ering_map(&ata_dev->ering, ata_show_ering, &arg);
return arg.written;
}
static DEVICE_ATTR(ering, S_IRUGO, show_ata_dev_ering, NULL);
static ssize_t
show_ata_dev_id(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ata_device *ata_dev = transport_class_to_dev(dev);
int written = 0, i = 0;
if (ata_dev->class == ATA_DEV_PMP)
return 0;
for(i=0;i<ATA_ID_WORDS;i++) {
written += snprintf(buf+written, 20, "%04x%c",
ata_dev->id[i],
((i+1) & 7) ? ' ' : '\n');
}
return written;
}
static DEVICE_ATTR(id, S_IRUGO, show_ata_dev_id, NULL);
static ssize_t
show_ata_dev_gscr(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ata_device *ata_dev = transport_class_to_dev(dev);
int written = 0, i = 0;
if (ata_dev->class != ATA_DEV_PMP)
return 0;
for(i=0;i<SATA_PMP_GSCR_DWORDS;i++) {
written += snprintf(buf+written, 20, "%08x%c",
ata_dev->gscr[i],
((i+1) & 3) ? ' ' : '\n');
}
if (SATA_PMP_GSCR_DWORDS & 3)
buf[written-1] = '\n';
return written;
}
static DEVICE_ATTR(gscr, S_IRUGO, show_ata_dev_gscr, NULL);
static DECLARE_TRANSPORT_CLASS(ata_dev_class,
"ata_device", NULL, NULL, NULL);
static void ata_tdev_release(struct device *dev)
{
put_device(dev->parent);
}
/**
* ata_is_ata_dev -- check if a struct device represents a ATA device
* @dev: device to check
*
* Returns:
* %1 if the device represents a ATA device, %0 else
*/
int ata_is_ata_dev(const struct device *dev)
{
return dev->release == ata_tdev_release;
}
static int ata_tdev_match(struct attribute_container *cont,
struct device *dev)
{
struct ata_internal* i = to_ata_internal(ata_scsi_transport_template);
if (!ata_is_ata_dev(dev))
return 0;
return &i->dev_attr_cont.ac == cont;
}
/**
* ata_tdev_free -- free a ATA LINK
* @dev: ATA PHY to free
*
* Frees the specified ATA PHY.
*
* Note:
* This function must only be called on a PHY that has not
* successfully been added using ata_tdev_add().
*/
static void ata_tdev_free(struct ata_device *dev)
{
transport_destroy_device(&dev->tdev);
put_device(&dev->tdev);
}
/**
* ata_tdev_delete -- remove ATA device
* @port: ATA PORT to remove
*
* Removes the specified ATA device.
*/
static void ata_tdev_delete(struct ata_device *ata_dev)
{
struct device *dev = &ata_dev->tdev;
transport_remove_device(dev);
device_del(dev);
ata_tdev_free(ata_dev);
}
/**
* ata_tdev_add -- initialize a transport ATA device structure.
* @ata_dev: ata_dev structure.
*
* Initialize an ATA device structure for sysfs. It will be added in the
* device tree below the ATA LINK device it belongs to.
*
* Returns %0 on success
*/
static int ata_tdev_add(struct ata_device *ata_dev)
{
struct device *dev = &ata_dev->tdev;
struct ata_link *link = ata_dev->link;
struct ata_port *ap = link->ap;
int error;
device_initialize(dev);
dev->parent = get_device(&link->tdev);
dev->release = ata_tdev_release;
if (ata_is_host_link(link))
dev_set_name(dev, "dev%d.%d", ap->print_id,ata_dev->devno);
else
dev_set_name(dev, "dev%d.%d.0", ap->print_id, link->pmp);
transport_setup_device(dev);
error = device_add(dev);
if (error) {
ata_tdev_free(ata_dev);
return error;
}
transport_add_device(dev);
transport_configure_device(dev);
return 0;
}
/*
* Setup / Teardown code
*/
#define SETUP_TEMPLATE(attrb, field, perm, test) \
i->private_##attrb[count] = dev_attr_##field; \
i->private_##attrb[count].attr.mode = perm; \
i->attrb[count] = &i->private_##attrb[count]; \
if (test) \
count++
#define SETUP_LINK_ATTRIBUTE(field) \
SETUP_TEMPLATE(link_attrs, field, S_IRUGO, 1)
#define SETUP_PORT_ATTRIBUTE(field) \
SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
#define SETUP_DEV_ATTRIBUTE(field) \
SETUP_TEMPLATE(dev_attrs, field, S_IRUGO, 1)
/**
* ata_attach_transport -- instantiate ATA transport template
*/
struct scsi_transport_template *ata_attach_transport(void)
{
struct ata_internal *i;
int count;
i = kzalloc(sizeof(struct ata_internal), GFP_KERNEL);
if (!i)
return NULL;
i->t.eh_strategy_handler = ata_scsi_error;
i->t.eh_timed_out = ata_scsi_timed_out;
i->t.user_scan = ata_scsi_user_scan;
i->t.host_attrs.ac.attrs = &i->port_attrs[0];
i->t.host_attrs.ac.class = &ata_port_class.class;
i->t.host_attrs.ac.match = ata_tport_match;
transport_container_register(&i->t.host_attrs);
i->link_attr_cont.ac.class = &ata_link_class.class;
i->link_attr_cont.ac.attrs = &i->link_attrs[0];
i->link_attr_cont.ac.match = ata_tlink_match;
transport_container_register(&i->link_attr_cont);
i->dev_attr_cont.ac.class = &ata_dev_class.class;
i->dev_attr_cont.ac.attrs = &i->dev_attrs[0];
i->dev_attr_cont.ac.match = ata_tdev_match;
transport_container_register(&i->dev_attr_cont);
count = 0;
SETUP_PORT_ATTRIBUTE(nr_pmp_links);
SETUP_PORT_ATTRIBUTE(idle_irq);
BUG_ON(count > ATA_PORT_ATTRS);
i->port_attrs[count] = NULL;
count = 0;
SETUP_LINK_ATTRIBUTE(hw_sata_spd_limit);
SETUP_LINK_ATTRIBUTE(sata_spd_limit);
SETUP_LINK_ATTRIBUTE(sata_spd);
BUG_ON(count > ATA_LINK_ATTRS);
i->link_attrs[count] = NULL;
count = 0;
SETUP_DEV_ATTRIBUTE(class);
SETUP_DEV_ATTRIBUTE(pio_mode);
SETUP_DEV_ATTRIBUTE(dma_mode);
SETUP_DEV_ATTRIBUTE(xfer_mode);
SETUP_DEV_ATTRIBUTE(spdn_cnt);
SETUP_DEV_ATTRIBUTE(ering);
SETUP_DEV_ATTRIBUTE(id);
SETUP_DEV_ATTRIBUTE(gscr);
BUG_ON(count > ATA_DEV_ATTRS);
i->dev_attrs[count] = NULL;
return &i->t;
}
/**
* ata_release_transport -- release ATA transport template instance
* @t: transport template instance
*/
void ata_release_transport(struct scsi_transport_template *t)
{
struct ata_internal *i = to_ata_internal(t);
transport_container_unregister(&i->t.host_attrs);
transport_container_unregister(&i->link_attr_cont);
transport_container_unregister(&i->dev_attr_cont);
kfree(i);
}
__init int libata_transport_init(void)
{
int error;
error = transport_class_register(&ata_link_class);
if (error)
goto out_unregister_transport;
error = transport_class_register(&ata_port_class);
if (error)
goto out_unregister_link;
error = transport_class_register(&ata_dev_class);
if (error)
goto out_unregister_port;
return 0;
out_unregister_port:
transport_class_unregister(&ata_port_class);
out_unregister_link:
transport_class_unregister(&ata_link_class);
out_unregister_transport:
return error;
}
void __exit libata_transport_exit(void)
{
transport_class_unregister(&ata_link_class);
transport_class_unregister(&ata_port_class);
transport_class_unregister(&ata_dev_class);
}
#ifndef _LIBATA_TRANSPORT_H
#define _LIBATA_TRANSPORT_H
extern struct scsi_transport_template *ata_scsi_transport_template;
int ata_tlink_add(struct ata_link *link);
void ata_tlink_delete(struct ata_link *link);
int ata_tport_add(struct device *parent, struct ata_port *ap);
void ata_tport_delete(struct ata_port *ap);
struct scsi_transport_template *ata_attach_transport(void);
void ata_release_transport(struct scsi_transport_template *t);
__init int libata_transport_init(void);
void __exit libata_transport_exit(void);
#endif
...@@ -86,6 +86,8 @@ extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, ...@@ -86,6 +86,8 @@ extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
extern int ata_dev_configure(struct ata_device *dev); extern int ata_dev_configure(struct ata_device *dev);
extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit); extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel); extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
extern unsigned int ata_dev_set_feature(struct ata_device *dev,
u8 enable, u8 feature);
extern void ata_sg_clean(struct ata_queued_cmd *qc); extern void ata_sg_clean(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc);
extern void ata_qc_issue(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc);
...@@ -100,8 +102,7 @@ extern int sata_link_init_spd(struct ata_link *link); ...@@ -100,8 +102,7 @@ extern int sata_link_init_spd(struct ata_link *link);
extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
extern struct ata_port *ata_port_alloc(struct ata_host *host); extern struct ata_port *ata_port_alloc(struct ata_host *host);
extern void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy); extern const char *sata_spd_string(unsigned int spd);
extern void ata_lpm_schedule(struct ata_port *ap, enum link_pm);
/* libata-acpi.c */ /* libata-acpi.c */
#ifdef CONFIG_ATA_ACPI #ifdef CONFIG_ATA_ACPI
...@@ -137,10 +138,15 @@ extern void ata_scsi_hotplug(struct work_struct *work); ...@@ -137,10 +138,15 @@ extern void ata_scsi_hotplug(struct work_struct *work);
extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
extern void ata_scsi_dev_rescan(struct work_struct *work); extern void ata_scsi_dev_rescan(struct work_struct *work);
extern int ata_bus_probe(struct ata_port *ap); extern int ata_bus_probe(struct ata_port *ap);
extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun);
/* libata-eh.c */ /* libata-eh.c */
extern unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd); extern unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);
extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd); extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd);
extern void ata_eh_acquire(struct ata_port *ap);
extern void ata_eh_release(struct ata_port *ap);
extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern enum blk_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);
...@@ -164,11 +170,16 @@ extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -164,11 +170,16 @@ extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_postreset_fn_t postreset, ata_postreset_fn_t postreset,
struct ata_link **r_failed_disk); struct ata_link **r_failed_disk);
extern void ata_eh_finish(struct ata_port *ap); extern void ata_eh_finish(struct ata_port *ap);
extern int ata_ering_map(struct ata_ering *ering,
int (*map_fn)(struct ata_ering_entry *, void *),
void *arg);
/* libata-pmp.c */ /* libata-pmp.c */
#ifdef CONFIG_SATA_PMP #ifdef CONFIG_SATA_PMP
extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val); extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val);
extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val); extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val);
extern int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
unsigned hints);
extern int sata_pmp_attach(struct ata_device *dev); extern int sata_pmp_attach(struct ata_device *dev);
#else /* CONFIG_SATA_PMP */ #else /* CONFIG_SATA_PMP */
static inline int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val) static inline int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val)
...@@ -181,6 +192,12 @@ static inline int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) ...@@ -181,6 +192,12 @@ static inline int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
return -EINVAL; return -EINVAL;
} }
static inline int sata_pmp_set_lpm(struct ata_link *link,
enum ata_lpm_policy policy, unsigned hints)
{
return -EINVAL;
}
static inline int sata_pmp_attach(struct ata_device *dev) static inline int sata_pmp_attach(struct ata_device *dev)
{ {
return -EINVAL; return -EINVAL;
......
...@@ -826,7 +826,7 @@ static void bfin_dev_select(struct ata_port *ap, unsigned int device) ...@@ -826,7 +826,7 @@ static void bfin_dev_select(struct ata_port *ap, unsigned int device)
* @ctl: value to write * @ctl: value to write
*/ */
static u8 bfin_set_devctl(struct ata_port *ap, u8 ctl) static void bfin_set_devctl(struct ata_port *ap, u8 ctl)
{ {
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
write_atapi_register(base, ATA_REG_CTRL, ctl); write_atapi_register(base, ATA_REG_CTRL, ctl);
...@@ -1046,7 +1046,7 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask) ...@@ -1046,7 +1046,7 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
dev1 = 0; dev1 = 0;
break; break;
} }
msleep(50); /* give drive a breather */ ata_msleep(ap, 50); /* give drive a breather */
} }
if (dev1) if (dev1)
ata_sff_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); ata_sff_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
...@@ -1087,7 +1087,7 @@ static unsigned int bfin_bus_softreset(struct ata_port *ap, ...@@ -1087,7 +1087,7 @@ static unsigned int bfin_bus_softreset(struct ata_port *ap,
* *
* Old drivers/ide uses the 2mS rule and then waits for ready * Old drivers/ide uses the 2mS rule and then waits for ready
*/ */
msleep(150); ata_msleep(ap, 150);
/* Before we perform post reset processing we want to see if /* Before we perform post reset processing we want to see if
* the bus shows 0xFF because the odd clown forgets the D7 * the bus shows 0xFF because the odd clown forgets the D7
......
...@@ -161,6 +161,17 @@ static int cmd640_port_start(struct ata_port *ap) ...@@ -161,6 +161,17 @@ static int cmd640_port_start(struct ata_port *ap)
return 0; return 0;
} }
static bool cmd640_sff_irq_check(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
int irq_reg = ap->port_no ? ARTIM23 : CFR;
u8 irq_stat, irq_mask = ap->port_no ? 0x10 : 0x04;
pci_read_config_byte(pdev, irq_reg, &irq_stat);
return irq_stat & irq_mask;
}
static struct scsi_host_template cmd640_sht = { static struct scsi_host_template cmd640_sht = {
ATA_PIO_SHT(DRV_NAME), ATA_PIO_SHT(DRV_NAME),
}; };
...@@ -169,6 +180,7 @@ static struct ata_port_operations cmd640_port_ops = { ...@@ -169,6 +180,7 @@ static struct ata_port_operations cmd640_port_ops = {
.inherits = &ata_sff_port_ops, .inherits = &ata_sff_port_ops,
/* In theory xfer_noirq is not needed once we kill the prefetcher */ /* In theory xfer_noirq is not needed once we kill the prefetcher */
.sff_data_xfer = ata_sff_data_xfer_noirq, .sff_data_xfer = ata_sff_data_xfer_noirq,
.sff_irq_check = cmd640_sff_irq_check,
.qc_issue = cmd640_qc_issue, .qc_issue = cmd640_qc_issue,
.cable_detect = ata_cable_40wire, .cable_detect = ata_cable_40wire,
.set_piomode = cmd640_set_piomode, .set_piomode = cmd640_set_piomode,
......
...@@ -44,6 +44,27 @@ static void pdc202xx_exec_command(struct ata_port *ap, ...@@ -44,6 +44,27 @@ static void pdc202xx_exec_command(struct ata_port *ap,
ndelay(400); ndelay(400);
} }
static bool pdc202xx_irq_check(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned long master = pci_resource_start(pdev, 4);
u8 sc1d = inb(master + 0x1d);
if (ap->port_no) {
/*
* bit 7: error, bit 6: interrupting,
* bit 5: FIFO full, bit 4: FIFO empty
*/
return sc1d & 0x40;
} else {
/*
* bit 3: error, bit 2: interrupting,
* bit 1: FIFO full, bit 0: FIFO empty
*/
return sc1d & 0x04;
}
}
/** /**
* pdc202xx_configure_piomode - set chip PIO timing * pdc202xx_configure_piomode - set chip PIO timing
* @ap: ATA interface * @ap: ATA interface
...@@ -282,6 +303,7 @@ static struct ata_port_operations pdc2024x_port_ops = { ...@@ -282,6 +303,7 @@ static struct ata_port_operations pdc2024x_port_ops = {
.set_dmamode = pdc202xx_set_dmamode, .set_dmamode = pdc202xx_set_dmamode,
.sff_exec_command = pdc202xx_exec_command, .sff_exec_command = pdc202xx_exec_command,
.sff_irq_check = pdc202xx_irq_check,
}; };
static struct ata_port_operations pdc2026x_port_ops = { static struct ata_port_operations pdc2026x_port_ops = {
...@@ -297,6 +319,7 @@ static struct ata_port_operations pdc2026x_port_ops = { ...@@ -297,6 +319,7 @@ static struct ata_port_operations pdc2026x_port_ops = {
.port_start = pdc2026x_port_start, .port_start = pdc2026x_port_start,
.sff_exec_command = pdc202xx_exec_command, .sff_exec_command = pdc202xx_exec_command,
.sff_irq_check = pdc202xx_irq_check,
}; };
static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
......
...@@ -322,7 +322,7 @@ static int pata_s3c_wait_after_reset(struct ata_link *link, ...@@ -322,7 +322,7 @@ static int pata_s3c_wait_after_reset(struct ata_link *link,
{ {
int rc; int rc;
msleep(ATA_WAIT_AFTER_RESET); ata_msleep(link->ap, ATA_WAIT_AFTER_RESET);
/* always check readiness of the master device */ /* always check readiness of the master device */
rc = ata_sff_wait_ready(link, deadline); rc = ata_sff_wait_ready(link, deadline);
......
...@@ -530,7 +530,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask, ...@@ -530,7 +530,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
* *
* Old drivers/ide uses the 2mS rule and then waits for ready. * Old drivers/ide uses the 2mS rule and then waits for ready.
*/ */
msleep(150); ata_msleep(ap, 150);
/* always check readiness of the master device */ /* always check readiness of the master device */
rc = ata_sff_wait_ready(link, deadline); rc = ata_sff_wait_ready(link, deadline);
...@@ -559,7 +559,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask, ...@@ -559,7 +559,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
lbal = in_be32(ioaddr->lbal_addr); lbal = in_be32(ioaddr->lbal_addr);
if ((nsect == 1) && (lbal == 1)) if ((nsect == 1) && (lbal == 1))
break; break;
msleep(50); /* give drive a breather */ ata_msleep(ap, 50); /* give drive a breather */
} }
rc = ata_sff_wait_ready(link, deadline); rc = ata_sff_wait_ready(link, deadline);
......
...@@ -202,7 +202,7 @@ static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev) ...@@ -202,7 +202,7 @@ static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev)
* LOCKING: * LOCKING:
* spin_lock_irqsave(host lock) * spin_lock_irqsave(host lock)
*/ */
void sil680_sff_exec_command(struct ata_port *ap, static void sil680_sff_exec_command(struct ata_port *ap,
const struct ata_taskfile *tf) const struct ata_taskfile *tf)
{ {
DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command); DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
...@@ -210,6 +210,17 @@ void sil680_sff_exec_command(struct ata_port *ap, ...@@ -210,6 +210,17 @@ void sil680_sff_exec_command(struct ata_port *ap,
ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
} }
static bool sil680_sff_irq_check(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned long addr = sil680_selreg(ap, 1);
u8 val;
pci_read_config_byte(pdev, addr, &val);
return val & 0x08;
}
static struct scsi_host_template sil680_sht = { static struct scsi_host_template sil680_sht = {
ATA_BMDMA_SHT(DRV_NAME), ATA_BMDMA_SHT(DRV_NAME),
}; };
...@@ -218,6 +229,7 @@ static struct scsi_host_template sil680_sht = { ...@@ -218,6 +229,7 @@ static struct scsi_host_template sil680_sht = {
static struct ata_port_operations sil680_port_ops = { static struct ata_port_operations sil680_port_ops = {
.inherits = &ata_bmdma32_port_ops, .inherits = &ata_bmdma32_port_ops,
.sff_exec_command = sil680_sff_exec_command, .sff_exec_command = sil680_sff_exec_command,
.sff_irq_check = sil680_sff_irq_check,
.cable_detect = sil680_cable_detect, .cable_detect = sil680_cable_detect,
.set_piomode = sil680_set_piomode, .set_piomode = sil680_set_piomode,
.set_dmamode = sil680_set_dmamode, .set_dmamode = sil680_set_dmamode,
......
...@@ -227,6 +227,16 @@ static int sl82c105_qc_defer(struct ata_queued_cmd *qc) ...@@ -227,6 +227,16 @@ static int sl82c105_qc_defer(struct ata_queued_cmd *qc)
return 0; return 0;
} }
static bool sl82c105_sff_irq_check(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 val, mask = ap->port_no ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
pci_read_config_dword(pdev, 0x40, &val);
return val & mask;
}
static struct scsi_host_template sl82c105_sht = { static struct scsi_host_template sl82c105_sht = {
ATA_BMDMA_SHT(DRV_NAME), ATA_BMDMA_SHT(DRV_NAME),
}; };
...@@ -239,6 +249,7 @@ static struct ata_port_operations sl82c105_port_ops = { ...@@ -239,6 +249,7 @@ static struct ata_port_operations sl82c105_port_ops = {
.cable_detect = ata_cable_40wire, .cable_detect = ata_cable_40wire,
.set_piomode = sl82c105_set_piomode, .set_piomode = sl82c105_set_piomode,
.prereset = sl82c105_pre_reset, .prereset = sl82c105_pre_reset,
.sff_irq_check = sl82c105_sff_irq_check,
}; };
/** /**
......
...@@ -678,7 +678,7 @@ static void sata_fsl_port_stop(struct ata_port *ap) ...@@ -678,7 +678,7 @@ static void sata_fsl_port_stop(struct ata_port *ap)
iowrite32(temp, hcr_base + HCONTROL); iowrite32(temp, hcr_base + HCONTROL);
/* Poll for controller to go offline - should happen immediately */ /* Poll for controller to go offline - should happen immediately */
ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 1); ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, ONLINE, 1, 1);
ap->private_data = NULL; ap->private_data = NULL;
dma_free_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ, dma_free_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ,
...@@ -729,7 +729,8 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class, ...@@ -729,7 +729,8 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class,
iowrite32(temp, hcr_base + HCONTROL); iowrite32(temp, hcr_base + HCONTROL);
/* Poll for controller to go offline */ /* Poll for controller to go offline */
temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 500); temp = ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, ONLINE,
1, 500);
if (temp & ONLINE) { if (temp & ONLINE) {
ata_port_printk(ap, KERN_ERR, ata_port_printk(ap, KERN_ERR,
...@@ -752,7 +753,7 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class, ...@@ -752,7 +753,7 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class,
/* /*
* PHY reset should remain asserted for atleast 1ms * PHY reset should remain asserted for atleast 1ms
*/ */
msleep(1); ata_msleep(ap, 1);
/* /*
* Now, bring the host controller online again, this can take time * Now, bring the host controller online again, this can take time
...@@ -766,7 +767,7 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class, ...@@ -766,7 +767,7 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class,
temp |= HCONTROL_PMP_ATTACHED; temp |= HCONTROL_PMP_ATTACHED;
iowrite32(temp, hcr_base + HCONTROL); iowrite32(temp, hcr_base + HCONTROL);
temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, 0, 1, 500); temp = ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, 0, 1, 500);
if (!(temp & ONLINE)) { if (!(temp & ONLINE)) {
ata_port_printk(ap, KERN_ERR, ata_port_printk(ap, KERN_ERR,
...@@ -784,7 +785,7 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class, ...@@ -784,7 +785,7 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class,
* presence * presence
*/ */
temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0, 1, 500); temp = ata_wait_register(ap, hcr_base + HSTATUS, 0xFF, 0, 1, 500);
if ((!(temp & 0x10)) || ata_link_offline(link)) { if ((!(temp & 0x10)) || ata_link_offline(link)) {
ata_port_printk(ap, KERN_WARNING, ata_port_printk(ap, KERN_WARNING,
"No Device OR PHYRDY change,Hstatus = 0x%x\n", "No Device OR PHYRDY change,Hstatus = 0x%x\n",
...@@ -797,7 +798,7 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class, ...@@ -797,7 +798,7 @@ static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class,
* Wait for the first D2H from device,i.e,signature update notification * Wait for the first D2H from device,i.e,signature update notification
*/ */
start_jiffies = jiffies; start_jiffies = jiffies;
temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0x10, temp = ata_wait_register(ap, hcr_base + HSTATUS, 0xFF, 0x10,
500, jiffies_to_msecs(deadline - start_jiffies)); 500, jiffies_to_msecs(deadline - start_jiffies));
if ((temp & 0xFF) != 0x18) { if ((temp & 0xFF) != 0x18) {
...@@ -880,7 +881,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class, ...@@ -880,7 +881,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
iowrite32(pmp, CQPMP + hcr_base); iowrite32(pmp, CQPMP + hcr_base);
iowrite32(1, CQ + hcr_base); iowrite32(1, CQ + hcr_base);
temp = ata_wait_register(CQ + hcr_base, 0x1, 0x1, 1, 5000); temp = ata_wait_register(ap, CQ + hcr_base, 0x1, 0x1, 1, 5000);
if (temp & 0x1) { if (temp & 0x1) {
ata_port_printk(ap, KERN_WARNING, "ATA_SRST issue failed\n"); ata_port_printk(ap, KERN_WARNING, "ATA_SRST issue failed\n");
...@@ -896,7 +897,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class, ...@@ -896,7 +897,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
goto err; goto err;
} }
msleep(1); ata_msleep(ap, 1);
/* /*
* SATA device enters reset state after receving a Control register * SATA device enters reset state after receving a Control register
...@@ -915,7 +916,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class, ...@@ -915,7 +916,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
if (pmp != SATA_PMP_CTRL_PORT) if (pmp != SATA_PMP_CTRL_PORT)
iowrite32(pmp, CQPMP + hcr_base); iowrite32(pmp, CQPMP + hcr_base);
iowrite32(1, CQ + hcr_base); iowrite32(1, CQ + hcr_base);
msleep(150); /* ?? */ ata_msleep(ap, 150); /* ?? */
/* /*
* The above command would have signalled an interrupt on command * The above command would have signalled an interrupt on command
...@@ -1137,17 +1138,13 @@ static void sata_fsl_host_intr(struct ata_port *ap) ...@@ -1137,17 +1138,13 @@ static void sata_fsl_host_intr(struct ata_port *ap)
ioread32(hcr_base + CE)); ioread32(hcr_base + CE));
for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) { for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) {
if (done_mask & (1 << i)) { if (done_mask & (1 << i))
qc = ata_qc_from_tag(ap, i);
if (qc) {
ata_qc_complete(qc);
}
DPRINTK DPRINTK
("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n", ("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n",
i, ioread32(hcr_base + CC), i, ioread32(hcr_base + CC),
ioread32(hcr_base + CA)); ioread32(hcr_base + CA));
} }
} ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
return; return;
} else if ((ap->qc_active & (1 << ATA_TAG_INTERNAL))) { } else if ((ap->qc_active & (1 << ATA_TAG_INTERNAL))) {
......
...@@ -614,7 +614,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class, ...@@ -614,7 +614,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
writew(IDMA_CTL_RST_ATA, idma_ctl); writew(IDMA_CTL_RST_ATA, idma_ctl);
readw(idma_ctl); /* flush */ readw(idma_ctl); /* flush */
msleep(1); ata_msleep(ap, 1);
writew(0, idma_ctl); writew(0, idma_ctl);
rc = sata_link_resume(link, timing, deadline); rc = sata_link_resume(link, timing, deadline);
......
...@@ -2743,18 +2743,11 @@ static void mv_err_intr(struct ata_port *ap) ...@@ -2743,18 +2743,11 @@ static void mv_err_intr(struct ata_port *ap)
} }
} }
static void mv_process_crpb_response(struct ata_port *ap, static bool mv_process_crpb_response(struct ata_port *ap,
struct mv_crpb *response, unsigned int tag, int ncq_enabled) struct mv_crpb *response, unsigned int tag, int ncq_enabled)
{ {
u8 ata_status; u8 ata_status;
u16 edma_status = le16_to_cpu(response->flags); u16 edma_status = le16_to_cpu(response->flags);
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
if (unlikely(!qc)) {
ata_port_printk(ap, KERN_ERR, "%s: no qc for tag=%d\n",
__func__, tag);
return;
}
/* /*
* edma_status from a response queue entry: * edma_status from a response queue entry:
...@@ -2768,13 +2761,14 @@ static void mv_process_crpb_response(struct ata_port *ap, ...@@ -2768,13 +2761,14 @@ static void mv_process_crpb_response(struct ata_port *ap,
* Error will be seen/handled by * Error will be seen/handled by
* mv_err_intr(). So do nothing at all here. * mv_err_intr(). So do nothing at all here.
*/ */
return; return false;
} }
} }
ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT; ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT;
if (!ac_err_mask(ata_status)) if (!ac_err_mask(ata_status))
ata_qc_complete(qc); return true;
/* else: leave it for mv_err_intr() */ /* else: leave it for mv_err_intr() */
return false;
} }
static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp) static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp)
...@@ -2783,6 +2777,7 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp ...@@ -2783,6 +2777,7 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
struct mv_host_priv *hpriv = ap->host->private_data; struct mv_host_priv *hpriv = ap->host->private_data;
u32 in_index; u32 in_index;
bool work_done = false; bool work_done = false;
u32 done_mask = 0;
int ncq_enabled = (pp->pp_flags & MV_PP_FLAG_NCQ_EN); int ncq_enabled = (pp->pp_flags & MV_PP_FLAG_NCQ_EN);
/* Get the hardware queue position index */ /* Get the hardware queue position index */
...@@ -2803,15 +2798,19 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp ...@@ -2803,15 +2798,19 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
/* Gen II/IIE: get command tag from CRPB entry */ /* Gen II/IIE: get command tag from CRPB entry */
tag = le16_to_cpu(response->id) & 0x1f; tag = le16_to_cpu(response->id) & 0x1f;
} }
mv_process_crpb_response(ap, response, tag, ncq_enabled); if (mv_process_crpb_response(ap, response, tag, ncq_enabled))
done_mask |= 1 << tag;
work_done = true; work_done = true;
} }
if (work_done) {
ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
/* Update the software queue position index in hardware */ /* Update the software queue position index in hardware */
if (work_done)
writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
(pp->resp_idx << EDMA_RSP_Q_PTR_SHIFT), (pp->resp_idx << EDMA_RSP_Q_PTR_SHIFT),
port_mmio + EDMA_RSP_Q_OUT_PTR); port_mmio + EDMA_RSP_Q_OUT_PTR);
}
} }
static void mv_port_intr(struct ata_port *ap, u32 port_cause) static void mv_port_intr(struct ata_port *ap, u32 port_cause)
......
...@@ -873,29 +873,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) ...@@ -873,29 +873,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
ata_port_freeze(ap); ata_port_freeze(ap);
else else
ata_port_abort(ap); ata_port_abort(ap);
return 1; return -1;
} }
if (likely(flags & NV_CPB_RESP_DONE)) { if (likely(flags & NV_CPB_RESP_DONE))
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
VPRINTK("CPB flags done, flags=0x%x\n", flags);
if (likely(qc)) {
DPRINTK("Completing qc from tag %d\n", cpb_num);
ata_qc_complete(qc);
} else {
struct ata_eh_info *ehi = &ap->link.eh_info;
/* Notifier bits set without a command may indicate the drive
is misbehaving. Raise host state machine violation on this
condition. */
ata_port_printk(ap, KERN_ERR,
"notifier for tag %d with no cmd?\n",
cpb_num);
ehi->err_mask |= AC_ERR_HSM;
ehi->action |= ATA_EH_RESET;
ata_port_freeze(ap);
return 1; return 1;
}
}
return 0; return 0;
} }
...@@ -1018,6 +1000,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) ...@@ -1018,6 +1000,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
NV_ADMA_STAT_CPBERR | NV_ADMA_STAT_CPBERR |
NV_ADMA_STAT_CMD_COMPLETE)) { NV_ADMA_STAT_CMD_COMPLETE)) {
u32 check_commands = notifier_clears[i]; u32 check_commands = notifier_clears[i];
u32 done_mask = 0;
int pos, rc; int pos, rc;
if (status & NV_ADMA_STAT_CPBERR) { if (status & NV_ADMA_STAT_CPBERR) {
...@@ -1034,10 +1017,13 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) ...@@ -1034,10 +1017,13 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
pos--; pos--;
rc = nv_adma_check_cpb(ap, pos, rc = nv_adma_check_cpb(ap, pos,
notifier_error & (1 << pos)); notifier_error & (1 << pos));
if (unlikely(rc)) if (rc > 0)
done_mask |= 1 << pos;
else if (unlikely(rc < 0))
check_commands = 0; check_commands = 0;
check_commands &= ~(1 << pos); check_commands &= ~(1 << pos);
} }
ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
} }
} }
...@@ -2132,7 +2118,6 @@ static int nv_swncq_sdbfis(struct ata_port *ap) ...@@ -2132,7 +2118,6 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
struct ata_eh_info *ehi = &ap->link.eh_info; struct ata_eh_info *ehi = &ap->link.eh_info;
u32 sactive; u32 sactive;
u32 done_mask; u32 done_mask;
int i;
u8 host_stat; u8 host_stat;
u8 lack_dhfis = 0; u8 lack_dhfis = 0;
...@@ -2152,27 +2137,11 @@ static int nv_swncq_sdbfis(struct ata_port *ap) ...@@ -2152,27 +2137,11 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
sactive = readl(pp->sactive_block); sactive = readl(pp->sactive_block);
done_mask = pp->qc_active ^ sactive; done_mask = pp->qc_active ^ sactive;
if (unlikely(done_mask & sactive)) { pp->qc_active &= ~done_mask;
ata_ehi_clear_desc(ehi); pp->dhfis_bits &= ~done_mask;
ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition" pp->dmafis_bits &= ~done_mask;
"(%08x->%08x)", pp->qc_active, sactive); pp->sdbfis_bits |= done_mask;
ehi->err_mask |= AC_ERR_HSM; ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
ehi->action |= ATA_EH_RESET;
return -EINVAL;
}
for (i = 0; i < ATA_MAX_QUEUE; i++) {
if (!(done_mask & (1 << i)))
continue;
qc = ata_qc_from_tag(ap, i);
if (qc) {
ata_qc_complete(qc);
pp->qc_active &= ~(1 << i);
pp->dhfis_bits &= ~(1 << i);
pp->dmafis_bits &= ~(1 << i);
pp->sdbfis_bits |= (1 << i);
}
}
if (!ap->qc_active) { if (!ap->qc_active) {
DPRINTK("over\n"); DPRINTK("over\n");
......
...@@ -589,9 +589,9 @@ static int sil24_init_port(struct ata_port *ap) ...@@ -589,9 +589,9 @@ static int sil24_init_port(struct ata_port *ap)
sil24_clear_pmp(ap); sil24_clear_pmp(ap);
writel(PORT_CS_INIT, port + PORT_CTRL_STAT); writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
ata_wait_register(port + PORT_CTRL_STAT, ata_wait_register(ap, port + PORT_CTRL_STAT,
PORT_CS_INIT, PORT_CS_INIT, 10, 100); PORT_CS_INIT, PORT_CS_INIT, 10, 100);
tmp = ata_wait_register(port + PORT_CTRL_STAT, tmp = ata_wait_register(ap, port + PORT_CTRL_STAT,
PORT_CS_RDY, 0, 10, 100); PORT_CS_RDY, 0, 10, 100);
if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) { if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
...@@ -631,7 +631,7 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp, ...@@ -631,7 +631,7 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4); writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT; irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0, irq_stat = ata_wait_register(ap, port + PORT_IRQ_STAT, irq_mask, 0x0,
10, timeout_msec); 10, timeout_msec);
writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */ writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
...@@ -719,9 +719,9 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class, ...@@ -719,9 +719,9 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class,
"state, performing PORT_RST\n"); "state, performing PORT_RST\n");
writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT); writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
msleep(10); ata_msleep(ap, 10);
writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0, ata_wait_register(ap, port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
10, 5000); 10, 5000);
/* restore port configuration */ /* restore port configuration */
...@@ -740,7 +740,7 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class, ...@@ -740,7 +740,7 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class,
tout_msec = 5000; tout_msec = 5000;
writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
tmp = ata_wait_register(port + PORT_CTRL_STAT, tmp = ata_wait_register(ap, port + PORT_CTRL_STAT,
PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10,
tout_msec); tout_msec);
...@@ -1253,7 +1253,7 @@ static void sil24_init_controller(struct ata_host *host) ...@@ -1253,7 +1253,7 @@ static void sil24_init_controller(struct ata_host *host)
tmp = readl(port + PORT_CTRL_STAT); tmp = readl(port + PORT_CTRL_STAT);
if (tmp & PORT_CS_PORT_RST) { if (tmp & PORT_CS_PORT_RST) {
writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
tmp = ata_wait_register(port + PORT_CTRL_STAT, tmp = ata_wait_register(NULL, port + PORT_CTRL_STAT,
PORT_CS_PORT_RST, PORT_CS_PORT_RST,
PORT_CS_PORT_RST, 10, 100); PORT_CS_PORT_RST, 10, 100);
if (tmp & PORT_CS_PORT_RST) if (tmp & PORT_CS_PORT_RST)
......
...@@ -349,7 +349,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline) ...@@ -349,7 +349,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
/* wait for phy to become ready, if necessary */ /* wait for phy to become ready, if necessary */
do { do {
msleep(200); ata_msleep(link->ap, 200);
svia_scr_read(link, SCR_STATUS, &sstatus); svia_scr_read(link, SCR_STATUS, &sstatus);
if ((sstatus & 0xf) != 1) if ((sstatus & 0xf) != 1)
break; break;
......
...@@ -89,6 +89,7 @@ enum { ...@@ -89,6 +89,7 @@ enum {
ATA_ID_SPG = 98, ATA_ID_SPG = 98,
ATA_ID_LBA_CAPACITY_2 = 100, ATA_ID_LBA_CAPACITY_2 = 100,
ATA_ID_SECTOR_SIZE = 106, ATA_ID_SECTOR_SIZE = 106,
ATA_ID_LOGICAL_SECTOR_SIZE = 117, /* and 118 */
ATA_ID_LAST_LUN = 126, ATA_ID_LAST_LUN = 126,
ATA_ID_DLF = 128, ATA_ID_DLF = 128,
ATA_ID_CSFO = 129, ATA_ID_CSFO = 129,
...@@ -640,16 +641,49 @@ static inline int ata_id_flush_ext_enabled(const u16 *id) ...@@ -640,16 +641,49 @@ static inline int ata_id_flush_ext_enabled(const u16 *id)
return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400; return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400;
} }
static inline int ata_id_has_large_logical_sectors(const u16 *id) static inline u32 ata_id_logical_sector_size(const u16 *id)
{ {
if ((id[ATA_ID_SECTOR_SIZE] & 0xc000) != 0x4000) /* T13/1699-D Revision 6a, Sep 6, 2008. Page 128.
* IDENTIFY DEVICE data, word 117-118.
* 0xd000 ignores bit 13 (logical:physical > 1)
*/
if ((id[ATA_ID_SECTOR_SIZE] & 0xd000) == 0x5000)
return (((id[ATA_ID_LOGICAL_SECTOR_SIZE+1] << 16)
+ id[ATA_ID_LOGICAL_SECTOR_SIZE]) * sizeof(u16)) ;
return ATA_SECT_SIZE;
}
static inline u8 ata_id_log2_per_physical_sector(const u16 *id)
{
/* T13/1699-D Revision 6a, Sep 6, 2008. Page 128.
* IDENTIFY DEVICE data, word 106.
* 0xe000 ignores bit 12 (logical sector > 512 bytes)
*/
if ((id[ATA_ID_SECTOR_SIZE] & 0xe000) == 0x6000)
return (id[ATA_ID_SECTOR_SIZE] & 0xf);
return 0; return 0;
return id[ATA_ID_SECTOR_SIZE] & (1 << 13);
} }
static inline u16 ata_id_logical_per_physical_sectors(const u16 *id) /* Offset of logical sectors relative to physical sectors.
*
* If device has more than one logical sector per physical sector
* (aka 512 byte emulation), vendors might offset the "sector 0" address
* so sector 63 is "naturally aligned" - e.g. FAT partition table.
* This avoids Read/Mod/Write penalties when using FAT partition table
* and updating "well aligned" (FS perspective) physical sectors on every
* transaction.
*/
static inline u16 ata_id_logical_sector_offset(const u16 *id,
u8 log2_per_phys)
{ {
return 1 << (id[ATA_ID_SECTOR_SIZE] & 0xf); u16 word_209 = id[209];
if ((log2_per_phys > 1) && (word_209 & 0xc000) == 0x4000) {
u16 first = word_209 & 0x3fff;
if (first > 0)
return (1 << log2_per_phys) - first;
}
return 0;
} }
static inline int ata_id_has_lba48(const u16 *id) static inline int ata_id_has_lba48(const u16 *id)
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/sched.h>
/* /*
* Define if arch has non-standard setup. This is a _PCI_ standard * Define if arch has non-standard setup. This is a _PCI_ standard
...@@ -172,6 +173,7 @@ enum { ...@@ -172,6 +173,7 @@ enum {
ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */ ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */
ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */ ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */
ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */ ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */
ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */
/* struct ata_port flags */ /* struct ata_port flags */
ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
...@@ -196,7 +198,7 @@ enum { ...@@ -196,7 +198,7 @@ enum {
ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */ ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */
ATA_FLAG_AN = (1 << 18), /* controller supports AN */ ATA_FLAG_AN = (1 << 18), /* controller supports AN */
ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */ ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */
ATA_FLAG_IPM = (1 << 20), /* driver can handle IPM */ ATA_FLAG_LPM = (1 << 20), /* driver can handle LPM */
ATA_FLAG_EM = (1 << 21), /* driver supports enclosure ATA_FLAG_EM = (1 << 21), /* driver supports enclosure
* management */ * management */
ATA_FLAG_SW_ACTIVITY = (1 << 22), /* driver supports sw activity ATA_FLAG_SW_ACTIVITY = (1 << 22), /* driver supports sw activity
...@@ -324,12 +326,11 @@ enum { ...@@ -324,12 +326,11 @@ enum {
ATA_EH_HARDRESET = (1 << 2), /* meaningful only in ->prereset */ ATA_EH_HARDRESET = (1 << 2), /* meaningful only in ->prereset */
ATA_EH_RESET = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, ATA_EH_RESET = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
ATA_EH_ENABLE_LINK = (1 << 3), ATA_EH_ENABLE_LINK = (1 << 3),
ATA_EH_LPM = (1 << 4), /* link power management action */
ATA_EH_PARK = (1 << 5), /* unload heads and stop I/O */ ATA_EH_PARK = (1 << 5), /* unload heads and stop I/O */
ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_PARK, ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_PARK,
ATA_EH_ALL_ACTIONS = ATA_EH_REVALIDATE | ATA_EH_RESET | ATA_EH_ALL_ACTIONS = ATA_EH_REVALIDATE | ATA_EH_RESET |
ATA_EH_ENABLE_LINK | ATA_EH_LPM, ATA_EH_ENABLE_LINK,
/* ata_eh_info->flags */ /* ata_eh_info->flags */
ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */
...@@ -341,7 +342,7 @@ enum { ...@@ -341,7 +342,7 @@ enum {
ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */ ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */
ATA_EHI_PRINTINFO = (1 << 18), /* print configuration info */ ATA_EHI_PRINTINFO = (1 << 18), /* print configuration info */
ATA_EHI_SETMODE = (1 << 19), /* configure transfer mode */ ATA_EHI_SETMODE = (1 << 19), /* configure transfer mode */
ATA_EHI_POST_SETMODE = (1 << 20), /* revaildating after setmode */ ATA_EHI_POST_SETMODE = (1 << 20), /* revalidating after setmode */
ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET,
...@@ -377,7 +378,6 @@ enum { ...@@ -377,7 +378,6 @@ enum {
ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */
ATA_HORKAGE_DISABLE = (1 << 5), /* Disable it */ ATA_HORKAGE_DISABLE = (1 << 5), /* Disable it */
ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */
ATA_HORKAGE_IPM = (1 << 7), /* Link PM problems */
ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */ ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */
ATA_HORKAGE_STUCK_ERR = (1 << 9), /* stuck ERR on next PACKET */ ATA_HORKAGE_STUCK_ERR = (1 << 9), /* stuck ERR on next PACKET */
ATA_HORKAGE_BRIDGE_OK = (1 << 10), /* no bridge limits */ ATA_HORKAGE_BRIDGE_OK = (1 << 10), /* no bridge limits */
...@@ -464,6 +464,22 @@ enum ata_completion_errors { ...@@ -464,6 +464,22 @@ enum ata_completion_errors {
AC_ERR_NCQ = (1 << 10), /* marker for offending NCQ qc */ AC_ERR_NCQ = (1 << 10), /* marker for offending NCQ qc */
}; };
/*
* Link power management policy: If you alter this, you also need to
* alter libata-scsi.c (for the ascii descriptions)
*/
enum ata_lpm_policy {
ATA_LPM_UNKNOWN,
ATA_LPM_MAX_POWER,
ATA_LPM_MED_POWER,
ATA_LPM_MIN_POWER,
};
enum ata_lpm_hints {
ATA_LPM_EMPTY = (1 << 0), /* port empty/probing */
ATA_LPM_HIPM = (1 << 1), /* may use HIPM */
};
/* forward declarations */ /* forward declarations */
struct scsi_device; struct scsi_device;
struct ata_port_operations; struct ata_port_operations;
...@@ -478,16 +494,6 @@ typedef int (*ata_reset_fn_t)(struct ata_link *link, unsigned int *classes, ...@@ -478,16 +494,6 @@ typedef int (*ata_reset_fn_t)(struct ata_link *link, unsigned int *classes,
unsigned long deadline); unsigned long deadline);
typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes); typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes);
/*
* host pm policy: If you alter this, you also need to alter libata-scsi.c
* (for the ascii descriptions)
*/
enum link_pm {
NOT_AVAILABLE,
MIN_POWER,
MAX_PERFORMANCE,
MEDIUM_POWER,
};
extern struct device_attribute dev_attr_link_power_management_policy; extern struct device_attribute dev_attr_link_power_management_policy;
extern struct device_attribute dev_attr_unload_heads; extern struct device_attribute dev_attr_unload_heads;
extern struct device_attribute dev_attr_em_message_type; extern struct device_attribute dev_attr_em_message_type;
...@@ -530,6 +536,10 @@ struct ata_host { ...@@ -530,6 +536,10 @@ struct ata_host {
void *private_data; void *private_data;
struct ata_port_operations *ops; struct ata_port_operations *ops;
unsigned long flags; unsigned long flags;
struct mutex eh_mutex;
struct task_struct *eh_owner;
#ifdef CONFIG_ATA_ACPI #ifdef CONFIG_ATA_ACPI
acpi_handle acpi_handle; acpi_handle acpi_handle;
#endif #endif
...@@ -560,13 +570,13 @@ struct ata_queued_cmd { ...@@ -560,13 +570,13 @@ struct ata_queued_cmd {
unsigned int extrabytes; unsigned int extrabytes;
unsigned int curbytes; unsigned int curbytes;
struct scatterlist *cursg;
unsigned int cursg_ofs;
struct scatterlist sgent; struct scatterlist sgent;
struct scatterlist *sg; struct scatterlist *sg;
struct scatterlist *cursg;
unsigned int cursg_ofs;
unsigned int err_mask; unsigned int err_mask;
struct ata_taskfile result_tf; struct ata_taskfile result_tf;
ata_qc_cb_t complete_fn; ata_qc_cb_t complete_fn;
...@@ -604,6 +614,7 @@ struct ata_device { ...@@ -604,6 +614,7 @@ struct ata_device {
union acpi_object *gtf_cache; union acpi_object *gtf_cache;
unsigned int gtf_filter; unsigned int gtf_filter;
#endif #endif
struct device tdev;
/* n_sector is CLEAR_BEGIN, read comment above CLEAR_BEGIN */ /* n_sector is CLEAR_BEGIN, read comment above CLEAR_BEGIN */
u64 n_sectors; /* size of device, if ATA */ u64 n_sectors; /* size of device, if ATA */
u64 n_native_sectors; /* native size, if ATA */ u64 n_native_sectors; /* native size, if ATA */
...@@ -690,6 +701,7 @@ struct ata_link { ...@@ -690,6 +701,7 @@ struct ata_link {
struct ata_port *ap; struct ata_port *ap;
int pmp; /* port multiplier port # */ int pmp; /* port multiplier port # */
struct device tdev;
unsigned int active_tag; /* active tag on this link */ unsigned int active_tag; /* active tag on this link */
u32 sactive; /* active NCQ commands */ u32 sactive; /* active NCQ commands */
...@@ -699,6 +711,7 @@ struct ata_link { ...@@ -699,6 +711,7 @@ struct ata_link {
unsigned int hw_sata_spd_limit; unsigned int hw_sata_spd_limit;
unsigned int sata_spd_limit; unsigned int sata_spd_limit;
unsigned int sata_spd; /* current SATA PHY speed */ unsigned int sata_spd; /* current SATA PHY speed */
enum ata_lpm_policy lpm_policy;
/* record runtime error info, protected by host_set lock */ /* record runtime error info, protected by host_set lock */
struct ata_eh_info eh_info; struct ata_eh_info eh_info;
...@@ -707,6 +720,8 @@ struct ata_link { ...@@ -707,6 +720,8 @@ struct ata_link {
struct ata_device device[ATA_MAX_DEVICES]; struct ata_device device[ATA_MAX_DEVICES];
}; };
#define ATA_LINK_CLEAR_BEGIN offsetof(struct ata_link, active_tag)
#define ATA_LINK_CLEAR_END offsetof(struct ata_link, device[0])
struct ata_port { struct ata_port {
struct Scsi_Host *scsi_host; /* our co-allocated scsi host */ struct Scsi_Host *scsi_host; /* our co-allocated scsi host */
...@@ -752,6 +767,7 @@ struct ata_port { ...@@ -752,6 +767,7 @@ struct ata_port {
struct ata_port_stats stats; struct ata_port_stats stats;
struct ata_host *host; struct ata_host *host;
struct device *dev; struct device *dev;
struct device tdev;
struct mutex scsi_scan_mutex; struct mutex scsi_scan_mutex;
struct delayed_work hotplug_task; struct delayed_work hotplug_task;
...@@ -767,7 +783,7 @@ struct ata_port { ...@@ -767,7 +783,7 @@ struct ata_port {
pm_message_t pm_mesg; pm_message_t pm_mesg;
int *pm_result; int *pm_result;
enum link_pm pm_policy; enum ata_lpm_policy target_lpm_policy;
struct timer_list fastdrain_timer; struct timer_list fastdrain_timer;
unsigned long fastdrain_cnt; unsigned long fastdrain_cnt;
...@@ -833,8 +849,8 @@ struct ata_port_operations { ...@@ -833,8 +849,8 @@ struct ata_port_operations {
int (*scr_write)(struct ata_link *link, unsigned int sc_reg, u32 val); int (*scr_write)(struct ata_link *link, unsigned int sc_reg, u32 val);
void (*pmp_attach)(struct ata_port *ap); void (*pmp_attach)(struct ata_port *ap);
void (*pmp_detach)(struct ata_port *ap); void (*pmp_detach)(struct ata_port *ap);
int (*enable_pm)(struct ata_port *ap, enum link_pm policy); int (*set_lpm)(struct ata_link *link, enum ata_lpm_policy policy,
void (*disable_pm)(struct ata_port *ap); unsigned hints);
/* /*
* Start, stop, suspend and resume * Start, stop, suspend and resume
...@@ -946,6 +962,8 @@ extern int sata_link_debounce(struct ata_link *link, ...@@ -946,6 +962,8 @@ extern int sata_link_debounce(struct ata_link *link,
const unsigned long *params, unsigned long deadline); const unsigned long *params, unsigned long deadline);
extern int sata_link_resume(struct ata_link *link, const unsigned long *params, extern int sata_link_resume(struct ata_link *link, const unsigned long *params,
unsigned long deadline); unsigned long deadline);
extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
bool spm_wakeup);
extern int sata_link_hardreset(struct ata_link *link, extern int sata_link_hardreset(struct ata_link *link,
const unsigned long *timing, unsigned long deadline, const unsigned long *timing, unsigned long deadline,
bool *online, int (*check_ready)(struct ata_link *)); bool *online, int (*check_ready)(struct ata_link *));
...@@ -991,8 +1009,9 @@ extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); ...@@ -991,8 +1009,9 @@ extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
extern void ata_host_resume(struct ata_host *host); extern void ata_host_resume(struct ata_host *host);
#endif #endif
extern int ata_ratelimit(void); extern int ata_ratelimit(void);
extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, extern void ata_msleep(struct ata_port *ap, unsigned int msecs);
unsigned long interval, unsigned long timeout); extern u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask,
u32 val, unsigned long interval, unsigned long timeout);
extern int atapi_cmd_type(u8 opcode); extern int atapi_cmd_type(u8 opcode);
extern void ata_tf_to_fis(const struct ata_taskfile *tf, extern void ata_tf_to_fis(const struct ata_taskfile *tf,
u8 pmp, int is_cmd, u8 *fis); u8 pmp, int is_cmd, u8 *fis);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册