⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sata_sil24.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * sata_sil24.c - Driver for Silicon Image 3124/3132 SATA-2 controllers * * Copyright 2005  Tejun Heo * * Based on preview driver from Silicon Image. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/dma-mapping.h>#include <linux/device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_cmnd.h>#include <linux/libata.h>#define DRV_NAME	"sata_sil24"#define DRV_VERSION	"1.1"/* * Port request block (PRB) 32 bytes */struct sil24_prb {	__le16	ctrl;	__le16	prot;	__le32	rx_cnt;	u8	fis[6 * 4];};/* * Scatter gather entry (SGE) 16 bytes */struct sil24_sge {	__le64	addr;	__le32	cnt;	__le32	flags;};/* * Port multiplier */struct sil24_port_multiplier {	__le32	diag;	__le32	sactive;};enum {	SIL24_HOST_BAR		= 0,	SIL24_PORT_BAR		= 2,	/* sil24 fetches in chunks of 64bytes.  The first block	 * contains the PRB and two SGEs.  From the second block, it's	 * consisted of four SGEs and called SGT.  Calculate the	 * number of SGTs that fit into one page.	 */	SIL24_PRB_SZ		= sizeof(struct sil24_prb)				  + 2 * sizeof(struct sil24_sge),	SIL24_MAX_SGT		= (PAGE_SIZE - SIL24_PRB_SZ)				  / (4 * sizeof(struct sil24_sge)),	/* This will give us one unused SGEs for ATA.  This extra SGE	 * will be used to store CDB for ATAPI devices.	 */	SIL24_MAX_SGE		= 4 * SIL24_MAX_SGT + 1,	/*	 * Global controller registers (128 bytes @ BAR0)	 */		/* 32 bit regs */	HOST_SLOT_STAT		= 0x00, /* 32 bit slot stat * 4 */	HOST_CTRL		= 0x40,	HOST_IRQ_STAT		= 0x44,	HOST_PHY_CFG		= 0x48,	HOST_BIST_CTRL		= 0x50,	HOST_BIST_PTRN		= 0x54,	HOST_BIST_STAT		= 0x58,	HOST_MEM_BIST_STAT	= 0x5c,	HOST_FLASH_CMD		= 0x70,		/* 8 bit regs */	HOST_FLASH_DATA		= 0x74,	HOST_TRANSITION_DETECT	= 0x75,	HOST_GPIO_CTRL		= 0x76,	HOST_I2C_ADDR		= 0x78, /* 32 bit */	HOST_I2C_DATA		= 0x7c,	HOST_I2C_XFER_CNT	= 0x7e,	HOST_I2C_CTRL		= 0x7f,	/* HOST_SLOT_STAT bits */	HOST_SSTAT_ATTN		= (1 << 31),	/* HOST_CTRL bits */	HOST_CTRL_M66EN		= (1 << 16), /* M66EN PCI bus signal */	HOST_CTRL_TRDY		= (1 << 17), /* latched PCI TRDY */	HOST_CTRL_STOP		= (1 << 18), /* latched PCI STOP */	HOST_CTRL_DEVSEL	= (1 << 19), /* latched PCI DEVSEL */	HOST_CTRL_REQ64		= (1 << 20), /* latched PCI REQ64 */	HOST_CTRL_GLOBAL_RST	= (1 << 31), /* global reset */	/*	 * Port registers	 * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2)	 */	PORT_REGS_SIZE		= 0x2000,	PORT_LRAM		= 0x0000, /* 31 LRAM slots and PMP regs */	PORT_LRAM_SLOT_SZ	= 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */	PORT_PMP		= 0x0f80, /* 8 bytes PMP * 16 (128 bytes) */	PORT_PMP_STATUS		= 0x0000, /* port device status offset */	PORT_PMP_QACTIVE	= 0x0004, /* port device QActive offset */	PORT_PMP_SIZE		= 0x0008, /* 8 bytes per PMP */		/* 32 bit regs */	PORT_CTRL_STAT		= 0x1000, /* write: ctrl-set, read: stat */	PORT_CTRL_CLR		= 0x1004, /* write: ctrl-clear */	PORT_IRQ_STAT		= 0x1008, /* high: status, low: interrupt */	PORT_IRQ_ENABLE_SET	= 0x1010, /* write: enable-set */	PORT_IRQ_ENABLE_CLR	= 0x1014, /* write: enable-clear */	PORT_ACTIVATE_UPPER_ADDR= 0x101c,	PORT_EXEC_FIFO		= 0x1020, /* command execution fifo */	PORT_CMD_ERR		= 0x1024, /* command error number */	PORT_FIS_CFG		= 0x1028,	PORT_FIFO_THRES		= 0x102c,		/* 16 bit regs */	PORT_DECODE_ERR_CNT	= 0x1040,	PORT_DECODE_ERR_THRESH	= 0x1042,	PORT_CRC_ERR_CNT	= 0x1044,	PORT_CRC_ERR_THRESH	= 0x1046,	PORT_HSHK_ERR_CNT	= 0x1048,	PORT_HSHK_ERR_THRESH	= 0x104a,		/* 32 bit regs */	PORT_PHY_CFG		= 0x1050,	PORT_SLOT_STAT		= 0x1800,	PORT_CMD_ACTIVATE	= 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */	PORT_CONTEXT		= 0x1e04,	PORT_EXEC_DIAG		= 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */	PORT_PSD_DIAG		= 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */	PORT_SCONTROL		= 0x1f00,	PORT_SSTATUS		= 0x1f04,	PORT_SERROR		= 0x1f08,	PORT_SACTIVE		= 0x1f0c,	/* PORT_CTRL_STAT bits */	PORT_CS_PORT_RST	= (1 << 0), /* port reset */	PORT_CS_DEV_RST		= (1 << 1), /* device reset */	PORT_CS_INIT		= (1 << 2), /* port initialize */	PORT_CS_IRQ_WOC		= (1 << 3), /* interrupt write one to clear */	PORT_CS_CDB16		= (1 << 5), /* 0=12b cdb, 1=16b cdb */	PORT_CS_PMP_RESUME	= (1 << 6), /* PMP resume */	PORT_CS_32BIT_ACTV	= (1 << 10), /* 32-bit activation */	PORT_CS_PMP_EN		= (1 << 13), /* port multiplier enable */	PORT_CS_RDY		= (1 << 31), /* port ready to accept commands */	/* PORT_IRQ_STAT/ENABLE_SET/CLR */	/* bits[11:0] are masked */	PORT_IRQ_COMPLETE	= (1 << 0), /* command(s) completed */	PORT_IRQ_ERROR		= (1 << 1), /* command execution error */	PORT_IRQ_PORTRDY_CHG	= (1 << 2), /* port ready change */	PORT_IRQ_PWR_CHG	= (1 << 3), /* power management change */	PORT_IRQ_PHYRDY_CHG	= (1 << 4), /* PHY ready change */	PORT_IRQ_COMWAKE	= (1 << 5), /* COMWAKE received */	PORT_IRQ_UNK_FIS	= (1 << 6), /* unknown FIS received */	PORT_IRQ_DEV_XCHG	= (1 << 7), /* device exchanged */	PORT_IRQ_8B10B		= (1 << 8), /* 8b/10b decode error threshold */	PORT_IRQ_CRC		= (1 << 9), /* CRC error threshold */	PORT_IRQ_HANDSHAKE	= (1 << 10), /* handshake error threshold */	PORT_IRQ_SDB_NOTIFY	= (1 << 11), /* SDB notify received */	DEF_PORT_IRQ		= PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |				  PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |				  PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY,	/* bits[27:16] are unmasked (raw) */	PORT_IRQ_RAW_SHIFT	= 16,	PORT_IRQ_MASKED_MASK	= 0x7ff,	PORT_IRQ_RAW_MASK	= (0x7ff << PORT_IRQ_RAW_SHIFT),	/* ENABLE_SET/CLR specific, intr steering - 2 bit field */	PORT_IRQ_STEER_SHIFT	= 30,	PORT_IRQ_STEER_MASK	= (3 << PORT_IRQ_STEER_SHIFT),	/* PORT_CMD_ERR constants */	PORT_CERR_DEV		= 1, /* Error bit in D2H Register FIS */	PORT_CERR_SDB		= 2, /* Error bit in SDB FIS */	PORT_CERR_DATA		= 3, /* Error in data FIS not detected by dev */	PORT_CERR_SEND		= 4, /* Initial cmd FIS transmission failure */	PORT_CERR_INCONSISTENT	= 5, /* Protocol mismatch */	PORT_CERR_DIRECTION	= 6, /* Data direction mismatch */	PORT_CERR_UNDERRUN	= 7, /* Ran out of SGEs while writing */	PORT_CERR_OVERRUN	= 8, /* Ran out of SGEs while reading */	PORT_CERR_PKT_PROT	= 11, /* DIR invalid in 1st PIO setup of ATAPI */	PORT_CERR_SGT_BOUNDARY	= 16, /* PLD ecode 00 - SGT not on qword boundary */	PORT_CERR_SGT_TGTABRT	= 17, /* PLD ecode 01 - target abort */	PORT_CERR_SGT_MSTABRT	= 18, /* PLD ecode 10 - master abort */	PORT_CERR_SGT_PCIPERR	= 19, /* PLD ecode 11 - PCI parity err while fetching SGT */	PORT_CERR_CMD_BOUNDARY	= 24, /* ctrl[15:13] 001 - PRB not on qword boundary */	PORT_CERR_CMD_TGTABRT	= 25, /* ctrl[15:13] 010 - target abort */	PORT_CERR_CMD_MSTABRT	= 26, /* ctrl[15:13] 100 - master abort */	PORT_CERR_CMD_PCIPERR	= 27, /* ctrl[15:13] 110 - PCI parity err while fetching PRB */	PORT_CERR_XFR_UNDEF	= 32, /* PSD ecode 00 - undefined */	PORT_CERR_XFR_TGTABRT	= 33, /* PSD ecode 01 - target abort */	PORT_CERR_XFR_MSTABRT	= 34, /* PSD ecode 10 - master abort */	PORT_CERR_XFR_PCIPERR	= 35, /* PSD ecode 11 - PCI prity err during transfer */	PORT_CERR_SENDSERVICE	= 36, /* FIS received while sending service */	/* bits of PRB control field */	PRB_CTRL_PROTOCOL	= (1 << 0), /* override def. ATA protocol */	PRB_CTRL_PACKET_READ	= (1 << 4), /* PACKET cmd read */	PRB_CTRL_PACKET_WRITE	= (1 << 5), /* PACKET cmd write */	PRB_CTRL_NIEN		= (1 << 6), /* Mask completion irq */	PRB_CTRL_SRST		= (1 << 7), /* Soft reset request (ign BSY?) */	/* PRB protocol field */	PRB_PROT_PACKET		= (1 << 0),	PRB_PROT_TCQ		= (1 << 1),	PRB_PROT_NCQ		= (1 << 2),	PRB_PROT_READ		= (1 << 3),	PRB_PROT_WRITE		= (1 << 4),	PRB_PROT_TRANSPARENT	= (1 << 5),	/*	 * Other constants	 */	SGE_TRM			= (1 << 31), /* Last SGE in chain */	SGE_LNK			= (1 << 30), /* linked list						Points to SGT, not SGE */	SGE_DRD			= (1 << 29), /* discard data read (/dev/null)						data address ignored */	SIL24_MAX_CMDS		= 31,	/* board id */	BID_SIL3124		= 0,	BID_SIL3132		= 1,	BID_SIL3131		= 2,	/* host flags */	SIL24_COMMON_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |				  ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA |				  ATA_FLAG_AN | ATA_FLAG_PMP,	SIL24_COMMON_LFLAGS	= ATA_LFLAG_SKIP_D2H_BSY,	SIL24_FLAG_PCIX_IRQ_WOC	= (1 << 24), /* IRQ loss errata on PCI-X */	IRQ_STAT_4PORTS		= 0xf,};struct sil24_ata_block {	struct sil24_prb prb;	struct sil24_sge sge[SIL24_MAX_SGE];};struct sil24_atapi_block {	struct sil24_prb prb;	u8 cdb[16];	struct sil24_sge sge[SIL24_MAX_SGE];};union sil24_cmd_block {	struct sil24_ata_block ata;	struct sil24_atapi_block atapi;};static struct sil24_cerr_info {	unsigned int err_mask, action;	const char *desc;} sil24_cerr_db[] = {	[0]			= { AC_ERR_DEV, 0,				    "device error" },	[PORT_CERR_DEV]		= { AC_ERR_DEV, 0,				    "device error via D2H FIS" },	[PORT_CERR_SDB]		= { AC_ERR_DEV, 0,				    "device error via SDB FIS" },	[PORT_CERR_DATA]	= { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,				    "error in data FIS" },	[PORT_CERR_SEND]	= { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,				    "failed to transmit command FIS" },	[PORT_CERR_INCONSISTENT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,				     "protocol mismatch" },	[PORT_CERR_DIRECTION]	= { AC_ERR_HSM, ATA_EH_SOFTRESET,				    "data directon mismatch" },	[PORT_CERR_UNDERRUN]	= { AC_ERR_HSM, ATA_EH_SOFTRESET,				    "ran out of SGEs while writing" },	[PORT_CERR_OVERRUN]	= { AC_ERR_HSM, ATA_EH_SOFTRESET,				    "ran out of SGEs while reading" },	[PORT_CERR_PKT_PROT]	= { AC_ERR_HSM, ATA_EH_SOFTRESET,				    "invalid data directon for ATAPI CDB" },	[PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,				     "SGT not on qword boundary" },	[PORT_CERR_SGT_TGTABRT]	= { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,				    "PCI target abort while fetching SGT" },	[PORT_CERR_SGT_MSTABRT]	= { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,				    "PCI master abort while fetching SGT" },	[PORT_CERR_SGT_PCIPERR]	= { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,				    "PCI parity error while fetching SGT" },	[PORT_CERR_CMD_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,				     "PRB not on qword boundary" },	[PORT_CERR_CMD_TGTABRT]	= { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,				    "PCI target abort while fetching PRB" },	[PORT_CERR_CMD_MSTABRT]	= { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,				    "PCI master abort while fetching PRB" },	[PORT_CERR_CMD_PCIPERR]	= { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,				    "PCI parity error while fetching PRB" },	[PORT_CERR_XFR_UNDEF]	= { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,				    "undefined error while transferring data" },	[PORT_CERR_XFR_TGTABRT]	= { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,				    "PCI target abort while transferring data" },	[PORT_CERR_XFR_MSTABRT]	= { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,				    "PCI master abort while transferring data" },	[PORT_CERR_XFR_PCIPERR]	= { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,				    "PCI parity error while transferring data" },	[PORT_CERR_SENDSERVICE]	= { AC_ERR_HSM, ATA_EH_SOFTRESET,				    "FIS received while sending service FIS" },};/* * ap->private_data * * The preview driver always returned 0 for status.  We emulate it * here from the previous interrupt. */struct sil24_port_priv {	union sil24_cmd_block *cmd_block;	/* 32 cmd blocks */	dma_addr_t cmd_block_dma;		/* DMA base addr for them */	struct ata_taskfile tf;			/* Cached taskfile registers */	int do_port_rst;};static void sil24_dev_config(struct ata_device *dev);static u8 sil24_check_status(struct ata_port *ap);static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);static int sil24_qc_defer(struct ata_queued_cmd *qc);static void sil24_qc_prep(struct ata_queued_cmd *qc);static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);static void sil24_irq_clear(struct ata_port *ap);static void sil24_pmp_attach(struct ata_port *ap);static void sil24_pmp_detach(struct ata_port *ap);static void sil24_freeze(struct ata_port *ap);static void sil24_thaw(struct ata_port *ap);static void sil24_error_handler(struct ata_port *ap);static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);static int sil24_port_start(struct ata_port *ap);static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);#ifdef CONFIG_PMstatic int sil24_pci_device_resume(struct pci_dev *pdev);static int sil24_port_resume(struct ata_port *ap);#endifstatic const struct pci_device_id sil24_pci_tbl[] = {	{ PCI_VDEVICE(CMD, 0x3124), BID_SIL3124 },	{ PCI_VDEVICE(INTEL, 0x3124), BID_SIL3124 },	{ PCI_VDEVICE(CMD, 0x3132), BID_SIL3132 },	{ PCI_VDEVICE(CMD, 0x0242), BID_SIL3132 },	{ PCI_VDEVICE(CMD, 0x3131), BID_SIL3131 },	{ PCI_VDEVICE(CMD, 0x3531), BID_SIL3131 },	{ } /* terminate list */};static struct pci_driver sil24_pci_driver = {	.name			= DRV_NAME,	.id_table		= sil24_pci_tbl,	.probe			= sil24_init_one,	.remove			= ata_pci_remove_one,#ifdef CONFIG_PM	.suspend		= ata_pci_device_suspend,	.resume			= sil24_pci_device_resume,#endif};static struct scsi_host_template sil24_sht = {	.module			= THIS_MODULE,	.name			= DRV_NAME,	.ioctl			= ata_scsi_ioctl,	.queuecommand		= ata_scsi_queuecmd,	.change_queue_depth	= ata_scsi_change_queue_depth,	.can_queue		= SIL24_MAX_CMDS,	.this_id		= ATA_SHT_THIS_ID,	.sg_tablesize		= SIL24_MAX_SGE,	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,	.emulated		= ATA_SHT_EMULATED,	.use_clustering		= ATA_SHT_USE_CLUSTERING,	.proc_name		= DRV_NAME,	.dma_boundary		= ATA_DMA_BOUNDARY,	.slave_configure	= ata_scsi_slave_config,	.slave_destroy		= ata_scsi_slave_destroy,	.bios_param		= ata_std_bios_param,};static const struct ata_port_operations sil24_ops = {	.dev_config		= sil24_dev_config,	.check_status		= sil24_check_status,	.check_altstatus	= sil24_check_status,	.dev_select		= ata_noop_dev_select,	.tf_read		= sil24_tf_read,	.qc_defer		= sil24_qc_defer,	.qc_prep		= sil24_qc_prep,	.qc_issue		= sil24_qc_issue,	.irq_clear		= sil24_irq_clear,	.scr_read		= sil24_scr_read,	.scr_write		= sil24_scr_write,	.pmp_attach		= sil24_pmp_attach,	.pmp_detach		= sil24_pmp_detach,	.freeze			= sil24_freeze,	.thaw			= sil24_thaw,	.error_handler		= sil24_error_handler,	.post_internal_cmd	= sil24_post_internal_cmd,	.port_start		= sil24_port_start,#ifdef CONFIG_PM	.port_resume		= sil24_port_resume,#endif};/* * Use bits 30-31 of port_flags to encode available port numbers. * Current maxium is 4. */#define SIL24_NPORTS2FLAG(nports)	((((unsigned)(nports) - 1) & 0x3) << 30)#define SIL24_FLAG2NPORTS(flag)		((((flag) >> 30) & 0x3) + 1)static const struct ata_port_info sil24_port_info[] = {	/* sil_3124 */	{		.flags		= SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |				  SIL24_FLAG_PCIX_IRQ_WOC,		.link_flags	= SIL24_COMMON_LFLAGS,		.pio_mask	= 0x1f,			/* pio0-4 */		.mwdma_mask	= 0x07,			/* mwdma0-2 */		.udma_mask	= ATA_UDMA5,		/* udma0-5 */		.port_ops	= &sil24_ops,	},	/* sil_3132 */	{		.flags		= SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),		.link_flags	= SIL24_COMMON_LFLAGS,		.pio_mask	= 0x1f,			/* pio0-4 */		.mwdma_mask	= 0x07,			/* mwdma0-2 */		.udma_mask	= ATA_UDMA5,		/* udma0-5 */		.port_ops	= &sil24_ops,	},	/* sil_3131/sil_3531 */	{		.flags		= SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),		.link_flags	= SIL24_COMMON_LFLAGS,		.pio_mask	= 0x1f,			/* pio0-4 */		.mwdma_mask	= 0x07,			/* mwdma0-2 */		.udma_mask	= ATA_UDMA5,		/* udma0-5 */		.port_ops	= &sil24_ops,	},};static int sil24_tag(int tag){	if (unlikely(ata_tag_internal(tag)))		return 0;	return tag;}static void sil24_dev_config(struct ata_device *dev){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -