📄 sata_nv.c
字号:
/* * sata_nv.c - NVIDIA nForce SATA * * Copyright 2004 NVIDIA Corp. All rights reserved. * Copyright 2004 Andrew Chew * * The contents of this file are subject to the Open * Software License version 1.1 that can be found at * http://www.opensource.org/licenses/osl-1.1.txt and is included herein * by reference. * * Alternatively, the contents of this file may be used under the terms * of the GNU General Public License version 2 (the "GPL") as distributed * in the kernel source COPYING file, in which case the provisions of * the GPL are applicable instead of the above. If you wish to allow * the use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under * the OSL, indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by the GPL. * If you do not delete the provisions above, a recipient may use your * version of this file under either the OSL or the GPL. * * 0.11 * - Added sgpio support * * 0.10 * - Fixed spurious interrupts issue seen with the Maxtor 6H500F0 500GB * drive. Also made the check_hotplug() callbacks return whether there * was a hotplug interrupt or not. This was not the source of the * spurious interrupts, but is the right thing to do anyway. * * 0.09 * - Fixed bug introduced by 0.08's MCP51 and MCP55 support. * * 0.08 * - Added support for MCP51 and MCP55. * * 0.07 * - Added support for RAID class code. * * 0.06 * - Added generic SATA support by using a pci_device_id that filters on * the IDE storage class code. * * 0.03 * - Fixed a bug where the hotplug handlers for non-CK804/MCP04 were using * mmio_base, which is only set for the CK804/MCP04 case. * * 0.02 * - Added support for CK804 SATA controller. * * 0.01 * - Initial revision. */#include <linux/config.h>#include <linux/version.h>#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 "scsi.h"#include <scsi/scsi_host.h>#include <linux/libata.h>#define DRV_NAME "sata_nv"#define DRV_VERSION "0.11-Driver Package V1.24"#define NV_PORTS 2#define NV_PIO_MASK 0x1f#define NV_MWDMA_MASK 0x07#define NV_UDMA_MASK 0x7f#define NV_PORT0_SCR_REG_OFFSET 0x00#define NV_PORT1_SCR_REG_OFFSET 0x40#define NV_INT_STATUS 0x10#define NV_INT_STATUS_CK804 0x440#define NV_INT_STATUS_MCP55 0x440#define NV_INT_STATUS_PDEV_INT 0x01#define NV_INT_STATUS_PDEV_PM 0x02#define NV_INT_STATUS_PDEV_ADDED 0x04#define NV_INT_STATUS_PDEV_REMOVED 0x08#define NV_INT_STATUS_SDEV_INT 0x10#define NV_INT_STATUS_SDEV_PM 0x20#define NV_INT_STATUS_SDEV_ADDED 0x40#define NV_INT_STATUS_SDEV_REMOVED 0x80#define NV_INT_STATUS_PDEV_HOTPLUG (NV_INT_STATUS_PDEV_ADDED | \ NV_INT_STATUS_PDEV_REMOVED)#define NV_INT_STATUS_SDEV_HOTPLUG (NV_INT_STATUS_SDEV_ADDED | \ NV_INT_STATUS_SDEV_REMOVED)#define NV_INT_STATUS_HOTPLUG (NV_INT_STATUS_PDEV_HOTPLUG | \ NV_INT_STATUS_SDEV_HOTPLUG)#define NV_INT_ENABLE 0x11#define NV_INT_ENABLE_CK804 0x441#define NV_INT_ENABLE_MCP55 0x444#define NV_INT_ENABLE_PDEV_MASK 0x01#define NV_INT_ENABLE_PDEV_PM 0x02#define NV_INT_ENABLE_PDEV_ADDED 0x04#define NV_INT_ENABLE_PDEV_REMOVED 0x08#define NV_INT_ENABLE_SDEV_MASK 0x10#define NV_INT_ENABLE_SDEV_PM 0x20#define NV_INT_ENABLE_SDEV_ADDED 0x40#define NV_INT_ENABLE_SDEV_REMOVED 0x80#define NV_INT_ENABLE_PDEV_HOTPLUG (NV_INT_ENABLE_PDEV_ADDED | \ NV_INT_ENABLE_PDEV_REMOVED)#define NV_INT_ENABLE_SDEV_HOTPLUG (NV_INT_ENABLE_SDEV_ADDED | \ NV_INT_ENABLE_SDEV_REMOVED)#define NV_INT_ENABLE_HOTPLUG (NV_INT_ENABLE_PDEV_HOTPLUG | \ NV_INT_ENABLE_SDEV_HOTPLUG)#define NV_INT_CONFIG 0x12#define NV_INT_CONFIG_METHD 0x01 // 0 = INT, 1 = SMI#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F// For PCI config register 20#define NV_MCP_SATA_CFG_20 0x50#define NV_MCP_SATA_CFG_20_SATA_SPACE_EN 0x04#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)#define RHAS3U7#endif#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,16)#define SLES10#endif//sgpio// Sgpio defines// SGPIO state defines#define NV_SGPIO_STATE_RESET 0#define NV_SGPIO_STATE_OPERATIONAL 1#define NV_SGPIO_STATE_ERROR 2// SGPIO command opcodes#define NV_SGPIO_CMD_RESET 0#define NV_SGPIO_CMD_READ_PARAMS 1#define NV_SGPIO_CMD_READ_DATA 2#define NV_SGPIO_CMD_WRITE_DATA 3// SGPIO command status defines#define NV_SGPIO_CMD_OK 0#define NV_SGPIO_CMD_ACTIVE 1#define NV_SGPIO_CMD_ERR 2#define NV_SGPIO_UPDATE_TICK 90#define NV_SGPIO_MIN_UPDATE_DELTA 33#define NV_CNTRLR_SHARE_INIT 2#define NV_SGPIO_MAX_ACTIVITY_ON 20#define NV_SGPIO_MIN_FORCE_OFF 5#define NV_SGPIO_PCI_CSR_OFFSET 0x58#define NV_SGPIO_PCI_CB_OFFSET 0x5C#define NV_SGPIO_DFLT_CB_SIZE 256#define NV_ON 1#define NV_OFF 0#ifndef bool#define bool u8#endifstatic inline unsigned int jiffies_to_msecs1(const unsigned long j){#if HZ <= 1000 && !(1000 % HZ) return (1000 / HZ) * j;#elif HZ > 1000 && !(HZ % 1000) return (j + (HZ / 1000) - 1)/(HZ / 1000);#else return (j * 1000) / HZ;#endif}#define BF_EXTRACT(v, off, bc) \ ((((u8)(v)) >> (off)) & ((1 << (bc)) - 1))#define BF_INS(v, ins, off, bc) \ (((v) & ~((((1 << (bc)) - 1)) << (off))) | \ (((u8)(ins)) << (off)))#define BF_EXTRACT_U32(v, off, bc) \ ((((u32)(v)) >> (off)) & ((1 << (bc)) - 1))#define BF_INS_U32(v, ins, off, bc) \ (((v) & ~((((1 << (bc)) - 1)) << (off))) | \ (((u32)(ins)) << (off)))#define GET_SGPIO_STATUS(v) BF_EXTRACT(v, 0, 2)#define GET_CMD_STATUS(v) BF_EXTRACT(v, 3, 2)#define GET_CMD(v) BF_EXTRACT(v, 5, 3)#define SET_CMD(v, cmd) BF_INS(v, cmd, 5, 3) #define GET_ENABLE(v) BF_EXTRACT_U32(v, 23, 1)#define SET_ENABLE(v) BF_INS_U32(v, 1, 23, 1)// Needs to have a u8 bit-field insert.#define GET_ACTIVITY(v) BF_EXTRACT(v, 5, 3)#define SET_ACTIVITY(v, on_off) BF_INS(v, on_off, 5, 3)union nv_sgpio_nvcr { struct { u8 init_cnt; u8 cb_size; u8 cbver; u8 rsvd; } bit; u32 all;};union nv_sgpio_tx { u8 tx_port[4]; u32 all;};struct nv_sgpio_cb { u64 scratch_space; union nv_sgpio_nvcr nvcr; u32 cr0; u32 rsvd[4]; union nv_sgpio_tx tx[2];};struct nv_sgpio_host_share{ spinlock_t *plock; unsigned long *ptstamp;};struct nv_sgpio_host_flags{ u8 sgpio_enabled:1; u8 need_update:1; u8 rsvd:6;}; struct nv_host_sgpio{ struct nv_sgpio_host_flags flags; u8 *pcsr; struct nv_sgpio_cb *pcb; struct nv_sgpio_host_share share; struct timer_list sgpio_timer;};struct nv_sgpio_port_flags{ u8 last_state:1; u8 recent_activity:1; u8 rsvd:6;};struct nv_sgpio_led { struct nv_sgpio_port_flags flags; u8 force_off; u8 last_cons_active;};struct nv_port_sgpio{ struct nv_sgpio_led activity;};static spinlock_t nv_sgpio_lock;static unsigned long nv_sgpio_tstamp;static inline void nv_sgpio_set_csr(u8 csr, unsigned long pcsr){ outb(csr, pcsr);}static inline u8 nv_sgpio_get_csr(unsigned long pcsr){ return inb(pcsr);}static inline u8 nv_sgpio_get_func(struct ata_host_set *host_set){ u8 devfn = (to_pci_dev(host_set->dev))->devfn; return (PCI_FUNC(devfn));}static inline u8 nv_sgpio_tx_host_offset(struct ata_host_set *host_set){ return (nv_sgpio_get_func(host_set)/NV_CNTRLR_SHARE_INIT);}static inline u8 nv_sgpio_calc_tx_offset(u8 cntrlr, u8 channel){ return (sizeof(union nv_sgpio_tx) - (NV_CNTRLR_SHARE_INIT * (cntrlr % NV_CNTRLR_SHARE_INIT)) - channel - 1);}static inline u8 nv_sgpio_tx_port_offset(struct ata_port *ap){ u8 cntrlr = nv_sgpio_get_func(ap->host_set); return (nv_sgpio_calc_tx_offset(cntrlr, ap->port_no));}static inline bool nv_sgpio_capable(const struct pci_device_id *ent){ if (ent->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2) return 1; else return 0;}static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);static irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs);static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);static void nv_host_stop (struct ata_host_set *host_set);static int nv_port_start(struct ata_port *ap);static void nv_port_stop(struct ata_port *ap);static int nv_qc_issue(struct ata_queued_cmd *qc);static void nv_enable_hotplug(struct ata_probe_ent *probe_ent);static void nv_disable_hotplug(struct ata_host_set *host_set);static void nv_check_hotplug(struct ata_host_set *host_set);static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent);static void nv_disable_hotplug_ck804(struct ata_host_set *host_set);static void nv_check_hotplug_ck804(struct ata_host_set *host_set);static void nv_enable_hotplug_mcp55(struct ata_probe_ent *probe_ent);static void nv_disable_hotplug_mcp55(struct ata_host_set *host_set);static void nv_check_hotplug_mcp55(struct ata_host_set *host_set);enum nv_host_type{ GENERIC, NFORCE2, NFORCE3, CK804, MCP55};static struct pci_device_id nv_pci_tbl[] = { { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP55 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP55 }, { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC }, { 0, } /* terminate list */};#define NV_HOST_FLAGS_SCR_MMIO 0x00000001struct nv_host_desc{ enum nv_host_type host_type; void (*enable_hotplug)(struct ata_probe_ent *probe_ent); void (*disable_hotplug)(struct ata_host_set *host_set); void (*check_hotplug)(struct ata_host_set *host_set);};static struct nv_host_desc nv_device_tbl[] = { { .host_type = GENERIC, .enable_hotplug = NULL, .disable_hotplug= NULL, .check_hotplug = NULL, }, { .host_type = NFORCE2, .enable_hotplug = nv_enable_hotplug, .disable_hotplug= nv_disable_hotplug, .check_hotplug = nv_check_hotplug, }, { .host_type = NFORCE3, .enable_hotplug = nv_enable_hotplug, .disable_hotplug= nv_disable_hotplug, .check_hotplug = nv_check_hotplug, }, { .host_type = CK804, .enable_hotplug = nv_enable_hotplug_ck804, .disable_hotplug= nv_disable_hotplug_ck804, .check_hotplug = nv_check_hotplug_ck804, }, { .host_type = MCP55, .enable_hotplug = nv_enable_hotplug_mcp55, .disable_hotplug= nv_disable_hotplug_mcp55, .check_hotplug = nv_check_hotplug_mcp55, },};struct nv_host{ struct nv_host_desc *host_desc; unsigned long host_flags; struct nv_host_sgpio host_sgpio; struct pci_dev *pdev;};struct nv_port{ struct nv_port_sgpio port_sgpio;};// SGPIO function prototypesstatic void nv_sgpio_init(struct pci_dev *pdev, struct nv_host *phost);static void nv_sgpio_reset(u8 *pcsr);static void nv_sgpio_set_timer(struct timer_list *ptimer, unsigned int timeout_msec);static void nv_sgpio_timer_handler(unsigned long ptr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -