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 + -
显示快捷键?