cpqfctsinit.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,099 行 · 第 1/5 页
C
2,099 行
/* Copyright(c) 2000, Compaq Computer Corporation * Fibre Channel Host Bus Adapter * 64-bit, 66MHz PCI * Originally developed and tested on: * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ... * SP# P225CXCBFIEL6T, Rev XC * SP# 161290-001, Rev XD * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5 * * 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. * Written by Don Zimmerman * IOCTL and procfs added by Jouke Numan * SMP testing by Chel Van Gennip * * portions copied from: * QLogic CPQFCTS SCSI-FCP * Written by Erik H. Moe, ehm@cris.com * Copyright 1995, Erik H. Moe * Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu> * Chris Loveland <cwl@iol.unh.edu> to support the isp2100 and isp2200*/#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))#include <linux/config.h> #include <linux/interrupt.h> #include <linux/module.h>#include <linux/version.h> #include <linux/blkdev.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/timer.h>#include <linux/init.h>#include <linux/ioport.h> // request_region() prototype#include <linux/completion.h>#include <asm/io.h>#include <asm/uaccess.h> // ioctl related#include <asm/irq.h>#include <linux/spinlock.h>#include "scsi.h"#include <scsi/scsi_host.h>#include <scsi/scsi_ioctl.h>#include "cpqfcTSchip.h"#include "cpqfcTSstructs.h"#include "cpqfcTStrigger.h"#include "cpqfcTS.h"/* Embedded module documentation macros - see module.h */MODULE_AUTHOR("Compaq Computer Corporation");MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.5.4");MODULE_LICENSE("GPL"); int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);// This struct was originally defined in // /usr/src/linux/include/linux/proc_fs.h// since it's only partially implemented, we only use first// few fields...// NOTE: proc_fs changes in 2.4 kernel#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)static struct proc_dir_entry proc_scsi_cpqfcTS ={ PROC_SCSI_CPQFCTS, // ushort low_ino (enumerated list) 7, // ushort namelen DEV_NAME, // const char* name S_IFDIR | S_IRUGO | S_IXUGO, // mode_t mode 2 // nlink_t nlink // etc. ...};#endif#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)# define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)# define CPQFC_WAITING waiting# define CPQFC_COMPLETE(x) complete(x)# define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);#else# define CPQFC_DECLARE_COMPLETION(x) DECLARE_MUTEX_LOCKED(x)# define CPQFC_WAITING sem# define CPQFC_COMPLETE(x) up(x)# define CPQFC_WAIT_FOR_COMPLETION(x) down(x)#endifstatic int cpqfc_alloc_private_data_pool(CPQFCHBA *hba);/* local function to load our per-HBA (local) data for chip registers, FC link state, all FC exchanges, etc. We allocate space and compute address offsets for the most frequently accessed addresses; others (like World Wide Name) are not necessary.*/static void Cpqfc_initHBAdata(CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev ){ cpqfcHBAdata->PciDev = PciDev; // copy PCI info ptr // since x86 port space is 64k, we only need the lower 16 bits cpqfcHBAdata->fcChip.Registers.IOBaseL = PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK; cpqfcHBAdata->fcChip.Registers.IOBaseU = PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK; // 32-bit memory addresses cpqfcHBAdata->fcChip.Registers.MemBase = PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK; cpqfcHBAdata->fcChip.Registers.ReMapMemBase = ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK, 0x200); cpqfcHBAdata->fcChip.Registers.RAMBase = PciDev->resource[4].start; cpqfcHBAdata->fcChip.Registers.SROMBase = // NULL for HP TS adapter PciDev->resource[5].start; // now the Tachlite chip registers // the REGISTER struct holds both the physical address & last // written value (some TL registers are WRITE ONLY) cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX; cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX; // TL Frame Manager cpqfcHBAdata->fcChip.Registers.FMconfig.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG; cpqfcHBAdata->fcChip.Registers.FMcontrol.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL; cpqfcHBAdata->fcChip.Registers.FMstatus.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS; cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1; cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2; cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0; // TL Control Regs cpqfcHBAdata->fcChip.Registers.TYconfig.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG; cpqfcHBAdata->fcChip.Registers.TYcontrol.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL; cpqfcHBAdata->fcChip.Registers.TYstatus.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS; cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA; cpqfcHBAdata->fcChip.Registers.ed_tov.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV; cpqfcHBAdata->fcChip.Registers.INTEN.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN; cpqfcHBAdata->fcChip.Registers.INTPEND.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND; cpqfcHBAdata->fcChip.Registers.INTSTAT.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT; DEBUG_PCI(printk(" cpqfcHBAdata->fcChip.Registers. :\n")); DEBUG_PCI(printk(" IOBaseL = %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL)); DEBUG_PCI(printk(" IOBaseU = %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU)); /* printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase); */ DEBUG_PCI(printk(" SFQconsumerIndex.address = %p\n", cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address)); DEBUG_PCI(printk(" ERQproducerIndex.address = %p\n", cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address)); DEBUG_PCI(printk(" TYconfig.address = %p\n", cpqfcHBAdata->fcChip.Registers.TYconfig.address)); DEBUG_PCI(printk(" FMconfig.address = %p\n", cpqfcHBAdata->fcChip.Registers.FMconfig.address)); DEBUG_PCI(printk(" FMcontrol.address = %p\n", cpqfcHBAdata->fcChip.Registers.FMcontrol.address)); // set default options for FC controller (chip) cpqfcHBAdata->fcChip.Options.initiator = 1; // default: SCSI initiator cpqfcHBAdata->fcChip.Options.target = 0; // default: SCSI target cpqfcHBAdata->fcChip.Options.extLoopback = 0;// default: no loopback @GBIC cpqfcHBAdata->fcChip.Options.intLoopback = 0;// default: no loopback inside chip // set highest and lowest FC-PH version the adapter/driver supports // (NOT strict compliance) cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3; cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43; // set function points for this controller / adapter cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite; cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite; cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite; cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues; cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues; cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite; cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl; cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry; cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager; cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN; cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM; if (cpqfc_alloc_private_data_pool(cpqfcHBAdata) != 0) { printk(KERN_WARNING "cpqfc: unable to allocate pool for passthru ioctls. " "Passthru ioctls disabled.\n"); }}/* (borrowed from linux/drivers/scsi/hosts.c) */static void launch_FCworker_thread(struct Scsi_Host *HostAdapter){ DECLARE_MUTEX_LOCKED(sem); CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; ENTER("launch_FC_worker_thread"); cpqfcHBAdata->notify_wt = &sem; /* must unlock before kernel_thread(), for it may cause a reschedule. */ spin_unlock_irq(HostAdapter->host_lock); kernel_thread((int (*)(void *))cpqfcTSWorkerThread, (void *) HostAdapter, 0); /* * Now wait for the kernel error thread to initialize itself */ down (&sem); spin_lock_irq(HostAdapter->host_lock); cpqfcHBAdata->notify_wt = NULL; LEAVE("launch_FC_worker_thread"); }/* "Entry" point to discover if any supported PCI bus adapter can be found*//* We're supporting: * Compaq 64-bit, 66MHz HBA with Tachyon TS * Agilent XL2 * HP Tachyon */#define HBA_TYPES 3#ifndef PCI_DEVICE_ID_COMPAQ_#define PCI_DEVICE_ID_COMPAQ_TACHYON 0xa0fc#endifstatic struct SupportedPCIcards cpqfc_boards[] __initdata = { {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TACHYON}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHLITE}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHYON},};int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate){ int NumberOfAdapters=0; // how many of our PCI adapters are found? struct pci_dev *PciDev = NULL; struct Scsi_Host *HostAdapter = NULL; CPQFCHBA *cpqfcHBAdata = NULL; struct timer_list *cpqfcTStimer = NULL; int i; ENTER("cpqfcTS_detect");#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27) ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;#else ScsiHostTemplate->proc_name = "cpqfcTS";#endif for( i=0; i < HBA_TYPES; i++) { // look for all HBAs of each type while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id, cpqfc_boards[i].device_id, PciDev))) { if (pci_enable_device(PciDev)) { printk(KERN_ERR "cpqfc: can't enable PCI device at %s\n", pci_name(PciDev)); goto err_continue; } if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) { printk(KERN_WARNING "cpqfc: HBA cannot support required DMA mask, skipping.\n"); goto err_disable_dev; } // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes... /* printk(" scsi_register allocating %d bytes for FC HBA\n", (ULONG)sizeof(CPQFCHBA)); */ HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) ); if(HostAdapter == NULL) { printk(KERN_WARNING "cpqfc: can't register SCSI HBA, skipping.\n"); goto err_disable_dev; } DEBUG_PCI( printk(" HBA found!\n")); DEBUG_PCI( printk(" HostAdapter->PciDev->irq = %u\n", PciDev->irq) ); DEBUG_PCI(printk(" PciDev->baseaddress[0]= %lx\n", PciDev->resource[0].start)); DEBUG_PCI(printk(" PciDev->baseaddress[1]= %lx\n", PciDev->resource[1].start)); DEBUG_PCI(printk(" PciDev->baseaddress[2]= %lx\n", PciDev->resource[2].start)); DEBUG_PCI(printk(" PciDev->baseaddress[3]= %lx\n", PciDev->resource[3].start)); scsi_set_device(HostAdapter, &PciDev->dev); HostAdapter->irq = PciDev->irq; // copy for Scsi layers // HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper), // for a total I/O port address space of 512 bytes. // mask out the I/O port address (lower) & record HostAdapter->io_port = (unsigned int) PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK; HostAdapter->n_io_port = 0xff; // i.e., expect 128 targets (arbitrary number), while the // RA-4000 supports 32 LUNs HostAdapter->max_id = 0; // incremented as devices log in HostAdapter->max_lun = CPQFCTS_MAX_LUN; // LUNs per FC device HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses? // get the pointer to our HBA specific data... (one for // each HBA on the PCI bus(ses)). cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; // make certain our data struct is clear memset( cpqfcHBAdata, 0, sizeof( CPQFCHBA ) ); // initialize our HBA info cpqfcHBAdata->HBAnum = NumberOfAdapters; cpqfcHBAdata->HostAdapter = HostAdapter; // back ptr Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields cpqfcHBAdata->HBAnum = NumberOfAdapters; cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED; // request necessary resources and check for conflicts if( request_irq( HostAdapter->irq, cpqfcTS_intr_handler, SA_INTERRUPT | SA_SHIRQ, DEV_NAME, HostAdapter) ) { printk(KERN_WARNING "cpqfc: IRQ %u already used\n", HostAdapter->irq); goto err_unregister; } // Since we have two 256-byte I/O port ranges (upper // and lower), check them both if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff, DEV_NAME ) ) { printk(KERN_WARNING "cpqfc: address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU); goto err_free_irq; } if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff, DEV_NAME ) ) { printk(KERN_WARNING "cpqfc: address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL); goto err_release_region_U; } // OK, we have grabbed everything we need now. DEBUG_PCI(printk(" Reserved 255 I/O addresses @ %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL )); DEBUG_PCI(printk(" Reserved 255 I/O addresses @ %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU )); // start our kernel worker thread spin_lock_irq(HostAdapter->host_lock); launch_FCworker_thread(HostAdapter); // start our TimerTask... cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer; init_timer( cpqfcTStimer); // Linux clears next/prev values cpqfcTStimer->expires = jiffies + HZ; // one second
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?