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

📄 sata_sil.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  sata_sil.c - Silicon Image SATA * *  Maintained by:  Jeff Garzik <jgarzik@pobox.com> *  		    Please ALWAYS copy linux-ide@vger.kernel.org *		    on emails. * *  Copyright 2003-2005 Red Hat, Inc. *  Copyright 2003 Benjamin Herrenschmidt * * *  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. * *  You should have received a copy of the GNU General Public License *  along with this program; see the file COPYING.  If not, write to *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * *  libata documentation is available via 'make {ps|pdf}docs', *  as Documentation/DocBook/libata.* * *  Documentation for SiI 3112: *  http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2 * *  Other errata and documentation available under NDA. * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/device.h>#include <scsi/scsi_host.h>#include <linux/libata.h>#define DRV_NAME	"sata_sil"#define DRV_VERSION	"2.3"enum {	SIL_MMIO_BAR		= 5,	/*	 * host flags	 */	SIL_FLAG_NO_SATA_IRQ	= (1 << 28),	SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),	SIL_FLAG_MOD15WRITE	= (1 << 30),	SIL_DFL_PORT_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |				  ATA_FLAG_MMIO,	SIL_DFL_LINK_FLAGS	= ATA_LFLAG_HRST_TO_RESUME,	/*	 * Controller IDs	 */	sil_3112		= 0,	sil_3112_no_sata_irq	= 1,	sil_3512		= 2,	sil_3114		= 3,	/*	 * Register offsets	 */	SIL_SYSCFG		= 0x48,	/*	 * Register bits	 */	/* SYSCFG */	SIL_MASK_IDE0_INT	= (1 << 22),	SIL_MASK_IDE1_INT	= (1 << 23),	SIL_MASK_IDE2_INT	= (1 << 24),	SIL_MASK_IDE3_INT	= (1 << 25),	SIL_MASK_2PORT		= SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT,	SIL_MASK_4PORT		= SIL_MASK_2PORT |				  SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,	/* BMDMA/BMDMA2 */	SIL_INTR_STEERING	= (1 << 1),	SIL_DMA_ENABLE		= (1 << 0),  /* DMA run switch */	SIL_DMA_RDWR		= (1 << 3),  /* DMA Rd-Wr */	SIL_DMA_SATA_IRQ	= (1 << 4),  /* OR of all SATA IRQs */	SIL_DMA_ACTIVE		= (1 << 16), /* DMA running */	SIL_DMA_ERROR		= (1 << 17), /* PCI bus error */	SIL_DMA_COMPLETE	= (1 << 18), /* cmd complete / IRQ pending */	SIL_DMA_N_SATA_IRQ	= (1 << 6),  /* SATA_IRQ for the next channel */	SIL_DMA_N_ACTIVE	= (1 << 24), /* ACTIVE for the next channel */	SIL_DMA_N_ERROR		= (1 << 25), /* ERROR for the next channel */	SIL_DMA_N_COMPLETE	= (1 << 26), /* COMPLETE for the next channel */	/* SIEN */	SIL_SIEN_N		= (1 << 16), /* triggered by SError.N */	/*	 * Others	 */	SIL_QUIRK_MOD15WRITE	= (1 << 0),	SIL_QUIRK_UDMA5MAX	= (1 << 1),};static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);#ifdef CONFIG_PMstatic int sil_pci_device_resume(struct pci_dev *pdev);#endifstatic void sil_dev_config(struct ata_device *dev);static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);static void sil_freeze(struct ata_port *ap);static void sil_thaw(struct ata_port *ap);static const struct pci_device_id sil_pci_tbl[] = {	{ PCI_VDEVICE(CMD, 0x3112), sil_3112 },	{ PCI_VDEVICE(CMD, 0x0240), sil_3112 },	{ PCI_VDEVICE(CMD, 0x3512), sil_3512 },	{ PCI_VDEVICE(CMD, 0x3114), sil_3114 },	{ PCI_VDEVICE(ATI, 0x436e), sil_3112 },	{ PCI_VDEVICE(ATI, 0x4379), sil_3112_no_sata_irq },	{ PCI_VDEVICE(ATI, 0x437a), sil_3112_no_sata_irq },	{ }	/* terminate list */};/* TODO firmware versions should be added - eric */static const struct sil_drivelist {	const char *product;	unsigned int quirk;} sil_blacklist [] = {	{ "ST320012AS",		SIL_QUIRK_MOD15WRITE },	{ "ST330013AS",		SIL_QUIRK_MOD15WRITE },	{ "ST340017AS",		SIL_QUIRK_MOD15WRITE },	{ "ST360015AS",		SIL_QUIRK_MOD15WRITE },	{ "ST380023AS",		SIL_QUIRK_MOD15WRITE },	{ "ST3120023AS",	SIL_QUIRK_MOD15WRITE },	{ "ST340014ASL",	SIL_QUIRK_MOD15WRITE },	{ "ST360014ASL",	SIL_QUIRK_MOD15WRITE },	{ "ST380011ASL",	SIL_QUIRK_MOD15WRITE },	{ "ST3120022ASL",	SIL_QUIRK_MOD15WRITE },	{ "ST3160021ASL",	SIL_QUIRK_MOD15WRITE },	{ "Maxtor 4D060H3",	SIL_QUIRK_UDMA5MAX },	{ }};static struct pci_driver sil_pci_driver = {	.name			= DRV_NAME,	.id_table		= sil_pci_tbl,	.probe			= sil_init_one,	.remove			= ata_pci_remove_one,#ifdef CONFIG_PM	.suspend		= ata_pci_device_suspend,	.resume			= sil_pci_device_resume,#endif};static struct scsi_host_template sil_sht = {	.module			= THIS_MODULE,	.name			= DRV_NAME,	.ioctl			= ata_scsi_ioctl,	.queuecommand		= ata_scsi_queuecmd,	.can_queue		= ATA_DEF_QUEUE,	.this_id		= ATA_SHT_THIS_ID,	.sg_tablesize		= LIBATA_MAX_PRD,	.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 sil_ops = {	.dev_config		= sil_dev_config,	.tf_load		= ata_tf_load,	.tf_read		= ata_tf_read,	.check_status		= ata_check_status,	.exec_command		= ata_exec_command,	.dev_select		= ata_std_dev_select,	.set_mode		= sil_set_mode,	.bmdma_setup            = ata_bmdma_setup,	.bmdma_start            = ata_bmdma_start,	.bmdma_stop		= ata_bmdma_stop,	.bmdma_status		= ata_bmdma_status,	.qc_prep		= ata_qc_prep,	.qc_issue		= ata_qc_issue_prot,	.data_xfer		= ata_data_xfer,	.freeze			= sil_freeze,	.thaw			= sil_thaw,	.error_handler		= ata_bmdma_error_handler,	.post_internal_cmd	= ata_bmdma_post_internal_cmd,	.irq_clear		= ata_bmdma_irq_clear,	.irq_on			= ata_irq_on,	.scr_read		= sil_scr_read,	.scr_write		= sil_scr_write,	.port_start		= ata_port_start,};static const struct ata_port_info sil_port_info[] = {	/* sil_3112 */	{		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,		.link_flags	= SIL_DFL_LINK_FLAGS,		.pio_mask	= 0x1f,			/* pio0-4 */		.mwdma_mask	= 0x07,			/* mwdma0-2 */		.udma_mask	= ATA_UDMA5,		.port_ops	= &sil_ops,	},	/* sil_3112_no_sata_irq */	{		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |				  SIL_FLAG_NO_SATA_IRQ,		.link_flags	= SIL_DFL_LINK_FLAGS,		.pio_mask	= 0x1f,			/* pio0-4 */		.mwdma_mask	= 0x07,			/* mwdma0-2 */		.udma_mask	= ATA_UDMA5,		.port_ops	= &sil_ops,	},	/* sil_3512 */	{		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,		.link_flags	= SIL_DFL_LINK_FLAGS,		.pio_mask	= 0x1f,			/* pio0-4 */		.mwdma_mask	= 0x07,			/* mwdma0-2 */		.udma_mask	= ATA_UDMA5,		.port_ops	= &sil_ops,	},	/* sil_3114 */	{		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,		.link_flags	= SIL_DFL_LINK_FLAGS,		.pio_mask	= 0x1f,			/* pio0-4 */		.mwdma_mask	= 0x07,			/* mwdma0-2 */		.udma_mask	= ATA_UDMA5,		.port_ops	= &sil_ops,	},};/* per-port register offsets *//* TODO: we can probably calculate rather than use a table */static const struct {	unsigned long tf;	/* ATA taskfile register block */	unsigned long ctl;	/* ATA control/altstatus register block */	unsigned long bmdma;	/* DMA register block */	unsigned long bmdma2;	/* DMA register block #2 */	unsigned long fifo_cfg;	/* FIFO Valid Byte Count and Control */	unsigned long scr;	/* SATA control register block */	unsigned long sien;	/* SATA Interrupt Enable register */	unsigned long xfer_mode;/* data transfer mode register */	unsigned long sfis_cfg;	/* SATA FIS reception config register */} sil_port[] = {	/* port 0 ... */	/*   tf    ctl  bmdma  bmdma2  fifo    scr   sien   mode   sfis */	{  0x80,  0x8A,   0x0,  0x10,  0x40, 0x100, 0x148,  0xb4, 0x14c },	{  0xC0,  0xCA,   0x8,  0x18,  0x44, 0x180, 0x1c8,  0xf4, 0x1cc },	{ 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c },	{ 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },	/* ... port 3 */};MODULE_AUTHOR("Jeff Garzik");MODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(pci, sil_pci_tbl);MODULE_VERSION(DRV_VERSION);static int slow_down;module_param(slow_down, int, 0444);MODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)");static unsigned char sil_get_device_cache_line(struct pci_dev *pdev){	u8 cache_line = 0;	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line);	return cache_line;}/** *	sil_set_mode		-	wrap set_mode functions *	@link: link to set up *	@r_failed: returned device when we fail * *	Wrap the libata method for device setup as after the setup we need *	to inspect the results and do some configuration work */static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed){	struct ata_port *ap = link->ap;	void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];	void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;	struct ata_device *dev;	u32 tmp, dev_mode[2] = { };	int rc;	rc = ata_do_set_mode(link, r_failed);	if (rc)		return rc;	ata_link_for_each_dev(dev, link) {		if (!ata_dev_enabled(dev))			dev_mode[dev->devno] = 0;	/* PIO0/1/2 */		else if (dev->flags & ATA_DFLAG_PIO)			dev_mode[dev->devno] = 1;	/* PIO3/4 */		else			dev_mode[dev->devno] = 3;	/* UDMA */		/* value 2 indicates MDMA */	}	tmp = readl(addr);	tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0));	tmp |= dev_mode[0];	tmp |= (dev_mode[1] << 4);	writel(tmp, addr);	readl(addr);	/* flush */	return 0;}static inline void __iomem *sil_scr_addr(struct ata_port *ap,					 unsigned int sc_reg){	void __iomem *offset = ap->ioaddr.scr_addr;	switch (sc_reg) {	case SCR_STATUS:		return offset + 4;	case SCR_ERROR:		return offset + 8;	case SCR_CONTROL:		return offset;	default:		/* do nothing */		break;	}	return NULL;}static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val){	void __iomem *mmio = sil_scr_addr(ap, sc_reg);	if (mmio) {		*val = readl(mmio);		return 0;	}	return -EINVAL;}static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val){	void __iomem *mmio = sil_scr_addr(ap, sc_reg);	if (mmio) {

⌨️ 快捷键说明

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