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

📄 cpqfctscontrol.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Copyright 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*//* These functions control the host bus adapter (HBA) hardware.  The main chip   control takes place in the interrupt handler where we process the IMQ    (Inbound Message Queue).  The IMQ is Tachyon's way of communicating FC link   events and state information to the driver.  The Single Frame Queue (SFQ)   buffers incoming FC frames for processing by the driver.  References to    "TL/TS UG" are for:   "HP HPFC-5100/5166 Tachyon TL/TS ICs User Guide", August 16, 1999, 1st Ed.   Hewlitt Packard Manual Part Number 5968-1083E.*/#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))#include <linux/blk.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/ioport.h>  // request_region() prototype#include <linux/sched.h>#include <linux/malloc.h>  // need "kfree" for ext. S/G pages#include <linux/types.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/unistd.h>#include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O#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 "hosts.h"   // Scsi_Host definition for INT handler#include "cpqfcTSchip.h"#include "cpqfcTSstructs.h"//#define IMQ_DEBUG 1static void fcParseLinkStatusCounters(TACHYON * fcChip);static void CpqTsGetSFQEntry(TACHYON * fcChip, 	      USHORT pi, ULONG * buffr, BOOLEAN UpdateChip); // Note special requirements for Q alignment!  (TL/TS UG pg. 190)// We place critical index pointers at end of QUE elements to assist// in non-symbolic (i.e. memory dump) debugging// opcode defines placement of Queues (e.g. local/external RAM)int CpqTsCreateTachLiteQues( void* pHBA, int opcode){  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;  PTACHYON fcChip = &cpqfcHBAdata->fcChip;  int iStatus=0;  unsigned long ulAddr;  // NOTE! fcMemManager() will return system virtual addresses.  // System (kernel) virtual addresses, though non-paged, still  // aren't physical addresses.  Convert to PHYSICAL_ADDRESS for Tachyon's  // DMA use.  ENTER("CreateTachLiteQues");  // Allocate primary EXCHANGES array...    printk("Allocating %u for %u Exchanges ", 	  (ULONG)sizeof(FC_EXCHANGES), TACH_MAX_XID);  fcChip->Exchanges = kmalloc( sizeof( FC_EXCHANGES), GFP_KERNEL );  printk("@ %p\n", fcChip->Exchanges);  if( fcChip->Exchanges == NULL ) // fatal error!!  {    printk("kmalloc failure on Exchanges: fatal error\n");    return -1;  }  // zero out the entire EXCHANGE space  memset( fcChip->Exchanges, 0, sizeof( FC_EXCHANGES));    printk("Allocating %u for LinkQ ", (ULONG)sizeof(FC_LINK_QUE));  cpqfcHBAdata->fcLQ = kmalloc( sizeof( FC_LINK_QUE), GFP_KERNEL );  printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH);  memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));  if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!!  {    printk("kmalloc failure on fc Link Que: fatal error\n");    return -1;  }  // zero out the entire EXCHANGE space  memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));      // Verify that basic Tach I/O registers are not NULL      if( !fcChip->Registers.ReMapMemBase )  {    printk("HBA base address NULL: fatal error\n");    return -1;  }  // Initialize the fcMemManager memory pairs (stores allocated/aligned  // pairs for future freeing)  memset( cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));    // Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)    fcChip->ERQ = fcMemManager( &cpqfcHBAdata->dynamic_mem[0],		  sizeof( TachLiteERQ ), 32*(ERQ_LEN), 0L );  if( !fcChip->ERQ )  {    printk("kmalloc/alignment failure on ERQ: fatal error\n");    return -1;  }  fcChip->ERQ->length = ERQ_LEN-1;  ulAddr = virt_to_bus( fcChip->ERQ);#if BITS_PER_LONG > 32  if( (ulAddr >> 32) )  {    printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n",		    (void*)ulAddr);    return -1;  // failed  }#endif  fcChip->ERQ->base = (ULONG)ulAddr;  // copy for quick reference  // Allocate Tach's Inbound Message Queue (32 bytes per entry)    fcChip->IMQ = fcMemManager( &cpqfcHBAdata->dynamic_mem[0],		  sizeof( TachyonIMQ ), 32*(IMQ_LEN), 0L );  if( !fcChip->IMQ )  {    printk("kmalloc/alignment failure on IMQ: fatal error\n");    return -1;  }  fcChip->IMQ->length = IMQ_LEN-1;  ulAddr = virt_to_bus( fcChip->IMQ);#if BITS_PER_LONG > 32  if( (ulAddr >> 32) )  {    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",		    (void*)ulAddr);    return -1;  // failed  }#endif  fcChip->IMQ->base = (ULONG)ulAddr;  // copy for quick reference  // Allocate Tach's  Single Frame Queue (64 bytes per entry)  fcChip->SFQ = fcMemManager( &cpqfcHBAdata->dynamic_mem[0],		  sizeof( TachLiteSFQ ), 64*(SFQ_LEN),0L );  if( !fcChip->SFQ )  {    printk("kmalloc/alignment failure on SFQ: fatal error\n");    return -1;  }  fcChip->SFQ->length = SFQ_LEN-1;      // i.e. Que length [# entries -                                       // min. 32; max.  4096 (0xffff)]    ulAddr = virt_to_bus( fcChip->SFQ);#if BITS_PER_LONG > 32  if( (ulAddr >> 32) )  {    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",		    (void*)ulAddr);    return -1;  // failed  }#endif  fcChip->SFQ->base = (ULONG)ulAddr;  // copy for quick reference  // Allocate SCSI Exchange State Table; aligned nearest @sizeof  // power-of-2 boundary  // LIVE DANGEROUSLY!  Assume the boundary for SEST mem will  // be on physical page (e.g. 4k) boundary.  printk("Allocating %u for TachSEST for %u Exchanges\n", 		 (ULONG)sizeof(TachSEST), TACH_SEST_LEN);  fcChip->SEST = fcMemManager( &cpqfcHBAdata->dynamic_mem[0],		  sizeof(TachSEST),  4, 0L );//		  sizeof(TachSEST),  64*TACH_SEST_LEN, 0L );  if( !fcChip->SEST )  {    printk("kmalloc/alignment failure on SEST: fatal error\n");    return -1;  }  fcChip->SEST->length = TACH_SEST_LEN;  // e.g. DON'T subtract one                                        // (TL/TS UG, pg 153)  ulAddr = virt_to_bus( fcChip->SEST);#if BITS_PER_LONG > 32  if( (ulAddr >> 32) )  {    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",		    (void*)ulAddr);    return -1;  // failed  }#endif  fcChip->SEST->base = (ULONG)ulAddr;  // copy for quick reference			      // Now that structures are defined,			      // fill in Tachyon chip registers...			      // EEEEEEEE  EXCHANGE REQUEST QUEUE  writel( fcChip->ERQ->base,     (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));        writel( fcChip->ERQ->length,    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));       fcChip->ERQ->producerIndex = 0L;  writel( fcChip->ERQ->producerIndex,    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));      		// NOTE! write consumer index last, since the write		// causes Tachyon to process the other registers  ulAddr = virt_to_bus( &fcChip->ERQ->consumerIndex);  // NOTE! Tachyon DMAs to the ERQ consumer Index host		// address; must be correctly aligned  writel( (ULONG)ulAddr,    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));				 // IIIIIIIIIIIII  INBOUND MESSAGE QUEUE				 // Tell Tachyon where the Que starts  // set the Host's pointer for Tachyon to access  printk("  cpqfcTS: writing IMQ BASE %Xh  ", fcChip->IMQ->base );  writel( fcChip->IMQ->base,     (fcChip->Registers.ReMapMemBase + IMQ_BASE));  writel( fcChip->IMQ->length,    (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));  writel( fcChip->IMQ->consumerIndex,    (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));		// NOTE: TachLite DMAs to the producerIndex host address		// must be correctly aligned with address bits 1-0 cleared    // Writing the BASE register clears the PI register, so write it last  ulAddr = virt_to_bus( &fcChip->IMQ->producerIndex);#if BITS_PER_LONG > 32  if( (ulAddr >> 32) )  {    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",		    (void*)ulAddr);    return -1;  // failed  }#endif//#if DBG  printk("  PI %Xh\n", (ULONG)ulAddr );//#endif  writel( (ULONG)ulAddr,     (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));				 // SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE				 // Tell TachLite where the Que starts  writel( fcChip->SFQ->base,     (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));  writel( fcChip->SFQ->length,    (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));         // tell TachLite where SEST table is & how long  writel( fcChip->SEST->base,    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));  printk("  cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n",    fcChip->SEST, fcChip->SEST->base,     fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE);  writel( fcChip->SEST->length,    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));        writel( (TL_EXT_SG_PAGE_COUNT-1),    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));  LEAVE("CreateTachLiteQues");  return iStatus;}// function to return TachLite to Power On state// 1st - reset tachyon ('SOFT' reset)// others - futureint CpqTsResetTachLite(void *pHBA, int type){  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;  PTACHYON fcChip = &cpqfcHBAdata->fcChip;  ULONG ulBuff, i;  int ret_status=0; // def. success  ENTER("ResetTach");    switch(type)  {    case CLEAR_FCPORTS:      // in case he was running previously, mask Tach's interrupt      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));           // de-allocate mem for any Logged in ports      // (e.g., our module is unloading)      // search the forward linked list, de-allocating      // the memory we allocated when the port was initially logged in      {        PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;        PFC_LOGGEDIN_PORT ptr;//        printk("checking for allocated LoggedInPorts...\n");			        while( pLoggedInPort )        {          ptr = pLoggedInPort;          pLoggedInPort = ptr->pNextPort;//	  printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",//			  ptr, ptr->port_id);          kfree( ptr );        }      }      // (continue resetting hardware...)    case 1:                   // RESTART Tachyon (power-up state)      // in case he was running previously, mask Tach's interrupt      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));			      // turn OFF laser (NOTE: laser is turned                              // off during reset, because GPIO4 is cleared                              // to 0 by reset action - see TLUM, sec 7.22)                              // However, CPQ 64-bit HBAs have a "health                              // circuit" which keeps laser ON for a brief                              // period after it is turned off ( < 1s)            fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 0);              // soft reset timing constraints require:            //   1. set RST to 1            //   2. read SOFTRST register             //      (128 times per R. Callison code)            //   3. clear PCI ints            //   4. clear RST to 0      writel( 0xff000001L,        (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));              for( i=0; i<128; i++)        ulBuff = readl( fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);

⌨️ 快捷键说明

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