📄 cpqfctsinit.c
字号:
/* 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 + -