mirror of
https://github.com/armbian/linux.git
synced 2026-01-06 10:13:00 -08:00
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 ...
This commit is contained in:
99
Documentation/ABI/testing/sysfs-ata
Normal file
99
Documentation/ABI/testing/sysfs-ata
Normal file
@@ -0,0 +1,99 @@
|
||||
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
|
||||
# Should be last libata driver
|
||||
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_SATA_PMP) += libata-pmp.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)
|
||||
ata_port_pbar_desc(ap, AHCI_PCI_BAR,
|
||||
0x100 + ap->port_no * 0x80, "port");
|
||||
|
||||
/* set initial link pm policy */
|
||||
ap->pm_policy = NOT_AVAILABLE;
|
||||
|
||||
/* set enclosure management message type */
|
||||
if (ap->flags & ATA_FLAG_EM)
|
||||
ap->em_message_type = hpriv->em_msg_type;
|
||||
|
||||
@@ -72,6 +72,7 @@ enum {
|
||||
AHCI_CMD_RESET = (1 << 8),
|
||||
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_SDB = 0x58, /* offset of SDB FIS data */
|
||||
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
|
||||
@@ -201,7 +202,6 @@ enum {
|
||||
AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */
|
||||
AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */
|
||||
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_YES_NCQ = (1 << 9), /* force NCQ cap on */
|
||||
AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */
|
||||
@@ -216,7 +216,7 @@ enum {
|
||||
AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
||||
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
|
||||
ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
|
||||
ATA_FLAG_IPM,
|
||||
ATA_FLAG_LPM,
|
||||
|
||||
ICH_MAP = 0x90, /* ICH MAP register */
|
||||
|
||||
|
||||
@@ -129,9 +129,6 @@ static int __init ahci_probe(struct platform_device *pdev)
|
||||
ata_port_desc(ap, "mmio %pR", mem);
|
||||
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 */
|
||||
if (ap->flags & ATA_FLAG_EM)
|
||||
ap->em_message_type = hpriv->em_msg_type;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
enum {
|
||||
ATA_GEN_CLASS_MATCH = (1 << 0),
|
||||
ATA_GEN_FORCE_DMA = (1 << 1),
|
||||
ATA_GEN_INTEL_IDER = (1 << 2),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -108,6 +109,49 @@ static struct ata_port_operations generic_port_ops = {
|
||||
|
||||
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
|
||||
* @dev: PCI device found
|
||||
@@ -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)
|
||||
return -ENODEV;
|
||||
|
||||
if (id->driver_data & ATA_GEN_INTEL_IDER)
|
||||
if (!is_intel_ider(dev))
|
||||
return -ENODEV;
|
||||
|
||||
/* Devices that need care */
|
||||
if (dev->vendor == PCI_VENDOR_ID_UMC &&
|
||||
dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
|
||||
@@ -186,7 +234,11 @@ static struct pci_device_id ata_generic[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), },
|
||||
{ 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 */
|
||||
{ PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL),
|
||||
.driver_data = ATA_GEN_CLASS_MATCH },
|
||||
|
||||
@@ -158,7 +158,6 @@ struct piix_map_db {
|
||||
struct piix_host_priv {
|
||||
const int *map;
|
||||
u32 saved_iocfg;
|
||||
spinlock_t sidpr_lock; /* FIXME: remove once locking in EH is fixed */
|
||||
void __iomem *sidpr;
|
||||
};
|
||||
|
||||
@@ -175,6 +174,8 @@ static int piix_sidpr_scr_read(struct ata_link *link,
|
||||
unsigned int reg, u32 *val);
|
||||
static int piix_sidpr_scr_write(struct ata_link *link,
|
||||
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);
|
||||
#ifdef CONFIG_PM
|
||||
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[] = {
|
||||
{ 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
|
||||
/* Intel ICH3 (E7500/1) UDMA 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 */
|
||||
{ 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 },
|
||||
@@ -348,11 +351,22 @@ static struct ata_port_operations ich_pata_ops = {
|
||||
.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 = {
|
||||
.inherits = &piix_sata_ops,
|
||||
.hardreset = sata_std_hardreset,
|
||||
.scr_read = piix_sidpr_scr_read,
|
||||
.scr_write = piix_sidpr_scr_write,
|
||||
.set_lpm = piix_sidpr_set_lpm,
|
||||
};
|
||||
|
||||
static const struct piix_map_db ich5_map_db = {
|
||||
@@ -956,15 +970,12 @@ static int piix_sidpr_scr_read(struct ata_link *link,
|
||||
unsigned int reg, u32 *val)
|
||||
{
|
||||
struct piix_host_priv *hpriv = link->ap->host->private_data;
|
||||
unsigned long flags;
|
||||
|
||||
if (reg >= ARRAY_SIZE(piix_sidx_map))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&hpriv->sidpr_lock, flags);
|
||||
piix_sidpr_sel(link, reg);
|
||||
*val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
|
||||
spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -972,18 +983,21 @@ static int piix_sidpr_scr_write(struct ata_link *link,
|
||||
unsigned int reg, u32 val)
|
||||
{
|
||||
struct piix_host_priv *hpriv = link->ap->host->private_data;
|
||||
unsigned long flags;
|
||||
|
||||
if (reg >= ARRAY_SIZE(piix_sidx_map))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&hpriv->sidpr_lock, flags);
|
||||
piix_sidpr_sel(link, reg);
|
||||
iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
|
||||
spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
|
||||
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)
|
||||
{
|
||||
if (unlikely(!ap->ioaddr.bmdma_addr))
|
||||
@@ -1543,6 +1557,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ata_port_info port_info[2];
|
||||
const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };
|
||||
struct scsi_host_template *sht = &piix_sht;
|
||||
unsigned long port_flags;
|
||||
struct ata_host *host;
|
||||
struct piix_host_priv *hpriv;
|
||||
@@ -1577,7 +1592,6 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
|
||||
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
|
||||
if (!hpriv)
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&hpriv->sidpr_lock);
|
||||
|
||||
/* Save IOCFG, this will be used for cable detection, quirk
|
||||
* detection and restoration on detach. This is necessary
|
||||
@@ -1612,6 +1626,8 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
|
||||
rc = piix_init_sidpr(host);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (host->ports[0]->ops == &piix_sidpr_sata_ops)
|
||||
sht = &piix_sidpr_sht;
|
||||
}
|
||||
|
||||
/* apply IOCFG bit18 quirk */
|
||||
@@ -1638,7 +1654,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
|
||||
host->flags |= ATA_HOST_PARALLEL_SCAN;
|
||||
|
||||
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)
|
||||
|
||||
@@ -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_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
|
||||
|
||||
static int ahci_enable_alpm(struct ata_port *ap,
|
||||
enum link_pm policy);
|
||||
static void ahci_disable_alpm(struct ata_port *ap);
|
||||
static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
|
||||
unsigned hints);
|
||||
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,
|
||||
size_t size);
|
||||
@@ -164,8 +163,7 @@ struct ata_port_operations ahci_ops = {
|
||||
.pmp_attach = ahci_pmp_attach,
|
||||
.pmp_detach = ahci_pmp_detach,
|
||||
|
||||
.enable_pm = ahci_enable_alpm,
|
||||
.disable_pm = ahci_disable_alpm,
|
||||
.set_lpm = ahci_set_lpm,
|
||||
.em_show = ahci_led_show,
|
||||
.em_store = ahci_led_store,
|
||||
.sw_activity_show = ahci_activity_show,
|
||||
@@ -569,7 +567,7 @@ int ahci_stop_engine(struct ata_port *ap)
|
||||
writel(tmp, port_mmio + PORT_CMD);
|
||||
|
||||
/* 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);
|
||||
if (tmp & PORT_CMD_LIST_ON)
|
||||
return -EIO;
|
||||
@@ -616,7 +614,7 @@ static int ahci_stop_fis_rx(struct ata_port *ap)
|
||||
writel(tmp, port_mmio + PORT_CMD);
|
||||
|
||||
/* 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);
|
||||
if (tmp & PORT_CMD_FIS_ON)
|
||||
return -EBUSY;
|
||||
@@ -642,127 +640,56 @@ static void ahci_power_up(struct ata_port *ap)
|
||||
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;
|
||||
void __iomem *port_mmio = ahci_port_base(ap);
|
||||
u32 cmd;
|
||||
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);
|
||||
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 (policy != ATA_LPM_MAX_POWER) {
|
||||
/*
|
||||
* 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.
|
||||
* Disable interrupts on Phy Ready. This keeps us from
|
||||
* getting woken up due to spurious phy ready
|
||||
* interrupts.
|
||||
*/
|
||||
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;
|
||||
pp->intr_mask &= ~PORT_IRQ_PHYRDY;
|
||||
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
|
||||
|
||||
sata_link_scr_lpm(link, policy, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable interrupts on Phy Ready. This keeps us from
|
||||
* getting woken up due to spurious phy ready interrupts
|
||||
* TBD - Hot plug should be done via polling now, is
|
||||
* that even supported?
|
||||
*/
|
||||
pp->intr_mask &= ~PORT_IRQ_PHYRDY;
|
||||
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
|
||||
if (hpriv->cap & HOST_CAP_ALPM) {
|
||||
u32 cmd = readl(port_mmio + PORT_CMD);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
|
||||
cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
|
||||
cmd |= PORT_CMD_ICC_ACTIVE;
|
||||
|
||||
/* get the existing command bits */
|
||||
cmd = readl(port_mmio + PORT_CMD);
|
||||
writel(cmd, port_mmio + PORT_CMD);
|
||||
readl(port_mmio + PORT_CMD);
|
||||
|
||||
/*
|
||||
* Set ASP based on Policy
|
||||
*/
|
||||
cmd |= asp;
|
||||
/* wait 10ms to be sure we've come out of LPM state */
|
||||
ata_msleep(ap, 10);
|
||||
} else {
|
||||
cmd |= PORT_CMD_ALPE;
|
||||
if (policy == ATA_LPM_MIN_POWER)
|
||||
cmd |= PORT_CMD_ASP;
|
||||
|
||||
/*
|
||||
* Setting this bit will instruct the HBA to aggressively
|
||||
* enter a lower power link state when it's appropriate and
|
||||
* based on the value set above for ASP
|
||||
*/
|
||||
cmd |= PORT_CMD_ALPE;
|
||||
/* write out new cmd value */
|
||||
writel(cmd, port_mmio + PORT_CMD);
|
||||
}
|
||||
}
|
||||
|
||||
/* write out new cmd value */
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -813,7 +740,7 @@ static void ahci_start_port(struct ata_port *ap)
|
||||
emp->led_state,
|
||||
4);
|
||||
if (rc == -EBUSY)
|
||||
msleep(1);
|
||||
ata_msleep(ap, 1);
|
||||
else
|
||||
break;
|
||||
}
|
||||
@@ -872,7 +799,7 @@ int ahci_reset_controller(struct ata_host *host)
|
||||
* reset must complete within 1 second, or
|
||||
* 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);
|
||||
|
||||
if (tmp & HOST_RESET) {
|
||||
@@ -1252,7 +1179,7 @@ int ahci_kick_engine(struct ata_port *ap)
|
||||
writel(tmp, port_mmio + PORT_CMD);
|
||||
|
||||
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);
|
||||
if (tmp & PORT_CMD_CLO)
|
||||
rc = -EIO;
|
||||
@@ -1282,8 +1209,8 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
|
||||
writel(1, port_mmio + PORT_CMD_ISSUE);
|
||||
|
||||
if (timeout_msec) {
|
||||
tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
|
||||
1, timeout_msec);
|
||||
tmp = ata_wait_register(ap, port_mmio + PORT_CMD_ISSUE,
|
||||
0x1, 0x1, 1, timeout_msec);
|
||||
if (tmp & 0x1) {
|
||||
ahci_kick_engine(ap);
|
||||
return -EBUSY;
|
||||
@@ -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 */
|
||||
msleep(1);
|
||||
ata_msleep(ap, 1);
|
||||
|
||||
/* issue the second D2H Register FIS */
|
||||
tf.ctl &= ~ATA_SRST;
|
||||
@@ -1660,15 +1587,10 @@ static void ahci_port_intr(struct ata_port *ap)
|
||||
if (unlikely(resetting))
|
||||
status &= ~PORT_IRQ_BAD_PMP;
|
||||
|
||||
/* If we are getting PhyRdy, this is
|
||||
* just a power state change, we should
|
||||
* clear out this, plus the PhyRdy/Comm
|
||||
* Wake bits from Serror
|
||||
*/
|
||||
if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
|
||||
(status & PORT_IRQ_PHYRDY)) {
|
||||
/* if LPM is enabled, PHYRDY doesn't mean anything */
|
||||
if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) {
|
||||
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)) {
|
||||
@@ -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)
|
||||
{
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -57,6 +57,7 @@ enum {
|
||||
/* error flags */
|
||||
ATA_EFLAG_IS_IO = (1 << 0),
|
||||
ATA_EFLAG_DUBIOUS_XFER = (1 << 1),
|
||||
ATA_EFLAG_OLD_ER = (1 << 31),
|
||||
|
||||
/* error categories */
|
||||
ATA_ECAT_NONE = 0,
|
||||
@@ -396,14 +397,9 @@ static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ata_ering_clear(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 *),
|
||||
void *arg)
|
||||
int ata_ering_map(struct ata_ering *ering,
|
||||
int (*map_fn)(struct ata_ering_entry *, void *),
|
||||
void *arg)
|
||||
{
|
||||
int idx, rc = 0;
|
||||
struct ata_ering_entry *ent;
|
||||
@@ -422,6 +418,17 @@ static int ata_ering_map(struct ata_ering *ering,
|
||||
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)
|
||||
{
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @cmd: timed out SCSI command
|
||||
@@ -572,19 +614,19 @@ void ata_scsi_error(struct Scsi_Host *host)
|
||||
int nr_timedout = 0;
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
|
||||
/* This must occur under the ap->lock as we don't want
|
||||
a polled recovery to race the real interrupt handler
|
||||
|
||||
|
||||
The lost_interrupt handler checks for any completed but
|
||||
non-notified command and completes much like an IRQ handler.
|
||||
|
||||
|
||||
We then fall into the error recovery code which will treat
|
||||
this as if normal completion won the race */
|
||||
|
||||
if (ap->ops->lost_interrupt)
|
||||
ap->ops->lost_interrupt(ap);
|
||||
|
||||
|
||||
list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
|
||||
struct ata_queued_cmd *qc;
|
||||
|
||||
@@ -628,15 +670,17 @@ void ata_scsi_error(struct Scsi_Host *host)
|
||||
ap->eh_tries = ATA_EH_MAX_TRIES;
|
||||
} else
|
||||
spin_unlock_wait(ap->lock);
|
||||
|
||||
|
||||
/* If we timed raced normal completion and there is nothing to
|
||||
recover nr_timedout == 0 why exactly are we doing error recovery ? */
|
||||
|
||||
repeat:
|
||||
/* invoke error handler */
|
||||
if (ap->ops->error_handler) {
|
||||
struct ata_link *link;
|
||||
|
||||
/* acquire EH ownership */
|
||||
ata_eh_acquire(ap);
|
||||
repeat:
|
||||
/* kill fast drain timer */
|
||||
del_timer_sync(&ap->fastdrain_timer);
|
||||
|
||||
@@ -711,6 +755,7 @@ void ata_scsi_error(struct Scsi_Host *host)
|
||||
host->host_eh_scheduled = 0;
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
ata_eh_release(ap);
|
||||
} else {
|
||||
WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL);
|
||||
ap->ops->eng_timeout(ap);
|
||||
@@ -772,7 +817,7 @@ void ata_port_wait_eh(struct ata_port *ap)
|
||||
|
||||
/* make sure SCSI EH is complete */
|
||||
if (scsi_host_in_recovery(ap->scsi_host)) {
|
||||
msleep(10);
|
||||
ata_msleep(ap, 10);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
@@ -1573,9 +1618,9 @@ static void ata_eh_analyze_serror(struct ata_link *link)
|
||||
* host links. For disabled PMP links, only N bit is
|
||||
* considered as X bit is left at 1 for link plugging.
|
||||
*/
|
||||
hotplug_mask = 0;
|
||||
|
||||
if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
|
||||
if (link->lpm_policy != ATA_LPM_MAX_POWER)
|
||||
hotplug_mask = 0; /* hotplug doesn't work w/ LPM */
|
||||
else if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
|
||||
hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
|
||||
else
|
||||
hotplug_mask = SERR_PHYRDY_CHG;
|
||||
@@ -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;
|
||||
int cat;
|
||||
|
||||
if (ent->timestamp < arg->since)
|
||||
if ((ent->eflags & ATA_EFLAG_OLD_ER) || (ent->timestamp < arg->since))
|
||||
return -1;
|
||||
|
||||
cat = ata_eh_categorize_error(ent->eflags, ent->err_mask,
|
||||
@@ -2777,8 +2822,9 @@ int ata_eh_reset(struct ata_link *link, int classify,
|
||||
ata_eh_done(link, NULL, ATA_EH_RESET);
|
||||
if (slave)
|
||||
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;
|
||||
link->lpm_policy = ATA_LPM_UNKNOWN; /* reset LPM state */
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
@@ -2810,8 +2856,10 @@ int ata_eh_reset(struct ata_link *link, int classify,
|
||||
"reset failed (errno=%d), retrying in %u secs\n",
|
||||
rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000));
|
||||
|
||||
ata_eh_release(ap);
|
||||
while (delta)
|
||||
delta = schedule_timeout_uninterruptible(delta);
|
||||
ata_eh_acquire(ap);
|
||||
}
|
||||
|
||||
if (try == max_tries - 1) {
|
||||
@@ -3204,6 +3252,124 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev)
|
||||
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)
|
||||
{
|
||||
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_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
|
||||
* error mask used is irrelevant. Because a successful device
|
||||
* 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,
|
||||
{
|
||||
struct ata_link *link;
|
||||
struct ata_device *dev;
|
||||
int nr_failed_devs;
|
||||
int rc;
|
||||
int rc, nr_fails;
|
||||
unsigned long flags, deadline;
|
||||
|
||||
DPRINTK("ENTER\n");
|
||||
@@ -3431,7 +3606,6 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
|
||||
|
||||
retry:
|
||||
rc = 0;
|
||||
nr_failed_devs = 0;
|
||||
|
||||
/* if UNLOADING, finish immediately */
|
||||
if (ap->pflags & ATA_PFLAG_UNLOADING)
|
||||
@@ -3501,8 +3675,10 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
|
||||
if (time_before_eq(deadline, now))
|
||||
break;
|
||||
|
||||
ata_eh_release(ap);
|
||||
deadline = wait_for_completion_timeout(&ap->park_req_pending,
|
||||
deadline - now);
|
||||
ata_eh_acquire(ap);
|
||||
} while (deadline);
|
||||
ata_for_each_link(link, ap, EDGE) {
|
||||
ata_for_each_dev(dev, link, ALL) {
|
||||
@@ -3516,13 +3692,17 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
if (sata_pmp_attached(ap) && ata_is_host_link(link))
|
||||
goto config_lpm;
|
||||
|
||||
/* revalidate existing devices and attach new ones */
|
||||
rc = ata_eh_revalidate_and_attach(link, &dev);
|
||||
if (rc)
|
||||
goto dev_fail;
|
||||
goto rest_fail;
|
||||
|
||||
/* if PMP got attached, return, pmp EH will take care of it */
|
||||
if (link->device->class == ATA_DEV_PMP) {
|
||||
@@ -3534,7 +3714,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
|
||||
if (ehc->i.flags & ATA_EHI_SETMODE) {
|
||||
rc = ata_set_mode(link, &dev);
|
||||
if (rc)
|
||||
goto dev_fail;
|
||||
goto rest_fail;
|
||||
ehc->i.flags &= ~ATA_EHI_SETMODE;
|
||||
}
|
||||
|
||||
@@ -3547,7 +3727,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
|
||||
continue;
|
||||
rc = atapi_eh_clear_ua(dev);
|
||||
if (rc)
|
||||
goto dev_fail;
|
||||
goto rest_fail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3557,21 +3737,25 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
|
||||
continue;
|
||||
rc = ata_eh_maybe_retry_flush(dev);
|
||||
if (rc)
|
||||
goto dev_fail;
|
||||
goto rest_fail;
|
||||
}
|
||||
|
||||
config_lpm:
|
||||
/* configure link power saving */
|
||||
if (ehc->i.action & ATA_EH_LPM)
|
||||
ata_for_each_dev(dev, link, ALL)
|
||||
ata_dev_enable_pm(dev, ap->pm_policy);
|
||||
if (link->lpm_policy != ap->target_lpm_policy) {
|
||||
rc = ata_eh_set_lpm(link, ap->target_lpm_policy, &dev);
|
||||
if (rc)
|
||||
goto rest_fail;
|
||||
}
|
||||
|
||||
/* this link is okay now */
|
||||
ehc->i.flags = 0;
|
||||
continue;
|
||||
|
||||
dev_fail:
|
||||
nr_failed_devs++;
|
||||
ata_eh_handle_dev_fail(dev, rc);
|
||||
rest_fail:
|
||||
nr_fails++;
|
||||
if (dev)
|
||||
ata_eh_handle_dev_fail(dev, rc);
|
||||
|
||||
if (ap->pflags & ATA_PFLAG_FROZEN) {
|
||||
/* PMP reset requires working host port.
|
||||
@@ -3583,7 +3767,7 @@ dev_fail:
|
||||
}
|
||||
}
|
||||
|
||||
if (nr_failed_devs)
|
||||
if (nr_fails)
|
||||
goto retry;
|
||||
|
||||
out:
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/libata.h>
|
||||
#include <linux/slab.h>
|
||||
#include "libata.h"
|
||||
#include "libata-transport.h"
|
||||
|
||||
const struct ata_port_operations sata_pmp_port_ops = {
|
||||
.inherits = &sata_port_ops,
|
||||
@@ -184,6 +185,27 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
|
||||
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
|
||||
* @dev: PMP device
|
||||
@@ -312,10 +334,10 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info)
|
||||
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;
|
||||
int i;
|
||||
int i, err;
|
||||
|
||||
if (!pmp_link) {
|
||||
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)
|
||||
ata_link_init(ap, &pmp_link[i], i);
|
||||
|
||||
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++) {
|
||||
@@ -339,6 +368,12 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -351,6 +386,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
|
||||
if (vendor == 0x1095 && devid == 0x3726) {
|
||||
/* sil3726 quirks */
|
||||
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
|
||||
* times out under certain configurations.
|
||||
*/
|
||||
@@ -366,6 +404,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
|
||||
} else if (vendor == 0x1095 && devid == 0x4723) {
|
||||
/* sil4723 quirks */
|
||||
ata_for_each_link(link, ap, EDGE) {
|
||||
/* link reports offline after LPM */
|
||||
link->flags |= ATA_LFLAG_NO_LPM;
|
||||
|
||||
/* class code report is unreliable */
|
||||
if (link->pmp < 2)
|
||||
link->flags |= ATA_LFLAG_ASSUME_ATA;
|
||||
@@ -378,6 +419,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
|
||||
} else if (vendor == 0x1095 && devid == 0x4726) {
|
||||
/* sil4726 quirks */
|
||||
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
|
||||
* times out under certain configurations.
|
||||
* Config device can be at port 0 or 5 and
|
||||
@@ -938,15 +982,25 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
|
||||
if (rc)
|
||||
goto link_fail;
|
||||
|
||||
/* Connection status might have changed while resetting other
|
||||
* links, check SATA_PMP_GSCR_ERROR before returning.
|
||||
*/
|
||||
|
||||
/* clear SNotification */
|
||||
rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
|
||||
if (rc == 0)
|
||||
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 */
|
||||
if (pmp_dev->flags & ATA_DFLAG_AN) {
|
||||
gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "libata.h"
|
||||
#include "libata-transport.h"
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
#define ATA_SCSI_RBUF_SIZE 4096
|
||||
|
||||
static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
|
||||
@@ -64,9 +64,6 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
|
||||
const struct scsi_device *scsidev);
|
||||
static struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
|
||||
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_LEN 12
|
||||
@@ -106,83 +103,55 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
|
||||
0, 30 /* extended self test time, see 05-359r1 */
|
||||
};
|
||||
|
||||
/*
|
||||
* libata transport template. libata doesn't do real transport stuff.
|
||||
* It just needs the eh_timed_out hook.
|
||||
*/
|
||||
static struct scsi_transport_template ata_scsi_transport_template = {
|
||||
.eh_strategy_handler = ata_scsi_error,
|
||||
.eh_timed_out = ata_scsi_timed_out,
|
||||
.user_scan = ata_scsi_user_scan,
|
||||
static const char *ata_lpm_policy_names[] = {
|
||||
[ATA_LPM_UNKNOWN] = "max_performance",
|
||||
[ATA_LPM_MAX_POWER] = "max_performance",
|
||||
[ATA_LPM_MED_POWER] = "medium_power",
|
||||
[ATA_LPM_MIN_POWER] = "min_power",
|
||||
};
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
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,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t ata_scsi_lpm_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct Scsi_Host *shost = class_to_shost(dev);
|
||||
struct ata_port *ap = ata_shost_to_port(shost);
|
||||
enum link_pm policy = 0;
|
||||
int i;
|
||||
enum ata_lpm_policy policy;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* we are skipping array location 0 on purpose - this
|
||||
* is because a value of NOT_AVAILABLE is displayed
|
||||
* to the user as max_performance, but when the user
|
||||
* writes "max_performance", they actually want the
|
||||
* value to match MAX_PERFORMANCE.
|
||||
*/
|
||||
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;
|
||||
/* UNKNOWN is internal state, iterate from MAX_POWER */
|
||||
for (policy = ATA_LPM_MAX_POWER;
|
||||
policy < ARRAY_SIZE(ata_lpm_policy_names); policy++) {
|
||||
const char *name = ata_lpm_policy_names[policy];
|
||||
|
||||
if (strncmp(name, buf, strlen(name)) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!policy)
|
||||
if (policy == ARRAY_SIZE(ata_lpm_policy_names))
|
||||
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;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ata_scsi_lpm_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t ata_scsi_lpm_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct Scsi_Host *shost = class_to_shost(dev);
|
||||
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 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,
|
||||
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);
|
||||
|
||||
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)
|
||||
memset(scsi_cmd, 0, sizeof(scsi_cmd));
|
||||
|
||||
if (args[3]) {
|
||||
argsize = SECTOR_SIZE * args[3];
|
||||
argsize = ATA_SECT_SIZE * args[3];
|
||||
argbuf = kmalloc(argsize, GFP_KERNEL);
|
||||
if (argbuf == NULL) {
|
||||
rc = -ENOMEM;
|
||||
@@ -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);
|
||||
} else {
|
||||
/* ATA devices must be sector aligned */
|
||||
sdev->sector_size = ata_id_logical_sector_size(dev->id);
|
||||
blk_queue_update_dma_alignment(sdev->request_queue,
|
||||
ATA_SECT_SIZE - 1);
|
||||
sdev->sector_size - 1);
|
||||
sdev->manage_start_stop = 1;
|
||||
}
|
||||
|
||||
@@ -1166,6 +1136,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
|
||||
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
|
||||
}
|
||||
|
||||
dev->sdev = sdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1696,7 +1667,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
|
||||
goto nothing_to_do;
|
||||
|
||||
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,
|
||||
qc->tag);
|
||||
@@ -2001,6 +1972,7 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)
|
||||
0x89, /* page 0x89, ata info page */
|
||||
0xb0, /* page 0xb0, block limits page */
|
||||
0xb1, /* page 0xb1, block device characteristics page */
|
||||
0xb2, /* page 0xb2, thin provisioning page */
|
||||
};
|
||||
|
||||
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)
|
||||
|
||||
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[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)
|
||||
* logical than physical sector size we need to figure out what the
|
||||
* latter is.
|
||||
*/
|
||||
if (ata_id_has_large_logical_sectors(args->id))
|
||||
min_io_sectors = ata_id_logical_per_physical_sectors(args->id);
|
||||
else
|
||||
min_io_sectors = 1;
|
||||
min_io_sectors = 1 << ata_id_log2_per_physical_sector(args->id);
|
||||
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)
|
||||
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.
|
||||
* @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)
|
||||
{
|
||||
struct ata_device *dev = args->dev;
|
||||
u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */
|
||||
u8 log_per_phys = 0;
|
||||
u16 lowest_aligned = 0;
|
||||
u16 word_106 = dev->id[106];
|
||||
u16 word_209 = dev->id[209];
|
||||
u32 sector_size; /* physical sector size in bytes */
|
||||
u8 log2_per_phys;
|
||||
u16 lowest_aligned;
|
||||
|
||||
if ((word_106 & 0xc000) == 0x4000) {
|
||||
/* Number and offset of logical sectors per physical sector */
|
||||
if (word_106 & (1 << 13))
|
||||
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;
|
||||
}
|
||||
}
|
||||
sector_size = ata_id_logical_sector_size(dev->id);
|
||||
log2_per_phys = ata_id_log2_per_physical_sector(dev->id);
|
||||
lowest_aligned = ata_id_logical_sector_offset(dev->id, log2_per_phys);
|
||||
|
||||
VPRINTK("ENTER\n");
|
||||
|
||||
@@ -2426,8 +2397,10 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
|
||||
rbuf[3] = last_lba;
|
||||
|
||||
/* sector size */
|
||||
rbuf[6] = ATA_SECT_SIZE >> 8;
|
||||
rbuf[7] = ATA_SECT_SIZE & 0xff;
|
||||
rbuf[4] = sector_size >> (8 * 3);
|
||||
rbuf[5] = sector_size >> (8 * 2);
|
||||
rbuf[6] = sector_size >> (8 * 1);
|
||||
rbuf[7] = sector_size;
|
||||
} else {
|
||||
/* sector count, 64-bit */
|
||||
rbuf[0] = last_lba >> (8 * 7);
|
||||
@@ -2440,11 +2413,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
|
||||
rbuf[7] = last_lba;
|
||||
|
||||
/* sector size */
|
||||
rbuf[10] = ATA_SECT_SIZE >> 8;
|
||||
rbuf[11] = ATA_SECT_SIZE & 0xff;
|
||||
rbuf[ 8] = sector_size >> (8 * 3);
|
||||
rbuf[ 9] = sector_size >> (8 * 2);
|
||||
rbuf[10] = sector_size >> (8 * 1);
|
||||
rbuf[11] = sector_size;
|
||||
|
||||
rbuf[12] = 0;
|
||||
rbuf[13] = log_per_phys;
|
||||
rbuf[13] = log2_per_phys;
|
||||
rbuf[14] = (lowest_aligned >> 8) & 0x3f;
|
||||
rbuf[15] = lowest_aligned;
|
||||
|
||||
@@ -2888,9 +2863,8 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
|
||||
tf->device = dev->devno ?
|
||||
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) {
|
||||
/* READ/WRITE LONG use a non-standard sect_size */
|
||||
case ATA_CMD_READ_LONG:
|
||||
case ATA_CMD_READ_LONG_ONCE:
|
||||
case ATA_CMD_WRITE_LONG:
|
||||
@@ -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)
|
||||
goto invalid_fld;
|
||||
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,
|
||||
case 0xb1:
|
||||
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1);
|
||||
break;
|
||||
case 0xb2:
|
||||
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2);
|
||||
break;
|
||||
default:
|
||||
ata_scsi_invalid_field(cmd, done);
|
||||
break;
|
||||
@@ -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;
|
||||
ap->scsi_host = shost;
|
||||
|
||||
shost->transportt = &ata_scsi_transport_template;
|
||||
shost->transportt = ata_scsi_transport_template;
|
||||
shost->unique_id = ap->print_id;
|
||||
shost->max_id = 16;
|
||||
shost->max_lun = 1;
|
||||
@@ -3393,6 +3409,8 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
|
||||
if (!IS_ERR(sdev)) {
|
||||
dev->sdev = sdev;
|
||||
scsi_device_put(sdev);
|
||||
} else {
|
||||
dev->sdev = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3616,8 +3634,8 @@ void ata_scsi_hotplug(struct work_struct *work)
|
||||
* RETURNS:
|
||||
* Zero.
|
||||
*/
|
||||
static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
|
||||
unsigned int id, unsigned int lun)
|
||||
int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
|
||||
unsigned int id, unsigned int lun)
|
||||
{
|
||||
struct ata_port *ap = ata_shost_to_port(shost);
|
||||
unsigned long flags;
|
||||
|
||||
@@ -222,7 +222,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
|
||||
timeout = ata_deadline(timer_start, tmout_pat);
|
||||
while (status != 0xff && (status & ATA_BUSY) &&
|
||||
time_before(jiffies, timeout)) {
|
||||
msleep(50);
|
||||
ata_msleep(ap, 50);
|
||||
status = ata_sff_busy_wait(ap, ATA_BUSY, 3);
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
|
||||
timeout = ata_deadline(timer_start, tmout);
|
||||
while (status != 0xff && (status & ATA_BUSY) &&
|
||||
time_before(jiffies, timeout)) {
|
||||
msleep(50);
|
||||
ata_msleep(ap, 50);
|
||||
status = ap->ops->sff_check_status(ap);
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ static void ata_dev_select(struct ata_port *ap, unsigned int device,
|
||||
|
||||
if (wait) {
|
||||
if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
|
||||
msleep(150);
|
||||
ata_msleep(ap, 150);
|
||||
ata_wait_idle(ap);
|
||||
}
|
||||
}
|
||||
@@ -1356,7 +1356,7 @@ fsm_start:
|
||||
*/
|
||||
status = ata_sff_busy_wait(ap, ATA_BUSY, 5);
|
||||
if (status & ATA_BUSY) {
|
||||
msleep(2);
|
||||
ata_msleep(ap, 2);
|
||||
status = ata_sff_busy_wait(ap, ATA_BUSY, 10);
|
||||
if (status & ATA_BUSY) {
|
||||
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,
|
||||
unsigned int dev1 = devmask & (1 << 1);
|
||||
int rc, ret = 0;
|
||||
|
||||
msleep(ATA_WAIT_AFTER_RESET);
|
||||
ata_msleep(ap, ATA_WAIT_AFTER_RESET);
|
||||
|
||||
/* always check readiness of the master device */
|
||||
rc = ata_sff_wait_ready(link, deadline);
|
||||
@@ -1966,7 +1966,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
|
||||
lbal = ioread8(ioaddr->lbal_addr);
|
||||
if ((nsect == 1) && (lbal == 1))
|
||||
break;
|
||||
msleep(50); /* give drive a breather */
|
||||
ata_msleep(ap, 50); /* give drive a breather */
|
||||
}
|
||||
|
||||
rc = ata_sff_wait_ready(link, deadline);
|
||||
@@ -3342,7 +3342,7 @@ int __init ata_sff_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit ata_sff_exit(void)
|
||||
void ata_sff_exit(void)
|
||||
{
|
||||
destroy_workqueue(ata_sff_wq);
|
||||
}
|
||||
|
||||
774
drivers/ata/libata-transport.c
Normal file
774
drivers/ata/libata-transport.c
Normal file
File diff suppressed because it is too large
Load Diff
18
drivers/ata/libata-transport.h
Normal file
18
drivers/ata/libata-transport.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#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,
|
||||
extern int ata_dev_configure(struct ata_device *dev);
|
||||
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 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_qc_free(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);
|
||||
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 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 void ata_lpm_schedule(struct ata_port *ap, enum link_pm);
|
||||
extern const char *sata_spd_string(unsigned int spd);
|
||||
|
||||
/* libata-acpi.c */
|
||||
#ifdef CONFIG_ATA_ACPI
|
||||
@@ -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_scsi_dev_rescan(struct work_struct *work);
|
||||
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 */
|
||||
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_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 void ata_scsi_error(struct Scsi_Host *host);
|
||||
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,
|
||||
ata_postreset_fn_t postreset,
|
||||
struct ata_link **r_failed_disk);
|
||||
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 */
|
||||
#ifdef CONFIG_SATA_PMP
|
||||
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_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
|
||||
unsigned hints);
|
||||
extern int sata_pmp_attach(struct ata_device *dev);
|
||||
#else /* CONFIG_SATA_PMP */
|
||||
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)
|
||||
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)
|
||||
{
|
||||
return -EINVAL;
|
||||
|
||||
@@ -826,7 +826,7 @@ static void bfin_dev_select(struct ata_port *ap, unsigned int device)
|
||||
* @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;
|
||||
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)
|
||||
dev1 = 0;
|
||||
break;
|
||||
}
|
||||
msleep(50); /* give drive a breather */
|
||||
ata_msleep(ap, 50); /* give drive a breather */
|
||||
}
|
||||
if (dev1)
|
||||
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,
|
||||
*
|
||||
* 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
|
||||
* the bus shows 0xFF because the odd clown forgets the D7
|
||||
|
||||
@@ -161,6 +161,17 @@ static int cmd640_port_start(struct ata_port *ap)
|
||||
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 = {
|
||||
ATA_PIO_SHT(DRV_NAME),
|
||||
};
|
||||
@@ -169,6 +180,7 @@ static struct ata_port_operations cmd640_port_ops = {
|
||||
.inherits = &ata_sff_port_ops,
|
||||
/* In theory xfer_noirq is not needed once we kill the prefetcher */
|
||||
.sff_data_xfer = ata_sff_data_xfer_noirq,
|
||||
.sff_irq_check = cmd640_sff_irq_check,
|
||||
.qc_issue = cmd640_qc_issue,
|
||||
.cable_detect = ata_cable_40wire,
|
||||
.set_piomode = cmd640_set_piomode,
|
||||
|
||||
@@ -44,6 +44,27 @@ static void pdc202xx_exec_command(struct ata_port *ap,
|
||||
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
|
||||
* @ap: ATA interface
|
||||
@@ -282,6 +303,7 @@ static struct ata_port_operations pdc2024x_port_ops = {
|
||||
.set_dmamode = pdc202xx_set_dmamode,
|
||||
|
||||
.sff_exec_command = pdc202xx_exec_command,
|
||||
.sff_irq_check = pdc202xx_irq_check,
|
||||
};
|
||||
|
||||
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,
|
||||
|
||||
.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)
|
||||
|
||||
@@ -322,7 +322,7 @@ static int pata_s3c_wait_after_reset(struct ata_link *link,
|
||||
{
|
||||
int rc;
|
||||
|
||||
msleep(ATA_WAIT_AFTER_RESET);
|
||||
ata_msleep(link->ap, ATA_WAIT_AFTER_RESET);
|
||||
|
||||
/* always check readiness of the master device */
|
||||
rc = ata_sff_wait_ready(link, deadline);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user