📄 isp_pci.c
字号:
/* @(#)isp_pci.c 1.25 *//* * Qlogic ISP Host Adapter PCI specific probe and attach routines *--------------------------------------- * Copyright (c) 1998, 1999, 2000, 2001 by Matthew Jacob * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * the GNU Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Matthew Jacob * Feral Software * PMB #825 * 5214-F Diamond Hts Blvd * San Francisco, CA, 94131 * mjacob@feral.com */#include "isp_linux.h"#if defined(__powerpc__) || defined(__sparc__)static int isp_pci_mapmem = 0xffffffff;#elsestatic int isp_pci_mapmem = 0;#endif#if defined(__sparc__)#undef ioremap_nocache#define ioremap_nocache ioremap#endifstatic int isplinux_pci_init(struct Scsi_Host *);static u_int16_t isp_pci_rd_reg(struct ispsoftc *, int);static void isp_pci_wr_reg(struct ispsoftc *, int, u_int16_t);#if !(defined(ISP_DISABLE_1080_SUPPORT) && defined(ISP_DISABLE_12160_SUPPORT))static u_int16_t isp_pci_rd_reg_1080(struct ispsoftc *, int);static void isp_pci_wr_reg_1080(struct ispsoftc *, int, u_int16_t);#endifstatic intisp_pci_rd_isr(struct ispsoftc *, u_int16_t *, u_int16_t *, u_int16_t *);#ifndef ISP_DISABLE_2300_SUPPORTstatic intisp_pci_rd_isr_2300(struct ispsoftc *, u_int16_t *, u_int16_t *, u_int16_t *);#endifstatic int isp_pci_mbxdma(struct ispsoftc *);static intisp_pci_dmasetup(struct ispsoftc *, XS_T *, ispreq_t *, u_int16_t *, u_int16_t);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)static void isp_pci_dmateardown(struct ispsoftc *, XS_T *, u_int16_t);#else#define isp_pci_dmateardown NULL#endifstatic void isp_pci_reset1(struct ispsoftc *);static void isp_pci_dumpregs(struct ispsoftc *, const char *);#ifndef ISP_CODE_ORG#define ISP_CODE_ORG 0x1000#endif#ifndef ISP_DISABLE_1020_SUPPORT#include "asm_1040.h"#define ISP_1040_RISC_CODE (u_int16_t *) isp_1040_risc_code#else#define ISP_1040_RISC_CODE NULL#endif#ifndef ISP_DISABLE_1080_SUPPORT#include "asm_1080.h"#define ISP_1080_RISC_CODE (u_int16_t *) isp_1080_risc_code#else#define ISP_1080_RISC_CODE NULL#endif#ifndef ISP_DISABLE_12160_SUPPORT#include "asm_12160.h"#define ISP_12160_RISC_CODE (u_int16_t *) isp_12160_risc_code#else#define ISP_12160_RISC_CODE NULL#endif#ifndef ISP_DISABLE_2100_SUPPORT#include "asm_2100.h"#define ISP_2100_RISC_CODE (u_int16_t *) isp_2100_risc_code#else#define ISP_2100_RISC_CODE NULL#endif#ifndef ISP_DISABLE_2200_SUPPORT#include "asm_2200.h"#define ISP_2200_RISC_CODE (u_int16_t *) isp_2200_risc_code#else#define ISP_2200_RISC_CODE NULL#endif#ifndef ISP_DISABLE_2300_SUPPORT#include "asm_2300.h"#define ISP_2300_RISC_CODE (u_int16_t *) isp_2300_risc_code#else#define ISP_2300_RISC_CODE NULL#endif#ifndef ISP_DISABLE_1020_SUPPORTstatic struct ispmdvec mdvec = { isp_pci_rd_isr, isp_pci_rd_reg, isp_pci_wr_reg, isp_pci_mbxdma, isp_pci_dmasetup, isp_pci_dmateardown, NULL, isp_pci_reset1, isp_pci_dumpregs, ISP_1040_RISC_CODE, BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64};#endif#ifndef ISP_DISABLE_1080_SUPPORTstatic struct ispmdvec mdvec_1080 = { isp_pci_rd_isr, isp_pci_rd_reg_1080, isp_pci_wr_reg_1080, isp_pci_mbxdma, isp_pci_dmasetup, isp_pci_dmateardown, NULL, isp_pci_reset1, isp_pci_dumpregs, ISP_1080_RISC_CODE, BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_128};#endif#ifndef ISP_DISABLE_12160_SUPPORTstatic struct ispmdvec mdvec_12160 = { isp_pci_rd_isr, isp_pci_rd_reg_1080, isp_pci_wr_reg_1080, isp_pci_mbxdma, isp_pci_dmasetup, isp_pci_dmateardown, NULL, isp_pci_reset1, isp_pci_dumpregs, ISP_12160_RISC_CODE, BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_128};#endif#ifndef ISP_DISABLE_2100_SUPPORTstatic struct ispmdvec mdvec_2100 = { isp_pci_rd_isr, isp_pci_rd_reg, isp_pci_wr_reg, isp_pci_mbxdma, isp_pci_dmasetup, isp_pci_dmateardown, NULL, isp_pci_reset1, isp_pci_dumpregs, ISP_2100_RISC_CODE};#endif#ifndef ISP_DISABLE_2200_SUPPORTstatic struct ispmdvec mdvec_2200 = { isp_pci_rd_isr, isp_pci_rd_reg, isp_pci_wr_reg, isp_pci_mbxdma, isp_pci_dmasetup, isp_pci_dmateardown, NULL, isp_pci_reset1, isp_pci_dumpregs, ISP_2200_RISC_CODE};#endif#ifndef ISP_DISABLE_2300_SUPPORTstatic struct ispmdvec mdvec_2300 = { isp_pci_rd_isr_2300, isp_pci_rd_reg, isp_pci_wr_reg, isp_pci_mbxdma, isp_pci_dmasetup, isp_pci_dmateardown, NULL, isp_pci_reset1, isp_pci_dumpregs, ISP_2300_RISC_CODE};#endif#ifndef PCI_DEVICE_ID_QLOGIC_ISP1020#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020#endif#ifndef PCI_DEVICE_ID_QLOGIC_ISP1020#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020#endif#ifndef PCI_DEVICE_ID_QLOGIC_ISP1080#define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080#endif#ifndef PCI_DEVICE_ID_QLOGIC_ISP12160#define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216#endif#ifndef PCI_DEVICE_ID_QLOGIC_ISP1240#define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240#endif#ifndef PCI_DEVICE_ID_QLOGIC_ISP1280#define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280#endif#ifndef PCI_DEVICE_ID_QLOGIC_ISP2100#define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100#endif#ifndef PCI_DEVICE_ID_QLOGIC_ISP2200#define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200#endif#ifndef PCI_DEVICE_ID_QLOGIC_ISP2300#define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300#endif#ifndef PCI_DEVICE_ID_QLOGIC_ISP2312#define PCI_DEVICE_ID_QLOGIC_ISP2312 0x2312#endif#define PCI_DFLT_LTNCY 0x40#define PCI_DFLT_LNSZ 0x10#define PCI_CMD_ISP \ (PCI_COMMAND_MASTER|PCI_COMMAND_INVALIDATE|PCI_COMMAND_PARITY|PCI_COMMAND_SERR)/* * Encapsulating softc... Order of elements is important. The tag * pci_isp must come first because of multiple structure punning * (Scsi_Host * == struct isp_pcisoftc * == struct ispsofct *). */struct isp_pcisoftc { struct ispsoftc pci_isp; struct pci_dev * pci_dev; vm_offset_t port; /* I/O port address */ vm_offset_t paddr; /* Physical Memory Address */ vm_offset_t vaddr; /* Mapped Memory Address */ vm_offset_t poff[_NREG_BLKS]; union pstore params;#ifdef LINUX_ISP_TARGET_MODE tmd_cmd_t rpool[NTGT_CMDS];#endif};/* * Gratefully borrowed from Gerard Roudier's sym53c8xx driver */static INLINE vm_offset_tmap_pci_mem(u_long base, u_long size){ u_long page_base = ((u_long) base) & PAGE_MASK; u_long page_offs = ((u_long) base) - page_base; u_long map_size = roundup(page_offs+size, PAGE_SIZE); u_long page_remapped = (u_long) ioremap_nocache(page_base, map_size); (void) map_size; return (vm_offset_t) (page_remapped ? (page_remapped + page_offs) : 0);}static INLINEvoid unmap_pci_mem(vm_offset_t vaddr, u_long size){ if (vaddr) iounmap((void *) (vaddr & PAGE_MASK));}static INLINE int map_isp_mem(struct isp_pcisoftc *isp_pci, u_short cmd, vm_offset_t mem_base){ if (cmd & PCI_COMMAND_MEMORY) { isp_pci->paddr = __pa(mem_base); isp_pci->paddr &= PCI_BASE_ADDRESS_MEM_MASK; isp_pci->vaddr = map_pci_mem(isp_pci->paddr, 0xff); return (isp_pci->vaddr != (vm_offset_t) 0); } return (0);}static INLINE int map_isp_io(struct isp_pcisoftc *isp_pci, u_short cmd, vm_offset_t io_base){ if ((cmd & PCI_COMMAND_IO) && (io_base & 3) == 1) { isp_pci->port = io_base & PCI_BASE_ADDRESS_IO_MASK; if (check_region(isp_pci->port, 0xff)) { return (0); } request_region(isp_pci->port, 0xff, "isp"); return (1); } return (0);}#define ISP_PCI_BUS pcidev->bus->number#define ISP_PCI_DEVICE pcidev->devfn#define ISEARCH_RESET pcidev = NULL#define ISEARCH(x) \ (pcidev = pci_find_device(PCI_VENDOR_ID_QLOGIC, x, pcidev)) != NULL#define ISEARCH_NEXT#define ISTORE_ARGS struct pci_dev *pcidev#define ISTORE_FNDARGS ISTORE_ARGS#define ISTORE_FNCARGS pcidev#define ISTORE_ISP_INFO(x) (x)->pci_dev = pcidevstatic INLINE struct isp_pcisoftc *isplinux_pci_addhost(Scsi_Host_Template *tmpt, ISTORE_FNDARGS){ struct Scsi_Host *host; struct ispsoftc *isp; struct isp_pcisoftc *pci_isp; host = scsi_register(tmpt, sizeof(struct isp_pcisoftc)); if (host == NULL) { printk("isp_detect: scsi_register failed\n"); return (NULL); } pci_isp = (struct isp_pcisoftc *) host->hostdata; if (pci_isp == NULL) { printk("isp_detect: cannot get softc out of scsi_register\n"); return (NULL); } ISTORE_ISP_INFO(pci_isp); isp = (struct ispsoftc *) pci_isp; isp->isp_host = host; isp->isp_osinfo.storep = &pci_isp->params; if (isplinux_pci_init(host)) { scsi_unregister(host); return (NULL); } isp->isp_next = isplist; isplist = isp;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) scsi_set_pci_device(host, pci_isp->pci_dev);#endif return (pci_isp);}intisplinux_pci_detect(Scsi_Host_Template *tmpt){ static const char *fmt = "ISP SCSI and Fibre Channel Host Adapter Driver\n" " Linux Platform Version %d.%d\n" " Common Core Code Version %d.%d\n" " Built on %s, %s\n"; int nfound = 0; struct isp_pcisoftc *pci_isp; ISTORE_ARGS; if (pci_present() == 0) { return (0); } printk(fmt, ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR, __DATE__ , __TIME__ );#ifndef ISP_DISABLE_1020_SUPPORT for (ISEARCH_RESET; ISEARCH(PCI_DEVICE_ID_QLOGIC_ISP1020); ISEARCH_NEXT) { pci_isp = isplinux_pci_addhost(tmpt, ISTORE_FNCARGS); if (pci_isp) { nfound++; } }#endif#ifndef ISP_DISABLE_1080_SUPPORT for (ISEARCH_RESET; ISEARCH(PCI_DEVICE_ID_QLOGIC_ISP1240); ISEARCH_NEXT) { pci_isp = isplinux_pci_addhost(tmpt, ISTORE_FNCARGS); if (pci_isp) { nfound++; } } for (ISEARCH_RESET; ISEARCH(PCI_DEVICE_ID_QLOGIC_ISP1080); ISEARCH_NEXT) { pci_isp = isplinux_pci_addhost(tmpt, ISTORE_FNCARGS); if (pci_isp) { nfound++; } } for (ISEARCH_RESET; ISEARCH(PCI_DEVICE_ID_QLOGIC_ISP1280); ISEARCH_NEXT) { pci_isp = isplinux_pci_addhost(tmpt, ISTORE_FNCARGS); if (pci_isp) { nfound++; } }#endif#ifndef ISP_DISABLE_12160_SUPPORT for (ISEARCH_RESET; ISEARCH(PCI_DEVICE_ID_QLOGIC_ISP12160); ISEARCH_NEXT) { pci_isp = isplinux_pci_addhost(tmpt, ISTORE_FNCARGS); if (pci_isp) { nfound++; } }#endif#ifndef ISP_DISABLE_2100_SUPPORT for (ISEARCH_RESET; ISEARCH(PCI_DEVICE_ID_QLOGIC_ISP2100); ISEARCH_NEXT) { pci_isp = isplinux_pci_addhost(tmpt, ISTORE_FNCARGS); if (pci_isp) { nfound++; } }#endif#ifndef ISP_DISABLE_2200_SUPPORT for (ISEARCH_RESET; ISEARCH(PCI_DEVICE_ID_QLOGIC_ISP2200); ISEARCH_NEXT) { pci_isp = isplinux_pci_addhost(tmpt, ISTORE_FNCARGS); if (pci_isp) { nfound++; } }#endif#ifndef ISP_DISABLE_2300_SUPPORT for (ISEARCH_RESET; ISEARCH(PCI_DEVICE_ID_QLOGIC_ISP2300); ISEARCH_NEXT) { pci_isp = isplinux_pci_addhost(tmpt, ISTORE_FNCARGS); if (pci_isp) { nfound++; } } for (ISEARCH_RESET; ISEARCH(PCI_DEVICE_ID_QLOGIC_ISP2312); ISEARCH_NEXT) { pci_isp = isplinux_pci_addhost(tmpt, ISTORE_FNCARGS); if (pci_isp) { nfound++; } }#endif return (nfound);}voidisplinux_pci_release(struct Scsi_Host *host){ struct ispsoftc *isp = (struct ispsoftc *) host->hostdata; struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) host->hostdata; free_irq(host->irq, pcs); if (pcs->vaddr != 0) { unmap_pci_mem(pcs->vaddr, 0xff); pcs->vaddr = 0; } else { release_region(pcs->port, 0xff); pcs->port = 0; } kfree(isp->isp_xflist);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pci_free_consistent(pcs->pci_dev, RQUEST_QUEUE_LEN(isp) * QENTRY_LEN, isp->isp_rquest, isp->isp_rquest_dma); pci_free_consistent(pcs->pci_dev, RESULT_QUEUE_LEN(isp) * QENTRY_LEN, isp->isp_result, isp->isp_result_dma); if (IS_FC(isp)) { pci_free_consistent(pcs->pci_dev, ISP2100_SCRLEN, FCPARAM(isp)->isp_scratch, FCPARAM(isp)->isp_scdma); }#else RlsPages(isp->isp_rquest, IspOrder(RQUEST_QUEUE_LEN(isp))); RlsPages(isp->isp_result, IspOrder(RESULT_QUEUE_LEN(isp))); if (IS_FC(isp) && FCPARAM(isp)->isp_scratch) { RlsPages(FCPARAM(isp)->isp_scratch, 1); }#endif}static intisplinux_pci_init(struct Scsi_Host *host){ static char *nomap = "cannot map either memory or I/O space"; unsigned long io_base, mem_base; unsigned int irq, pci_cmd_isp = PCI_CMD_ISP; struct isp_pcisoftc *isp_pci; u_char rev, lnsz, timer; u_short vid, did, cmd; char loc[32]; struct ispsoftc *isp; isp_pci = (struct isp_pcisoftc *) host->hostdata; isp = (struct ispsoftc *) isp_pci; sprintf(loc, "isp@<PCI%d,Slot%d,Func%d>", isp_pci->pci_dev->bus->number, PCI_SLOT(isp_pci->pci_dev->devfn), PCI_FUNC(isp_pci->pci_dev->devfn)); if (PRDW(isp_pci, PCI_COMMAND, &cmd) || PRDB(isp_pci, PCI_CACHE_LINE_SIZE, &lnsz) || PRDB(isp_pci, PCI_LATENCY_TIMER, &timer) || PRDB(isp_pci, PCI_CLASS_REVISION, &rev)) { printk("%s: error reading PCI configuration", loc);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -