162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *    ata_piix.c - Intel PATA/SATA controllers
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *    Maintained by:  Tejun Heo <tj@kernel.org>
662306a36Sopenharmony_ci *    		    Please ALWAYS copy linux-ide@vger.kernel.org
762306a36Sopenharmony_ci *		    on emails.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *	Copyright 2003-2005 Red Hat Inc
1062306a36Sopenharmony_ci *	Copyright 2003-2005 Jeff Garzik
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *	Copyright header from piix.c:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
1562306a36Sopenharmony_ci *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
1662306a36Sopenharmony_ci *  Copyright (C) 2003 Red Hat Inc
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *  libata documentation is available via 'make {ps|pdf}docs',
1962306a36Sopenharmony_ci *  as Documentation/driver-api/libata.rst
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci *  Hardware documentation available at http://developer.intel.com/
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Documentation
2462306a36Sopenharmony_ci *	Publicly available from Intel web site. Errata documentation
2562306a36Sopenharmony_ci * is also publicly available. As an aide to anyone hacking on this
2662306a36Sopenharmony_ci * driver the list of errata that are relevant is below, going back to
2762306a36Sopenharmony_ci * PIIX4. Older device documentation is now a bit tricky to find.
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * The chipsets all follow very much the same design. The original Triton
3062306a36Sopenharmony_ci * series chipsets do _not_ support independent device timings, but this
3162306a36Sopenharmony_ci * is fixed in Triton II. With the odd mobile exception the chips then
3262306a36Sopenharmony_ci * change little except in gaining more modes until SATA arrives. This
3362306a36Sopenharmony_ci * driver supports only the chips with independent timing (that is those
3462306a36Sopenharmony_ci * with SITRE and the 0x44 timing register). See pata_oldpiix and pata_mpiix
3562306a36Sopenharmony_ci * for the early chip drivers.
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * Errata of note:
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * Unfixable
4062306a36Sopenharmony_ci *	PIIX4    errata #9	- Only on ultra obscure hw
4162306a36Sopenharmony_ci *	ICH3	 errata #13     - Not observed to affect real hw
4262306a36Sopenharmony_ci *				  by Intel
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * Things we must deal with
4562306a36Sopenharmony_ci *	PIIX4	errata #10	- BM IDE hang with non UDMA
4662306a36Sopenharmony_ci *				  (must stop/start dma to recover)
4762306a36Sopenharmony_ci *	440MX   errata #15	- As PIIX4 errata #10
4862306a36Sopenharmony_ci *	PIIX4	errata #15	- Must not read control registers
4962306a36Sopenharmony_ci * 				  during a PIO transfer
5062306a36Sopenharmony_ci *	440MX   errata #13	- As PIIX4 errata #15
5162306a36Sopenharmony_ci *	ICH2	errata #21	- DMA mode 0 doesn't work right
5262306a36Sopenharmony_ci *	ICH0/1  errata #55	- As ICH2 errata #21
5362306a36Sopenharmony_ci *	ICH2	spec c #9	- Extra operations needed to handle
5462306a36Sopenharmony_ci *				  drive hotswap [NOT YET SUPPORTED]
5562306a36Sopenharmony_ci *	ICH2    spec c #20	- IDE PRD must not cross a 64K boundary
5662306a36Sopenharmony_ci *				  and must be dword aligned
5762306a36Sopenharmony_ci *	ICH2    spec c #24	- UDMA mode 4,5 t85/86 should be 6ns not 3.3
5862306a36Sopenharmony_ci *	ICH7	errata #16	- MWDMA1 timings are incorrect
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci * Should have been BIOS fixed:
6162306a36Sopenharmony_ci *	450NX:	errata #19	- DMA hangs on old 450NX
6262306a36Sopenharmony_ci *	450NX:  errata #20	- DMA hangs on old 450NX
6362306a36Sopenharmony_ci *	450NX:  errata #25	- Corruption with DMA on old 450NX
6462306a36Sopenharmony_ci *	ICH3    errata #15      - IDE deadlock under high load
6562306a36Sopenharmony_ci *				  (BIOS must set dev 31 fn 0 bit 23)
6662306a36Sopenharmony_ci *	ICH3	errata #18	- Don't use native mode
6762306a36Sopenharmony_ci */
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#include <linux/kernel.h>
7062306a36Sopenharmony_ci#include <linux/module.h>
7162306a36Sopenharmony_ci#include <linux/pci.h>
7262306a36Sopenharmony_ci#include <linux/init.h>
7362306a36Sopenharmony_ci#include <linux/blkdev.h>
7462306a36Sopenharmony_ci#include <linux/delay.h>
7562306a36Sopenharmony_ci#include <linux/device.h>
7662306a36Sopenharmony_ci#include <linux/gfp.h>
7762306a36Sopenharmony_ci#include <scsi/scsi_host.h>
7862306a36Sopenharmony_ci#include <linux/libata.h>
7962306a36Sopenharmony_ci#include <linux/dmi.h>
8062306a36Sopenharmony_ci#include <trace/events/libata.h>
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define DRV_NAME	"ata_piix"
8362306a36Sopenharmony_ci#define DRV_VERSION	"2.13"
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cienum {
8662306a36Sopenharmony_ci	PIIX_IOCFG		= 0x54, /* IDE I/O configuration register */
8762306a36Sopenharmony_ci	ICH5_PMR		= 0x90, /* address map register */
8862306a36Sopenharmony_ci	ICH5_PCS		= 0x92,	/* port control and status */
8962306a36Sopenharmony_ci	PIIX_SIDPR_BAR		= 5,
9062306a36Sopenharmony_ci	PIIX_SIDPR_LEN		= 16,
9162306a36Sopenharmony_ci	PIIX_SIDPR_IDX		= 0,
9262306a36Sopenharmony_ci	PIIX_SIDPR_DATA		= 4,
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	PIIX_FLAG_CHECKINTR	= (1 << 28), /* make sure PCI INTx enabled */
9562306a36Sopenharmony_ci	PIIX_FLAG_SIDPR		= (1 << 29), /* SATA idx/data pair regs */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	PIIX_PATA_FLAGS		= ATA_FLAG_SLAVE_POSS,
9862306a36Sopenharmony_ci	PIIX_SATA_FLAGS		= ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR,
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	PIIX_FLAG_PIO16		= (1 << 30), /*support 16bit PIO only*/
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	PIIX_80C_PRI		= (1 << 5) | (1 << 4),
10362306a36Sopenharmony_ci	PIIX_80C_SEC		= (1 << 7) | (1 << 6),
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* constants for mapping table */
10662306a36Sopenharmony_ci	P0			= 0,  /* port 0 */
10762306a36Sopenharmony_ci	P1			= 1,  /* port 1 */
10862306a36Sopenharmony_ci	P2			= 2,  /* port 2 */
10962306a36Sopenharmony_ci	P3			= 3,  /* port 3 */
11062306a36Sopenharmony_ci	IDE			= -1, /* IDE */
11162306a36Sopenharmony_ci	NA			= -2, /* not available */
11262306a36Sopenharmony_ci	RV			= -3, /* reserved */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	PIIX_AHCI_DEVICE	= 6,
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* host->flags bits */
11762306a36Sopenharmony_ci	PIIX_HOST_BROKEN_SUSPEND = (1 << 24),
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cienum piix_controller_ids {
12162306a36Sopenharmony_ci	/* controller IDs */
12262306a36Sopenharmony_ci	piix_pata_mwdma,	/* PIIX3 MWDMA only */
12362306a36Sopenharmony_ci	piix_pata_33,		/* PIIX4 at 33Mhz */
12462306a36Sopenharmony_ci	ich_pata_33,		/* ICH up to UDMA 33 only */
12562306a36Sopenharmony_ci	ich_pata_66,		/* ICH up to 66 Mhz */
12662306a36Sopenharmony_ci	ich_pata_100,		/* ICH up to UDMA 100 */
12762306a36Sopenharmony_ci	ich_pata_100_nomwdma1,	/* ICH up to UDMA 100 but with no MWDMA1*/
12862306a36Sopenharmony_ci	ich5_sata,
12962306a36Sopenharmony_ci	ich6_sata,
13062306a36Sopenharmony_ci	ich6m_sata,
13162306a36Sopenharmony_ci	ich8_sata,
13262306a36Sopenharmony_ci	ich8_2port_sata,
13362306a36Sopenharmony_ci	ich8m_apple_sata,	/* locks up on second port enable */
13462306a36Sopenharmony_ci	tolapai_sata,
13562306a36Sopenharmony_ci	piix_pata_vmw,			/* PIIX4 for VMware, spurious DMA_ERR */
13662306a36Sopenharmony_ci	ich8_sata_snb,
13762306a36Sopenharmony_ci	ich8_2port_sata_snb,
13862306a36Sopenharmony_ci	ich8_2port_sata_byt,
13962306a36Sopenharmony_ci};
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistruct piix_map_db {
14262306a36Sopenharmony_ci	const u32 mask;
14362306a36Sopenharmony_ci	const u16 port_enable;
14462306a36Sopenharmony_ci	const int map[][4];
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistruct piix_host_priv {
14862306a36Sopenharmony_ci	const int *map;
14962306a36Sopenharmony_ci	u32 saved_iocfg;
15062306a36Sopenharmony_ci	void __iomem *sidpr;
15162306a36Sopenharmony_ci};
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic unsigned int in_module_init = 1;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic const struct pci_device_id piix_pci_tbl[] = {
15662306a36Sopenharmony_ci	/* Intel PIIX3 for the 430HX etc */
15762306a36Sopenharmony_ci	{ 0x8086, 0x7010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_mwdma },
15862306a36Sopenharmony_ci	/* VMware ICH4 */
15962306a36Sopenharmony_ci	{ 0x8086, 0x7111, 0x15ad, 0x1976, 0, 0, piix_pata_vmw },
16062306a36Sopenharmony_ci	/* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */
16162306a36Sopenharmony_ci	/* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */
16262306a36Sopenharmony_ci	{ 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
16362306a36Sopenharmony_ci	/* Intel PIIX4 */
16462306a36Sopenharmony_ci	{ 0x8086, 0x7199, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
16562306a36Sopenharmony_ci	/* Intel PIIX4 */
16662306a36Sopenharmony_ci	{ 0x8086, 0x7601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
16762306a36Sopenharmony_ci	/* Intel PIIX */
16862306a36Sopenharmony_ci	{ 0x8086, 0x84CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
16962306a36Sopenharmony_ci	/* Intel ICH (i810, i815, i840) UDMA 66*/
17062306a36Sopenharmony_ci	{ 0x8086, 0x2411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_66 },
17162306a36Sopenharmony_ci	/* Intel ICH0 : UDMA 33*/
17262306a36Sopenharmony_ci	{ 0x8086, 0x2421, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_33 },
17362306a36Sopenharmony_ci	/* Intel ICH2M */
17462306a36Sopenharmony_ci	{ 0x8086, 0x244A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
17562306a36Sopenharmony_ci	/* Intel ICH2 (i810E2, i845, 850, 860) UDMA 100 */
17662306a36Sopenharmony_ci	{ 0x8086, 0x244B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
17762306a36Sopenharmony_ci	/*  Intel ICH3M */
17862306a36Sopenharmony_ci	{ 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
17962306a36Sopenharmony_ci	/* Intel ICH3 (E7500/1) UDMA 100 */
18062306a36Sopenharmony_ci	{ 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
18162306a36Sopenharmony_ci	/* Intel ICH4-L */
18262306a36Sopenharmony_ci	{ 0x8086, 0x24C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
18362306a36Sopenharmony_ci	/* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */
18462306a36Sopenharmony_ci	{ 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
18562306a36Sopenharmony_ci	{ 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
18662306a36Sopenharmony_ci	/* Intel ICH5 */
18762306a36Sopenharmony_ci	{ 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
18862306a36Sopenharmony_ci	/* C-ICH (i810E2) */
18962306a36Sopenharmony_ci	{ 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
19062306a36Sopenharmony_ci	/* ESB (855GME/875P + 6300ESB) UDMA 100  */
19162306a36Sopenharmony_ci	{ 0x8086, 0x25A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
19262306a36Sopenharmony_ci	/* ICH6 (and 6) (i915) UDMA 100 */
19362306a36Sopenharmony_ci	{ 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
19462306a36Sopenharmony_ci	/* ICH7/7-R (i945, i975) UDMA 100*/
19562306a36Sopenharmony_ci	{ 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100_nomwdma1 },
19662306a36Sopenharmony_ci	{ 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100_nomwdma1 },
19762306a36Sopenharmony_ci	/* ICH8 Mobile PATA Controller */
19862306a36Sopenharmony_ci	{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	/* SATA ports */
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/* 82801EB (ICH5) */
20362306a36Sopenharmony_ci	{ 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
20462306a36Sopenharmony_ci	/* 82801EB (ICH5) */
20562306a36Sopenharmony_ci	{ 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
20662306a36Sopenharmony_ci	/* 6300ESB (ICH5 variant with broken PCS present bits) */
20762306a36Sopenharmony_ci	{ 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
20862306a36Sopenharmony_ci	/* 6300ESB pretending RAID */
20962306a36Sopenharmony_ci	{ 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
21062306a36Sopenharmony_ci	/* 82801FB/FW (ICH6/ICH6W) */
21162306a36Sopenharmony_ci	{ 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
21262306a36Sopenharmony_ci	/* 82801FR/FRW (ICH6R/ICH6RW) */
21362306a36Sopenharmony_ci	{ 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
21462306a36Sopenharmony_ci	/* 82801FBM ICH6M (ICH6R with only port 0 and 2 implemented).
21562306a36Sopenharmony_ci	 * Attach iff the controller is in IDE mode. */
21662306a36Sopenharmony_ci	{ 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID,
21762306a36Sopenharmony_ci	  PCI_CLASS_STORAGE_IDE << 8, 0xffff00, ich6m_sata },
21862306a36Sopenharmony_ci	/* 82801GB/GR/GH (ICH7, identical to ICH6) */
21962306a36Sopenharmony_ci	{ 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
22062306a36Sopenharmony_ci	/* 82801GBM/GHM (ICH7M, identical to ICH6M)  */
22162306a36Sopenharmony_ci	{ 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata },
22262306a36Sopenharmony_ci	/* Enterprise Southbridge 2 (631xESB/632xESB) */
22362306a36Sopenharmony_ci	{ 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
22462306a36Sopenharmony_ci	/* SATA Controller 1 IDE (ICH8) */
22562306a36Sopenharmony_ci	{ 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
22662306a36Sopenharmony_ci	/* SATA Controller 2 IDE (ICH8) */
22762306a36Sopenharmony_ci	{ 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
22862306a36Sopenharmony_ci	/* Mobile SATA Controller IDE (ICH8M), Apple */
22962306a36Sopenharmony_ci	{ 0x8086, 0x2828, 0x106b, 0x00a0, 0, 0, ich8m_apple_sata },
23062306a36Sopenharmony_ci	{ 0x8086, 0x2828, 0x106b, 0x00a1, 0, 0, ich8m_apple_sata },
23162306a36Sopenharmony_ci	{ 0x8086, 0x2828, 0x106b, 0x00a3, 0, 0, ich8m_apple_sata },
23262306a36Sopenharmony_ci	/* Mobile SATA Controller IDE (ICH8M) */
23362306a36Sopenharmony_ci	{ 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
23462306a36Sopenharmony_ci	/* SATA Controller IDE (ICH9) */
23562306a36Sopenharmony_ci	{ 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
23662306a36Sopenharmony_ci	/* SATA Controller IDE (ICH9) */
23762306a36Sopenharmony_ci	{ 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
23862306a36Sopenharmony_ci	/* SATA Controller IDE (ICH9) */
23962306a36Sopenharmony_ci	{ 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
24062306a36Sopenharmony_ci	/* SATA Controller IDE (ICH9M) */
24162306a36Sopenharmony_ci	{ 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
24262306a36Sopenharmony_ci	/* SATA Controller IDE (ICH9M) */
24362306a36Sopenharmony_ci	{ 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
24462306a36Sopenharmony_ci	/* SATA Controller IDE (ICH9M) */
24562306a36Sopenharmony_ci	{ 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
24662306a36Sopenharmony_ci	/* SATA Controller IDE (Tolapai) */
24762306a36Sopenharmony_ci	{ 0x8086, 0x5028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, tolapai_sata },
24862306a36Sopenharmony_ci	/* SATA Controller IDE (ICH10) */
24962306a36Sopenharmony_ci	{ 0x8086, 0x3a00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
25062306a36Sopenharmony_ci	/* SATA Controller IDE (ICH10) */
25162306a36Sopenharmony_ci	{ 0x8086, 0x3a06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
25262306a36Sopenharmony_ci	/* SATA Controller IDE (ICH10) */
25362306a36Sopenharmony_ci	{ 0x8086, 0x3a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
25462306a36Sopenharmony_ci	/* SATA Controller IDE (ICH10) */
25562306a36Sopenharmony_ci	{ 0x8086, 0x3a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
25662306a36Sopenharmony_ci	/* SATA Controller IDE (PCH) */
25762306a36Sopenharmony_ci	{ 0x8086, 0x3b20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
25862306a36Sopenharmony_ci	/* SATA Controller IDE (PCH) */
25962306a36Sopenharmony_ci	{ 0x8086, 0x3b21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
26062306a36Sopenharmony_ci	/* SATA Controller IDE (PCH) */
26162306a36Sopenharmony_ci	{ 0x8086, 0x3b26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
26262306a36Sopenharmony_ci	/* SATA Controller IDE (PCH) */
26362306a36Sopenharmony_ci	{ 0x8086, 0x3b28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
26462306a36Sopenharmony_ci	/* SATA Controller IDE (PCH) */
26562306a36Sopenharmony_ci	{ 0x8086, 0x3b2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
26662306a36Sopenharmony_ci	/* SATA Controller IDE (PCH) */
26762306a36Sopenharmony_ci	{ 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
26862306a36Sopenharmony_ci	/* SATA Controller IDE (CPT) */
26962306a36Sopenharmony_ci	{ 0x8086, 0x1c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
27062306a36Sopenharmony_ci	/* SATA Controller IDE (CPT) */
27162306a36Sopenharmony_ci	{ 0x8086, 0x1c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
27262306a36Sopenharmony_ci	/* SATA Controller IDE (CPT) */
27362306a36Sopenharmony_ci	{ 0x8086, 0x1c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
27462306a36Sopenharmony_ci	/* SATA Controller IDE (CPT) */
27562306a36Sopenharmony_ci	{ 0x8086, 0x1c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
27662306a36Sopenharmony_ci	/* SATA Controller IDE (PBG) */
27762306a36Sopenharmony_ci	{ 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
27862306a36Sopenharmony_ci	/* SATA Controller IDE (PBG) */
27962306a36Sopenharmony_ci	{ 0x8086, 0x1d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
28062306a36Sopenharmony_ci	/* SATA Controller IDE (Panther Point) */
28162306a36Sopenharmony_ci	{ 0x8086, 0x1e00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
28262306a36Sopenharmony_ci	/* SATA Controller IDE (Panther Point) */
28362306a36Sopenharmony_ci	{ 0x8086, 0x1e01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
28462306a36Sopenharmony_ci	/* SATA Controller IDE (Panther Point) */
28562306a36Sopenharmony_ci	{ 0x8086, 0x1e08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
28662306a36Sopenharmony_ci	/* SATA Controller IDE (Panther Point) */
28762306a36Sopenharmony_ci	{ 0x8086, 0x1e09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
28862306a36Sopenharmony_ci	/* SATA Controller IDE (Lynx Point) */
28962306a36Sopenharmony_ci	{ 0x8086, 0x8c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
29062306a36Sopenharmony_ci	/* SATA Controller IDE (Lynx Point) */
29162306a36Sopenharmony_ci	{ 0x8086, 0x8c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
29262306a36Sopenharmony_ci	/* SATA Controller IDE (Lynx Point) */
29362306a36Sopenharmony_ci	{ 0x8086, 0x8c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
29462306a36Sopenharmony_ci	/* SATA Controller IDE (Lynx Point) */
29562306a36Sopenharmony_ci	{ 0x8086, 0x8c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
29662306a36Sopenharmony_ci	/* SATA Controller IDE (Lynx Point-LP) */
29762306a36Sopenharmony_ci	{ 0x8086, 0x9c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
29862306a36Sopenharmony_ci	/* SATA Controller IDE (Lynx Point-LP) */
29962306a36Sopenharmony_ci	{ 0x8086, 0x9c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
30062306a36Sopenharmony_ci	/* SATA Controller IDE (Lynx Point-LP) */
30162306a36Sopenharmony_ci	{ 0x8086, 0x9c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
30262306a36Sopenharmony_ci	/* SATA Controller IDE (Lynx Point-LP) */
30362306a36Sopenharmony_ci	{ 0x8086, 0x9c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
30462306a36Sopenharmony_ci	/* SATA Controller IDE (DH89xxCC) */
30562306a36Sopenharmony_ci	{ 0x8086, 0x2326, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
30662306a36Sopenharmony_ci	/* SATA Controller IDE (Avoton) */
30762306a36Sopenharmony_ci	{ 0x8086, 0x1f20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
30862306a36Sopenharmony_ci	/* SATA Controller IDE (Avoton) */
30962306a36Sopenharmony_ci	{ 0x8086, 0x1f21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
31062306a36Sopenharmony_ci	/* SATA Controller IDE (Avoton) */
31162306a36Sopenharmony_ci	{ 0x8086, 0x1f30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
31262306a36Sopenharmony_ci	/* SATA Controller IDE (Avoton) */
31362306a36Sopenharmony_ci	{ 0x8086, 0x1f31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
31462306a36Sopenharmony_ci	/* SATA Controller IDE (Wellsburg) */
31562306a36Sopenharmony_ci	{ 0x8086, 0x8d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
31662306a36Sopenharmony_ci	/* SATA Controller IDE (Wellsburg) */
31762306a36Sopenharmony_ci	{ 0x8086, 0x8d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
31862306a36Sopenharmony_ci	/* SATA Controller IDE (Wellsburg) */
31962306a36Sopenharmony_ci	{ 0x8086, 0x8d60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
32062306a36Sopenharmony_ci	/* SATA Controller IDE (Wellsburg) */
32162306a36Sopenharmony_ci	{ 0x8086, 0x8d68, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
32262306a36Sopenharmony_ci	/* SATA Controller IDE (BayTrail) */
32362306a36Sopenharmony_ci	{ 0x8086, 0x0F20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
32462306a36Sopenharmony_ci	{ 0x8086, 0x0F21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
32562306a36Sopenharmony_ci	/* SATA Controller IDE (Coleto Creek) */
32662306a36Sopenharmony_ci	{ 0x8086, 0x23a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
32762306a36Sopenharmony_ci	/* SATA Controller IDE (9 Series) */
32862306a36Sopenharmony_ci	{ 0x8086, 0x8c88, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
32962306a36Sopenharmony_ci	/* SATA Controller IDE (9 Series) */
33062306a36Sopenharmony_ci	{ 0x8086, 0x8c89, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
33162306a36Sopenharmony_ci	/* SATA Controller IDE (9 Series) */
33262306a36Sopenharmony_ci	{ 0x8086, 0x8c80, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
33362306a36Sopenharmony_ci	/* SATA Controller IDE (9 Series) */
33462306a36Sopenharmony_ci	{ 0x8086, 0x8c81, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	{ }	/* terminate list */
33762306a36Sopenharmony_ci};
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic const struct piix_map_db ich5_map_db = {
34062306a36Sopenharmony_ci	.mask = 0x7,
34162306a36Sopenharmony_ci	.port_enable = 0x3,
34262306a36Sopenharmony_ci	.map = {
34362306a36Sopenharmony_ci		/* PM   PS   SM   SS       MAP  */
34462306a36Sopenharmony_ci		{  P0,  NA,  P1,  NA }, /* 000b */
34562306a36Sopenharmony_ci		{  P1,  NA,  P0,  NA }, /* 001b */
34662306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV },
34762306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV },
34862306a36Sopenharmony_ci		{  P0,  P1, IDE, IDE }, /* 100b */
34962306a36Sopenharmony_ci		{  P1,  P0, IDE, IDE }, /* 101b */
35062306a36Sopenharmony_ci		{ IDE, IDE,  P0,  P1 }, /* 110b */
35162306a36Sopenharmony_ci		{ IDE, IDE,  P1,  P0 }, /* 111b */
35262306a36Sopenharmony_ci	},
35362306a36Sopenharmony_ci};
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic const struct piix_map_db ich6_map_db = {
35662306a36Sopenharmony_ci	.mask = 0x3,
35762306a36Sopenharmony_ci	.port_enable = 0xf,
35862306a36Sopenharmony_ci	.map = {
35962306a36Sopenharmony_ci		/* PM   PS   SM   SS       MAP */
36062306a36Sopenharmony_ci		{  P0,  P2,  P1,  P3 }, /* 00b */
36162306a36Sopenharmony_ci		{ IDE, IDE,  P1,  P3 }, /* 01b */
36262306a36Sopenharmony_ci		{  P0,  P2, IDE, IDE }, /* 10b */
36362306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV },
36462306a36Sopenharmony_ci	},
36562306a36Sopenharmony_ci};
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic const struct piix_map_db ich6m_map_db = {
36862306a36Sopenharmony_ci	.mask = 0x3,
36962306a36Sopenharmony_ci	.port_enable = 0x5,
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/* Map 01b isn't specified in the doc but some notebooks use
37262306a36Sopenharmony_ci	 * it anyway.  MAP 01b have been spotted on both ICH6M and
37362306a36Sopenharmony_ci	 * ICH7M.
37462306a36Sopenharmony_ci	 */
37562306a36Sopenharmony_ci	.map = {
37662306a36Sopenharmony_ci		/* PM   PS   SM   SS       MAP */
37762306a36Sopenharmony_ci		{  P0,  P2,  NA,  NA }, /* 00b */
37862306a36Sopenharmony_ci		{ IDE, IDE,  P1,  P3 }, /* 01b */
37962306a36Sopenharmony_ci		{  P0,  P2, IDE, IDE }, /* 10b */
38062306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV },
38162306a36Sopenharmony_ci	},
38262306a36Sopenharmony_ci};
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic const struct piix_map_db ich8_map_db = {
38562306a36Sopenharmony_ci	.mask = 0x3,
38662306a36Sopenharmony_ci	.port_enable = 0xf,
38762306a36Sopenharmony_ci	.map = {
38862306a36Sopenharmony_ci		/* PM   PS   SM   SS       MAP */
38962306a36Sopenharmony_ci		{  P0,  P2,  P1,  P3 }, /* 00b (hardwired when in AHCI) */
39062306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV },
39162306a36Sopenharmony_ci		{  P0,  P2, IDE, IDE }, /* 10b (IDE mode) */
39262306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV },
39362306a36Sopenharmony_ci	},
39462306a36Sopenharmony_ci};
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic const struct piix_map_db ich8_2port_map_db = {
39762306a36Sopenharmony_ci	.mask = 0x3,
39862306a36Sopenharmony_ci	.port_enable = 0x3,
39962306a36Sopenharmony_ci	.map = {
40062306a36Sopenharmony_ci		/* PM   PS   SM   SS       MAP */
40162306a36Sopenharmony_ci		{  P0,  NA,  P1,  NA }, /* 00b */
40262306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV }, /* 01b */
40362306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV }, /* 10b */
40462306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV },
40562306a36Sopenharmony_ci	},
40662306a36Sopenharmony_ci};
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic const struct piix_map_db ich8m_apple_map_db = {
40962306a36Sopenharmony_ci	.mask = 0x3,
41062306a36Sopenharmony_ci	.port_enable = 0x1,
41162306a36Sopenharmony_ci	.map = {
41262306a36Sopenharmony_ci		/* PM   PS   SM   SS       MAP */
41362306a36Sopenharmony_ci		{  P0,  NA,  NA,  NA }, /* 00b */
41462306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV },
41562306a36Sopenharmony_ci		{  P0,  P2, IDE, IDE }, /* 10b */
41662306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV },
41762306a36Sopenharmony_ci	},
41862306a36Sopenharmony_ci};
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic const struct piix_map_db tolapai_map_db = {
42162306a36Sopenharmony_ci	.mask = 0x3,
42262306a36Sopenharmony_ci	.port_enable = 0x3,
42362306a36Sopenharmony_ci	.map = {
42462306a36Sopenharmony_ci		/* PM   PS   SM   SS       MAP */
42562306a36Sopenharmony_ci		{  P0,  NA,  P1,  NA }, /* 00b */
42662306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV }, /* 01b */
42762306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV }, /* 10b */
42862306a36Sopenharmony_ci		{  RV,  RV,  RV,  RV },
42962306a36Sopenharmony_ci	},
43062306a36Sopenharmony_ci};
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic const struct piix_map_db *piix_map_db_table[] = {
43362306a36Sopenharmony_ci	[ich5_sata]		= &ich5_map_db,
43462306a36Sopenharmony_ci	[ich6_sata]		= &ich6_map_db,
43562306a36Sopenharmony_ci	[ich6m_sata]		= &ich6m_map_db,
43662306a36Sopenharmony_ci	[ich8_sata]		= &ich8_map_db,
43762306a36Sopenharmony_ci	[ich8_2port_sata]	= &ich8_2port_map_db,
43862306a36Sopenharmony_ci	[ich8m_apple_sata]	= &ich8m_apple_map_db,
43962306a36Sopenharmony_ci	[tolapai_sata]		= &tolapai_map_db,
44062306a36Sopenharmony_ci	[ich8_sata_snb]		= &ich8_map_db,
44162306a36Sopenharmony_ci	[ich8_2port_sata_snb]	= &ich8_2port_map_db,
44262306a36Sopenharmony_ci	[ich8_2port_sata_byt]	= &ich8_2port_map_db,
44362306a36Sopenharmony_ci};
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic const struct pci_bits piix_enable_bits[] = {
44662306a36Sopenharmony_ci	{ 0x41U, 1U, 0x80UL, 0x80UL },	/* port 0 */
44762306a36Sopenharmony_ci	{ 0x43U, 1U, 0x80UL, 0x80UL },	/* port 1 */
44862306a36Sopenharmony_ci};
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ciMODULE_AUTHOR("Andre Hedrick, Alan Cox, Andrzej Krzysztofowicz, Jeff Garzik");
45162306a36Sopenharmony_ciMODULE_DESCRIPTION("SCSI low-level driver for Intel PIIX/ICH ATA controllers");
45262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
45362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, piix_pci_tbl);
45462306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistruct ich_laptop {
45762306a36Sopenharmony_ci	u16 device;
45862306a36Sopenharmony_ci	u16 subvendor;
45962306a36Sopenharmony_ci	u16 subdevice;
46062306a36Sopenharmony_ci};
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci/*
46362306a36Sopenharmony_ci *	List of laptops that use short cables rather than 80 wire
46462306a36Sopenharmony_ci */
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic const struct ich_laptop ich_laptop[] = {
46762306a36Sopenharmony_ci	/* devid, subvendor, subdev */
46862306a36Sopenharmony_ci	{ 0x27DF, 0x0005, 0x0280 },	/* ICH7 on Acer 5602WLMi */
46962306a36Sopenharmony_ci	{ 0x27DF, 0x1025, 0x0102 },	/* ICH7 on Acer 5602aWLMi */
47062306a36Sopenharmony_ci	{ 0x27DF, 0x1025, 0x0110 },	/* ICH7 on Acer 3682WLMi */
47162306a36Sopenharmony_ci	{ 0x27DF, 0x1028, 0x02b0 },	/* ICH7 on unknown Dell */
47262306a36Sopenharmony_ci	{ 0x27DF, 0x1043, 0x1267 },	/* ICH7 on Asus W5F */
47362306a36Sopenharmony_ci	{ 0x27DF, 0x103C, 0x30A1 },	/* ICH7 on HP Compaq nc2400 */
47462306a36Sopenharmony_ci	{ 0x27DF, 0x103C, 0x361a },	/* ICH7 on unknown HP  */
47562306a36Sopenharmony_ci	{ 0x27DF, 0x1071, 0xD221 },	/* ICH7 on Hercules EC-900 */
47662306a36Sopenharmony_ci	{ 0x27DF, 0x152D, 0x0778 },	/* ICH7 on unknown Intel */
47762306a36Sopenharmony_ci	{ 0x24CA, 0x1025, 0x0061 },	/* ICH4 on ACER Aspire 2023WLMi */
47862306a36Sopenharmony_ci	{ 0x24CA, 0x1025, 0x003d },	/* ICH4 on ACER TM290 */
47962306a36Sopenharmony_ci	{ 0x24CA, 0x10CF, 0x11AB },	/* ICH4M on Fujitsu-Siemens Lifebook S6120 */
48062306a36Sopenharmony_ci	{ 0x266F, 0x1025, 0x0066 },	/* ICH6 on ACER Aspire 1694WLMi */
48162306a36Sopenharmony_ci	{ 0x2653, 0x1043, 0x82D8 },	/* ICH6M on Asus Eee 701 */
48262306a36Sopenharmony_ci	{ 0x27df, 0x104d, 0x900e },	/* ICH7 on Sony TZ-90 */
48362306a36Sopenharmony_ci	/* end marker */
48462306a36Sopenharmony_ci	{ 0, }
48562306a36Sopenharmony_ci};
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic int piix_port_start(struct ata_port *ap)
48862306a36Sopenharmony_ci{
48962306a36Sopenharmony_ci	if (!(ap->flags & PIIX_FLAG_PIO16))
49062306a36Sopenharmony_ci		ap->pflags |= ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	return ata_bmdma_port_start(ap);
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci/**
49662306a36Sopenharmony_ci *	ich_pata_cable_detect - Probe host controller cable detect info
49762306a36Sopenharmony_ci *	@ap: Port for which cable detect info is desired
49862306a36Sopenharmony_ci *
49962306a36Sopenharmony_ci *	Read 80c cable indicator from ATA PCI device's PCI config
50062306a36Sopenharmony_ci *	register.  This register is normally set by firmware (BIOS).
50162306a36Sopenharmony_ci *
50262306a36Sopenharmony_ci *	LOCKING:
50362306a36Sopenharmony_ci *	None (inherited from caller).
50462306a36Sopenharmony_ci */
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic int ich_pata_cable_detect(struct ata_port *ap)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
50962306a36Sopenharmony_ci	struct piix_host_priv *hpriv = ap->host->private_data;
51062306a36Sopenharmony_ci	const struct ich_laptop *lap = &ich_laptop[0];
51162306a36Sopenharmony_ci	u8 mask;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	/* Check for specials */
51462306a36Sopenharmony_ci	while (lap->device) {
51562306a36Sopenharmony_ci		if (lap->device == pdev->device &&
51662306a36Sopenharmony_ci		    lap->subvendor == pdev->subsystem_vendor &&
51762306a36Sopenharmony_ci		    lap->subdevice == pdev->subsystem_device)
51862306a36Sopenharmony_ci			return ATA_CBL_PATA40_SHORT;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		lap++;
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* check BIOS cable detect results */
52462306a36Sopenharmony_ci	mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
52562306a36Sopenharmony_ci	if ((hpriv->saved_iocfg & mask) == 0)
52662306a36Sopenharmony_ci		return ATA_CBL_PATA40;
52762306a36Sopenharmony_ci	return ATA_CBL_PATA80;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci/**
53162306a36Sopenharmony_ci *	piix_pata_prereset - prereset for PATA host controller
53262306a36Sopenharmony_ci *	@link: Target link
53362306a36Sopenharmony_ci *	@deadline: deadline jiffies for the operation
53462306a36Sopenharmony_ci *
53562306a36Sopenharmony_ci *	LOCKING:
53662306a36Sopenharmony_ci *	None (inherited from caller).
53762306a36Sopenharmony_ci */
53862306a36Sopenharmony_cistatic int piix_pata_prereset(struct ata_link *link, unsigned long deadline)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct ata_port *ap = link->ap;
54162306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
54462306a36Sopenharmony_ci		return -ENOENT;
54562306a36Sopenharmony_ci	return ata_sff_prereset(link, deadline);
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(piix_lock);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic void piix_set_timings(struct ata_port *ap, struct ata_device *adev,
55162306a36Sopenharmony_ci			     u8 pio)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct pci_dev *dev	= to_pci_dev(ap->host->dev);
55462306a36Sopenharmony_ci	unsigned long flags;
55562306a36Sopenharmony_ci	unsigned int is_slave	= (adev->devno != 0);
55662306a36Sopenharmony_ci	unsigned int master_port= ap->port_no ? 0x42 : 0x40;
55762306a36Sopenharmony_ci	unsigned int slave_port	= 0x44;
55862306a36Sopenharmony_ci	u16 master_data;
55962306a36Sopenharmony_ci	u8 slave_data;
56062306a36Sopenharmony_ci	u8 udma_enable;
56162306a36Sopenharmony_ci	int control = 0;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	/*
56462306a36Sopenharmony_ci	 *	See Intel Document 298600-004 for the timing programing rules
56562306a36Sopenharmony_ci	 *	for ICH controllers.
56662306a36Sopenharmony_ci	 */
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	static const	 /* ISP  RTC */
56962306a36Sopenharmony_ci	u8 timings[][2]	= { { 0, 0 },
57062306a36Sopenharmony_ci			    { 0, 0 },
57162306a36Sopenharmony_ci			    { 1, 0 },
57262306a36Sopenharmony_ci			    { 2, 1 },
57362306a36Sopenharmony_ci			    { 2, 3 }, };
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	if (pio >= 2)
57662306a36Sopenharmony_ci		control |= 1;	/* TIME1 enable */
57762306a36Sopenharmony_ci	if (ata_pio_need_iordy(adev))
57862306a36Sopenharmony_ci		control |= 2;	/* IE enable */
57962306a36Sopenharmony_ci	/* Intel specifies that the PPE functionality is for disk only */
58062306a36Sopenharmony_ci	if (adev->class == ATA_DEV_ATA)
58162306a36Sopenharmony_ci		control |= 4;	/* PPE enable */
58262306a36Sopenharmony_ci	/*
58362306a36Sopenharmony_ci	 * If the drive MWDMA is faster than it can do PIO then
58462306a36Sopenharmony_ci	 * we must force PIO into PIO0
58562306a36Sopenharmony_ci	 */
58662306a36Sopenharmony_ci	if (adev->pio_mode < XFER_PIO_0 + pio)
58762306a36Sopenharmony_ci		/* Enable DMA timing only */
58862306a36Sopenharmony_ci		control |= 8;	/* PIO cycles in PIO0 */
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	spin_lock_irqsave(&piix_lock, flags);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	/* PIO configuration clears DTE unconditionally.  It will be
59362306a36Sopenharmony_ci	 * programmed in set_dmamode which is guaranteed to be called
59462306a36Sopenharmony_ci	 * after set_piomode if any DMA mode is available.
59562306a36Sopenharmony_ci	 */
59662306a36Sopenharmony_ci	pci_read_config_word(dev, master_port, &master_data);
59762306a36Sopenharmony_ci	if (is_slave) {
59862306a36Sopenharmony_ci		/* clear TIME1|IE1|PPE1|DTE1 */
59962306a36Sopenharmony_ci		master_data &= 0xff0f;
60062306a36Sopenharmony_ci		/* enable PPE1, IE1 and TIME1 as needed */
60162306a36Sopenharmony_ci		master_data |= (control << 4);
60262306a36Sopenharmony_ci		pci_read_config_byte(dev, slave_port, &slave_data);
60362306a36Sopenharmony_ci		slave_data &= (ap->port_no ? 0x0f : 0xf0);
60462306a36Sopenharmony_ci		/* Load the timing nibble for this slave */
60562306a36Sopenharmony_ci		slave_data |= ((timings[pio][0] << 2) | timings[pio][1])
60662306a36Sopenharmony_ci						<< (ap->port_no ? 4 : 0);
60762306a36Sopenharmony_ci	} else {
60862306a36Sopenharmony_ci		/* clear ISP|RCT|TIME0|IE0|PPE0|DTE0 */
60962306a36Sopenharmony_ci		master_data &= 0xccf0;
61062306a36Sopenharmony_ci		/* Enable PPE, IE and TIME as appropriate */
61162306a36Sopenharmony_ci		master_data |= control;
61262306a36Sopenharmony_ci		/* load ISP and RCT */
61362306a36Sopenharmony_ci		master_data |=
61462306a36Sopenharmony_ci			(timings[pio][0] << 12) |
61562306a36Sopenharmony_ci			(timings[pio][1] << 8);
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/* Enable SITRE (separate slave timing register) */
61962306a36Sopenharmony_ci	master_data |= 0x4000;
62062306a36Sopenharmony_ci	pci_write_config_word(dev, master_port, master_data);
62162306a36Sopenharmony_ci	if (is_slave)
62262306a36Sopenharmony_ci		pci_write_config_byte(dev, slave_port, slave_data);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	/* Ensure the UDMA bit is off - it will be turned back on if
62562306a36Sopenharmony_ci	   UDMA is selected */
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	if (ap->udma_mask) {
62862306a36Sopenharmony_ci		pci_read_config_byte(dev, 0x48, &udma_enable);
62962306a36Sopenharmony_ci		udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
63062306a36Sopenharmony_ci		pci_write_config_byte(dev, 0x48, udma_enable);
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	spin_unlock_irqrestore(&piix_lock, flags);
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci/**
63762306a36Sopenharmony_ci *	piix_set_piomode - Initialize host controller PATA PIO timings
63862306a36Sopenharmony_ci *	@ap: Port whose timings we are configuring
63962306a36Sopenharmony_ci *	@adev: Drive in question
64062306a36Sopenharmony_ci *
64162306a36Sopenharmony_ci *	Set PIO mode for device, in host controller PCI config space.
64262306a36Sopenharmony_ci *
64362306a36Sopenharmony_ci *	LOCKING:
64462306a36Sopenharmony_ci *	None (inherited from caller).
64562306a36Sopenharmony_ci */
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic void piix_set_piomode(struct ata_port *ap, struct ata_device *adev)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	piix_set_timings(ap, adev, adev->pio_mode - XFER_PIO_0);
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci/**
65362306a36Sopenharmony_ci *	do_pata_set_dmamode - Initialize host controller PATA PIO timings
65462306a36Sopenharmony_ci *	@ap: Port whose timings we are configuring
65562306a36Sopenharmony_ci *	@adev: Drive in question
65662306a36Sopenharmony_ci *	@isich: set if the chip is an ICH device
65762306a36Sopenharmony_ci *
65862306a36Sopenharmony_ci *	Set UDMA mode for device, in host controller PCI config space.
65962306a36Sopenharmony_ci *
66062306a36Sopenharmony_ci *	LOCKING:
66162306a36Sopenharmony_ci *	None (inherited from caller).
66262306a36Sopenharmony_ci */
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic void do_pata_set_dmamode(struct ata_port *ap, struct ata_device *adev, int isich)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	struct pci_dev *dev	= to_pci_dev(ap->host->dev);
66762306a36Sopenharmony_ci	unsigned long flags;
66862306a36Sopenharmony_ci	u8 speed		= adev->dma_mode;
66962306a36Sopenharmony_ci	int devid		= adev->devno + 2 * ap->port_no;
67062306a36Sopenharmony_ci	u8 udma_enable		= 0;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	if (speed >= XFER_UDMA_0) {
67362306a36Sopenharmony_ci		unsigned int udma = speed - XFER_UDMA_0;
67462306a36Sopenharmony_ci		u16 udma_timing;
67562306a36Sopenharmony_ci		u16 ideconf;
67662306a36Sopenharmony_ci		int u_clock, u_speed;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci		spin_lock_irqsave(&piix_lock, flags);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		pci_read_config_byte(dev, 0x48, &udma_enable);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		/*
68362306a36Sopenharmony_ci		 * UDMA is handled by a combination of clock switching and
68462306a36Sopenharmony_ci		 * selection of dividers
68562306a36Sopenharmony_ci		 *
68662306a36Sopenharmony_ci		 * Handy rule: Odd modes are UDMATIMx 01, even are 02
68762306a36Sopenharmony_ci		 *	       except UDMA0 which is 00
68862306a36Sopenharmony_ci		 */
68962306a36Sopenharmony_ci		u_speed = min(2 - (udma & 1), udma);
69062306a36Sopenharmony_ci		if (udma == 5)
69162306a36Sopenharmony_ci			u_clock = 0x1000;	/* 100Mhz */
69262306a36Sopenharmony_ci		else if (udma > 2)
69362306a36Sopenharmony_ci			u_clock = 1;		/* 66Mhz */
69462306a36Sopenharmony_ci		else
69562306a36Sopenharmony_ci			u_clock = 0;		/* 33Mhz */
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci		udma_enable |= (1 << devid);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		/* Load the CT/RP selection */
70062306a36Sopenharmony_ci		pci_read_config_word(dev, 0x4A, &udma_timing);
70162306a36Sopenharmony_ci		udma_timing &= ~(3 << (4 * devid));
70262306a36Sopenharmony_ci		udma_timing |= u_speed << (4 * devid);
70362306a36Sopenharmony_ci		pci_write_config_word(dev, 0x4A, udma_timing);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		if (isich) {
70662306a36Sopenharmony_ci			/* Select a 33/66/100Mhz clock */
70762306a36Sopenharmony_ci			pci_read_config_word(dev, 0x54, &ideconf);
70862306a36Sopenharmony_ci			ideconf &= ~(0x1001 << devid);
70962306a36Sopenharmony_ci			ideconf |= u_clock << devid;
71062306a36Sopenharmony_ci			/* For ICH or later we should set bit 10 for better
71162306a36Sopenharmony_ci			   performance (WR_PingPong_En) */
71262306a36Sopenharmony_ci			pci_write_config_word(dev, 0x54, ideconf);
71362306a36Sopenharmony_ci		}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci		pci_write_config_byte(dev, 0x48, udma_enable);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		spin_unlock_irqrestore(&piix_lock, flags);
71862306a36Sopenharmony_ci	} else {
71962306a36Sopenharmony_ci		/* MWDMA is driven by the PIO timings. */
72062306a36Sopenharmony_ci		unsigned int mwdma = speed - XFER_MW_DMA_0;
72162306a36Sopenharmony_ci		const unsigned int needed_pio[3] = {
72262306a36Sopenharmony_ci			XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
72362306a36Sopenharmony_ci		};
72462306a36Sopenharmony_ci		int pio = needed_pio[mwdma] - XFER_PIO_0;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci		/* XFER_PIO_0 is never used currently */
72762306a36Sopenharmony_ci		piix_set_timings(ap, adev, pio);
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci/**
73262306a36Sopenharmony_ci *	piix_set_dmamode - Initialize host controller PATA DMA timings
73362306a36Sopenharmony_ci *	@ap: Port whose timings we are configuring
73462306a36Sopenharmony_ci *	@adev: um
73562306a36Sopenharmony_ci *
73662306a36Sopenharmony_ci *	Set MW/UDMA mode for device, in host controller PCI config space.
73762306a36Sopenharmony_ci *
73862306a36Sopenharmony_ci *	LOCKING:
73962306a36Sopenharmony_ci *	None (inherited from caller).
74062306a36Sopenharmony_ci */
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	do_pata_set_dmamode(ap, adev, 0);
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci/**
74862306a36Sopenharmony_ci *	ich_set_dmamode - Initialize host controller PATA DMA timings
74962306a36Sopenharmony_ci *	@ap: Port whose timings we are configuring
75062306a36Sopenharmony_ci *	@adev: um
75162306a36Sopenharmony_ci *
75262306a36Sopenharmony_ci *	Set MW/UDMA mode for device, in host controller PCI config space.
75362306a36Sopenharmony_ci *
75462306a36Sopenharmony_ci *	LOCKING:
75562306a36Sopenharmony_ci *	None (inherited from caller).
75662306a36Sopenharmony_ci */
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	do_pata_set_dmamode(ap, adev, 1);
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci/*
76462306a36Sopenharmony_ci * Serial ATA Index/Data Pair Superset Registers access
76562306a36Sopenharmony_ci *
76662306a36Sopenharmony_ci * Beginning from ICH8, there's a sane way to access SCRs using index
76762306a36Sopenharmony_ci * and data register pair located at BAR5 which means that we have
76862306a36Sopenharmony_ci * separate SCRs for master and slave.  This is handled using libata
76962306a36Sopenharmony_ci * slave_link facility.
77062306a36Sopenharmony_ci */
77162306a36Sopenharmony_cistatic const int piix_sidx_map[] = {
77262306a36Sopenharmony_ci	[SCR_STATUS]	= 0,
77362306a36Sopenharmony_ci	[SCR_ERROR]	= 2,
77462306a36Sopenharmony_ci	[SCR_CONTROL]	= 1,
77562306a36Sopenharmony_ci};
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic void piix_sidpr_sel(struct ata_link *link, unsigned int reg)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	struct ata_port *ap = link->ap;
78062306a36Sopenharmony_ci	struct piix_host_priv *hpriv = ap->host->private_data;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	iowrite32(((ap->port_no * 2 + link->pmp) << 8) | piix_sidx_map[reg],
78362306a36Sopenharmony_ci		  hpriv->sidpr + PIIX_SIDPR_IDX);
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic int piix_sidpr_scr_read(struct ata_link *link,
78762306a36Sopenharmony_ci			       unsigned int reg, u32 *val)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	struct piix_host_priv *hpriv = link->ap->host->private_data;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (reg >= ARRAY_SIZE(piix_sidx_map))
79262306a36Sopenharmony_ci		return -EINVAL;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	piix_sidpr_sel(link, reg);
79562306a36Sopenharmony_ci	*val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
79662306a36Sopenharmony_ci	return 0;
79762306a36Sopenharmony_ci}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_cistatic int piix_sidpr_scr_write(struct ata_link *link,
80062306a36Sopenharmony_ci				unsigned int reg, u32 val)
80162306a36Sopenharmony_ci{
80262306a36Sopenharmony_ci	struct piix_host_priv *hpriv = link->ap->host->private_data;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	if (reg >= ARRAY_SIZE(piix_sidx_map))
80562306a36Sopenharmony_ci		return -EINVAL;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	piix_sidpr_sel(link, reg);
80862306a36Sopenharmony_ci	iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
80962306a36Sopenharmony_ci	return 0;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
81362306a36Sopenharmony_ci			      unsigned hints)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	return sata_link_scr_lpm(link, policy, false);
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic bool piix_irq_check(struct ata_port *ap)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	unsigned char host_stat;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	if (unlikely(!ap->ioaddr.bmdma_addr))
82362306a36Sopenharmony_ci		return false;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	host_stat = ap->ops->bmdma_status(ap);
82662306a36Sopenharmony_ci	trace_ata_bmdma_status(ap, host_stat);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	return host_stat & ATA_DMA_INTR;
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
83262306a36Sopenharmony_cistatic int piix_broken_suspend(void)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	static const struct dmi_system_id sysids[] = {
83562306a36Sopenharmony_ci		{
83662306a36Sopenharmony_ci			.ident = "TECRA M3",
83762306a36Sopenharmony_ci			.matches = {
83862306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
83962306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M3"),
84062306a36Sopenharmony_ci			},
84162306a36Sopenharmony_ci		},
84262306a36Sopenharmony_ci		{
84362306a36Sopenharmony_ci			.ident = "TECRA M3",
84462306a36Sopenharmony_ci			.matches = {
84562306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
84662306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "Tecra M3"),
84762306a36Sopenharmony_ci			},
84862306a36Sopenharmony_ci		},
84962306a36Sopenharmony_ci		{
85062306a36Sopenharmony_ci			.ident = "TECRA M3",
85162306a36Sopenharmony_ci			.matches = {
85262306a36Sopenharmony_ci				DMI_MATCH(DMI_OEM_STRING, "Tecra M3,"),
85362306a36Sopenharmony_ci			},
85462306a36Sopenharmony_ci		},
85562306a36Sopenharmony_ci		{
85662306a36Sopenharmony_ci			.ident = "TECRA M4",
85762306a36Sopenharmony_ci			.matches = {
85862306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
85962306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "Tecra M4"),
86062306a36Sopenharmony_ci			},
86162306a36Sopenharmony_ci		},
86262306a36Sopenharmony_ci		{
86362306a36Sopenharmony_ci			.ident = "TECRA M4",
86462306a36Sopenharmony_ci			.matches = {
86562306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
86662306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M4"),
86762306a36Sopenharmony_ci			},
86862306a36Sopenharmony_ci		},
86962306a36Sopenharmony_ci		{
87062306a36Sopenharmony_ci			.ident = "TECRA M5",
87162306a36Sopenharmony_ci			.matches = {
87262306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
87362306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M5"),
87462306a36Sopenharmony_ci			},
87562306a36Sopenharmony_ci		},
87662306a36Sopenharmony_ci		{
87762306a36Sopenharmony_ci			.ident = "TECRA M6",
87862306a36Sopenharmony_ci			.matches = {
87962306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
88062306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M6"),
88162306a36Sopenharmony_ci			},
88262306a36Sopenharmony_ci		},
88362306a36Sopenharmony_ci		{
88462306a36Sopenharmony_ci			.ident = "TECRA M7",
88562306a36Sopenharmony_ci			.matches = {
88662306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
88762306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M7"),
88862306a36Sopenharmony_ci			},
88962306a36Sopenharmony_ci		},
89062306a36Sopenharmony_ci		{
89162306a36Sopenharmony_ci			.ident = "TECRA A8",
89262306a36Sopenharmony_ci			.matches = {
89362306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
89462306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A8"),
89562306a36Sopenharmony_ci			},
89662306a36Sopenharmony_ci		},
89762306a36Sopenharmony_ci		{
89862306a36Sopenharmony_ci			.ident = "Satellite R20",
89962306a36Sopenharmony_ci			.matches = {
90062306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
90162306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "Satellite R20"),
90262306a36Sopenharmony_ci			},
90362306a36Sopenharmony_ci		},
90462306a36Sopenharmony_ci		{
90562306a36Sopenharmony_ci			.ident = "Satellite R25",
90662306a36Sopenharmony_ci			.matches = {
90762306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
90862306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "Satellite R25"),
90962306a36Sopenharmony_ci			},
91062306a36Sopenharmony_ci		},
91162306a36Sopenharmony_ci		{
91262306a36Sopenharmony_ci			.ident = "Satellite U200",
91362306a36Sopenharmony_ci			.matches = {
91462306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
91562306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U200"),
91662306a36Sopenharmony_ci			},
91762306a36Sopenharmony_ci		},
91862306a36Sopenharmony_ci		{
91962306a36Sopenharmony_ci			.ident = "Satellite U200",
92062306a36Sopenharmony_ci			.matches = {
92162306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
92262306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE U200"),
92362306a36Sopenharmony_ci			},
92462306a36Sopenharmony_ci		},
92562306a36Sopenharmony_ci		{
92662306a36Sopenharmony_ci			.ident = "Satellite Pro U200",
92762306a36Sopenharmony_ci			.matches = {
92862306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
92962306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE PRO U200"),
93062306a36Sopenharmony_ci			},
93162306a36Sopenharmony_ci		},
93262306a36Sopenharmony_ci		{
93362306a36Sopenharmony_ci			.ident = "Satellite U205",
93462306a36Sopenharmony_ci			.matches = {
93562306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
93662306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U205"),
93762306a36Sopenharmony_ci			},
93862306a36Sopenharmony_ci		},
93962306a36Sopenharmony_ci		{
94062306a36Sopenharmony_ci			.ident = "SATELLITE U205",
94162306a36Sopenharmony_ci			.matches = {
94262306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
94362306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE U205"),
94462306a36Sopenharmony_ci			},
94562306a36Sopenharmony_ci		},
94662306a36Sopenharmony_ci		{
94762306a36Sopenharmony_ci			.ident = "Satellite Pro A120",
94862306a36Sopenharmony_ci			.matches = {
94962306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
95062306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "Satellite Pro A120"),
95162306a36Sopenharmony_ci			},
95262306a36Sopenharmony_ci		},
95362306a36Sopenharmony_ci		{
95462306a36Sopenharmony_ci			.ident = "Portege M500",
95562306a36Sopenharmony_ci			.matches = {
95662306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
95762306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M500"),
95862306a36Sopenharmony_ci			},
95962306a36Sopenharmony_ci		},
96062306a36Sopenharmony_ci		{
96162306a36Sopenharmony_ci			.ident = "VGN-BX297XP",
96262306a36Sopenharmony_ci			.matches = {
96362306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
96462306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "VGN-BX297XP"),
96562306a36Sopenharmony_ci			},
96662306a36Sopenharmony_ci		},
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci		{ }	/* terminate list */
96962306a36Sopenharmony_ci	};
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	if (dmi_check_system(sysids))
97262306a36Sopenharmony_ci		return 1;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	/* TECRA M4 sometimes forgets its identify and reports bogus
97562306a36Sopenharmony_ci	 * DMI information.  As the bogus information is a bit
97662306a36Sopenharmony_ci	 * generic, match as many entries as possible.  This manual
97762306a36Sopenharmony_ci	 * matching is necessary because dmi_system_id.matches is
97862306a36Sopenharmony_ci	 * limited to four entries.
97962306a36Sopenharmony_ci	 */
98062306a36Sopenharmony_ci	if (dmi_match(DMI_SYS_VENDOR, "TOSHIBA") &&
98162306a36Sopenharmony_ci	    dmi_match(DMI_PRODUCT_NAME, "000000") &&
98262306a36Sopenharmony_ci	    dmi_match(DMI_PRODUCT_VERSION, "000000") &&
98362306a36Sopenharmony_ci	    dmi_match(DMI_PRODUCT_SERIAL, "000000") &&
98462306a36Sopenharmony_ci	    dmi_match(DMI_BOARD_VENDOR, "TOSHIBA") &&
98562306a36Sopenharmony_ci	    dmi_match(DMI_BOARD_NAME, "Portable PC") &&
98662306a36Sopenharmony_ci	    dmi_match(DMI_BOARD_VERSION, "Version A0"))
98762306a36Sopenharmony_ci		return 1;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	return 0;
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	struct ata_host *host = pci_get_drvdata(pdev);
99562306a36Sopenharmony_ci	unsigned long flags;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	ata_host_suspend(host, mesg);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	/* Some braindamaged ACPI suspend implementations expect the
100062306a36Sopenharmony_ci	 * controller to be awake on entry; otherwise, it burns cpu
100162306a36Sopenharmony_ci	 * cycles and power trying to do something to the sleeping
100262306a36Sopenharmony_ci	 * beauty.
100362306a36Sopenharmony_ci	 */
100462306a36Sopenharmony_ci	if (piix_broken_suspend() && (mesg.event & PM_EVENT_SLEEP)) {
100562306a36Sopenharmony_ci		pci_save_state(pdev);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci		/* mark its power state as "unknown", since we don't
100862306a36Sopenharmony_ci		 * know if e.g. the BIOS will change its device state
100962306a36Sopenharmony_ci		 * when we suspend.
101062306a36Sopenharmony_ci		 */
101162306a36Sopenharmony_ci		if (pdev->current_state == PCI_D0)
101262306a36Sopenharmony_ci			pdev->current_state = PCI_UNKNOWN;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci		/* tell resume that it's waking up from broken suspend */
101562306a36Sopenharmony_ci		spin_lock_irqsave(&host->lock, flags);
101662306a36Sopenharmony_ci		host->flags |= PIIX_HOST_BROKEN_SUSPEND;
101762306a36Sopenharmony_ci		spin_unlock_irqrestore(&host->lock, flags);
101862306a36Sopenharmony_ci	} else
101962306a36Sopenharmony_ci		ata_pci_device_do_suspend(pdev, mesg);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	return 0;
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic int piix_pci_device_resume(struct pci_dev *pdev)
102562306a36Sopenharmony_ci{
102662306a36Sopenharmony_ci	struct ata_host *host = pci_get_drvdata(pdev);
102762306a36Sopenharmony_ci	unsigned long flags;
102862306a36Sopenharmony_ci	int rc;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (host->flags & PIIX_HOST_BROKEN_SUSPEND) {
103162306a36Sopenharmony_ci		spin_lock_irqsave(&host->lock, flags);
103262306a36Sopenharmony_ci		host->flags &= ~PIIX_HOST_BROKEN_SUSPEND;
103362306a36Sopenharmony_ci		spin_unlock_irqrestore(&host->lock, flags);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci		pci_set_power_state(pdev, PCI_D0);
103662306a36Sopenharmony_ci		pci_restore_state(pdev);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci		/* PCI device wasn't disabled during suspend.  Use
103962306a36Sopenharmony_ci		 * pci_reenable_device() to avoid affecting the enable
104062306a36Sopenharmony_ci		 * count.
104162306a36Sopenharmony_ci		 */
104262306a36Sopenharmony_ci		rc = pci_reenable_device(pdev);
104362306a36Sopenharmony_ci		if (rc)
104462306a36Sopenharmony_ci			dev_err(&pdev->dev,
104562306a36Sopenharmony_ci				"failed to enable device after resume (%d)\n",
104662306a36Sopenharmony_ci				rc);
104762306a36Sopenharmony_ci	} else
104862306a36Sopenharmony_ci		rc = ata_pci_device_do_resume(pdev);
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	if (rc == 0)
105162306a36Sopenharmony_ci		ata_host_resume(host);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	return rc;
105462306a36Sopenharmony_ci}
105562306a36Sopenharmony_ci#endif
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cistatic u8 piix_vmw_bmdma_status(struct ata_port *ap)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	return ata_bmdma_status(ap) & ~ATA_DMA_ERR;
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cistatic const struct scsi_host_template piix_sht = {
106362306a36Sopenharmony_ci	ATA_BMDMA_SHT(DRV_NAME),
106462306a36Sopenharmony_ci};
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_cistatic struct ata_port_operations piix_sata_ops = {
106762306a36Sopenharmony_ci	.inherits		= &ata_bmdma32_port_ops,
106862306a36Sopenharmony_ci	.sff_irq_check		= piix_irq_check,
106962306a36Sopenharmony_ci	.port_start		= piix_port_start,
107062306a36Sopenharmony_ci};
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic struct ata_port_operations piix_pata_ops = {
107362306a36Sopenharmony_ci	.inherits		= &piix_sata_ops,
107462306a36Sopenharmony_ci	.cable_detect		= ata_cable_40wire,
107562306a36Sopenharmony_ci	.set_piomode		= piix_set_piomode,
107662306a36Sopenharmony_ci	.set_dmamode		= piix_set_dmamode,
107762306a36Sopenharmony_ci	.prereset		= piix_pata_prereset,
107862306a36Sopenharmony_ci};
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic struct ata_port_operations piix_vmw_ops = {
108162306a36Sopenharmony_ci	.inherits		= &piix_pata_ops,
108262306a36Sopenharmony_ci	.bmdma_status		= piix_vmw_bmdma_status,
108362306a36Sopenharmony_ci};
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic struct ata_port_operations ich_pata_ops = {
108662306a36Sopenharmony_ci	.inherits		= &piix_pata_ops,
108762306a36Sopenharmony_ci	.cable_detect		= ich_pata_cable_detect,
108862306a36Sopenharmony_ci	.set_dmamode		= ich_set_dmamode,
108962306a36Sopenharmony_ci};
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_cistatic struct attribute *piix_sidpr_shost_attrs[] = {
109262306a36Sopenharmony_ci	&dev_attr_link_power_management_policy.attr,
109362306a36Sopenharmony_ci	NULL
109462306a36Sopenharmony_ci};
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ciATTRIBUTE_GROUPS(piix_sidpr_shost);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_cistatic const struct scsi_host_template piix_sidpr_sht = {
109962306a36Sopenharmony_ci	ATA_BMDMA_SHT(DRV_NAME),
110062306a36Sopenharmony_ci	.shost_groups		= piix_sidpr_shost_groups,
110162306a36Sopenharmony_ci};
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cistatic struct ata_port_operations piix_sidpr_sata_ops = {
110462306a36Sopenharmony_ci	.inherits		= &piix_sata_ops,
110562306a36Sopenharmony_ci	.hardreset		= sata_std_hardreset,
110662306a36Sopenharmony_ci	.scr_read		= piix_sidpr_scr_read,
110762306a36Sopenharmony_ci	.scr_write		= piix_sidpr_scr_write,
110862306a36Sopenharmony_ci	.set_lpm		= piix_sidpr_set_lpm,
110962306a36Sopenharmony_ci};
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_cistatic struct ata_port_info piix_port_info[] = {
111262306a36Sopenharmony_ci	[piix_pata_mwdma] =	/* PIIX3 MWDMA only */
111362306a36Sopenharmony_ci	{
111462306a36Sopenharmony_ci		.flags		= PIIX_PATA_FLAGS,
111562306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
111662306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA12_ONLY, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
111762306a36Sopenharmony_ci		.port_ops	= &piix_pata_ops,
111862306a36Sopenharmony_ci	},
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	[piix_pata_33] =	/* PIIX4 at 33MHz */
112162306a36Sopenharmony_ci	{
112262306a36Sopenharmony_ci		.flags		= PIIX_PATA_FLAGS,
112362306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
112462306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA12_ONLY, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
112562306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA2,
112662306a36Sopenharmony_ci		.port_ops	= &piix_pata_ops,
112762306a36Sopenharmony_ci	},
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	[ich_pata_33] =		/* ICH0 - ICH at 33Mhz*/
113062306a36Sopenharmony_ci	{
113162306a36Sopenharmony_ci		.flags		= PIIX_PATA_FLAGS,
113262306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
113362306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA12_ONLY, /* Check: maybe MWDMA0 is ok  */
113462306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA2,
113562306a36Sopenharmony_ci		.port_ops	= &ich_pata_ops,
113662306a36Sopenharmony_ci	},
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	[ich_pata_66] =		/* ICH controllers up to 66MHz */
113962306a36Sopenharmony_ci	{
114062306a36Sopenharmony_ci		.flags		= PIIX_PATA_FLAGS,
114162306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
114262306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA12_ONLY, /* MWDMA0 is broken on chip */
114362306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA4,
114462306a36Sopenharmony_ci		.port_ops	= &ich_pata_ops,
114562306a36Sopenharmony_ci	},
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	[ich_pata_100] =
114862306a36Sopenharmony_ci	{
114962306a36Sopenharmony_ci		.flags		= PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
115062306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
115162306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA12_ONLY,
115262306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA5,
115362306a36Sopenharmony_ci		.port_ops	= &ich_pata_ops,
115462306a36Sopenharmony_ci	},
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	[ich_pata_100_nomwdma1] =
115762306a36Sopenharmony_ci	{
115862306a36Sopenharmony_ci		.flags		= PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
115962306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
116062306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2_ONLY,
116162306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA5,
116262306a36Sopenharmony_ci		.port_ops	= &ich_pata_ops,
116362306a36Sopenharmony_ci	},
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	[ich5_sata] =
116662306a36Sopenharmony_ci	{
116762306a36Sopenharmony_ci		.flags		= PIIX_SATA_FLAGS,
116862306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
116962306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
117062306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
117162306a36Sopenharmony_ci		.port_ops	= &piix_sata_ops,
117262306a36Sopenharmony_ci	},
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	[ich6_sata] =
117562306a36Sopenharmony_ci	{
117662306a36Sopenharmony_ci		.flags		= PIIX_SATA_FLAGS,
117762306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
117862306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
117962306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
118062306a36Sopenharmony_ci		.port_ops	= &piix_sata_ops,
118162306a36Sopenharmony_ci	},
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	[ich6m_sata] =
118462306a36Sopenharmony_ci	{
118562306a36Sopenharmony_ci		.flags		= PIIX_SATA_FLAGS,
118662306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
118762306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
118862306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
118962306a36Sopenharmony_ci		.port_ops	= &piix_sata_ops,
119062306a36Sopenharmony_ci	},
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	[ich8_sata] =
119362306a36Sopenharmony_ci	{
119462306a36Sopenharmony_ci		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR,
119562306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
119662306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
119762306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
119862306a36Sopenharmony_ci		.port_ops	= &piix_sata_ops,
119962306a36Sopenharmony_ci	},
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	[ich8_2port_sata] =
120262306a36Sopenharmony_ci	{
120362306a36Sopenharmony_ci		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR,
120462306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
120562306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
120662306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
120762306a36Sopenharmony_ci		.port_ops	= &piix_sata_ops,
120862306a36Sopenharmony_ci	},
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	[tolapai_sata] =
121162306a36Sopenharmony_ci	{
121262306a36Sopenharmony_ci		.flags		= PIIX_SATA_FLAGS,
121362306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
121462306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
121562306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
121662306a36Sopenharmony_ci		.port_ops	= &piix_sata_ops,
121762306a36Sopenharmony_ci	},
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	[ich8m_apple_sata] =
122062306a36Sopenharmony_ci	{
122162306a36Sopenharmony_ci		.flags		= PIIX_SATA_FLAGS,
122262306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
122362306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
122462306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
122562306a36Sopenharmony_ci		.port_ops	= &piix_sata_ops,
122662306a36Sopenharmony_ci	},
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	[piix_pata_vmw] =
122962306a36Sopenharmony_ci	{
123062306a36Sopenharmony_ci		.flags		= PIIX_PATA_FLAGS,
123162306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
123262306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA12_ONLY, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
123362306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA2,
123462306a36Sopenharmony_ci		.port_ops	= &piix_vmw_ops,
123562306a36Sopenharmony_ci	},
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	/*
123862306a36Sopenharmony_ci	 * some Sandybridge chipsets have broken 32 mode up to now,
123962306a36Sopenharmony_ci	 * see https://bugzilla.kernel.org/show_bug.cgi?id=40592
124062306a36Sopenharmony_ci	 */
124162306a36Sopenharmony_ci	[ich8_sata_snb] =
124262306a36Sopenharmony_ci	{
124362306a36Sopenharmony_ci		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR | PIIX_FLAG_PIO16,
124462306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
124562306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
124662306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
124762306a36Sopenharmony_ci		.port_ops	= &piix_sata_ops,
124862306a36Sopenharmony_ci	},
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	[ich8_2port_sata_snb] =
125162306a36Sopenharmony_ci	{
125262306a36Sopenharmony_ci		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR
125362306a36Sopenharmony_ci					| PIIX_FLAG_PIO16,
125462306a36Sopenharmony_ci		.pio_mask	= ATA_PIO4,
125562306a36Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
125662306a36Sopenharmony_ci		.udma_mask	= ATA_UDMA6,
125762306a36Sopenharmony_ci		.port_ops	= &piix_sata_ops,
125862306a36Sopenharmony_ci	},
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	[ich8_2port_sata_byt] =
126162306a36Sopenharmony_ci	{
126262306a36Sopenharmony_ci		.flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR | PIIX_FLAG_PIO16,
126362306a36Sopenharmony_ci		.pio_mask       = ATA_PIO4,
126462306a36Sopenharmony_ci		.mwdma_mask     = ATA_MWDMA2,
126562306a36Sopenharmony_ci		.udma_mask      = ATA_UDMA6,
126662306a36Sopenharmony_ci		.port_ops       = &piix_sata_ops,
126762306a36Sopenharmony_ci	},
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci};
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci#define AHCI_PCI_BAR 5
127262306a36Sopenharmony_ci#define AHCI_GLOBAL_CTL 0x04
127362306a36Sopenharmony_ci#define AHCI_ENABLE (1 << 31)
127462306a36Sopenharmony_cistatic int piix_disable_ahci(struct pci_dev *pdev)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	void __iomem *mmio;
127762306a36Sopenharmony_ci	u32 tmp;
127862306a36Sopenharmony_ci	int rc = 0;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	/* BUG: pci_enable_device has not yet been called.  This
128162306a36Sopenharmony_ci	 * works because this device is usually set up by BIOS.
128262306a36Sopenharmony_ci	 */
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	if (!pci_resource_start(pdev, AHCI_PCI_BAR) ||
128562306a36Sopenharmony_ci	    !pci_resource_len(pdev, AHCI_PCI_BAR))
128662306a36Sopenharmony_ci		return 0;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	mmio = pci_iomap(pdev, AHCI_PCI_BAR, 64);
128962306a36Sopenharmony_ci	if (!mmio)
129062306a36Sopenharmony_ci		return -ENOMEM;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	tmp = ioread32(mmio + AHCI_GLOBAL_CTL);
129362306a36Sopenharmony_ci	if (tmp & AHCI_ENABLE) {
129462306a36Sopenharmony_ci		tmp &= ~AHCI_ENABLE;
129562306a36Sopenharmony_ci		iowrite32(tmp, mmio + AHCI_GLOBAL_CTL);
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci		tmp = ioread32(mmio + AHCI_GLOBAL_CTL);
129862306a36Sopenharmony_ci		if (tmp & AHCI_ENABLE)
129962306a36Sopenharmony_ci			rc = -EIO;
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	pci_iounmap(pdev, mmio);
130362306a36Sopenharmony_ci	return rc;
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci/**
130762306a36Sopenharmony_ci *	piix_check_450nx_errata	-	Check for problem 450NX setup
130862306a36Sopenharmony_ci *	@ata_dev: the PCI device to check
130962306a36Sopenharmony_ci *
131062306a36Sopenharmony_ci *	Check for the present of 450NX errata #19 and errata #25. If
131162306a36Sopenharmony_ci *	they are found return an error code so we can turn off DMA
131262306a36Sopenharmony_ci */
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_cistatic int piix_check_450nx_errata(struct pci_dev *ata_dev)
131562306a36Sopenharmony_ci{
131662306a36Sopenharmony_ci	struct pci_dev *pdev = NULL;
131762306a36Sopenharmony_ci	u16 cfg;
131862306a36Sopenharmony_ci	int no_piix_dma = 0;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev)) != NULL) {
132162306a36Sopenharmony_ci		/* Look for 450NX PXB. Check for problem configurations
132262306a36Sopenharmony_ci		   A PCI quirk checks bit 6 already */
132362306a36Sopenharmony_ci		pci_read_config_word(pdev, 0x41, &cfg);
132462306a36Sopenharmony_ci		/* Only on the original revision: IDE DMA can hang */
132562306a36Sopenharmony_ci		if (pdev->revision == 0x00)
132662306a36Sopenharmony_ci			no_piix_dma = 1;
132762306a36Sopenharmony_ci		/* On all revisions below 5 PXB bus lock must be disabled for IDE */
132862306a36Sopenharmony_ci		else if (cfg & (1<<14) && pdev->revision < 5)
132962306a36Sopenharmony_ci			no_piix_dma = 2;
133062306a36Sopenharmony_ci	}
133162306a36Sopenharmony_ci	if (no_piix_dma)
133262306a36Sopenharmony_ci		dev_warn(&ata_dev->dev,
133362306a36Sopenharmony_ci			 "450NX errata present, disabling IDE DMA%s\n",
133462306a36Sopenharmony_ci			 no_piix_dma == 2 ? " - a BIOS update may resolve this"
133562306a36Sopenharmony_ci			 : "");
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	return no_piix_dma;
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_cistatic void piix_init_pcs(struct ata_host *host,
134162306a36Sopenharmony_ci			  const struct piix_map_db *map_db)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(host->dev);
134462306a36Sopenharmony_ci	u16 pcs, new_pcs;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	pci_read_config_word(pdev, ICH5_PCS, &pcs);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	new_pcs = pcs | map_db->port_enable;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	if (new_pcs != pcs) {
135162306a36Sopenharmony_ci		pci_write_config_word(pdev, ICH5_PCS, new_pcs);
135262306a36Sopenharmony_ci		msleep(150);
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_cistatic const int *piix_init_sata_map(struct pci_dev *pdev,
135762306a36Sopenharmony_ci				     struct ata_port_info *pinfo,
135862306a36Sopenharmony_ci				     const struct piix_map_db *map_db)
135962306a36Sopenharmony_ci{
136062306a36Sopenharmony_ci	const int *map;
136162306a36Sopenharmony_ci	int i, invalid_map = 0;
136262306a36Sopenharmony_ci	u8 map_value;
136362306a36Sopenharmony_ci	char buf[32];
136462306a36Sopenharmony_ci	char *p = buf, *end = buf + sizeof(buf);
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	pci_read_config_byte(pdev, ICH5_PMR, &map_value);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	map = map_db->map[map_value & map_db->mask];
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
137162306a36Sopenharmony_ci		switch (map[i]) {
137262306a36Sopenharmony_ci		case RV:
137362306a36Sopenharmony_ci			invalid_map = 1;
137462306a36Sopenharmony_ci			p += scnprintf(p, end - p, " XX");
137562306a36Sopenharmony_ci			break;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci		case NA:
137862306a36Sopenharmony_ci			p += scnprintf(p, end - p, " --");
137962306a36Sopenharmony_ci			break;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci		case IDE:
138262306a36Sopenharmony_ci			WARN_ON((i & 1) || map[i + 1] != IDE);
138362306a36Sopenharmony_ci			pinfo[i / 2] = piix_port_info[ich_pata_100];
138462306a36Sopenharmony_ci			i++;
138562306a36Sopenharmony_ci			p += scnprintf(p, end - p, " IDE IDE");
138662306a36Sopenharmony_ci			break;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci		default:
138962306a36Sopenharmony_ci			p += scnprintf(p, end - p, " P%d", map[i]);
139062306a36Sopenharmony_ci			if (i & 1)
139162306a36Sopenharmony_ci				pinfo[i / 2].flags |= ATA_FLAG_SLAVE_POSS;
139262306a36Sopenharmony_ci			break;
139362306a36Sopenharmony_ci		}
139462306a36Sopenharmony_ci	}
139562306a36Sopenharmony_ci	dev_info(&pdev->dev, "MAP [%s ]\n", buf);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if (invalid_map)
139862306a36Sopenharmony_ci		dev_err(&pdev->dev, "invalid MAP value %u\n", map_value);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	return map;
140162306a36Sopenharmony_ci}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_cistatic bool piix_no_sidpr(struct ata_host *host)
140462306a36Sopenharmony_ci{
140562306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(host->dev);
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	/*
140862306a36Sopenharmony_ci	 * Samsung DB-P70 only has three ATA ports exposed and
140962306a36Sopenharmony_ci	 * curiously the unconnected first port reports link online
141062306a36Sopenharmony_ci	 * while not responding to SRST protocol causing excessive
141162306a36Sopenharmony_ci	 * detection delay.
141262306a36Sopenharmony_ci	 *
141362306a36Sopenharmony_ci	 * Unfortunately, the system doesn't carry enough DMI
141462306a36Sopenharmony_ci	 * information to identify the machine but does have subsystem
141562306a36Sopenharmony_ci	 * vendor and device set.  As it's unclear whether the
141662306a36Sopenharmony_ci	 * subsystem vendor/device is used only for this specific
141762306a36Sopenharmony_ci	 * board, the port can't be disabled solely with the
141862306a36Sopenharmony_ci	 * information; however, turning off SIDPR access works around
141962306a36Sopenharmony_ci	 * the problem.  Turn it off.
142062306a36Sopenharmony_ci	 *
142162306a36Sopenharmony_ci	 * This problem is reported in bnc#441240.
142262306a36Sopenharmony_ci	 *
142362306a36Sopenharmony_ci	 * https://bugzilla.novell.com/show_bug.cgi?id=441420
142462306a36Sopenharmony_ci	 */
142562306a36Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x2920 &&
142662306a36Sopenharmony_ci	    pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG &&
142762306a36Sopenharmony_ci	    pdev->subsystem_device == 0xb049) {
142862306a36Sopenharmony_ci		dev_warn(host->dev,
142962306a36Sopenharmony_ci			 "Samsung DB-P70 detected, disabling SIDPR\n");
143062306a36Sopenharmony_ci		return true;
143162306a36Sopenharmony_ci	}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	return false;
143462306a36Sopenharmony_ci}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_cistatic int piix_init_sidpr(struct ata_host *host)
143762306a36Sopenharmony_ci{
143862306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(host->dev);
143962306a36Sopenharmony_ci	struct piix_host_priv *hpriv = host->private_data;
144062306a36Sopenharmony_ci	struct ata_link *link0 = &host->ports[0]->link;
144162306a36Sopenharmony_ci	u32 scontrol;
144262306a36Sopenharmony_ci	int i, rc;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	/* check for availability */
144562306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
144662306a36Sopenharmony_ci		if (hpriv->map[i] == IDE)
144762306a36Sopenharmony_ci			return 0;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	/* is it blacklisted? */
145062306a36Sopenharmony_ci	if (piix_no_sidpr(host))
145162306a36Sopenharmony_ci		return 0;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
145462306a36Sopenharmony_ci		return 0;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 ||
145762306a36Sopenharmony_ci	    pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN)
145862306a36Sopenharmony_ci		return 0;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME))
146162306a36Sopenharmony_ci		return 0;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	/* SCR access via SIDPR doesn't work on some configurations.
146662306a36Sopenharmony_ci	 * Give it a test drive by inhibiting power save modes which
146762306a36Sopenharmony_ci	 * we'll do anyway.
146862306a36Sopenharmony_ci	 */
146962306a36Sopenharmony_ci	piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	/* if IPM is already 3, SCR access is probably working.  Don't
147262306a36Sopenharmony_ci	 * un-inhibit power save modes as BIOS might have inhibited
147362306a36Sopenharmony_ci	 * them for a reason.
147462306a36Sopenharmony_ci	 */
147562306a36Sopenharmony_ci	if ((scontrol & 0xf00) != 0x300) {
147662306a36Sopenharmony_ci		scontrol |= 0x300;
147762306a36Sopenharmony_ci		piix_sidpr_scr_write(link0, SCR_CONTROL, scontrol);
147862306a36Sopenharmony_ci		piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci		if ((scontrol & 0xf00) != 0x300) {
148162306a36Sopenharmony_ci			dev_info(host->dev,
148262306a36Sopenharmony_ci				 "SCR access via SIDPR is available but doesn't work\n");
148362306a36Sopenharmony_ci			return 0;
148462306a36Sopenharmony_ci		}
148562306a36Sopenharmony_ci	}
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	/* okay, SCRs available, set ops and ask libata for slave_link */
148862306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
148962306a36Sopenharmony_ci		struct ata_port *ap = host->ports[i];
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci		ap->ops = &piix_sidpr_sata_ops;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci		if (ap->flags & ATA_FLAG_SLAVE_POSS) {
149462306a36Sopenharmony_ci			rc = ata_slave_link_init(ap);
149562306a36Sopenharmony_ci			if (rc)
149662306a36Sopenharmony_ci				return rc;
149762306a36Sopenharmony_ci		}
149862306a36Sopenharmony_ci	}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	return 0;
150162306a36Sopenharmony_ci}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_cistatic void piix_iocfg_bit18_quirk(struct ata_host *host)
150462306a36Sopenharmony_ci{
150562306a36Sopenharmony_ci	static const struct dmi_system_id sysids[] = {
150662306a36Sopenharmony_ci		{
150762306a36Sopenharmony_ci			/* Clevo M570U sets IOCFG bit 18 if the cdrom
150862306a36Sopenharmony_ci			 * isn't used to boot the system which
150962306a36Sopenharmony_ci			 * disables the channel.
151062306a36Sopenharmony_ci			 */
151162306a36Sopenharmony_ci			.ident = "M570U",
151262306a36Sopenharmony_ci			.matches = {
151362306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Clevo Co."),
151462306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "M570U"),
151562306a36Sopenharmony_ci			},
151662306a36Sopenharmony_ci		},
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci		{ }	/* terminate list */
151962306a36Sopenharmony_ci	};
152062306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(host->dev);
152162306a36Sopenharmony_ci	struct piix_host_priv *hpriv = host->private_data;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	if (!dmi_check_system(sysids))
152462306a36Sopenharmony_ci		return;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	/* The datasheet says that bit 18 is NOOP but certain systems
152762306a36Sopenharmony_ci	 * seem to use it to disable a channel.  Clear the bit on the
152862306a36Sopenharmony_ci	 * affected systems.
152962306a36Sopenharmony_ci	 */
153062306a36Sopenharmony_ci	if (hpriv->saved_iocfg & (1 << 18)) {
153162306a36Sopenharmony_ci		dev_info(&pdev->dev, "applying IOCFG bit18 quirk\n");
153262306a36Sopenharmony_ci		pci_write_config_dword(pdev, PIIX_IOCFG,
153362306a36Sopenharmony_ci				       hpriv->saved_iocfg & ~(1 << 18));
153462306a36Sopenharmony_ci	}
153562306a36Sopenharmony_ci}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_cistatic bool piix_broken_system_poweroff(struct pci_dev *pdev)
153862306a36Sopenharmony_ci{
153962306a36Sopenharmony_ci	static const struct dmi_system_id broken_systems[] = {
154062306a36Sopenharmony_ci		{
154162306a36Sopenharmony_ci			.ident = "HP Compaq 2510p",
154262306a36Sopenharmony_ci			.matches = {
154362306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
154462306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 2510p"),
154562306a36Sopenharmony_ci			},
154662306a36Sopenharmony_ci			/* PCI slot number of the controller */
154762306a36Sopenharmony_ci			.driver_data = (void *)0x1FUL,
154862306a36Sopenharmony_ci		},
154962306a36Sopenharmony_ci		{
155062306a36Sopenharmony_ci			.ident = "HP Compaq nc6000",
155162306a36Sopenharmony_ci			.matches = {
155262306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
155362306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nc6000"),
155462306a36Sopenharmony_ci			},
155562306a36Sopenharmony_ci			/* PCI slot number of the controller */
155662306a36Sopenharmony_ci			.driver_data = (void *)0x1FUL,
155762306a36Sopenharmony_ci		},
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci		{ }	/* terminate list */
156062306a36Sopenharmony_ci	};
156162306a36Sopenharmony_ci	const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	if (dmi) {
156462306a36Sopenharmony_ci		unsigned long slot = (unsigned long)dmi->driver_data;
156562306a36Sopenharmony_ci		/* apply the quirk only to on-board controllers */
156662306a36Sopenharmony_ci		return slot == PCI_SLOT(pdev->devfn);
156762306a36Sopenharmony_ci	}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	return false;
157062306a36Sopenharmony_ci}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_cistatic int prefer_ms_hyperv = 1;
157362306a36Sopenharmony_cimodule_param(prefer_ms_hyperv, int, 0);
157462306a36Sopenharmony_ciMODULE_PARM_DESC(prefer_ms_hyperv,
157562306a36Sopenharmony_ci	"Prefer Hyper-V paravirtualization drivers instead of ATA, "
157662306a36Sopenharmony_ci	"0 - Use ATA drivers, "
157762306a36Sopenharmony_ci	"1 (Default) - Use the paravirtualization drivers.");
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cistatic void piix_ignore_devices_quirk(struct ata_host *host)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_HYPERV_STORAGE)
158262306a36Sopenharmony_ci	static const struct dmi_system_id ignore_hyperv[] = {
158362306a36Sopenharmony_ci		{
158462306a36Sopenharmony_ci			/* On Hyper-V hypervisors the disks are exposed on
158562306a36Sopenharmony_ci			 * both the emulated SATA controller and on the
158662306a36Sopenharmony_ci			 * paravirtualised drivers.  The CD/DVD devices
158762306a36Sopenharmony_ci			 * are only exposed on the emulated controller.
158862306a36Sopenharmony_ci			 * Request we ignore ATA devices on this host.
158962306a36Sopenharmony_ci			 */
159062306a36Sopenharmony_ci			.ident = "Hyper-V Virtual Machine",
159162306a36Sopenharmony_ci			.matches = {
159262306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR,
159362306a36Sopenharmony_ci						"Microsoft Corporation"),
159462306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
159562306a36Sopenharmony_ci			},
159662306a36Sopenharmony_ci		},
159762306a36Sopenharmony_ci		{ }	/* terminate list */
159862306a36Sopenharmony_ci	};
159962306a36Sopenharmony_ci	static const struct dmi_system_id allow_virtual_pc[] = {
160062306a36Sopenharmony_ci		{
160162306a36Sopenharmony_ci			/* In MS Virtual PC guests the DMI ident is nearly
160262306a36Sopenharmony_ci			 * identical to a Hyper-V guest. One difference is the
160362306a36Sopenharmony_ci			 * product version which is used here to identify
160462306a36Sopenharmony_ci			 * a Virtual PC guest. This entry allows ata_piix to
160562306a36Sopenharmony_ci			 * drive the emulated hardware.
160662306a36Sopenharmony_ci			 */
160762306a36Sopenharmony_ci			.ident = "MS Virtual PC 2007",
160862306a36Sopenharmony_ci			.matches = {
160962306a36Sopenharmony_ci				DMI_MATCH(DMI_SYS_VENDOR,
161062306a36Sopenharmony_ci						"Microsoft Corporation"),
161162306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
161262306a36Sopenharmony_ci				DMI_MATCH(DMI_PRODUCT_VERSION, "VS2005R2"),
161362306a36Sopenharmony_ci			},
161462306a36Sopenharmony_ci		},
161562306a36Sopenharmony_ci		{ }	/* terminate list */
161662306a36Sopenharmony_ci	};
161762306a36Sopenharmony_ci	const struct dmi_system_id *ignore = dmi_first_match(ignore_hyperv);
161862306a36Sopenharmony_ci	const struct dmi_system_id *allow = dmi_first_match(allow_virtual_pc);
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	if (ignore && !allow && prefer_ms_hyperv) {
162162306a36Sopenharmony_ci		host->flags |= ATA_HOST_IGNORE_ATA;
162262306a36Sopenharmony_ci		dev_info(host->dev, "%s detected, ATA device ignore set\n",
162362306a36Sopenharmony_ci			ignore->ident);
162462306a36Sopenharmony_ci	}
162562306a36Sopenharmony_ci#endif
162662306a36Sopenharmony_ci}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci/**
162962306a36Sopenharmony_ci *	piix_init_one - Register PIIX ATA PCI device with kernel services
163062306a36Sopenharmony_ci *	@pdev: PCI device to register
163162306a36Sopenharmony_ci *	@ent: Entry in piix_pci_tbl matching with @pdev
163262306a36Sopenharmony_ci *
163362306a36Sopenharmony_ci *	Called from kernel PCI layer.  We probe for combined mode (sigh),
163462306a36Sopenharmony_ci *	and then hand over control to libata, for it to do the rest.
163562306a36Sopenharmony_ci *
163662306a36Sopenharmony_ci *	LOCKING:
163762306a36Sopenharmony_ci *	Inherited from PCI layer (may sleep).
163862306a36Sopenharmony_ci *
163962306a36Sopenharmony_ci *	RETURNS:
164062306a36Sopenharmony_ci *	Zero on success, or -ERRNO value.
164162306a36Sopenharmony_ci */
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_cistatic int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
164662306a36Sopenharmony_ci	struct ata_port_info port_info[2];
164762306a36Sopenharmony_ci	const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };
164862306a36Sopenharmony_ci	const struct scsi_host_template *sht = &piix_sht;
164962306a36Sopenharmony_ci	unsigned long port_flags;
165062306a36Sopenharmony_ci	struct ata_host *host;
165162306a36Sopenharmony_ci	struct piix_host_priv *hpriv;
165262306a36Sopenharmony_ci	int rc;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	ata_print_version_once(&pdev->dev, DRV_VERSION);
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	/* no hotplugging support for later devices (FIXME) */
165762306a36Sopenharmony_ci	if (!in_module_init && ent->driver_data >= ich5_sata)
165862306a36Sopenharmony_ci		return -ENODEV;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	if (piix_broken_system_poweroff(pdev)) {
166162306a36Sopenharmony_ci		piix_port_info[ent->driver_data].flags |=
166262306a36Sopenharmony_ci				ATA_FLAG_NO_POWEROFF_SPINDOWN |
166362306a36Sopenharmony_ci					ATA_FLAG_NO_HIBERNATE_SPINDOWN;
166462306a36Sopenharmony_ci		dev_info(&pdev->dev, "quirky BIOS, skipping spindown "
166562306a36Sopenharmony_ci				"on poweroff and hibernation\n");
166662306a36Sopenharmony_ci	}
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	port_info[0] = piix_port_info[ent->driver_data];
166962306a36Sopenharmony_ci	port_info[1] = piix_port_info[ent->driver_data];
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	port_flags = port_info[0].flags;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	/* enable device and prepare host */
167462306a36Sopenharmony_ci	rc = pcim_enable_device(pdev);
167562306a36Sopenharmony_ci	if (rc)
167662306a36Sopenharmony_ci		return rc;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
167962306a36Sopenharmony_ci	if (!hpriv)
168062306a36Sopenharmony_ci		return -ENOMEM;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	/* Save IOCFG, this will be used for cable detection, quirk
168362306a36Sopenharmony_ci	 * detection and restoration on detach.  This is necessary
168462306a36Sopenharmony_ci	 * because some ACPI implementations mess up cable related
168562306a36Sopenharmony_ci	 * bits on _STM.  Reported on kernel bz#11879.
168662306a36Sopenharmony_ci	 */
168762306a36Sopenharmony_ci	pci_read_config_dword(pdev, PIIX_IOCFG, &hpriv->saved_iocfg);
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	/* ICH6R may be driven by either ata_piix or ahci driver
169062306a36Sopenharmony_ci	 * regardless of BIOS configuration.  Make sure AHCI mode is
169162306a36Sopenharmony_ci	 * off.
169262306a36Sopenharmony_ci	 */
169362306a36Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x2652) {
169462306a36Sopenharmony_ci		rc = piix_disable_ahci(pdev);
169562306a36Sopenharmony_ci		if (rc)
169662306a36Sopenharmony_ci			return rc;
169762306a36Sopenharmony_ci	}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	/* SATA map init can change port_info, do it before prepping host */
170062306a36Sopenharmony_ci	if (port_flags & ATA_FLAG_SATA)
170162306a36Sopenharmony_ci		hpriv->map = piix_init_sata_map(pdev, port_info,
170262306a36Sopenharmony_ci					piix_map_db_table[ent->driver_data]);
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
170562306a36Sopenharmony_ci	if (rc)
170662306a36Sopenharmony_ci		return rc;
170762306a36Sopenharmony_ci	host->private_data = hpriv;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	/* initialize controller */
171062306a36Sopenharmony_ci	if (port_flags & ATA_FLAG_SATA) {
171162306a36Sopenharmony_ci		piix_init_pcs(host, piix_map_db_table[ent->driver_data]);
171262306a36Sopenharmony_ci		rc = piix_init_sidpr(host);
171362306a36Sopenharmony_ci		if (rc)
171462306a36Sopenharmony_ci			return rc;
171562306a36Sopenharmony_ci		if (host->ports[0]->ops == &piix_sidpr_sata_ops)
171662306a36Sopenharmony_ci			sht = &piix_sidpr_sht;
171762306a36Sopenharmony_ci	}
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	/* apply IOCFG bit18 quirk */
172062306a36Sopenharmony_ci	piix_iocfg_bit18_quirk(host);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	/* On ICH5, some BIOSen disable the interrupt using the
172362306a36Sopenharmony_ci	 * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
172462306a36Sopenharmony_ci	 * On ICH6, this bit has the same effect, but only when
172562306a36Sopenharmony_ci	 * MSI is disabled (and it is disabled, as we don't use
172662306a36Sopenharmony_ci	 * message-signalled interrupts currently).
172762306a36Sopenharmony_ci	 */
172862306a36Sopenharmony_ci	if (port_flags & PIIX_FLAG_CHECKINTR)
172962306a36Sopenharmony_ci		pci_intx(pdev, 1);
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	if (piix_check_450nx_errata(pdev)) {
173262306a36Sopenharmony_ci		/* This writes into the master table but it does not
173362306a36Sopenharmony_ci		   really matter for this errata as we will apply it to
173462306a36Sopenharmony_ci		   all the PIIX devices on the board */
173562306a36Sopenharmony_ci		host->ports[0]->mwdma_mask = 0;
173662306a36Sopenharmony_ci		host->ports[0]->udma_mask = 0;
173762306a36Sopenharmony_ci		host->ports[1]->mwdma_mask = 0;
173862306a36Sopenharmony_ci		host->ports[1]->udma_mask = 0;
173962306a36Sopenharmony_ci	}
174062306a36Sopenharmony_ci	host->flags |= ATA_HOST_PARALLEL_SCAN;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	/* Allow hosts to specify device types to ignore when scanning. */
174362306a36Sopenharmony_ci	piix_ignore_devices_quirk(host);
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	pci_set_master(pdev);
174662306a36Sopenharmony_ci	return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
174762306a36Sopenharmony_ci}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_cistatic void piix_remove_one(struct pci_dev *pdev)
175062306a36Sopenharmony_ci{
175162306a36Sopenharmony_ci	struct ata_host *host = pci_get_drvdata(pdev);
175262306a36Sopenharmony_ci	struct piix_host_priv *hpriv = host->private_data;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	pci_write_config_dword(pdev, PIIX_IOCFG, hpriv->saved_iocfg);
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	ata_pci_remove_one(pdev);
175762306a36Sopenharmony_ci}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_cistatic struct pci_driver piix_pci_driver = {
176062306a36Sopenharmony_ci	.name			= DRV_NAME,
176162306a36Sopenharmony_ci	.id_table		= piix_pci_tbl,
176262306a36Sopenharmony_ci	.probe			= piix_init_one,
176362306a36Sopenharmony_ci	.remove			= piix_remove_one,
176462306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
176562306a36Sopenharmony_ci	.suspend		= piix_pci_device_suspend,
176662306a36Sopenharmony_ci	.resume			= piix_pci_device_resume,
176762306a36Sopenharmony_ci#endif
176862306a36Sopenharmony_ci};
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_cistatic int __init piix_init(void)
177162306a36Sopenharmony_ci{
177262306a36Sopenharmony_ci	int rc;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	rc = pci_register_driver(&piix_pci_driver);
177562306a36Sopenharmony_ci	if (rc)
177662306a36Sopenharmony_ci		return rc;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	in_module_init = 0;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	return 0;
178162306a36Sopenharmony_ci}
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_cistatic void __exit piix_exit(void)
178462306a36Sopenharmony_ci{
178562306a36Sopenharmony_ci	pci_unregister_driver(&piix_pci_driver);
178662306a36Sopenharmony_ci}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_cimodule_init(piix_init);
178962306a36Sopenharmony_cimodule_exit(piix_exit);
1790