155716d26SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23af9a77aSTejun Heo /*
33af9a77aSTejun Heo * libata-pmp.c - libata port multiplier support
43af9a77aSTejun Heo *
53af9a77aSTejun Heo * Copyright (c) 2007 SUSE Linux Products GmbH
63af9a77aSTejun Heo * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
73af9a77aSTejun Heo */
83af9a77aSTejun Heo
93af9a77aSTejun Heo #include <linux/kernel.h>
1038789fdaSPaul Gortmaker #include <linux/export.h>
113af9a77aSTejun Heo #include <linux/libata.h>
125a0e3ad6STejun Heo #include <linux/slab.h>
133af9a77aSTejun Heo #include "libata.h"
14d9027470SGwendal Grignou #include "libata-transport.h"
153af9a77aSTejun Heo
1648515f6cSTejun Heo const struct ata_port_operations sata_pmp_port_ops = {
1748515f6cSTejun Heo .inherits = &sata_port_ops,
1848515f6cSTejun Heo .pmp_prereset = ata_std_prereset,
1948515f6cSTejun Heo .pmp_hardreset = sata_std_hardreset,
2048515f6cSTejun Heo .pmp_postreset = ata_std_postreset,
2148515f6cSTejun Heo .error_handler = sata_pmp_error_handler,
2248515f6cSTejun Heo };
2348515f6cSTejun Heo
243af9a77aSTejun Heo /**
253af9a77aSTejun Heo * sata_pmp_read - read PMP register
263af9a77aSTejun Heo * @link: link to read PMP register for
273af9a77aSTejun Heo * @reg: register to read
283af9a77aSTejun Heo * @r_val: resulting value
293af9a77aSTejun Heo *
30b06ce3e5STejun Heo * Read PMP register.
313af9a77aSTejun Heo *
323af9a77aSTejun Heo * LOCKING:
333af9a77aSTejun Heo * Kernel thread context (may sleep).
343af9a77aSTejun Heo *
353af9a77aSTejun Heo * RETURNS:
36b06ce3e5STejun Heo * 0 on success, AC_ERR_* mask on failure.
373af9a77aSTejun Heo */
sata_pmp_read(struct ata_link * link,int reg,u32 * r_val)38b06ce3e5STejun Heo static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
393af9a77aSTejun Heo {
403af9a77aSTejun Heo struct ata_port *ap = link->ap;
413af9a77aSTejun Heo struct ata_device *pmp_dev = ap->link.device;
42b06ce3e5STejun Heo struct ata_taskfile tf;
43b06ce3e5STejun Heo unsigned int err_mask;
443af9a77aSTejun Heo
45b06ce3e5STejun Heo ata_tf_init(pmp_dev, &tf);
46b06ce3e5STejun Heo tf.command = ATA_CMD_PMP_READ;
47b06ce3e5STejun Heo tf.protocol = ATA_PROT_NODATA;
4839f25e70SMark Lord tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48;
49b06ce3e5STejun Heo tf.feature = reg;
50b06ce3e5STejun Heo tf.device = link->pmp;
513af9a77aSTejun Heo
52b06ce3e5STejun Heo err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
53bf1bff6fSTejun Heo SATA_PMP_RW_TIMEOUT);
54b06ce3e5STejun Heo if (err_mask)
55b06ce3e5STejun Heo return err_mask;
56b06ce3e5STejun Heo
57b06ce3e5STejun Heo *r_val = tf.nsect | tf.lbal << 8 | tf.lbam << 16 | tf.lbah << 24;
58b06ce3e5STejun Heo return 0;
593af9a77aSTejun Heo }
603af9a77aSTejun Heo
613af9a77aSTejun Heo /**
623af9a77aSTejun Heo * sata_pmp_write - write PMP register
633af9a77aSTejun Heo * @link: link to write PMP register for
643af9a77aSTejun Heo * @reg: register to write
65*32db9fadSLee Jones * @val: value to write
663af9a77aSTejun Heo *
67b06ce3e5STejun Heo * Write PMP register.
683af9a77aSTejun Heo *
693af9a77aSTejun Heo * LOCKING:
703af9a77aSTejun Heo * Kernel thread context (may sleep).
713af9a77aSTejun Heo *
723af9a77aSTejun Heo * RETURNS:
73b06ce3e5STejun Heo * 0 on success, AC_ERR_* mask on failure.
743af9a77aSTejun Heo */
sata_pmp_write(struct ata_link * link,int reg,u32 val)75b06ce3e5STejun Heo static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
763af9a77aSTejun Heo {
773af9a77aSTejun Heo struct ata_port *ap = link->ap;
783af9a77aSTejun Heo struct ata_device *pmp_dev = ap->link.device;
79b06ce3e5STejun Heo struct ata_taskfile tf;
803af9a77aSTejun Heo
81b06ce3e5STejun Heo ata_tf_init(pmp_dev, &tf);
82b06ce3e5STejun Heo tf.command = ATA_CMD_PMP_WRITE;
83b06ce3e5STejun Heo tf.protocol = ATA_PROT_NODATA;
8439f25e70SMark Lord tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48;
85b06ce3e5STejun Heo tf.feature = reg;
86b06ce3e5STejun Heo tf.device = link->pmp;
87b06ce3e5STejun Heo tf.nsect = val & 0xff;
88b06ce3e5STejun Heo tf.lbal = (val >> 8) & 0xff;
89b06ce3e5STejun Heo tf.lbam = (val >> 16) & 0xff;
90b06ce3e5STejun Heo tf.lbah = (val >> 24) & 0xff;
913af9a77aSTejun Heo
92b06ce3e5STejun Heo return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
93bf1bff6fSTejun Heo SATA_PMP_RW_TIMEOUT);
943af9a77aSTejun Heo }
953af9a77aSTejun Heo
963af9a77aSTejun Heo /**
9731f88384STejun Heo * sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP
9831f88384STejun Heo * @qc: ATA command in question
9931f88384STejun Heo *
10031f88384STejun Heo * A host which has command switching PMP support cannot issue
10131f88384STejun Heo * commands to multiple links simultaneously.
10231f88384STejun Heo *
10331f88384STejun Heo * LOCKING:
10431f88384STejun Heo * spin_lock_irqsave(host lock)
10531f88384STejun Heo *
10631f88384STejun Heo * RETURNS:
10731f88384STejun Heo * ATA_DEFER_* if deferring is needed, 0 otherwise.
10831f88384STejun Heo */
sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd * qc)10931f88384STejun Heo int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc)
11031f88384STejun Heo {
11131f88384STejun Heo struct ata_link *link = qc->dev->link;
11231f88384STejun Heo struct ata_port *ap = link->ap;
11331f88384STejun Heo
11431f88384STejun Heo if (ap->excl_link == NULL || ap->excl_link == link) {
11531f88384STejun Heo if (ap->nr_active_links == 0 || ata_link_active(link)) {
11631f88384STejun Heo qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
11731f88384STejun Heo return ata_std_qc_defer(qc);
11831f88384STejun Heo }
11931f88384STejun Heo
12031f88384STejun Heo ap->excl_link = link;
12131f88384STejun Heo }
12231f88384STejun Heo
12331f88384STejun Heo return ATA_DEFER_PORT;
12431f88384STejun Heo }
12531f88384STejun Heo
12631f88384STejun Heo /**
1273af9a77aSTejun Heo * sata_pmp_scr_read - read PSCR
1283af9a77aSTejun Heo * @link: ATA link to read PSCR for
1293af9a77aSTejun Heo * @reg: PSCR to read
1303af9a77aSTejun Heo * @r_val: resulting value
1313af9a77aSTejun Heo *
1323af9a77aSTejun Heo * Read PSCR @reg into @r_val for @link, to be called from
1333af9a77aSTejun Heo * ata_scr_read().
1343af9a77aSTejun Heo *
1353af9a77aSTejun Heo * LOCKING:
1363af9a77aSTejun Heo * Kernel thread context (may sleep).
1373af9a77aSTejun Heo *
1383af9a77aSTejun Heo * RETURNS:
1393af9a77aSTejun Heo * 0 on success, -errno on failure.
1403af9a77aSTejun Heo */
sata_pmp_scr_read(struct ata_link * link,int reg,u32 * r_val)1413af9a77aSTejun Heo int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val)
1423af9a77aSTejun Heo {
143b06ce3e5STejun Heo unsigned int err_mask;
144b06ce3e5STejun Heo
1453af9a77aSTejun Heo if (reg > SATA_PMP_PSCR_CONTROL)
1463af9a77aSTejun Heo return -EINVAL;
1473af9a77aSTejun Heo
148b06ce3e5STejun Heo err_mask = sata_pmp_read(link, reg, r_val);
149b06ce3e5STejun Heo if (err_mask) {
150a9a79dfeSJoe Perches ata_link_warn(link, "failed to read SCR %d (Emask=0x%x)\n",
151a9a79dfeSJoe Perches reg, err_mask);
152b06ce3e5STejun Heo return -EIO;
153b06ce3e5STejun Heo }
154b06ce3e5STejun Heo return 0;
1553af9a77aSTejun Heo }
1563af9a77aSTejun Heo
1573af9a77aSTejun Heo /**
1583af9a77aSTejun Heo * sata_pmp_scr_write - write PSCR
1593af9a77aSTejun Heo * @link: ATA link to write PSCR for
1603af9a77aSTejun Heo * @reg: PSCR to write
1613af9a77aSTejun Heo * @val: value to be written
1623af9a77aSTejun Heo *
1633af9a77aSTejun Heo * Write @val to PSCR @reg for @link, to be called from
1643af9a77aSTejun Heo * ata_scr_write() and ata_scr_write_flush().
1653af9a77aSTejun Heo *
1663af9a77aSTejun Heo * LOCKING:
1673af9a77aSTejun Heo * Kernel thread context (may sleep).
1683af9a77aSTejun Heo *
1693af9a77aSTejun Heo * RETURNS:
1703af9a77aSTejun Heo * 0 on success, -errno on failure.
1713af9a77aSTejun Heo */
sata_pmp_scr_write(struct ata_link * link,int reg,u32 val)1723af9a77aSTejun Heo int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
1733af9a77aSTejun Heo {
174b06ce3e5STejun Heo unsigned int err_mask;
175b06ce3e5STejun Heo
1763af9a77aSTejun Heo if (reg > SATA_PMP_PSCR_CONTROL)
1773af9a77aSTejun Heo return -EINVAL;
1783af9a77aSTejun Heo
179b06ce3e5STejun Heo err_mask = sata_pmp_write(link, reg, val);
180b06ce3e5STejun Heo if (err_mask) {
181a9a79dfeSJoe Perches ata_link_warn(link, "failed to write SCR %d (Emask=0x%x)\n",
182a9a79dfeSJoe Perches reg, err_mask);
183b06ce3e5STejun Heo return -EIO;
184b06ce3e5STejun Heo }
185b06ce3e5STejun Heo return 0;
1863af9a77aSTejun Heo }
1873af9a77aSTejun Heo
1883af9a77aSTejun Heo /**
1896c8ea89cSTejun Heo * sata_pmp_set_lpm - configure LPM for a PMP link
1906c8ea89cSTejun Heo * @link: PMP link to configure LPM for
1916c8ea89cSTejun Heo * @policy: target LPM policy
1926c8ea89cSTejun Heo * @hints: LPM hints
1936c8ea89cSTejun Heo *
1946c8ea89cSTejun Heo * Configure LPM for @link. This function will contain any PMP
1956c8ea89cSTejun Heo * specific workarounds if necessary.
1966c8ea89cSTejun Heo *
1976c8ea89cSTejun Heo * LOCKING:
1986c8ea89cSTejun Heo * EH context.
1996c8ea89cSTejun Heo *
2006c8ea89cSTejun Heo * RETURNS:
2016c8ea89cSTejun Heo * 0 on success, -errno on failure.
2026c8ea89cSTejun Heo */
sata_pmp_set_lpm(struct ata_link * link,enum ata_lpm_policy policy,unsigned hints)2036c8ea89cSTejun Heo int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
2046c8ea89cSTejun Heo unsigned hints)
2056c8ea89cSTejun Heo {
2066c8ea89cSTejun Heo return sata_link_scr_lpm(link, policy, true);
2076c8ea89cSTejun Heo }
2086c8ea89cSTejun Heo
2096c8ea89cSTejun Heo /**
2103af9a77aSTejun Heo * sata_pmp_read_gscr - read GSCR block of SATA PMP
2113af9a77aSTejun Heo * @dev: PMP device
2123af9a77aSTejun Heo * @gscr: buffer to read GSCR block into
2133af9a77aSTejun Heo *
2143af9a77aSTejun Heo * Read selected PMP GSCRs from the PMP at @dev. This will serve
2153af9a77aSTejun Heo * as configuration and identification info for the PMP.
2163af9a77aSTejun Heo *
2173af9a77aSTejun Heo * LOCKING:
2183af9a77aSTejun Heo * Kernel thread context (may sleep).
2193af9a77aSTejun Heo *
2203af9a77aSTejun Heo * RETURNS:
2213af9a77aSTejun Heo * 0 on success, -errno on failure.
2223af9a77aSTejun Heo */
sata_pmp_read_gscr(struct ata_device * dev,u32 * gscr)2233af9a77aSTejun Heo static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr)
2243af9a77aSTejun Heo {
2253af9a77aSTejun Heo static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 };
226b06ce3e5STejun Heo int i;
2273af9a77aSTejun Heo
2283af9a77aSTejun Heo for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) {
2293af9a77aSTejun Heo int reg = gscr_to_read[i];
230b06ce3e5STejun Heo unsigned int err_mask;
2313af9a77aSTejun Heo
232b06ce3e5STejun Heo err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]);
233b06ce3e5STejun Heo if (err_mask) {
234a9a79dfeSJoe Perches ata_dev_err(dev, "failed to read PMP GSCR[%d] (Emask=0x%x)\n",
235a9a79dfeSJoe Perches reg, err_mask);
236b06ce3e5STejun Heo return -EIO;
2373af9a77aSTejun Heo }
2383af9a77aSTejun Heo }
2393af9a77aSTejun Heo
2403af9a77aSTejun Heo return 0;
2413af9a77aSTejun Heo }
2423af9a77aSTejun Heo
sata_pmp_spec_rev_str(const u32 * gscr)2433af9a77aSTejun Heo static const char *sata_pmp_spec_rev_str(const u32 *gscr)
2443af9a77aSTejun Heo {
2453af9a77aSTejun Heo u32 rev = gscr[SATA_PMP_GSCR_REV];
2463af9a77aSTejun Heo
247deeb003eSShane Huang if (rev & (1 << 3))
248deeb003eSShane Huang return "1.2";
2493af9a77aSTejun Heo if (rev & (1 << 2))
2503af9a77aSTejun Heo return "1.1";
2513af9a77aSTejun Heo if (rev & (1 << 1))
2523af9a77aSTejun Heo return "1.0";
2533af9a77aSTejun Heo return "<unknown>";
2543af9a77aSTejun Heo }
2553af9a77aSTejun Heo
2564f2c7748SGrant Grundler #define PMP_GSCR_SII_POL 129
2574f2c7748SGrant Grundler
sata_pmp_configure(struct ata_device * dev,int print_info)2583af9a77aSTejun Heo static int sata_pmp_configure(struct ata_device *dev, int print_info)
2593af9a77aSTejun Heo {
2603af9a77aSTejun Heo struct ata_port *ap = dev->link->ap;
2613af9a77aSTejun Heo u32 *gscr = dev->gscr;
2624f2c7748SGrant Grundler u16 vendor = sata_pmp_gscr_vendor(gscr);
2634f2c7748SGrant Grundler u16 devid = sata_pmp_gscr_devid(gscr);
264b06ce3e5STejun Heo unsigned int err_mask = 0;
2653af9a77aSTejun Heo const char *reason;
2663af9a77aSTejun Heo int nr_ports, rc;
2673af9a77aSTejun Heo
2683af9a77aSTejun Heo nr_ports = sata_pmp_gscr_ports(gscr);
2693af9a77aSTejun Heo
2703af9a77aSTejun Heo if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) {
2713af9a77aSTejun Heo rc = -EINVAL;
2723af9a77aSTejun Heo reason = "invalid nr_ports";
2733af9a77aSTejun Heo goto fail;
2743af9a77aSTejun Heo }
2753af9a77aSTejun Heo
2763af9a77aSTejun Heo if ((ap->flags & ATA_FLAG_AN) &&
2773af9a77aSTejun Heo (gscr[SATA_PMP_GSCR_FEAT] & SATA_PMP_FEAT_NOTIFY))
2783af9a77aSTejun Heo dev->flags |= ATA_DFLAG_AN;
2793af9a77aSTejun Heo
2803af9a77aSTejun Heo /* monitor SERR_PHYRDY_CHG on fan-out ports */
281b06ce3e5STejun Heo err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN,
282b06ce3e5STejun Heo SERR_PHYRDY_CHG);
283b06ce3e5STejun Heo if (err_mask) {
284b06ce3e5STejun Heo rc = -EIO;
2853af9a77aSTejun Heo reason = "failed to write GSCR_ERROR_EN";
2863af9a77aSTejun Heo goto fail;
2873af9a77aSTejun Heo }
2883af9a77aSTejun Heo
2894f2c7748SGrant Grundler /* Disable sending Early R_OK.
2904f2c7748SGrant Grundler * With "cached read" HDD testing and multiple ports busy on a SATA
2918ffff94dSTerry Suereth * host controller, 3x26 PMP will very rarely drop a deferred
2924f2c7748SGrant Grundler * R_OK that was intended for the host. Symptom will be all
2934f2c7748SGrant Grundler * 5 drives under test will timeout, get reset, and recover.
2944f2c7748SGrant Grundler */
2958ffff94dSTerry Suereth if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
2964f2c7748SGrant Grundler u32 reg;
2974f2c7748SGrant Grundler
2984f2c7748SGrant Grundler err_mask = sata_pmp_read(&ap->link, PMP_GSCR_SII_POL, ®);
2994f2c7748SGrant Grundler if (err_mask) {
3004f2c7748SGrant Grundler rc = -EIO;
3018ffff94dSTerry Suereth reason = "failed to read Sil3x26 Private Register";
3024f2c7748SGrant Grundler goto fail;
3034f2c7748SGrant Grundler }
3044f2c7748SGrant Grundler reg &= ~0x1;
3054f2c7748SGrant Grundler err_mask = sata_pmp_write(&ap->link, PMP_GSCR_SII_POL, reg);
3064f2c7748SGrant Grundler if (err_mask) {
3074f2c7748SGrant Grundler rc = -EIO;
3088ffff94dSTerry Suereth reason = "failed to write Sil3x26 Private Register";
3094f2c7748SGrant Grundler goto fail;
3104f2c7748SGrant Grundler }
3114f2c7748SGrant Grundler }
3124f2c7748SGrant Grundler
3133af9a77aSTejun Heo if (print_info) {
314a9a79dfeSJoe Perches ata_dev_info(dev, "Port Multiplier %s, "
3153af9a77aSTejun Heo "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
3164f2c7748SGrant Grundler sata_pmp_spec_rev_str(gscr), vendor, devid,
3173af9a77aSTejun Heo sata_pmp_gscr_rev(gscr),
3183af9a77aSTejun Heo nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN],
3193af9a77aSTejun Heo gscr[SATA_PMP_GSCR_FEAT]);
3203af9a77aSTejun Heo
3213af9a77aSTejun Heo if (!(dev->flags & ATA_DFLAG_AN))
322a9a79dfeSJoe Perches ata_dev_info(dev,
3233af9a77aSTejun Heo "Asynchronous notification not supported, "
324a9a79dfeSJoe Perches "hotplug won't work on fan-out ports. Use warm-plug instead.\n");
3253af9a77aSTejun Heo }
3263af9a77aSTejun Heo
3273af9a77aSTejun Heo return 0;
3283af9a77aSTejun Heo
3293af9a77aSTejun Heo fail:
330a9a79dfeSJoe Perches ata_dev_err(dev,
331b06ce3e5STejun Heo "failed to configure Port Multiplier (%s, Emask=0x%x)\n",
332b06ce3e5STejun Heo reason, err_mask);
3333af9a77aSTejun Heo return rc;
3343af9a77aSTejun Heo }
3353af9a77aSTejun Heo
sata_pmp_init_links(struct ata_port * ap,int nr_ports)3363af9a77aSTejun Heo static int sata_pmp_init_links (struct ata_port *ap, int nr_ports)
3373af9a77aSTejun Heo {
3383af9a77aSTejun Heo struct ata_link *pmp_link = ap->pmp_link;
339d9027470SGwendal Grignou int i, err;
3403af9a77aSTejun Heo
3413af9a77aSTejun Heo if (!pmp_link) {
3426396bb22SKees Cook pmp_link = kcalloc(SATA_PMP_MAX_PORTS, sizeof(pmp_link[0]),
3433af9a77aSTejun Heo GFP_NOIO);
3443af9a77aSTejun Heo if (!pmp_link)
3453af9a77aSTejun Heo return -ENOMEM;
3463af9a77aSTejun Heo
3473af9a77aSTejun Heo for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
3483af9a77aSTejun Heo ata_link_init(ap, &pmp_link[i], i);
3493af9a77aSTejun Heo
3503af9a77aSTejun Heo ap->pmp_link = pmp_link;
351d9027470SGwendal Grignou
352d9027470SGwendal Grignou for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
353d9027470SGwendal Grignou err = ata_tlink_add(&pmp_link[i]);
354d9027470SGwendal Grignou if (err) {
355d9027470SGwendal Grignou goto err_tlink;
356d9027470SGwendal Grignou }
357d9027470SGwendal Grignou }
3583af9a77aSTejun Heo }
3593af9a77aSTejun Heo
3603af9a77aSTejun Heo for (i = 0; i < nr_ports; i++) {
3613af9a77aSTejun Heo struct ata_link *link = &pmp_link[i];
3623af9a77aSTejun Heo struct ata_eh_context *ehc = &link->eh_context;
3633af9a77aSTejun Heo
3643af9a77aSTejun Heo link->flags = 0;
365b558edddSTejun Heo ehc->i.probe_mask |= ATA_ALL_DEVICES;
366cf480626STejun Heo ehc->i.action |= ATA_EH_RESET;
3673af9a77aSTejun Heo }
3683af9a77aSTejun Heo
3693af9a77aSTejun Heo return 0;
370d9027470SGwendal Grignou err_tlink:
371d9027470SGwendal Grignou while (--i >= 0)
372d9027470SGwendal Grignou ata_tlink_delete(&pmp_link[i]);
373d9027470SGwendal Grignou kfree(pmp_link);
374d9027470SGwendal Grignou ap->pmp_link = NULL;
375d9027470SGwendal Grignou return err;
3763af9a77aSTejun Heo }
3773af9a77aSTejun Heo
sata_pmp_quirks(struct ata_port * ap)3783af9a77aSTejun Heo static void sata_pmp_quirks(struct ata_port *ap)
3793af9a77aSTejun Heo {
3803af9a77aSTejun Heo u32 *gscr = ap->link.device->gscr;
3813af9a77aSTejun Heo u16 vendor = sata_pmp_gscr_vendor(gscr);
3823af9a77aSTejun Heo u16 devid = sata_pmp_gscr_devid(gscr);
3833af9a77aSTejun Heo struct ata_link *link;
3843af9a77aSTejun Heo
3858ffff94dSTerry Suereth if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
3868ffff94dSTerry Suereth /* sil3x26 quirks */
3871eca4365STejun Heo ata_for_each_link(link, ap, EDGE) {
3886c8ea89cSTejun Heo /* link reports offline after LPM */
3896c8ea89cSTejun Heo link->flags |= ATA_LFLAG_NO_LPM;
3906c8ea89cSTejun Heo
3917a87718dSTejun Heo /*
3927a87718dSTejun Heo * Class code report is unreliable and SRST times
3937a87718dSTejun Heo * out under certain configurations.
3947a87718dSTejun Heo */
3953af9a77aSTejun Heo if (link->pmp < 5)
3967a87718dSTejun Heo link->flags |= ATA_LFLAG_NO_SRST |
3977a87718dSTejun Heo ATA_LFLAG_ASSUME_ATA;
3983af9a77aSTejun Heo
3993af9a77aSTejun Heo /* port 5 is for SEMB device and it doesn't like SRST */
4003af9a77aSTejun Heo if (link->pmp == 5)
4013af9a77aSTejun Heo link->flags |= ATA_LFLAG_NO_SRST |
4023af9a77aSTejun Heo ATA_LFLAG_ASSUME_SEMB;
4033af9a77aSTejun Heo }
4043af9a77aSTejun Heo } else if (vendor == 0x1095 && devid == 0x4723) {
4057a87718dSTejun Heo /*
4067a87718dSTejun Heo * sil4723 quirks
4077a87718dSTejun Heo *
4087a87718dSTejun Heo * Link reports offline after LPM. Class code report is
4097a87718dSTejun Heo * unreliable. SIMG PMPs never got SRST reliable and the
4107a87718dSTejun Heo * config device at port 2 locks up on SRST.
4117a87718dSTejun Heo */
4127a87718dSTejun Heo ata_for_each_link(link, ap, EDGE)
4137a87718dSTejun Heo link->flags |= ATA_LFLAG_NO_LPM |
4147a87718dSTejun Heo ATA_LFLAG_NO_SRST |
4153af9a77aSTejun Heo ATA_LFLAG_ASSUME_ATA;
4163af9a77aSTejun Heo } else if (vendor == 0x1095 && devid == 0x4726) {
4173af9a77aSTejun Heo /* sil4726 quirks */
4181eca4365STejun Heo ata_for_each_link(link, ap, EDGE) {
4196c8ea89cSTejun Heo /* link reports offline after LPM */
4206c8ea89cSTejun Heo link->flags |= ATA_LFLAG_NO_LPM;
4216c8ea89cSTejun Heo
4228048307dSTejun Heo /* Class code report is unreliable and SRST
4238048307dSTejun Heo * times out under certain configurations.
4248048307dSTejun Heo * Config device can be at port 0 or 5 and
4258048307dSTejun Heo * locks up on SRST.
4263af9a77aSTejun Heo */
4278048307dSTejun Heo if (link->pmp <= 5)
4283af9a77aSTejun Heo link->flags |= ATA_LFLAG_NO_SRST |
4293af9a77aSTejun Heo ATA_LFLAG_ASSUME_ATA;
4303af9a77aSTejun Heo
4313af9a77aSTejun Heo /* Port 6 is for SEMB device which doesn't
4323af9a77aSTejun Heo * like SRST either.
4333af9a77aSTejun Heo */
4343af9a77aSTejun Heo if (link->pmp == 6)
4353af9a77aSTejun Heo link->flags |= ATA_LFLAG_NO_SRST |
4363af9a77aSTejun Heo ATA_LFLAG_ASSUME_SEMB;
4373af9a77aSTejun Heo }
4383af9a77aSTejun Heo } else if (vendor == 0x1095 && (devid == 0x5723 || devid == 0x5733 ||
4393af9a77aSTejun Heo devid == 0x5734 || devid == 0x5744)) {
4403af9a77aSTejun Heo /* sil5723/5744 quirks */
4413af9a77aSTejun Heo
4423af9a77aSTejun Heo /* sil5723/5744 has either two or three downstream
4433af9a77aSTejun Heo * ports depending on operation mode. The last port
4443af9a77aSTejun Heo * is empty if any actual IO device is available or
4453af9a77aSTejun Heo * occupied by a pseudo configuration device
4463af9a77aSTejun Heo * otherwise. Don't try hard to recover it.
4473af9a77aSTejun Heo */
4483af9a77aSTejun Heo ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
449efb9e0f4SDenis V. Lunev } else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) {
450efb9e0f4SDenis V. Lunev /*
451efb9e0f4SDenis V. Lunev * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350?
452efb9e0f4SDenis V. Lunev * 0x0325: jmicron JMB394.
453efb9e0f4SDenis V. Lunev */
4540afc6f5bSPavel Herrmann ata_for_each_link(link, ap, EDGE) {
4550afc6f5bSPavel Herrmann /* SRST breaks detection and disks get misclassified
4560afc6f5bSPavel Herrmann * LPM disabled to avoid potential problems
4570afc6f5bSPavel Herrmann */
4580afc6f5bSPavel Herrmann link->flags |= ATA_LFLAG_NO_LPM |
4590afc6f5bSPavel Herrmann ATA_LFLAG_NO_SRST |
4600afc6f5bSPavel Herrmann ATA_LFLAG_ASSUME_ATA;
4610afc6f5bSPavel Herrmann }
462945b4744SLior Amsalem } else if (vendor == 0x11ab && devid == 0x4140) {
463945b4744SLior Amsalem /* Marvell 4140 quirks */
464945b4744SLior Amsalem ata_for_each_link(link, ap, EDGE) {
465945b4744SLior Amsalem /* port 4 is for SEMB device and it doesn't like SRST */
466945b4744SLior Amsalem if (link->pmp == 4)
467945b4744SLior Amsalem link->flags |= ATA_LFLAG_DISABLED;
468945b4744SLior Amsalem }
4693af9a77aSTejun Heo }
4703af9a77aSTejun Heo }
4713af9a77aSTejun Heo
4723af9a77aSTejun Heo /**
4733af9a77aSTejun Heo * sata_pmp_attach - attach a SATA PMP device
4743af9a77aSTejun Heo * @dev: SATA PMP device to attach
4753af9a77aSTejun Heo *
4763af9a77aSTejun Heo * Configure and attach SATA PMP device @dev. This function is
4773af9a77aSTejun Heo * also responsible for allocating and initializing PMP links.
4783af9a77aSTejun Heo *
4793af9a77aSTejun Heo * LOCKING:
4803af9a77aSTejun Heo * Kernel thread context (may sleep).
4813af9a77aSTejun Heo *
4823af9a77aSTejun Heo * RETURNS:
4833af9a77aSTejun Heo * 0 on success, -errno on failure.
4843af9a77aSTejun Heo */
sata_pmp_attach(struct ata_device * dev)4853af9a77aSTejun Heo int sata_pmp_attach(struct ata_device *dev)
4863af9a77aSTejun Heo {
4873af9a77aSTejun Heo struct ata_link *link = dev->link;
4883af9a77aSTejun Heo struct ata_port *ap = link->ap;
4893af9a77aSTejun Heo unsigned long flags;
4903af9a77aSTejun Heo struct ata_link *tlink;
4913af9a77aSTejun Heo int rc;
4923af9a77aSTejun Heo
4933af9a77aSTejun Heo /* is it hanging off the right place? */
494071f44b1STejun Heo if (!sata_pmp_supported(ap)) {
495a9a79dfeSJoe Perches ata_dev_err(dev, "host does not support Port Multiplier\n");
4963af9a77aSTejun Heo return -EINVAL;
4973af9a77aSTejun Heo }
4983af9a77aSTejun Heo
4993af9a77aSTejun Heo if (!ata_is_host_link(link)) {
500a9a79dfeSJoe Perches ata_dev_err(dev, "Port Multipliers cannot be nested\n");
5013af9a77aSTejun Heo return -EINVAL;
5023af9a77aSTejun Heo }
5033af9a77aSTejun Heo
5043af9a77aSTejun Heo if (dev->devno) {
505a9a79dfeSJoe Perches ata_dev_err(dev, "Port Multiplier must be the first device\n");
5063af9a77aSTejun Heo return -EINVAL;
5073af9a77aSTejun Heo }
5083af9a77aSTejun Heo
5093af9a77aSTejun Heo WARN_ON(link->pmp != 0);
5103af9a77aSTejun Heo link->pmp = SATA_PMP_CTRL_PORT;
5113af9a77aSTejun Heo
5123af9a77aSTejun Heo /* read GSCR block */
5133af9a77aSTejun Heo rc = sata_pmp_read_gscr(dev, dev->gscr);
5143af9a77aSTejun Heo if (rc)
5153af9a77aSTejun Heo goto fail;
5163af9a77aSTejun Heo
5173af9a77aSTejun Heo /* config PMP */
5183af9a77aSTejun Heo rc = sata_pmp_configure(dev, 1);
5193af9a77aSTejun Heo if (rc)
5203af9a77aSTejun Heo goto fail;
5213af9a77aSTejun Heo
5223af9a77aSTejun Heo rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr));
5233af9a77aSTejun Heo if (rc) {
524a9a79dfeSJoe Perches ata_dev_info(dev, "failed to initialize PMP links\n");
5253af9a77aSTejun Heo goto fail;
5263af9a77aSTejun Heo }
5273af9a77aSTejun Heo
5283af9a77aSTejun Heo /* attach it */
5293af9a77aSTejun Heo spin_lock_irqsave(ap->lock, flags);
5303af9a77aSTejun Heo WARN_ON(ap->nr_pmp_links);
5313af9a77aSTejun Heo ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr);
5323af9a77aSTejun Heo spin_unlock_irqrestore(ap->lock, flags);
5333af9a77aSTejun Heo
5343af9a77aSTejun Heo sata_pmp_quirks(ap);
5353af9a77aSTejun Heo
5363af9a77aSTejun Heo if (ap->ops->pmp_attach)
5373af9a77aSTejun Heo ap->ops->pmp_attach(ap);
5383af9a77aSTejun Heo
5391eca4365STejun Heo ata_for_each_link(tlink, ap, EDGE)
5403af9a77aSTejun Heo sata_link_init_spd(tlink);
5413af9a77aSTejun Heo
5423af9a77aSTejun Heo return 0;
5433af9a77aSTejun Heo
5443af9a77aSTejun Heo fail:
5453af9a77aSTejun Heo link->pmp = 0;
5463af9a77aSTejun Heo return rc;
5473af9a77aSTejun Heo }
5483af9a77aSTejun Heo
5493af9a77aSTejun Heo /**
5503af9a77aSTejun Heo * sata_pmp_detach - detach a SATA PMP device
5513af9a77aSTejun Heo * @dev: SATA PMP device to detach
5523af9a77aSTejun Heo *
5533af9a77aSTejun Heo * Detach SATA PMP device @dev. This function is also
5543af9a77aSTejun Heo * responsible for deconfiguring PMP links.
5553af9a77aSTejun Heo *
5563af9a77aSTejun Heo * LOCKING:
5573af9a77aSTejun Heo * Kernel thread context (may sleep).
5583af9a77aSTejun Heo */
sata_pmp_detach(struct ata_device * dev)5593af9a77aSTejun Heo static void sata_pmp_detach(struct ata_device *dev)
5603af9a77aSTejun Heo {
5613af9a77aSTejun Heo struct ata_link *link = dev->link;
5623af9a77aSTejun Heo struct ata_port *ap = link->ap;
5633af9a77aSTejun Heo struct ata_link *tlink;
5643af9a77aSTejun Heo unsigned long flags;
5653af9a77aSTejun Heo
566a9a79dfeSJoe Perches ata_dev_info(dev, "Port Multiplier detaching\n");
5673af9a77aSTejun Heo
5683af9a77aSTejun Heo WARN_ON(!ata_is_host_link(link) || dev->devno ||
5693af9a77aSTejun Heo link->pmp != SATA_PMP_CTRL_PORT);
5703af9a77aSTejun Heo
5713af9a77aSTejun Heo if (ap->ops->pmp_detach)
5723af9a77aSTejun Heo ap->ops->pmp_detach(ap);
5733af9a77aSTejun Heo
5741eca4365STejun Heo ata_for_each_link(tlink, ap, EDGE)
5753af9a77aSTejun Heo ata_eh_detach_dev(tlink->device);
5763af9a77aSTejun Heo
5773af9a77aSTejun Heo spin_lock_irqsave(ap->lock, flags);
5783af9a77aSTejun Heo ap->nr_pmp_links = 0;
5793af9a77aSTejun Heo link->pmp = 0;
5803af9a77aSTejun Heo spin_unlock_irqrestore(ap->lock, flags);
5813af9a77aSTejun Heo }
5823af9a77aSTejun Heo
5833af9a77aSTejun Heo /**
5843af9a77aSTejun Heo * sata_pmp_same_pmp - does new GSCR matches the configured PMP?
5853af9a77aSTejun Heo * @dev: PMP device to compare against
5863af9a77aSTejun Heo * @new_gscr: GSCR block of the new device
5873af9a77aSTejun Heo *
5883af9a77aSTejun Heo * Compare @new_gscr against @dev and determine whether @dev is
5893af9a77aSTejun Heo * the PMP described by @new_gscr.
5903af9a77aSTejun Heo *
5913af9a77aSTejun Heo * LOCKING:
5923af9a77aSTejun Heo * None.
5933af9a77aSTejun Heo *
5943af9a77aSTejun Heo * RETURNS:
5953af9a77aSTejun Heo * 1 if @dev matches @new_gscr, 0 otherwise.
5963af9a77aSTejun Heo */
sata_pmp_same_pmp(struct ata_device * dev,const u32 * new_gscr)5973af9a77aSTejun Heo static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr)
5983af9a77aSTejun Heo {
5993af9a77aSTejun Heo const u32 *old_gscr = dev->gscr;
6003af9a77aSTejun Heo u16 old_vendor, new_vendor, old_devid, new_devid;
6013af9a77aSTejun Heo int old_nr_ports, new_nr_ports;
6023af9a77aSTejun Heo
6033af9a77aSTejun Heo old_vendor = sata_pmp_gscr_vendor(old_gscr);
6043af9a77aSTejun Heo new_vendor = sata_pmp_gscr_vendor(new_gscr);
6053af9a77aSTejun Heo old_devid = sata_pmp_gscr_devid(old_gscr);
6063af9a77aSTejun Heo new_devid = sata_pmp_gscr_devid(new_gscr);
6073af9a77aSTejun Heo old_nr_ports = sata_pmp_gscr_ports(old_gscr);
6083af9a77aSTejun Heo new_nr_ports = sata_pmp_gscr_ports(new_gscr);
6093af9a77aSTejun Heo
6103af9a77aSTejun Heo if (old_vendor != new_vendor) {
611a9a79dfeSJoe Perches ata_dev_info(dev,
612a9a79dfeSJoe Perches "Port Multiplier vendor mismatch '0x%x' != '0x%x'\n",
6133af9a77aSTejun Heo old_vendor, new_vendor);
6143af9a77aSTejun Heo return 0;
6153af9a77aSTejun Heo }
6163af9a77aSTejun Heo
6173af9a77aSTejun Heo if (old_devid != new_devid) {
618a9a79dfeSJoe Perches ata_dev_info(dev,
619a9a79dfeSJoe Perches "Port Multiplier device ID mismatch '0x%x' != '0x%x'\n",
6203af9a77aSTejun Heo old_devid, new_devid);
6213af9a77aSTejun Heo return 0;
6223af9a77aSTejun Heo }
6233af9a77aSTejun Heo
6243af9a77aSTejun Heo if (old_nr_ports != new_nr_ports) {
625a9a79dfeSJoe Perches ata_dev_info(dev,
626a9a79dfeSJoe Perches "Port Multiplier nr_ports mismatch '0x%x' != '0x%x'\n",
6273af9a77aSTejun Heo old_nr_ports, new_nr_ports);
6283af9a77aSTejun Heo return 0;
6293af9a77aSTejun Heo }
6303af9a77aSTejun Heo
6313af9a77aSTejun Heo return 1;
6323af9a77aSTejun Heo }
6333af9a77aSTejun Heo
6343af9a77aSTejun Heo /**
6353af9a77aSTejun Heo * sata_pmp_revalidate - revalidate SATA PMP
6363af9a77aSTejun Heo * @dev: PMP device to revalidate
6373af9a77aSTejun Heo * @new_class: new class code
6383af9a77aSTejun Heo *
6393af9a77aSTejun Heo * Re-read GSCR block and make sure @dev is still attached to the
6403af9a77aSTejun Heo * port and properly configured.
6413af9a77aSTejun Heo *
6423af9a77aSTejun Heo * LOCKING:
6433af9a77aSTejun Heo * Kernel thread context (may sleep).
6443af9a77aSTejun Heo *
6453af9a77aSTejun Heo * RETURNS:
6463af9a77aSTejun Heo * 0 on success, -errno otherwise.
6473af9a77aSTejun Heo */
sata_pmp_revalidate(struct ata_device * dev,unsigned int new_class)6483af9a77aSTejun Heo static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class)
6493af9a77aSTejun Heo {
6503af9a77aSTejun Heo struct ata_link *link = dev->link;
6513af9a77aSTejun Heo struct ata_port *ap = link->ap;
6523af9a77aSTejun Heo u32 *gscr = (void *)ap->sector_buf;
6533af9a77aSTejun Heo int rc;
6543af9a77aSTejun Heo
6553af9a77aSTejun Heo ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE);
6563af9a77aSTejun Heo
6573af9a77aSTejun Heo if (!ata_dev_enabled(dev)) {
6583af9a77aSTejun Heo rc = -ENODEV;
6593af9a77aSTejun Heo goto fail;
6603af9a77aSTejun Heo }
6613af9a77aSTejun Heo
6623af9a77aSTejun Heo /* wrong class? */
6633af9a77aSTejun Heo if (ata_class_enabled(new_class) && new_class != ATA_DEV_PMP) {
6643af9a77aSTejun Heo rc = -ENODEV;
6653af9a77aSTejun Heo goto fail;
6663af9a77aSTejun Heo }
6673af9a77aSTejun Heo
6683af9a77aSTejun Heo /* read GSCR */
6693af9a77aSTejun Heo rc = sata_pmp_read_gscr(dev, gscr);
6703af9a77aSTejun Heo if (rc)
6713af9a77aSTejun Heo goto fail;
6723af9a77aSTejun Heo
6733af9a77aSTejun Heo /* is the pmp still there? */
6743af9a77aSTejun Heo if (!sata_pmp_same_pmp(dev, gscr)) {
6753af9a77aSTejun Heo rc = -ENODEV;
6763af9a77aSTejun Heo goto fail;
6773af9a77aSTejun Heo }
6783af9a77aSTejun Heo
6793af9a77aSTejun Heo memcpy(dev->gscr, gscr, sizeof(gscr[0]) * SATA_PMP_GSCR_DWORDS);
6803af9a77aSTejun Heo
6813af9a77aSTejun Heo rc = sata_pmp_configure(dev, 0);
6823af9a77aSTejun Heo if (rc)
6833af9a77aSTejun Heo goto fail;
6843af9a77aSTejun Heo
6853af9a77aSTejun Heo ata_eh_done(link, NULL, ATA_EH_REVALIDATE);
6863af9a77aSTejun Heo
6873af9a77aSTejun Heo return 0;
6883af9a77aSTejun Heo
6893af9a77aSTejun Heo fail:
690a9a79dfeSJoe Perches ata_dev_err(dev, "PMP revalidation failed (errno=%d)\n", rc);
6913af9a77aSTejun Heo return rc;
6923af9a77aSTejun Heo }
6933af9a77aSTejun Heo
6943af9a77aSTejun Heo /**
6953af9a77aSTejun Heo * sata_pmp_revalidate_quick - revalidate SATA PMP quickly
6963af9a77aSTejun Heo * @dev: PMP device to revalidate
6973af9a77aSTejun Heo *
6983af9a77aSTejun Heo * Make sure the attached PMP is accessible.
6993af9a77aSTejun Heo *
7003af9a77aSTejun Heo * LOCKING:
7013af9a77aSTejun Heo * Kernel thread context (may sleep).
7023af9a77aSTejun Heo *
7033af9a77aSTejun Heo * RETURNS:
7043af9a77aSTejun Heo * 0 on success, -errno otherwise.
7053af9a77aSTejun Heo */
sata_pmp_revalidate_quick(struct ata_device * dev)7063af9a77aSTejun Heo static int sata_pmp_revalidate_quick(struct ata_device *dev)
7073af9a77aSTejun Heo {
708b06ce3e5STejun Heo unsigned int err_mask;
7093af9a77aSTejun Heo u32 prod_id;
7103af9a77aSTejun Heo
711b06ce3e5STejun Heo err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id);
712b06ce3e5STejun Heo if (err_mask) {
713a9a79dfeSJoe Perches ata_dev_err(dev,
714a9a79dfeSJoe Perches "failed to read PMP product ID (Emask=0x%x)\n",
715a9a79dfeSJoe Perches err_mask);
716b06ce3e5STejun Heo return -EIO;
7173af9a77aSTejun Heo }
7183af9a77aSTejun Heo
7193af9a77aSTejun Heo if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) {
720a9a79dfeSJoe Perches ata_dev_err(dev, "PMP product ID mismatch\n");
7213af9a77aSTejun Heo /* something weird is going on, request full PMP recovery */
7223af9a77aSTejun Heo return -EIO;
7233af9a77aSTejun Heo }
7243af9a77aSTejun Heo
7253af9a77aSTejun Heo return 0;
7263af9a77aSTejun Heo }
7273af9a77aSTejun Heo
7283af9a77aSTejun Heo /**
7293af9a77aSTejun Heo * sata_pmp_eh_recover_pmp - recover PMP
7303af9a77aSTejun Heo * @ap: ATA port PMP is attached to
7313af9a77aSTejun Heo * @prereset: prereset method (can be NULL)
7323af9a77aSTejun Heo * @softreset: softreset method
7333af9a77aSTejun Heo * @hardreset: hardreset method
7343af9a77aSTejun Heo * @postreset: postreset method (can be NULL)
7353af9a77aSTejun Heo *
7363af9a77aSTejun Heo * Recover PMP attached to @ap. Recovery procedure is somewhat
7373af9a77aSTejun Heo * similar to that of ata_eh_recover() except that reset should
7383af9a77aSTejun Heo * always be performed in hard->soft sequence and recovery
7393af9a77aSTejun Heo * failure results in PMP detachment.
7403af9a77aSTejun Heo *
7413af9a77aSTejun Heo * LOCKING:
7423af9a77aSTejun Heo * Kernel thread context (may sleep).
7433af9a77aSTejun Heo *
7443af9a77aSTejun Heo * RETURNS:
7453af9a77aSTejun Heo * 0 on success, -errno on failure.
7463af9a77aSTejun Heo */
sata_pmp_eh_recover_pmp(struct ata_port * ap,ata_prereset_fn_t prereset,ata_reset_fn_t softreset,ata_reset_fn_t hardreset,ata_postreset_fn_t postreset)7473af9a77aSTejun Heo static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
7483af9a77aSTejun Heo ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
7493af9a77aSTejun Heo ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
7503af9a77aSTejun Heo {
7513af9a77aSTejun Heo struct ata_link *link = &ap->link;
7523af9a77aSTejun Heo struct ata_eh_context *ehc = &link->eh_context;
7533af9a77aSTejun Heo struct ata_device *dev = link->device;
7543af9a77aSTejun Heo int tries = ATA_EH_PMP_TRIES;
7553af9a77aSTejun Heo int detach = 0, rc = 0;
7563af9a77aSTejun Heo int reval_failed = 0;
7573af9a77aSTejun Heo
7583af9a77aSTejun Heo if (dev->flags & ATA_DFLAG_DETACH) {
7593af9a77aSTejun Heo detach = 1;
7608305f72fSKai-Heng Feng rc = -ENODEV;
7613af9a77aSTejun Heo goto fail;
7623af9a77aSTejun Heo }
7633af9a77aSTejun Heo
7643af9a77aSTejun Heo retry:
7653af9a77aSTejun Heo ehc->classes[0] = ATA_DEV_UNKNOWN;
7663af9a77aSTejun Heo
767cf480626STejun Heo if (ehc->i.action & ATA_EH_RESET) {
7683af9a77aSTejun Heo struct ata_link *tlink;
7693af9a77aSTejun Heo
7703af9a77aSTejun Heo /* reset */
7713af9a77aSTejun Heo rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
7723af9a77aSTejun Heo postreset);
7733af9a77aSTejun Heo if (rc) {
774a9a79dfeSJoe Perches ata_link_err(link, "failed to reset PMP, giving up\n");
7753af9a77aSTejun Heo goto fail;
7763af9a77aSTejun Heo }
7773af9a77aSTejun Heo
7783af9a77aSTejun Heo /* PMP is reset, SErrors cannot be trusted, scan all */
7791eca4365STejun Heo ata_for_each_link(tlink, ap, EDGE) {
780b558edddSTejun Heo struct ata_eh_context *ehc = &tlink->eh_context;
781b558edddSTejun Heo
782b558edddSTejun Heo ehc->i.probe_mask |= ATA_ALL_DEVICES;
783b558edddSTejun Heo ehc->i.action |= ATA_EH_RESET;
784b558edddSTejun Heo }
7853af9a77aSTejun Heo }
7863af9a77aSTejun Heo
7873af9a77aSTejun Heo /* If revalidation is requested, revalidate and reconfigure;
7883af9a77aSTejun Heo * otherwise, do quick revalidation.
7893af9a77aSTejun Heo */
7903af9a77aSTejun Heo if (ehc->i.action & ATA_EH_REVALIDATE)
7913af9a77aSTejun Heo rc = sata_pmp_revalidate(dev, ehc->classes[0]);
7923af9a77aSTejun Heo else
7933af9a77aSTejun Heo rc = sata_pmp_revalidate_quick(dev);
7943af9a77aSTejun Heo
7953af9a77aSTejun Heo if (rc) {
7963af9a77aSTejun Heo tries--;
7973af9a77aSTejun Heo
7983af9a77aSTejun Heo if (rc == -ENODEV) {
799b558edddSTejun Heo ehc->i.probe_mask |= ATA_ALL_DEVICES;
8003af9a77aSTejun Heo detach = 1;
8013af9a77aSTejun Heo /* give it just two more chances */
8023af9a77aSTejun Heo tries = min(tries, 2);
8033af9a77aSTejun Heo }
8043af9a77aSTejun Heo
8053af9a77aSTejun Heo if (tries) {
8063af9a77aSTejun Heo /* consecutive revalidation failures? speed down */
8073af9a77aSTejun Heo if (reval_failed)
808a07d499bSTejun Heo sata_down_spd_limit(link, 0);
8093af9a77aSTejun Heo else
8103af9a77aSTejun Heo reval_failed = 1;
8113af9a77aSTejun Heo
812cf480626STejun Heo ehc->i.action |= ATA_EH_RESET;
8133af9a77aSTejun Heo goto retry;
8143af9a77aSTejun Heo } else {
815a9a79dfeSJoe Perches ata_dev_err(dev,
816a9a79dfeSJoe Perches "failed to recover PMP after %d tries, giving up\n",
8173af9a77aSTejun Heo ATA_EH_PMP_TRIES);
8183af9a77aSTejun Heo goto fail;
8193af9a77aSTejun Heo }
8203af9a77aSTejun Heo }
8213af9a77aSTejun Heo
8223af9a77aSTejun Heo /* okay, PMP resurrected */
8233af9a77aSTejun Heo ehc->i.flags = 0;
8243af9a77aSTejun Heo
8253af9a77aSTejun Heo return 0;
8263af9a77aSTejun Heo
8273af9a77aSTejun Heo fail:
8283af9a77aSTejun Heo sata_pmp_detach(dev);
8293af9a77aSTejun Heo if (detach)
8303af9a77aSTejun Heo ata_eh_detach_dev(dev);
8313af9a77aSTejun Heo else
8323af9a77aSTejun Heo ata_dev_disable(dev);
8333af9a77aSTejun Heo
8343af9a77aSTejun Heo return rc;
8353af9a77aSTejun Heo }
8363af9a77aSTejun Heo
sata_pmp_eh_handle_disabled_links(struct ata_port * ap)8373af9a77aSTejun Heo static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
8383af9a77aSTejun Heo {
8393af9a77aSTejun Heo struct ata_link *link;
8403af9a77aSTejun Heo unsigned long flags;
8413af9a77aSTejun Heo int rc;
8423af9a77aSTejun Heo
8433af9a77aSTejun Heo spin_lock_irqsave(ap->lock, flags);
8443af9a77aSTejun Heo
8451eca4365STejun Heo ata_for_each_link(link, ap, EDGE) {
8463af9a77aSTejun Heo if (!(link->flags & ATA_LFLAG_DISABLED))
8473af9a77aSTejun Heo continue;
8483af9a77aSTejun Heo
8493af9a77aSTejun Heo spin_unlock_irqrestore(ap->lock, flags);
8503af9a77aSTejun Heo
8513af9a77aSTejun Heo /* Some PMPs require hardreset sequence to get
8523af9a77aSTejun Heo * SError.N working.
8533af9a77aSTejun Heo */
8543af9a77aSTejun Heo sata_link_hardreset(link, sata_deb_timing_normal,
855341c2c95STejun Heo ata_deadline(jiffies, ATA_TMOUT_INTERNAL_QUICK),
856341c2c95STejun Heo NULL, NULL);
8573af9a77aSTejun Heo
8583af9a77aSTejun Heo /* unconditionally clear SError.N */
8593af9a77aSTejun Heo rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
8603af9a77aSTejun Heo if (rc) {
861a9a79dfeSJoe Perches ata_link_err(link,
862a9a79dfeSJoe Perches "failed to clear SError.N (errno=%d)\n",
863a9a79dfeSJoe Perches rc);
8643af9a77aSTejun Heo return rc;
8653af9a77aSTejun Heo }
8663af9a77aSTejun Heo
8673af9a77aSTejun Heo spin_lock_irqsave(ap->lock, flags);
8683af9a77aSTejun Heo }
8693af9a77aSTejun Heo
8703af9a77aSTejun Heo spin_unlock_irqrestore(ap->lock, flags);
8713af9a77aSTejun Heo
8723af9a77aSTejun Heo return 0;
8733af9a77aSTejun Heo }
8743af9a77aSTejun Heo
sata_pmp_handle_link_fail(struct ata_link * link,int * link_tries)8753af9a77aSTejun Heo static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries)
8763af9a77aSTejun Heo {
8773af9a77aSTejun Heo struct ata_port *ap = link->ap;
8783af9a77aSTejun Heo unsigned long flags;
8793af9a77aSTejun Heo
8803af9a77aSTejun Heo if (link_tries[link->pmp] && --link_tries[link->pmp])
8813af9a77aSTejun Heo return 1;
8823af9a77aSTejun Heo
8833af9a77aSTejun Heo /* disable this link */
8843af9a77aSTejun Heo if (!(link->flags & ATA_LFLAG_DISABLED)) {
885a9a79dfeSJoe Perches ata_link_warn(link,
8863af9a77aSTejun Heo "failed to recover link after %d tries, disabling\n",
8873af9a77aSTejun Heo ATA_EH_PMP_LINK_TRIES);
8883af9a77aSTejun Heo
8893af9a77aSTejun Heo spin_lock_irqsave(ap->lock, flags);
8903af9a77aSTejun Heo link->flags |= ATA_LFLAG_DISABLED;
8913af9a77aSTejun Heo spin_unlock_irqrestore(ap->lock, flags);
8923af9a77aSTejun Heo }
8933af9a77aSTejun Heo
8943af9a77aSTejun Heo ata_dev_disable(link->device);
8953af9a77aSTejun Heo link->eh_context.i.action = 0;
8963af9a77aSTejun Heo
8973af9a77aSTejun Heo return 0;
8983af9a77aSTejun Heo }
8993af9a77aSTejun Heo
9003af9a77aSTejun Heo /**
9013af9a77aSTejun Heo * sata_pmp_eh_recover - recover PMP-enabled port
9023af9a77aSTejun Heo * @ap: ATA port to recover
9033af9a77aSTejun Heo *
9043af9a77aSTejun Heo * Drive EH recovery operation for PMP enabled port @ap. This
9053af9a77aSTejun Heo * function recovers host and PMP ports with proper retrials and
9063af9a77aSTejun Heo * fallbacks. Actual recovery operations are performed using
9073af9a77aSTejun Heo * ata_eh_recover() and sata_pmp_eh_recover_pmp().
9083af9a77aSTejun Heo *
9093af9a77aSTejun Heo * LOCKING:
9103af9a77aSTejun Heo * Kernel thread context (may sleep).
9113af9a77aSTejun Heo *
9123af9a77aSTejun Heo * RETURNS:
9133af9a77aSTejun Heo * 0 on success, -errno on failure.
9143af9a77aSTejun Heo */
sata_pmp_eh_recover(struct ata_port * ap)915a1efdabaSTejun Heo static int sata_pmp_eh_recover(struct ata_port *ap)
9163af9a77aSTejun Heo {
917a1efdabaSTejun Heo struct ata_port_operations *ops = ap->ops;
9183af9a77aSTejun Heo int pmp_tries, link_tries[SATA_PMP_MAX_PORTS];
9193af9a77aSTejun Heo struct ata_link *pmp_link = &ap->link;
9203af9a77aSTejun Heo struct ata_device *pmp_dev = pmp_link->device;
9213af9a77aSTejun Heo struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
922f1bbfb90STejun Heo u32 *gscr = pmp_dev->gscr;
9233af9a77aSTejun Heo struct ata_link *link;
9243af9a77aSTejun Heo struct ata_device *dev;
925b06ce3e5STejun Heo unsigned int err_mask;
9263af9a77aSTejun Heo u32 gscr_error, sntf;
9273af9a77aSTejun Heo int cnt, rc;
9283af9a77aSTejun Heo
9293af9a77aSTejun Heo pmp_tries = ATA_EH_PMP_TRIES;
9301eca4365STejun Heo ata_for_each_link(link, ap, EDGE)
9313af9a77aSTejun Heo link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
9323af9a77aSTejun Heo
9333af9a77aSTejun Heo retry:
9343af9a77aSTejun Heo /* PMP attached? */
935071f44b1STejun Heo if (!sata_pmp_attached(ap)) {
936a1efdabaSTejun Heo rc = ata_eh_recover(ap, ops->prereset, ops->softreset,
937a1efdabaSTejun Heo ops->hardreset, ops->postreset, NULL);
9383af9a77aSTejun Heo if (rc) {
9391eca4365STejun Heo ata_for_each_dev(dev, &ap->link, ALL)
9403af9a77aSTejun Heo ata_dev_disable(dev);
9413af9a77aSTejun Heo return rc;
9423af9a77aSTejun Heo }
9433af9a77aSTejun Heo
9443af9a77aSTejun Heo if (pmp_dev->class != ATA_DEV_PMP)
9453af9a77aSTejun Heo return 0;
9463af9a77aSTejun Heo
9473af9a77aSTejun Heo /* new PMP online */
9481eca4365STejun Heo ata_for_each_link(link, ap, EDGE)
9493af9a77aSTejun Heo link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
9503af9a77aSTejun Heo
9513af9a77aSTejun Heo /* fall through */
9523af9a77aSTejun Heo }
9533af9a77aSTejun Heo
9543af9a77aSTejun Heo /* recover pmp */
955a1efdabaSTejun Heo rc = sata_pmp_eh_recover_pmp(ap, ops->prereset, ops->softreset,
956a1efdabaSTejun Heo ops->hardreset, ops->postreset);
9573af9a77aSTejun Heo if (rc)
9583af9a77aSTejun Heo goto pmp_fail;
9593af9a77aSTejun Heo
960f1bbfb90STejun Heo /* PHY event notification can disturb reset and other recovery
961f1bbfb90STejun Heo * operations. Turn it off.
962f1bbfb90STejun Heo */
963f1bbfb90STejun Heo if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
964f1bbfb90STejun Heo gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
965f1bbfb90STejun Heo
966f1bbfb90STejun Heo err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
967f1bbfb90STejun Heo gscr[SATA_PMP_GSCR_FEAT_EN]);
968f1bbfb90STejun Heo if (err_mask) {
969a9a79dfeSJoe Perches ata_link_warn(pmp_link,
970f1bbfb90STejun Heo "failed to disable NOTIFY (err_mask=0x%x)\n",
971f1bbfb90STejun Heo err_mask);
972f1bbfb90STejun Heo goto pmp_fail;
973f1bbfb90STejun Heo }
974f1bbfb90STejun Heo }
975f1bbfb90STejun Heo
9763af9a77aSTejun Heo /* handle disabled links */
9773af9a77aSTejun Heo rc = sata_pmp_eh_handle_disabled_links(ap);
9783af9a77aSTejun Heo if (rc)
9793af9a77aSTejun Heo goto pmp_fail;
9803af9a77aSTejun Heo
9813af9a77aSTejun Heo /* recover links */
982a1efdabaSTejun Heo rc = ata_eh_recover(ap, ops->pmp_prereset, ops->pmp_softreset,
983a1efdabaSTejun Heo ops->pmp_hardreset, ops->pmp_postreset, &link);
9843af9a77aSTejun Heo if (rc)
9853af9a77aSTejun Heo goto link_fail;
9863af9a77aSTejun Heo
9873af9a77aSTejun Heo /* clear SNotification */
9883af9a77aSTejun Heo rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
9893af9a77aSTejun Heo if (rc == 0)
9903af9a77aSTejun Heo sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
9913af9a77aSTejun Heo
9926c8ea89cSTejun Heo /*
9936c8ea89cSTejun Heo * If LPM is active on any fan-out port, hotplug wouldn't
9946c8ea89cSTejun Heo * work. Return w/ PHY event notification disabled.
9956c8ea89cSTejun Heo */
9966c8ea89cSTejun Heo ata_for_each_link(link, ap, EDGE)
9976c8ea89cSTejun Heo if (link->lpm_policy > ATA_LPM_MAX_POWER)
9986c8ea89cSTejun Heo return 0;
9996c8ea89cSTejun Heo
10006c8ea89cSTejun Heo /*
10016c8ea89cSTejun Heo * Connection status might have changed while resetting other
10026c8ea89cSTejun Heo * links, enable notification and check SATA_PMP_GSCR_ERROR
10036c8ea89cSTejun Heo * before returning.
10046c8ea89cSTejun Heo */
10056c8ea89cSTejun Heo
10063af9a77aSTejun Heo /* enable notification */
10073af9a77aSTejun Heo if (pmp_dev->flags & ATA_DFLAG_AN) {
1008f1bbfb90STejun Heo gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
10093af9a77aSTejun Heo
1010f1bbfb90STejun Heo err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
1011f1bbfb90STejun Heo gscr[SATA_PMP_GSCR_FEAT_EN]);
1012b06ce3e5STejun Heo if (err_mask) {
1013a9a79dfeSJoe Perches ata_dev_err(pmp_dev,
1014a9a79dfeSJoe Perches "failed to write PMP_FEAT_EN (Emask=0x%x)\n",
1015a9a79dfeSJoe Perches err_mask);
1016b06ce3e5STejun Heo rc = -EIO;
10173af9a77aSTejun Heo goto pmp_fail;
10183af9a77aSTejun Heo }
10193af9a77aSTejun Heo }
10203af9a77aSTejun Heo
10213af9a77aSTejun Heo /* check GSCR_ERROR */
1022b06ce3e5STejun Heo err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error);
1023b06ce3e5STejun Heo if (err_mask) {
1024a9a79dfeSJoe Perches ata_dev_err(pmp_dev,
1025a9a79dfeSJoe Perches "failed to read PMP_GSCR_ERROR (Emask=0x%x)\n",
1026a9a79dfeSJoe Perches err_mask);
1027b06ce3e5STejun Heo rc = -EIO;
10283af9a77aSTejun Heo goto pmp_fail;
10293af9a77aSTejun Heo }
10303af9a77aSTejun Heo
10313af9a77aSTejun Heo cnt = 0;
10321eca4365STejun Heo ata_for_each_link(link, ap, EDGE) {
10333af9a77aSTejun Heo if (!(gscr_error & (1 << link->pmp)))
10343af9a77aSTejun Heo continue;
10353af9a77aSTejun Heo
10363af9a77aSTejun Heo if (sata_pmp_handle_link_fail(link, link_tries)) {
10373af9a77aSTejun Heo ata_ehi_hotplugged(&link->eh_context.i);
10383af9a77aSTejun Heo cnt++;
10393af9a77aSTejun Heo } else {
1040a9a79dfeSJoe Perches ata_link_warn(link,
1041a9a79dfeSJoe Perches "PHY status changed but maxed out on retries, giving up\n");
1042a9a79dfeSJoe Perches ata_link_warn(link,
1043a9a79dfeSJoe Perches "Manually issue scan to resume this link\n");
10443af9a77aSTejun Heo }
10453af9a77aSTejun Heo }
10463af9a77aSTejun Heo
10473af9a77aSTejun Heo if (cnt) {
1048a9a79dfeSJoe Perches ata_port_info(ap,
1049a9a79dfeSJoe Perches "PMP SError.N set for some ports, repeating recovery\n");
10503af9a77aSTejun Heo goto retry;
10513af9a77aSTejun Heo }
10523af9a77aSTejun Heo
10533af9a77aSTejun Heo return 0;
10543af9a77aSTejun Heo
10553af9a77aSTejun Heo link_fail:
10563af9a77aSTejun Heo if (sata_pmp_handle_link_fail(link, link_tries)) {
1057cf480626STejun Heo pmp_ehc->i.action |= ATA_EH_RESET;
10583af9a77aSTejun Heo goto retry;
10593af9a77aSTejun Heo }
10603af9a77aSTejun Heo
10613af9a77aSTejun Heo /* fall through */
10623af9a77aSTejun Heo pmp_fail:
10633af9a77aSTejun Heo /* Control always ends up here after detaching PMP. Shut up
10643af9a77aSTejun Heo * and return if we're unloading.
10653af9a77aSTejun Heo */
10663af9a77aSTejun Heo if (ap->pflags & ATA_PFLAG_UNLOADING)
10673af9a77aSTejun Heo return rc;
10683af9a77aSTejun Heo
1069071f44b1STejun Heo if (!sata_pmp_attached(ap))
10703af9a77aSTejun Heo goto retry;
10713af9a77aSTejun Heo
10723af9a77aSTejun Heo if (--pmp_tries) {
1073cf480626STejun Heo pmp_ehc->i.action |= ATA_EH_RESET;
10743af9a77aSTejun Heo goto retry;
10753af9a77aSTejun Heo }
10763af9a77aSTejun Heo
1077a9a79dfeSJoe Perches ata_port_err(ap, "failed to recover PMP after %d tries, giving up\n",
10783af9a77aSTejun Heo ATA_EH_PMP_TRIES);
10793af9a77aSTejun Heo sata_pmp_detach(pmp_dev);
10803af9a77aSTejun Heo ata_dev_disable(pmp_dev);
10813af9a77aSTejun Heo
10823af9a77aSTejun Heo return rc;
10833af9a77aSTejun Heo }
10843af9a77aSTejun Heo
10853af9a77aSTejun Heo /**
1086a1efdabaSTejun Heo * sata_pmp_error_handler - do standard error handling for PMP-enabled host
10873af9a77aSTejun Heo * @ap: host port to handle error for
10883af9a77aSTejun Heo *
10893af9a77aSTejun Heo * Perform standard error handling sequence for PMP-enabled host
10903af9a77aSTejun Heo * @ap.
10913af9a77aSTejun Heo *
10923af9a77aSTejun Heo * LOCKING:
10933af9a77aSTejun Heo * Kernel thread context (may sleep).
10943af9a77aSTejun Heo */
sata_pmp_error_handler(struct ata_port * ap)1095a1efdabaSTejun Heo void sata_pmp_error_handler(struct ata_port *ap)
10963af9a77aSTejun Heo {
10973af9a77aSTejun Heo ata_eh_autopsy(ap);
10983af9a77aSTejun Heo ata_eh_report(ap);
1099a1efdabaSTejun Heo sata_pmp_eh_recover(ap);
11003af9a77aSTejun Heo ata_eh_finish(ap);
11013af9a77aSTejun Heo }
110248515f6cSTejun Heo
110348515f6cSTejun Heo EXPORT_SYMBOL_GPL(sata_pmp_port_ops);
110448515f6cSTejun Heo EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch);
110548515f6cSTejun Heo EXPORT_SYMBOL_GPL(sata_pmp_error_handler);
1106