diff options
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/Makefile | 1 | ||||
-rw-r--r-- | drivers/ata/libata-core.c | 245 | ||||
-rw-r--r-- | drivers/ata/libata-sata.c | 258 |
3 files changed, 259 insertions, 245 deletions
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index cdaf965fed25..b8aebfb14e82 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -123,6 +123,7 @@ obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o libata-y := libata-core.o libata-scsi.o libata-eh.o \ libata-transport.o libata-trace.o +libata-$(CONFIG_SATA_HOST) += libata-sata.o libata-$(CONFIG_ATA_SFF) += libata-sff.o libata-$(CONFIG_SATA_PMP) += libata-pmp.o libata-$(CONFIG_ATA_ACPI) += libata-acpi.o diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index dcdb7fb46dbd..b4a952dce7ab 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -531,81 +531,6 @@ int atapi_cmd_type(u8 opcode) } EXPORT_SYMBOL_GPL(atapi_cmd_type); -/** - * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure - * @tf: Taskfile to convert - * @pmp: Port multiplier port - * @is_cmd: This FIS is for command - * @fis: Buffer into which data will output - * - * Converts a standard ATA taskfile to a Serial ATA - * FIS structure (Register - Host to Device). - * - * LOCKING: - * Inherited from caller. - */ -void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis) -{ - fis[0] = 0x27; /* Register - Host to Device FIS */ - fis[1] = pmp & 0xf; /* Port multiplier number*/ - if (is_cmd) - fis[1] |= (1 << 7); /* bit 7 indicates Command FIS */ - - fis[2] = tf->command; - fis[3] = tf->feature; - - fis[4] = tf->lbal; - fis[5] = tf->lbam; - fis[6] = tf->lbah; - fis[7] = tf->device; - - fis[8] = tf->hob_lbal; - fis[9] = tf->hob_lbam; - fis[10] = tf->hob_lbah; - fis[11] = tf->hob_feature; - - fis[12] = tf->nsect; - fis[13] = tf->hob_nsect; - fis[14] = 0; - fis[15] = tf->ctl; - - fis[16] = tf->auxiliary & 0xff; - fis[17] = (tf->auxiliary >> 8) & 0xff; - fis[18] = (tf->auxiliary >> 16) & 0xff; - fis[19] = (tf->auxiliary >> 24) & 0xff; -} -EXPORT_SYMBOL_GPL(ata_tf_to_fis); - -/** - * ata_tf_from_fis - Convert SATA FIS to ATA taskfile - * @fis: Buffer from which data will be input - * @tf: Taskfile to output - * - * Converts a serial ATA FIS structure to a standard ATA taskfile. - * - * LOCKING: - * Inherited from caller. - */ - -void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf) -{ - tf->command = fis[2]; /* status */ - tf->feature = fis[3]; /* error */ - - tf->lbal = fis[4]; - tf->lbam = fis[5]; - tf->lbah = fis[6]; - tf->device = fis[7]; - - tf->hob_lbal = fis[8]; - tf->hob_lbam = fis[9]; - tf->hob_lbah = fis[10]; - - tf->nsect = fis[12]; - tf->hob_nsect = fis[13]; -} -EXPORT_SYMBOL_GPL(ata_tf_from_fis); - static const u8 ata_rw_cmds[] = { /* pio multi */ ATA_CMD_READ_MULTI, @@ -3780,81 +3705,6 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, EXPORT_SYMBOL_GPL(sata_link_resume); /** - * 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 success, -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 |= (0x7 << 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 |= (0x6 << 8); - break; - case ATA_LPM_MED_POWER_WITH_DIPM: - case ATA_LPM_MIN_POWER_WITH_PARTIAL: - case ATA_LPM_MIN_POWER: - if (ata_link_nr_enabled(link) > 0) - /* no restrictions on LPM transitions */ - scontrol &= ~(0x7 << 8); - else { - /* empty port, power off */ - scontrol &= ~0xf; - scontrol |= (0x1 << 2); - } - 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); -} -EXPORT_SYMBOL_GPL(sata_link_scr_lpm); - -/** * ata_std_prereset - prepare for reset * @link: ATA link to be reset * @deadline: deadline jiffies for the operation @@ -6118,69 +5968,6 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev, } EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo); -/** - * ata_slave_link_init - initialize slave link - * @ap: port to initialize slave link for - * - * Create and initialize slave link for @ap. This enables slave - * link handling on the port. - * - * In libata, a port contains links and a link contains devices. - * There is single host link but if a PMP is attached to it, - * there can be multiple fan-out links. On SATA, there's usually - * a single device connected to a link but PATA and SATA - * controllers emulating TF based interface can have two - master - * and slave. - * - * However, there are a few controllers which don't fit into this - * abstraction too well - SATA controllers which emulate TF - * interface with both master and slave devices but also have - * separate SCR register sets for each device. These controllers - * need separate links for physical link handling - * (e.g. onlineness, link speed) but should be treated like a - * traditional M/S controller for everything else (e.g. command - * issue, softreset). - * - * slave_link is libata's way of handling this class of - * controllers without impacting core layer too much. For - * anything other than physical link handling, the default host - * link is used for both master and slave. For physical link - * handling, separate @ap->slave_link is used. All dirty details - * are implemented inside libata core layer. From LLD's POV, the - * only difference is that prereset, hardreset and postreset are - * called once more for the slave link, so the reset sequence - * looks like the following. - * - * prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) -> - * softreset(M) -> postreset(M) -> postreset(S) - * - * Note that softreset is called only for the master. Softreset - * resets both M/S by definition, so SRST on master should handle - * both (the standard method will work just fine). - * - * LOCKING: - * Should be called before host is registered. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int ata_slave_link_init(struct ata_port *ap) -{ - struct ata_link *link; - - WARN_ON(ap->slave_link); - WARN_ON(ap->flags & ATA_FLAG_PMP); - - link = kzalloc(sizeof(*link), GFP_KERNEL); - if (!link) - return -ENOMEM; - - ata_link_init(ap, link, 1); - ap->slave_link = link; - return 0; -} -EXPORT_SYMBOL_GPL(ata_slave_link_init); - static void ata_host_stop(struct device *gendev, void *res) { struct ata_host *host = dev_get_drvdata(gendev); @@ -7106,38 +6893,6 @@ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val, } EXPORT_SYMBOL_GPL(ata_wait_register); -/** - * sata_lpm_ignore_phy_events - test if PHY event should be ignored - * @link: Link receiving the event - * - * Test whether the received PHY event has to be ignored or not. - * - * LOCKING: - * None: - * - * RETURNS: - * True if the event has to be ignored. - */ -bool sata_lpm_ignore_phy_events(struct ata_link *link) -{ - unsigned long lpm_timeout = link->last_lpm_change + - msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY); - - /* if LPM is enabled, PHYRDY doesn't mean anything */ - if (link->lpm_policy > ATA_LPM_MAX_POWER) - return true; - - /* ignore the first PHY event after the LPM policy changed - * as it is might be spurious - */ - if ((link->flags & ATA_LFLAG_CHANGED) && - time_before(jiffies, lpm_timeout)) - return true; - - return false; -} -EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events); - /* * Dummy port_ops */ diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c new file mode 100644 index 000000000000..04f1ecaf414c --- /dev/null +++ b/drivers/ata/libata-sata.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * SATA specific part of ATA helper library + * + * Copyright 2003-2004 Red Hat, Inc. All rights reserved. + * Copyright 2003-2004 Jeff Garzik + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/libata.h> + +#include "libata.h" + +/** + * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure + * @tf: Taskfile to convert + * @pmp: Port multiplier port + * @is_cmd: This FIS is for command + * @fis: Buffer into which data will output + * + * Converts a standard ATA taskfile to a Serial ATA + * FIS structure (Register - Host to Device). + * + * LOCKING: + * Inherited from caller. + */ +void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis) +{ + fis[0] = 0x27; /* Register - Host to Device FIS */ + fis[1] = pmp & 0xf; /* Port multiplier number*/ + if (is_cmd) + fis[1] |= (1 << 7); /* bit 7 indicates Command FIS */ + + fis[2] = tf->command; + fis[3] = tf->feature; + + fis[4] = tf->lbal; + fis[5] = tf->lbam; + fis[6] = tf->lbah; + fis[7] = tf->device; + + fis[8] = tf->hob_lbal; + fis[9] = tf->hob_lbam; + fis[10] = tf->hob_lbah; + fis[11] = tf->hob_feature; + + fis[12] = tf->nsect; + fis[13] = tf->hob_nsect; + fis[14] = 0; + fis[15] = tf->ctl; + + fis[16] = tf->auxiliary & 0xff; + fis[17] = (tf->auxiliary >> 8) & 0xff; + fis[18] = (tf->auxiliary >> 16) & 0xff; + fis[19] = (tf->auxiliary >> 24) & 0xff; +} +EXPORT_SYMBOL_GPL(ata_tf_to_fis); + +/** + * ata_tf_from_fis - Convert SATA FIS to ATA taskfile + * @fis: Buffer from which data will be input + * @tf: Taskfile to output + * + * Converts a serial ATA FIS structure to a standard ATA taskfile. + * + * LOCKING: + * Inherited from caller. + */ + +void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf) +{ + tf->command = fis[2]; /* status */ + tf->feature = fis[3]; /* error */ + + tf->lbal = fis[4]; + tf->lbam = fis[5]; + tf->lbah = fis[6]; + tf->device = fis[7]; + + tf->hob_lbal = fis[8]; + tf->hob_lbam = fis[9]; + tf->hob_lbah = fis[10]; + + tf->nsect = fis[12]; + tf->hob_nsect = fis[13]; +} +EXPORT_SYMBOL_GPL(ata_tf_from_fis); + +/** + * 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 success, -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 |= (0x7 << 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 |= (0x6 << 8); + break; + case ATA_LPM_MED_POWER_WITH_DIPM: + case ATA_LPM_MIN_POWER_WITH_PARTIAL: + case ATA_LPM_MIN_POWER: + if (ata_link_nr_enabled(link) > 0) + /* no restrictions on LPM transitions */ + scontrol &= ~(0x7 << 8); + else { + /* empty port, power off */ + scontrol &= ~0xf; + scontrol |= (0x1 << 2); + } + 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); +} +EXPORT_SYMBOL_GPL(sata_link_scr_lpm); + +/** + * ata_slave_link_init - initialize slave link + * @ap: port to initialize slave link for + * + * Create and initialize slave link for @ap. This enables slave + * link handling on the port. + * + * In libata, a port contains links and a link contains devices. + * There is single host link but if a PMP is attached to it, + * there can be multiple fan-out links. On SATA, there's usually + * a single device connected to a link but PATA and SATA + * controllers emulating TF based interface can have two - master + * and slave. + * + * However, there are a few controllers which don't fit into this + * abstraction too well - SATA controllers which emulate TF + * interface with both master and slave devices but also have + * separate SCR register sets for each device. These controllers + * need separate links for physical link handling + * (e.g. onlineness, link speed) but should be treated like a + * traditional M/S controller for everything else (e.g. command + * issue, softreset). + * + * slave_link is libata's way of handling this class of + * controllers without impacting core layer too much. For + * anything other than physical link handling, the default host + * link is used for both master and slave. For physical link + * handling, separate @ap->slave_link is used. All dirty details + * are implemented inside libata core layer. From LLD's POV, the + * only difference is that prereset, hardreset and postreset are + * called once more for the slave link, so the reset sequence + * looks like the following. + * + * prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) -> + * softreset(M) -> postreset(M) -> postreset(S) + * + * Note that softreset is called only for the master. Softreset + * resets both M/S by definition, so SRST on master should handle + * both (the standard method will work just fine). + * + * LOCKING: + * Should be called before host is registered. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int ata_slave_link_init(struct ata_port *ap) +{ + struct ata_link *link; + + WARN_ON(ap->slave_link); + WARN_ON(ap->flags & ATA_FLAG_PMP); + + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) + return -ENOMEM; + + ata_link_init(ap, link, 1); + ap->slave_link = link; + return 0; +} +EXPORT_SYMBOL_GPL(ata_slave_link_init); + +/** + * sata_lpm_ignore_phy_events - test if PHY event should be ignored + * @link: Link receiving the event + * + * Test whether the received PHY event has to be ignored or not. + * + * LOCKING: + * None: + * + * RETURNS: + * True if the event has to be ignored. + */ +bool sata_lpm_ignore_phy_events(struct ata_link *link) +{ + unsigned long lpm_timeout = link->last_lpm_change + + msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY); + + /* if LPM is enabled, PHYRDY doesn't mean anything */ + if (link->lpm_policy > ATA_LPM_MAX_POWER) + return true; + + /* ignore the first PHY event after the LPM policy changed + * as it is might be spurious + */ + if ((link->flags & ATA_LFLAG_CHANGED) && + time_before(jiffies, lpm_timeout)) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events); |