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

📄 cpqfctsinit.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* 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/blk.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/timer.h>#include <linux/ioport.h>  // request_region() prototype#include <linux/vmalloc.h> // ioremap()#ifdef __alpha__#define __KERNEL_SYSCALLS__#endif#include <asm/unistd.h>#include <asm/io.h>#include <asm/uaccess.h>   // ioctl related#include <asm/irq.h>#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)#include <asm/spinlock.h>#else#include <linux/spinlock.h>#endif#include "sd.h"#include <scsi/scsi_ioctl.h>#include "hosts.h"#include "cpqfcTSchip.h"#include "cpqfcTSstructs.h"#include "cpqfcTS.h"#include <linux/module.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");// 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/* 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->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;    cpqfcHBAdata->fcChip.Registers.IOBaseU =     PciDev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;    // 32-bit memory addresses  cpqfcHBAdata->fcChip.Registers.MemBase =     PciDev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK;  cpqfcHBAdata->fcChip.Registers.ReMapMemBase =     ioremap( PciDev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK,             0x200);    cpqfcHBAdata->fcChip.Registers.RAMBase =     PciDev->base_address[4];    cpqfcHBAdata->fcChip.Registers.SROMBase =  // NULL for HP TS adapter    PciDev->base_address[5];    // 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; }/* (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;  kernel_thread((int (*)(void *))cpqfcTSWorkerThread,                           (void *) HostAdapter, 0);  /*   * Now wait for the kernel error thread to initialize itself   */  down (&sem);  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 #define HBA_TYPES 2int 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;  SupportedPCIcards PCIids[HBA_TYPES];  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    if( pci_present() == 0) // no PCI busses?  {    printk( "  no PCI bus?@#!\n");    return NumberOfAdapters;  }  // what HBA adapters are we supporting?  PCIids[0].vendor_id = PCI_VENDOR_ID_COMPAQ;  PCIids[0].device_id = CPQ_DEVICE_ID;  PCIids[1].vendor_id = PCI_VENDOR_ID_HP; // i.e. 103Ch (Agilent == HP for now)  PCIids[1].device_id = AGILENT_XL2_ID;   // i.e. 1029h  for( i=0; i < HBA_TYPES; i++)  {    // look for all HBAs of each type    while( (PciDev =      pci_find_device( PCIids[i].vendor_id, PCIids[i].device_id, PciDev) ))    {      // 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)      	continue;      DEBUG_PCI( printk("  HBA found!\n"));      DEBUG_PCI( printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq) );      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[0]));      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[1]));      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[2]));      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[3]));            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->base_address[1] & 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?      HostAdapter->hostt->use_new_eh_code = 1; // new error handling            // 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;      // request necessary resources and check for conflicts      if( request_irq( HostAdapter->irq,		       cpqfcTS_intr_handler,	               SA_INTERRUPT | SA_SHIRQ,	               DEV_NAME,		       HostAdapter) )      {	printk(" IRQ %u already used\n", HostAdapter->irq);        scsi_unregister( HostAdapter);	continue;      }      // Since we have two 256-byte I/O port ranges (upper      // and lower), check them both      if( check_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff) )      {	printk("  cpqfcTS address in use: %x\n", 			cpqfcHBAdata->fcChip.Registers.IOBaseU);	free_irq( HostAdapter->irq, HostAdapter);        scsi_unregister( HostAdapter);	continue;      }	            if( check_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff) )      {  	printk("  cpqfcTS address in use: %x\n", 	      			cpqfcHBAdata->fcChip.Registers.IOBaseL);	free_irq( HostAdapter->irq, HostAdapter);        scsi_unregister( HostAdapter);	continue;      }	            // OK, we should be able to grab everything we need now.      request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff, DEV_NAME);      request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff, DEV_NAME);      DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n",        cpqfcHBAdata->fcChip.Registers.IOBaseL ));      DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n",        cpqfcHBAdata->fcChip.Registers.IOBaseU ));            // start our kernel worker thread      launch_FCworker_thread(HostAdapter);      // start our TimerTask...      cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;      init_timer( cpqfcTStimer); // Linux clears next/prev values      cpqfcTStimer->expires = jiffies + HZ; // one second      cpqfcTStimer->data = (unsigned long)cpqfcHBAdata; // this adapter      cpqfcTStimer->function = cpqfcTSheartbeat; // handles timeouts, housekeeping      add_timer( cpqfcTStimer);  // give it to Linux      // now initialize our hardware...      cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1);      cpqfcHBAdata->fcStatsTime = jiffies;  // (for FC Statistics delta)            // give our HBA time to initialize and login current devices...      {	// The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,	// has the following algorithm for FL_Port startup:	// Time(sec) Action	// 0:        Device Plugin and LIP(F7,F7) transmission	// 1.0       LIP incoming        // 1.027     LISA incoming, no CLS! (link not up)	// 1.028     NOS incoming (switch test for N_Port)        // 1.577     ED_TOV expired, transmit LIPs again		// 3.0       LIP(F8,F7) incoming (switch passes Tach Prim.Sig)	// 3.028     LILP received, link up, FLOGI starts	// slowest(worst) case, measured on 1Gb Finisar GT analyzer		int wait_time;        for( wait_time = jiffies + 4*HZ; wait_time > jiffies; )	  schedule();  // (our worker task needs to run)      }            NumberOfAdapters++;     } // end of while()  }  LEAVE("cpqfcTS_detect");   return NumberOfAdapters;}static void my_ioctl_done (Scsi_Cmnd * SCpnt){    struct request * req;        req = &SCpnt->request;    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */      if (req->sem != NULL) {	up(req->sem);    }}   int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg){  int result = 0;  struct Scsi_Host *HostAdapter = ScsiDev->host;  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;  PTACHYON fcChip = &cpqfcHBAdata->fcChip;  PFC_LOGGEDIN_PORT pLoggedInPort;  Scsi_Cmnd DumCmnd;  int i, j;  VENDOR_IOCTL_REQ ioc;  cpqfc_passthru_t *vendor_cmd;

⌨️ 快捷键说明

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