linux-old/drivers/scsi/cpqfcTScontrol.c
<<
>>
Prefs
   1/* Copyright 2000, Compaq Computer Corporation 
   2 * Fibre Channel Host Bus Adapter 
   3 * 64-bit, 66MHz PCI 
   4 * Originally developed and tested on:
   5 * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
   6 *          SP# P225CXCBFIEL6T, Rev XC
   7 *          SP# 161290-001, Rev XD
   8 * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
   9 *
  10 * This program is free software; you can redistribute it and/or modify it
  11 * under the terms of the GNU General Public License as published by the
  12 * Free Software Foundation; either version 2, or (at your option) any
  13 * later version.
  14 *
  15 * This program is distributed in the hope that it will be useful, but
  16 * WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 * General Public License for more details.
  19 * Written by Don Zimmerman
  20*/
  21/* These functions control the host bus adapter (HBA) hardware.  The main chip
  22   control takes place in the interrupt handler where we process the IMQ 
  23   (Inbound Message Queue).  The IMQ is Tachyon's way of communicating FC link
  24   events and state information to the driver.  The Single Frame Queue (SFQ)
  25   buffers incoming FC frames for processing by the driver.  References to 
  26   "TL/TS UG" are for:
  27   "HP HPFC-5100/5166 Tachyon TL/TS ICs User Guide", August 16, 1999, 1st Ed.
  28   Hewlitt Packard Manual Part Number 5968-1083E.
  29*/
  30
  31#include <linux/blk.h>
  32#include <linux/kernel.h>
  33#include <linux/string.h>
  34#include <linux/ioport.h>       // request_region() prototype
  35#include <linux/sched.h>
  36#include <linux/slab.h>         // need "kfree" for ext. S/G pages
  37#include <linux/types.h>
  38#include <linux/pci.h>
  39#include <linux/delay.h>
  40#include <linux/unistd.h>
  41#include <asm/io.h>             // struct pt_regs for IRQ handler & Port I/O
  42#include <asm/irq.h>
  43#include <linux/spinlock.h>
  44
  45#include "sd.h"
  46#include "hosts.h"              // Scsi_Host definition for INT handler
  47#include "cpqfcTSchip.h"
  48#include "cpqfcTSstructs.h"
  49
  50//#define IMQ_DEBUG 1
  51
  52static void fcParseLinkStatusCounters(TACHYON * fcChip);
  53static void CpqTsGetSFQEntry(TACHYON * fcChip, u16 pi, u32 * buffr, u8 UpdateChip);
  54
  55static void cpqfc_free_dma_consistent(CPQFCHBA * cpqfcHBAdata)
  56{
  57        // free up the primary EXCHANGES struct and Link Q
  58        PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  59
  60        if (fcChip->Exchanges != NULL)
  61                pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES), fcChip->Exchanges, fcChip->exch_dma_handle);
  62        fcChip->Exchanges = NULL;
  63        if (cpqfcHBAdata->fcLQ != NULL)
  64                pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE), cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle);
  65        cpqfcHBAdata->fcLQ = NULL;
  66}
  67
  68// Note special requirements for Q alignment!  (TL/TS UG pg. 190)
  69// We place critical index pointers at end of QUE elements to assist
  70// in non-symbolic (i.e. memory dump) debugging
  71// opcode defines placement of Queues (e.g. local/external RAM)
  72
  73int CpqTsCreateTachLiteQues(void *pHBA, int opcode)
  74{
  75        CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
  76        PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  77
  78        int iStatus = 0;
  79        unsigned long ulAddr;
  80        dma_addr_t ERQdma, IMQdma, SPQdma, SESTdma;
  81        int i;
  82
  83        // NOTE! fcMemManager() will return system virtual addresses.
  84        // System (kernel) virtual addresses, though non-paged, still
  85        // aren't physical addresses.  Convert to PHYSICAL_ADDRESS for Tachyon's
  86        // DMA use.
  87        ENTER("CreateTachLiteQues");
  88
  89
  90        // Allocate primary EXCHANGES array...
  91        fcChip->Exchanges = NULL;
  92        cpqfcHBAdata->fcLQ = NULL;
  93
  94        printk("Allocating %u for %u Exchanges ", (u32) sizeof(FC_EXCHANGES), TACH_MAX_XID);
  95        fcChip->Exchanges = pci_alloc_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES), &fcChip->exch_dma_handle);
  96        printk("@ %p\n", fcChip->Exchanges);
  97
  98        if (fcChip->Exchanges == NULL)  // fatal error!!
  99        {
 100                printk("pci_alloc_consistent failure on Exchanges: fatal error\n");
 101                return -1;
 102        }
 103        // zero out the entire EXCHANGE space
 104        memset(fcChip->Exchanges, 0, sizeof(FC_EXCHANGES));
 105
 106
 107        printk("Allocating %u for LinkQ ", (u32) sizeof(FC_LINK_QUE));
 108        cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle);
 109        printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH);
 110        memset(cpqfcHBAdata->fcLQ, 0, sizeof(FC_LINK_QUE));
 111
 112        if (cpqfcHBAdata->fcLQ == NULL) // fatal error!!
 113        {
 114                cpqfc_free_dma_consistent(cpqfcHBAdata);
 115                printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
 116                return -1;
 117        }
 118        // zero out the entire EXCHANGE space
 119        memset(cpqfcHBAdata->fcLQ, 0, sizeof(FC_LINK_QUE));
 120
 121        // Verify that basic Tach I/O registers are not NULL  
 122        if (!fcChip->Registers.ReMapMemBase) {
 123                cpqfc_free_dma_consistent(cpqfcHBAdata);
 124                printk("HBA base address NULL: fatal error\n");
 125                return -1;
 126        }
 127
 128        // Initialize the fcMemManager memory pairs (stores allocated/aligned
 129        // pairs for future freeing)
 130        memset(cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
 131
 132
 133        // Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
 134
 135        fcChip->ERQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachLiteERQ), 32 * (ERQ_LEN), 0L, &ERQdma);
 136        if (!fcChip->ERQ) {
 137                cpqfc_free_dma_consistent(cpqfcHBAdata);
 138                printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
 139                return -1;
 140        }
 141        fcChip->ERQ->length = ERQ_LEN - 1;
 142        ulAddr = (u32) ERQdma;
 143#if BITS_PER_LONG > 32
 144        if ((ulAddr >> 32)) {
 145                cpqfc_free_dma_consistent(cpqfcHBAdata);
 146                printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
 147                return -1;      // failed
 148        }
 149#endif
 150        fcChip->ERQ->base = (u32) ulAddr;       // copy for quick reference
 151
 152
 153        // Allocate Tach's Inbound Message Queue (32 bytes per entry)
 154
 155        fcChip->IMQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachyonIMQ), 32 * (IMQ_LEN), 0L, &IMQdma);
 156        if (!fcChip->IMQ) {
 157                cpqfc_free_dma_consistent(cpqfcHBAdata);
 158                printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
 159                return -1;
 160        }
 161        fcChip->IMQ->length = IMQ_LEN - 1;
 162
 163        ulAddr = IMQdma;
 164#if BITS_PER_LONG > 32
 165        if ((ulAddr >> 32)) {
 166                cpqfc_free_dma_consistent(cpqfcHBAdata);
 167                printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
 168                return -1;      // failed
 169        }
 170#endif
 171        fcChip->IMQ->base = (u32) ulAddr;       // copy for quick reference
 172
 173
 174        // Allocate Tach's  Single Frame Queue (64 bytes per entry)
 175        fcChip->SFQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachLiteSFQ), 64 * (SFQ_LEN), 0L, &SPQdma);
 176        if (!fcChip->SFQ) {
 177                cpqfc_free_dma_consistent(cpqfcHBAdata);
 178                printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
 179                return -1;
 180        }
 181        fcChip->SFQ->length = SFQ_LEN - 1;      // i.e. Que length [# entries -
 182        // min. 32; max.  4096 (0xffff)]
 183
 184        ulAddr = SPQdma;
 185#if BITS_PER_LONG > 32
 186        if ((ulAddr >> 32)) {
 187                cpqfc_free_dma_consistent(cpqfcHBAdata);
 188                printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
 189                return -1;      // failed
 190        }
 191#endif
 192        fcChip->SFQ->base = (u32) ulAddr;       // copy for quick reference
 193
 194
 195        // Allocate SCSI Exchange State Table; aligned nearest @sizeof
 196        // power-of-2 boundary
 197        // LIVE DANGEROUSLY!  Assume the boundary for SEST mem will
 198        // be on physical page (e.g. 4k) boundary.
 199        printk("Allocating %u for TachSEST for %u Exchanges\n", (u32) sizeof(TachSEST), TACH_SEST_LEN);
 200        fcChip->SEST = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachSEST), 4, 0L, &SESTdma);
 201//                sizeof(TachSEST),  64*TACH_SEST_LEN, 0L );
 202        if (!fcChip->SEST) {
 203                cpqfc_free_dma_consistent(cpqfcHBAdata);
 204                printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
 205                return -1;
 206        }
 207
 208        for (i = 0; i < TACH_SEST_LEN; i++)     // for each exchange
 209                fcChip->SEST->sgPages[i] = NULL;
 210
 211        fcChip->SEST->length = TACH_SEST_LEN;   // e.g. DON'T subtract one 
 212        // (TL/TS UG, pg 153)
 213
 214        ulAddr = SESTdma;
 215#if BITS_PER_LONG > 32
 216        if ((ulAddr >> 32)) {
 217                cpqfc_free_dma_consistent(cpqfcHBAdata);
 218                printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
 219                return -1;      // failed
 220        }
 221#endif
 222        fcChip->SEST->base = (u32) ulAddr;      // copy for quick reference
 223
 224
 225        // Now that structures are defined,
 226        // fill in Tachyon chip registers...
 227
 228        // EEEEEEEE  EXCHANGE REQUEST QUEUE
 229
 230        writel(fcChip->ERQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
 231
 232        writel(fcChip->ERQ->length, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
 233
 234
 235        fcChip->ERQ->producerIndex = 0L;
 236        writel(fcChip->ERQ->producerIndex, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
 237
 238
 239        // NOTE! write consumer index last, since the write
 240        // causes Tachyon to process the other registers
 241
 242        ulAddr = ((unsigned long) &fcChip->ERQ->consumerIndex - (unsigned long) fcChip->ERQ) + (unsigned long) ERQdma;
 243
 244        // NOTE! Tachyon DMAs to the ERQ consumer Index host
 245        // address; must be correctly aligned
 246        writel((u32) ulAddr, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
 247
 248
 249
 250        // IIIIIIIIIIIII  INBOUND MESSAGE QUEUE
 251        // Tell Tachyon where the Que starts
 252
 253        // set the Host's pointer for Tachyon to access
 254
 255        printk("  cpqfcTS: writing IMQ BASE %Xh  ", fcChip->IMQ->base);
 256        writel(fcChip->IMQ->base, (fcChip->Registers.ReMapMemBase + IMQ_BASE));
 257
 258        writel(fcChip->IMQ->length, (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
 259
 260        writel(fcChip->IMQ->consumerIndex, (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
 261
 262
 263        // NOTE: TachLite DMAs to the producerIndex host address
 264        // must be correctly aligned with address bits 1-0 cleared
 265        // Writing the BASE register clears the PI register, so write it last
 266        ulAddr = ((unsigned long) &fcChip->IMQ->producerIndex - (unsigned long) fcChip->IMQ) + (unsigned long) IMQdma;
 267
 268#if BITS_PER_LONG > 32
 269        if ((ulAddr >> 32)) {
 270                cpqfc_free_dma_consistent(cpqfcHBAdata);
 271                printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
 272                return -1;      // failed
 273        }
 274#endif
 275//#if DBG
 276        printk("  PI %Xh\n", (u32) ulAddr);
 277//#endif
 278        writel((u32) ulAddr, (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
 279
 280
 281
 282        // SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
 283        // Tell TachLite where the Que starts
 284
 285        writel(fcChip->SFQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
 286
 287        writel(fcChip->SFQ->length, (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
 288
 289
 290        // tell TachLite where SEST table is & how long
 291        writel(fcChip->SEST->base, (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
 292
 293        printk("  cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n", fcChip->SEST, fcChip->SEST->base, fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE);
 294
 295        writel(fcChip->SEST->length, (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
 296
 297        writel((TL_EXT_SG_PAGE_COUNT - 1), (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
 298
 299
 300        LEAVE("CreateTachLiteQues");
 301
 302        return iStatus;
 303}
 304
 305
 306
 307// function to return TachLite to Power On state
 308// 1st - reset tachyon ('SOFT' reset)
 309// others - future
 310
 311int CpqTsResetTachLite(void *pHBA, int type)
 312{
 313        CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
 314        PTACHYON fcChip = &cpqfcHBAdata->fcChip;
 315        u32 ulBuff, i;
 316        int ret_status = 0;     // def. success
 317
 318        ENTER("ResetTach");
 319
 320        switch (type) {
 321
 322        case CLEAR_FCPORTS:
 323
 324                // in case he was running previously, mask Tach's interrupt
 325                writeb(0, (fcChip->Registers.ReMapMemBase + IINTEN));
 326
 327                // de-allocate mem for any Logged in ports
 328                // (e.g., our module is unloading)
 329                // search the forward linked list, de-allocating
 330                // the memory we allocated when the port was initially logged in
 331                {
 332                        PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
 333                        PFC_LOGGEDIN_PORT ptr;
 334//        printk("checking for allocated LoggedInPorts...\n");
 335
 336                        while (pLoggedInPort) {
 337                                ptr = pLoggedInPort;
 338                                pLoggedInPort = ptr->pNextPort;
 339//        printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
 340//                        ptr, ptr->port_id);
 341                                kfree(ptr);
 342                        }
 343                }
 344                // (continue resetting hardware...)
 345
 346        case 1:         // RESTART Tachyon (power-up state)
 347
 348                // in case he was running previously, mask Tach's interrupt
 349                writeb(0, (fcChip->Registers.ReMapMemBase + IINTEN));
 350                // turn OFF laser (NOTE: laser is turned
 351                // off during reset, because GPIO4 is cleared
 352                // to 0 by reset action - see TLUM, sec 7.22)
 353                // However, CPQ 64-bit HBAs have a "health
 354                // circuit" which keeps laser ON for a brief
 355                // period after it is turned off ( < 1s)
 356
 357                fcChip->LaserControl(fcChip->Registers.ReMapMemBase, 0);
 358
 359
 360
 361                // soft reset timing constraints require:
 362                //   1. set RST to 1
 363                //   2. read SOFTRST register 
 364                //      (128 times per R. Callison code)
 365                //   3. clear PCI ints
 366                //   4. clear RST to 0
 367                writel(0xff000001L, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
 368
 369                for (i = 0; i < 128; i++)
 370                        ulBuff = readl(fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
 371
 372                // clear the soft reset
 373                for (i = 0; i < 8; i++)
 374                        writel(0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
 375
 376
 377
 378                // clear out our copy of Tach regs,
 379                // because they must be invalid now,
 380                // since TachLite reset all his regs.
 381                CpqTsDestroyTachLiteQues(cpqfcHBAdata, 0);      // remove Host-based Que structs
 382                cpqfcTSClearLinkStatusCounters(fcChip); // clear our s/w accumulators
 383                // lower bits give GBIC info
 384                fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
 385                break;
 386
 387/*
 388    case 2:                   // freeze SCSI
 389    case 3:                   // reset Outbound command que (ERQ)
 390    case 4:                   // unfreeze OSM (Outbound Seq. Man.) 'er'
 391    case 5:                   // report status
 392
 393    break;
 394*/
 395        default:
 396                ret_status = -1;        // invalid option passed to RESET function
 397                break;
 398        }
 399        LEAVE("ResetTach");
 400        return ret_status;
 401}
 402
 403
 404
 405
 406
 407
 408// 'addrBase' is IOBaseU for both TachLite and (older) Tachyon
 409int CpqTsLaserControl(void *addrBase, int opcode)
 410{
 411        u32 dwBuff;
 412
 413        dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL));       // read TL Control reg
 414        // (change only bit 4)
 415        if (opcode == 1)
 416                dwBuff |= ~0xffffffefL; // set - ON
 417        else
 418                dwBuff &= 0xffffffefL;  // clear - OFF
 419        writel(dwBuff, (addrBase + TL_MEM_TACH_CONTROL));       // write TL Control reg
 420        return 0;
 421}
 422
 423
 424
 425
 426
 427// Use controller's "Options" field to determine loopback mode (if any)
 428//   internal loopback (silicon - no GBIC)
 429//   external loopback (GBIC - no FC loop)
 430//   no loopback: L_PORT, external cable from GBIC required
 431
 432int CpqTsInitializeFrameManager(void *pChip, int opcode)
 433{
 434        PTACHYON fcChip;
 435        int iStatus;
 436        u32 wwnLo, wwnHi;       // for readback verification
 437
 438        ENTER("InitializeFrameManager");
 439        fcChip = (PTACHYON) pChip;
 440        if (!fcChip->Registers.ReMapMemBase)    // undefined controller?
 441                return -1;
 442
 443        // TL/TS UG, pg. 184
 444        // 0x0065 = 100ms for RT_TOV
 445        // 0x01f5 = 500ms for ED_TOV
 446        // 0x07D1 = 2000ms 
 447        fcChip->Registers.ed_tov.value = 0x006507D1;
 448        writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
 449
 450
 451        // Set LP_TOV to the FC-AL2 specified 2 secs.
 452        // TL/TS UG, pg. 185
 453        writel(0x07d00010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
 454
 455
 456        // Now try to read the WWN from the adapter's NVRAM
 457        iStatus = CpqTsReadWriteWWN(fcChip, 1); // '1' for READ
 458
 459        if (iStatus)            // NVRAM read failed?
 460        {
 461                printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
 462                // make up a WWN.  If NULL or duplicated on loop, FC loop may hang!
 463
 464
 465                fcChip->Registers.wwn_hi = (__u32) jiffies;
 466                fcChip->Registers.wwn_hi |= 0x50000000L;
 467                fcChip->Registers.wwn_lo = 0x44556677L;
 468        }
 469
 470
 471        writel(fcChip->Registers.wwn_hi, fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
 472
 473        writel(fcChip->Registers.wwn_lo, fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
 474
 475
 476        // readback for verification:
 477        wwnHi = readl(fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
 478
 479        wwnLo = readl(fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
 480        // test for correct chip register WRITE/READ
 481        DEBUG_PCI(printk("  WWN %08X%08X\n", fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo));
 482
 483        if (wwnHi != fcChip->Registers.wwn_hi || wwnLo != fcChip->Registers.wwn_lo) {
 484                printk("cpqfcTS: WorldWideName register load failed\n");
 485                return -1;      // FAILED!
 486        }
 487
 488
 489        // set Frame Manager Initialize command
 490        fcChip->Registers.FMcontrol.value = 0x06;
 491
 492        // Note: for test/debug purposes, we may use "Hard" address,
 493        // but we completely support "soft" addressing, including
 494        // dynamically changing our address.
 495        if (fcChip->Options.intLoopback == 1)   // internal loopback
 496                fcChip->Registers.FMconfig.value = 0x0f002080L;
 497        else if (fcChip->Options.extLoopback == 1)      // internal loopback
 498                fcChip->Registers.FMconfig.value = 0x0f004080L;
 499        else                    // L_Port
 500                fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
 501//    fcChip->Registers.FMconfig.value = 0x01000080L; // soft address (can't pick)
 502//    fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
 503
 504        // write config to FM
 505
 506        if (!fcChip->Options.intLoopback && !fcChip->Options.extLoopback)
 507                // (also need LASER for real LOOP)
 508                fcChip->LaserControl(fcChip->Registers.ReMapMemBase, 1);        // turn on LASER
 509
 510        writel(fcChip->Registers.FMconfig.value, fcChip->Registers.FMconfig.address);
 511
 512
 513        // issue INITIALIZE command to FM - ACTION!
 514        writel(fcChip->Registers.FMcontrol.value, fcChip->Registers.FMcontrol.address);
 515
 516        LEAVE("InitializeFrameManager");
 517
 518        return 0;
 519}
 520
 521
 522
 523
 524
 525// This "look ahead" function examines the IMQ for occurence of
 526// "type".  Returns 1 if found, 0 if not.
 527static int PeekIMQEntry(PTACHYON fcChip, u32 type)
 528{
 529        u32 CI = fcChip->IMQ->consumerIndex;
 530        u32 PI = fcChip->IMQ->producerIndex;    // snapshot of IMQ indexes
 531
 532        while (CI != PI) {      // proceed with search
 533                if ((++CI) >= IMQ_LEN)
 534                        CI = 0; // rollover check
 535
 536                switch (type) {
 537                case ELS_LILP_FRAME:
 538                        {
 539                                // first, we need to find an Inbound Completion message,
 540                                // If we find it, check the incoming frame payload (1st word)
 541                                // for LILP frame
 542                                if ((fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104) {
 543                                        TachFCHDR_GCMND *fchs;
 544                                        u32 ulFibreFrame[2048 / 4];     // max DWORDS in incoming FC Frame
 545                                        u16 SFQpi = (u16) (fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
 546
 547                                        CpqTsGetSFQEntry(fcChip, SFQpi, // SFQ producer ndx         
 548                                                         ulFibreFrame,  // contiguous dest. buffer
 549                                                         FALSE);        // DON'T update chip--this is a "lookahead"
 550
 551                                        fchs = (TachFCHDR_GCMND *) & ulFibreFrame;
 552                                        if (fchs->pl[0] == ELS_LILP_FRAME) {
 553                                                return 1;       // found the LILP frame!
 554                                        } else {
 555                                                // keep looking...
 556                                        }
 557                                }
 558                        }
 559                        break;
 560
 561                case OUTBOUND_COMPLETION:
 562                        if ((fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00) {
 563
 564                                // any OCM errors?
 565                                if (fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L)
 566                                        return 1;       // found OCM error
 567                        }
 568                        break;
 569
 570
 571
 572                default:
 573                        break;
 574                }
 575        }
 576        return 0;               // failed to find "type"
 577}
 578
 579
 580static void SetTachTOV(CPQFCHBA * cpqfcHBAdata)
 581{
 582        PTACHYON fcChip = &cpqfcHBAdata->fcChip;
 583
 584        // TL/TS UG, pg. 184
 585        // 0x0065 = 100ms for RT_TOV
 586        // 0x01f5 = 500ms for ED_TOV
 587        // 0x07d1 = 2000ms for ED_TOV
 588
 589        // SANMark Level 1 requires an "initialization backoff"
 590        // (See "SANMark Test Suite Level 1":
 591        // initialization_timeout.fcal.SANMark-1.fc)
 592        // We have to use 2sec, 24sec, then 128sec when login/
 593        // port discovery processes fail to complete.
 594
 595        // when port discovery completes (logins done), we set
 596        // ED_TOV to 500ms -- this is the normal operational case
 597        // On the first Link Down, we'll move to 2 secs (7D1 ms)
 598        if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x1f5)
 599                fcChip->Registers.ed_tov.value = 0x006507D1;
 600
 601        // If we get another LST after we moved TOV to 2 sec,
 602        // increase to 24 seconds (5DC1 ms) per SANMark!
 603        else if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x7D1)
 604                fcChip->Registers.ed_tov.value = 0x00655DC1;
 605
 606        // If we get still another LST, set the max TOV (Tachyon
 607        // has only 16 bits for ms timer, so the max is 65.5 sec)
 608        else if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x5DC1)
 609                fcChip->Registers.ed_tov.value = 0x0065FFFF;
 610
 611        writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
 612        // keep the same 2sec LP_TOV 
 613        writel(0x07D00010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
 614}
 615
 616
 617// The IMQ is an array with IMQ_LEN length, each element (QEntry)
 618// with eight 32-bit words.  Tachyon PRODUCES a QEntry with each
 619// message it wants to send to the host.  The host CONSUMES IMQ entries
 620
 621// This function copies the current
 622// (or oldest not-yet-processed) QEntry to
 623// the caller, clears/ re-enables the interrupt, and updates the
 624// (Host) Consumer Index.
 625// Return value:
 626//  0   message processed, none remain (producer and consumer
 627//        indexes match)
 628//  1   message processed, more messages remain
 629// -1   no message processed - none were available to process
 630// Remarks:
 631//   TL/TS UG specifices that the following actions for
 632//   INTA_L handling:
 633//   1. read PCI Interrupt Status register (0xff)
 634//   2. all IMQ messages should be processed before writing the
 635//      IMQ consumer index.
 636
 637
 638int CpqTsProcessIMQEntry(void *host)
 639{
 640        struct Scsi_Host *HostAdapter = (struct Scsi_Host *) host;
 641        CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
 642        PTACHYON fcChip = &cpqfcHBAdata->fcChip;
 643        FC_EXCHANGES *Exchanges = fcChip->Exchanges;
 644        int iStatus;
 645        u16 i, RPCset, DPCset;
 646        u32 x_ID;
 647        u32 ulBuff, dwStatus;
 648        TachFCHDR_GCMND *fchs;
 649        u32 ulFibreFrame[2048 / 4];     // max number of DWORDS in incoming Fibre Frame
 650        u8 ucInboundMessageType;        // Inbound CM, dword 3 "type" field
 651
 652        ENTER("ProcessIMQEntry");
 653
 654
 655        // check TachLite's IMQ producer index -
 656        // is a new message waiting for us?
 657        // equal indexes means empty que
 658
 659        if (fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex) { // need to process message
 660
 661
 662#ifdef IMQ_DEBUG
 663                printk("PI %X, CI %X  type: %X\n", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex, fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
 664#endif
 665                // Examine Completion Messages in IMQ
 666                // what CM_Type?
 667                switch ((u8) (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type & 0xffL)) {
 668                case OUTBOUND_COMPLETION:
 669
 670                        // Remarks:
 671                        // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
 672                        // (starting at 0), and SFS entries (starting at
 673                        // SEST_LEN -- outside the SEST space).
 674                        // Psuedo code:
 675                        // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
 676                        // range check - x_ID
 677                        //   if x_ID outside 'Transactions' length, error - exit
 678                        // if any OCM error, copy error status to Exchange slot
 679                        // if FCP ASSIST transaction (x_ID within SEST),
 680                        //   call fcComplete (to App)
 681                        // ...
 682
 683
 684                        ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
 685                        x_ID = ulBuff & 0x7fffL;        // lower 14 bits SEST_Index/Trans_ID
 686                        // Range check CM OX/RX_ID value...
 687                        if (x_ID < TACH_MAX_XID)        // don't go beyond array space
 688                        {
 689
 690
 691                                if (ulBuff & 0x20000000L)       // RPC -Response Phase Complete?
 692                                        RPCset = 1;     // (SEST transactions only)
 693                                else
 694                                        RPCset = 0;
 695
 696                                if (ulBuff & 0x40000000L)       // DPC -Data Phase Complete?
 697                                        DPCset = 1;     // (SEST transactions only)
 698                                else
 699                                        DPCset = 0;
 700                                // set the status for this Outbound transaction's ID
 701                                dwStatus = 0L;
 702                                if (ulBuff & 0x10000000L)       // SPE? (SEST Programming Error)
 703                                        dwStatus |= SESTPROG_ERR;
 704
 705                                ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
 706                                if (ulBuff & 0x7a000000L)       // any other errs?
 707                                {
 708                                        if (ulBuff & 0x40000000L)
 709                                                dwStatus |= INV_ENTRY;
 710                                        if (ulBuff & 0x20000000L)
 711                                                dwStatus |= FRAME_TO;   // FTO
 712                                        if (ulBuff & 0x10000000L)
 713                                                dwStatus |= HOSTPROG_ERR;
 714                                        if (ulBuff & 0x08000000L)
 715                                                dwStatus |= LINKFAIL_TX;
 716                                        if (ulBuff & 0x02000000L)
 717                                                dwStatus |= ABORTSEQ_NOTIFY;    // ASN
 718                                }
 719
 720
 721                                if (dwStatus)   // any errors?
 722                                {
 723                                        // set the Outbound Completion status
 724                                        Exchanges->fcExchange[x_ID].status |= dwStatus;
 725
 726                                        // if this Outbound frame was for a SEST entry, automatically
 727                                        // reque it in the case of LINKFAIL (it will restart on PDISC)
 728                                        if (x_ID < TACH_SEST_LEN) {
 729
 730                                                printk(" #OCM error %Xh x_ID %X# ", dwStatus, x_ID);
 731
 732                                                Exchanges->fcExchange[x_ID].timeOut = 30000;    // seconds default
 733
 734
 735                                                // We Q ABTS for each exchange.
 736                                                // NOTE: We can get FRAME_TO on bad alpa (device gone).  Since
 737                                                // bad alpa is reported before FRAME_TO, examine the status
 738                                                // flags to see if the device is removed.  If so, DON'T
 739                                                // post an ABTS, since it will be terminated by the bad alpa
 740                                                // message.
 741                                                if (dwStatus & FRAME_TO)        // check for device removed...
 742                                                {
 743                                                        if (!(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)) {
 744                                                                // presumes device is still there: send ABTS.
 745
 746                                                                cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
 747                                                        }
 748                                                } else  // Abort all other errors
 749                                                {
 750                                                        cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
 751                                                }
 752
 753                                                // if the HPE bit is set, we have to CLose the LOOP
 754                                                // (see TL/TS UG, pg. 239)
 755
 756                                                if (dwStatus &= HOSTPROG_ERR)
 757                                                        // set CL bit (see TL/TS UG, pg. 172)
 758                                                        writel(4, fcChip->Registers.FMcontrol.address);
 759                                        }
 760                                }
 761                                // NOTE: we don't necessarily care about ALL completion messages...
 762                                // SCSI resp. complete OR
 763                                if (((x_ID < TACH_SEST_LEN) && RPCset) || (x_ID >= TACH_SEST_LEN))      // non-SCSI command
 764                                {
 765                                        // exchange done; complete to upper levels with status
 766                                        // (if necessary) and free the exchange slot
 767
 768
 769                                        if (x_ID >= TACH_SEST_LEN)      // Link Service Outbound frame?
 770                                                // A Request or Reply has been sent
 771                                        {       // signal waiting WorkerThread
 772
 773                                                up(cpqfcHBAdata->TYOBcomplete); // frame is OUT of Tach
 774
 775                                                // WorkerThread will complete Xchng
 776                                        } else  // X_ID is for FCP assist (SEST)
 777                                        {
 778                                                // TBD (target mode)
 779//            fcCompleteExchange( fcChip, x_ID); // TRE completed
 780                                        }
 781                                }
 782                        } else  // ERROR CONDITION!  bogus x_ID in completion message
 783                        {
 784
 785                                printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
 786
 787                        }
 788
 789
 790
 791                        // Load the Frame Manager's error counters.  We check them here
 792                        // because presumably the link is up and healthy enough for the
 793                        // counters to be meaningful (i.e., don't check them while loop
 794                        // is initializing).
 795                        fcChip->Registers.FMLinkStatus1.value = // get TL's counter
 796                            readl(fcChip->Registers.FMLinkStatus1.address);
 797
 798                        fcChip->Registers.FMLinkStatus2.value = // get TL's counter
 799                            readl(fcChip->Registers.FMLinkStatus2.address);
 800
 801
 802                        fcParseLinkStatusCounters(fcChip);      // load into 6 s/w accumulators
 803                        break;
 804
 805
 806
 807                case ERROR_IDLE_COMPLETION:     // TachLite Error Idle...
 808
 809                        // We usually get this when the link goes down during heavy traffic.
 810                        // For now, presume that if SEST Exchanges are open, we will
 811                        // get this as our cue to INVALIDATE all SEST entries
 812                        // (and we OWN all the SEST entries).
 813                        // See TL/TS UG, pg. 53
 814
 815                        for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
 816
 817                                // Does this VALid SEST entry need to be invalidated for Abort?
 818                                fcChip->SEST->u[x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
 819                        }
 820
 821                        CpqTsUnFreezeTachlite(fcChip, 2);       // unfreeze Tachyon, if Link OK
 822
 823                        break;
 824
 825
 826                case INBOUND_SFS_COMPLETION:    //0x04
 827                        // NOTE! we must process this SFQ message to avoid SFQ filling
 828                        // up and stopping TachLite.  Incoming commands are placed here,
 829                        // as well as 'unknown' frames (e.g. LIP loop position data)
 830                        // write this CM's producer index to global...
 831                        // TL/TS UG, pg 234:
 832                        // Type: 0 - reserved
 833                        //       1 - Unassisted FCP
 834                        //       2 - BAD FCP
 835                        //       3 - Unkown Frame
 836                        //       4-F reserved
 837
 838
 839                        fcChip->SFQ->producerIndex = (u16)
 840                            (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
 841
 842
 843                        ucInboundMessageType = 0;       // default to useless frame
 844
 845                        // we can only process two Types: 1, Unassisted FCP, and 3, Unknown
 846                        // Also, we aren't interested in processing frame fragments
 847                        // so don't Que anything with 'LKF' bit set
 848                        if (!(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2]
 849                              & 0x40000000))    // 'LKF' link failure bit clear?
 850                        {
 851                                ucInboundMessageType = (u8)     // ICM DWord3, "Type"
 852                                    (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
 853                        } else {
 854                                fcChip->fcStats.linkFailRX++;
 855//        printk("LKF (link failure) bit set on inbound message\n");
 856                        }
 857
 858                        // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
 859                        CpqTsGetSFQEntry(fcChip,        // i.e. this Device Object
 860                                         (u16) fcChip->SFQ->producerIndex,      // SFQ producer ndx         
 861                                         ulFibreFrame, TRUE);   // contiguous destination buffer, update chip
 862
 863                        // analyze the incoming frame outside the INT handler...
 864                        // (i.e., Worker)
 865
 866                        if (ucInboundMessageType == 1) {
 867                                fchs = (TachFCHDR_GCMND *) ulFibreFrame;        // cast to examine IB frame
 868                                // don't fill up our Q with garbage - only accept FCP-CMND  
 869                                // or XRDY frames
 870                                if ((fchs->d_id & 0xFF000000) == 0x06000000)    // CMND
 871                                {
 872                                        // someone sent us a SCSI command
 873
 874//          fcPutScsiQue( cpqfcHBAdata, 
 875//                        SFQ_UNASSISTED_FCP, ulFibreFrame); 
 876                                } else if (((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status)
 877                                           (fchs->d_id & 0xFF000000) == 0x05000000)     // XRDY  
 878                                {
 879                                        u32 x_ID;
 880                                        // Unfortunately, ABTS requires a Freeze on the chip so
 881                                        // we can modify the shared memory SEST.  When frozen,
 882                                        // any received Exchange frames cannot be processed by
 883                                        // Tachyon, so they will be dumped in here.  It is too
 884                                        // complex to attempt the reconstruct these frames in
 885                                        // the correct Exchange context, so we simply seek to
 886                                        // find status or transfer ready frames, and cause the
 887                                        // exchange to complete with errors before the timeout
 888                                        // expires.  We use a Linux Scsi Cmnd result code that
 889                                        // causes immediate retry.
 890
 891
 892                                        // Do we have an open exchange that matches this s_id
 893                                        // and ox_id?
 894                                        for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
 895                                                if ((fchs->s_id & 0xFFFFFF) == (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF)
 896                                                    && (fchs->ox_rx_id & 0xFFFF0000) == (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000)) {
 897                                                        //          printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
 898                                                        // simulate the anticipated error - since the
 899                                                        // SEST was frozen, frames were lost...
 900                                                        Exchanges->fcExchange[x_ID].status |= SFQ_FRAME;
 901
 902                                                        // presumes device is still there: send ABTS.
 903                                                        cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
 904                                                        break;  // done
 905                                                }
 906                                        }
 907                                }
 908
 909                        }
 910
 911                        else if (ucInboundMessageType == 3) {
 912                                // FC Link Service frames (e.g. PLOGI, ACC) come in here.  
 913                                cpqfcTSPutLinkQue(cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame);
 914
 915                        }
 916
 917                        else if (ucInboundMessageType == 2)     // "bad FCP"?
 918                        {
 919#ifdef IMQ_DEBUG
 920                                printk("Bad FCP incoming frame discarded\n");
 921#endif
 922                        }
 923
 924                        else    // don't know this type
 925                        {
 926#ifdef IMQ_DEBUG
 927                                printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
 928#endif
 929                        }
 930
 931                        // Check the Frame Manager's error counters.  We check them here
 932                        // because presumably the link is up and healthy enough for the
 933                        // counters to be meaningful (i.e., don't check them while loop
 934                        // is initializing).
 935                        fcChip->Registers.FMLinkStatus1.value = // get TL's counter
 936                            readl(fcChip->Registers.FMLinkStatus1.address);
 937
 938
 939                        fcChip->Registers.FMLinkStatus2.value = // get TL's counter
 940                            readl(fcChip->Registers.FMLinkStatus2.address);
 941
 942
 943                        break;
 944
 945
 946
 947
 948                        // We get this CM because we issued a freeze
 949                        // command to stop outbound frames.  We issue the
 950                        // freeze command at Link Up time; when this message
 951                        // is received, the ERQ base can be switched and PDISC
 952                        // frames can be sent.
 953
 954
 955                case ERQ_FROZEN_COMPLETION:     // note: expect ERQ followed immediately
 956                        // by FCP when freezing TL
 957                        fcChip->Registers.TYstatus.value =      // read what's frozen
 958                            readl(fcChip->Registers.TYstatus.address);
 959                        // (do nothing; wait for FCP frozen message)
 960                        break;
 961                case FCP_FROZEN_COMPLETION:
 962
 963                        fcChip->Registers.TYstatus.value =      // read what's frozen
 964                            readl(fcChip->Registers.TYstatus.address);
 965
 966                        // Signal the kernel thread to proceed with SEST modification
 967                        up(cpqfcHBAdata->TachFrozen);
 968
 969                        break;
 970
 971
 972
 973                case INBOUND_C1_TIMEOUT:
 974                case MFS_BUF_WARN:
 975                case IMQ_BUF_WARN:
 976                        break;
 977
 978
 979
 980
 981
 982                        // In older Tachyons, we 'clear' the internal 'core' interrupt state
 983                        // by reading the FMstatus register.  In newer TachLite (Tachyon),
 984                        // we must WRITE the register
 985                        // to clear the condition (TL/TS UG, pg 179)
 986                case FRAME_MGR_INTERRUPT:
 987                        {
 988                                PFC_LOGGEDIN_PORT pLoggedInPort;
 989
 990                                fcChip->Registers.FMstatus.value = readl(fcChip->Registers.FMstatus.address);
 991
 992                                // PROBLEM: It is possible, especially with "dumb" hubs that
 993                                // don't automatically LIP on by-pass of ports that are going
 994                                // away, for the hub by-pass process to destroy critical 
 995                                // ordered sets of a frame.  The result of this is a hung LPSM
 996                                // (Loop Port State Machine), which on Tachyon results in a
 997                                // (default 2 sec) Loop State Timeout (LST) FM message.  We 
 998                                // want to avoid this relatively huge timeout by detecting
 999                                // likely scenarios which will result in LST.
1000                                // To do this, we could examine FMstatus for Loss of Synchronization
1001                                // and/or Elastic Store (ES) errors.  Of these, Elastic Store is better
1002                                // because we get this indication more quickly than the LOS.
1003                                // Not all ES errors are harmfull, so we don't want to LIP on every
1004                                // ES.  Instead, on every ES, detect whether our LPSM in in one
1005                                // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
1006                                // or RECEIVED CLOSE.  (See TL/TS UG, pg. 181)
1007                                // If any of these LPSM states are detected
1008                                // in combination with the LIP while LDn is not set, 
1009                                // send an FM init (LIP F7,F7 for loops)!
1010                                // It is critical to the physical link stability NOT to reset (LIP)
1011                                // more than absolutely necessary; this is a basic premise of the
1012                                // SANMark level 1 spec.
1013                                {
1014                                        u32 Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >> 4;
1015
1016                                        if ((fcChip->Registers.FMstatus.value & 0x400)  // ElasticStore?
1017                                            && !(fcChip->Registers.FMstatus.value & 0x100)      // NOT LDn
1018                                            && !(fcChip->Registers.FMstatus.value & 0x1000))    // NOT LF
1019                                        {
1020                                                if ((Lpsm != 0) ||      // not MONITORING? or
1021                                                    !(Lpsm & 0x8))      // not already offline?
1022                                                {
1023                                                        // now check the particular LST states...
1024                                                        if ((Lpsm == ARBITRATING) || (Lpsm == OPEN) || (Lpsm == OPENED) || (Lpsm == XMITTD_CLOSE) || (Lpsm == RCVD_CLOSE)) {
1025                                                                // re-init the loop before it hangs itself!
1026                                                                printk(" #req FMinit on E-S: LPSM %Xh# ", Lpsm);
1027
1028
1029                                                                fcChip->fcStats.FMinits++;
1030                                                                writel(6, fcChip->Registers.FMcontrol.address); // LIP
1031                                                        }
1032                                                }
1033                                        } else if (fcChip->Registers.FMstatus.value & 0x40000)  // LST?
1034                                        {
1035                                                printk(" #req FMinit on LST, LPSM %Xh# ", Lpsm);
1036
1037                                                fcChip->fcStats.FMinits++;
1038                                                writel(6, fcChip->Registers.FMcontrol.address); // LIP
1039                                        }
1040                                }
1041
1042
1043                                // clear only the 'interrupting' type bits for this REG read
1044                                writel((fcChip->Registers.FMstatus.value & 0xff3fff00L), fcChip->Registers.FMstatus.address);
1045
1046
1047                                // copy frame manager status to unused u32 slot
1048                                fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] = fcChip->Registers.FMstatus.value;     // (for debugging)
1049
1050
1051                                // Load the Frame Manager's error counters.  We check them here
1052                                // because presumably the link is up and healthy enough for the
1053                                // counters to be meaningful (i.e., don't check them while loop
1054                                // is initializing).
1055                                fcChip->Registers.FMLinkStatus1.value = // get TL's counter
1056                                    readl(fcChip->Registers.FMLinkStatus1.address);
1057
1058                                fcChip->Registers.FMLinkStatus2.value = // get TL's counter
1059                                    readl(fcChip->Registers.FMLinkStatus2.address);
1060
1061                                // Get FM BB_Credit Zero Reg - does not clear on READ
1062                                fcChip->Registers.FMBB_CreditZero.value =       // get TL's counter
1063                                    readl(fcChip->Registers.FMBB_CreditZero.address);
1064
1065
1066
1067                                fcParseLinkStatusCounters(fcChip);      // load into 6 s/w accumulators
1068
1069
1070                                // LINK DOWN
1071
1072                                if (fcChip->Registers.FMstatus.value & 0x100L)  // Link DOWN bit
1073                                {
1074
1075#ifdef IMQ_DEBUG
1076                                        printk("LinkDn\n");
1077#endif
1078                                        printk(" #LDn# ");
1079
1080                                        fcChip->fcStats.linkDown++;
1081
1082                                        SetTachTOV(cpqfcHBAdata);       // must set according to SANMark
1083
1084                                        // Check the ERQ - force it to be "empty" to prevent Tach
1085                                        // from sending out frames before we do logins.
1086
1087
1088                                        if (fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex) {
1089//        printk("#ERQ PI != CI#");
1090                                                CpqTsFreezeTachlite(fcChip, 1); // freeze ERQ only     
1091                                                fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
1092                                                writel(fcChip->ERQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
1093                                                // re-writing base forces ERQ PI to equal CI
1094
1095                                        }
1096                                        // link down transition occurred -- port_ids can change
1097                                        // on next LinkUp, so we must invalidate current logins
1098                                        // (and any I/O in progress) until PDISC or PLOGI/PRLI
1099                                        // completes
1100                                        {
1101                                                pLoggedInPort = &fcChip->fcPorts;
1102                                                while (pLoggedInPort)   // for all ports which are expecting
1103                                                        // PDISC after the next LIP, set the
1104                                                        // logoutTimer
1105                                                {
1106
1107                                                        if (pLoggedInPort->pdisc)       // expecting PDISC within 2 sec?
1108                                                        {
1109                                                                pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
1110                                                                // but Timer granularity
1111                                                                // is 1 second
1112                                                        }
1113                                                        // suspend any I/O in progress until
1114                                                        // PDISC received...
1115                                                        pLoggedInPort->prli = FALSE;    // block FCP-SCSI commands
1116
1117                                                        pLoggedInPort = pLoggedInPort->pNextPort;
1118                                                }       // ... all Previously known ports checked
1119                                        }
1120
1121                                        // since any hot plugging device may NOT support LILP frames
1122                                        // (such as early Tachyon chips), clear this flag indicating
1123                                        // we shouldn't use (our copy of) a LILP map.
1124                                        // If we receive an LILP frame, we'll set it again.
1125                                        fcChip->Options.LILPin = 0;     // our LILPmap is invalid
1126                                        cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports!
1127
1128                                        // also, we want to invalidate (i.e. INITIATOR_ABORT) any
1129                                        // open Login exchanges, in case the LinkDown happened in the
1130                                        // middle of logins.  It's possible that some ports already
1131                                        // ACCepted login commands which we have not processed before
1132                                        // another LinkDown occurred.  Any accepted Login exhanges are
1133                                        // invalidated by LinkDown, even before they are acknowledged.
1134                                        // It's also possible for a port to have a Queued Reply or Request
1135                                        // for login which was interrupted by LinkDown; it may come later,
1136                                        // but it will be unacceptable to us.
1137
1138                                        // we must scan the entire exchange space, find every Login type
1139                                        // originated by us, and abort it. This is NOT an abort due to
1140                                        // timeout, so we don't actually send abort to the other port -
1141                                        // we just complete it to free up the fcExchange slot.
1142
1143                                        for (i = TACH_SEST_LEN; i < TACH_MAX_XID; i++) {        // looking for Extended Link Serv.Exchanges
1144                                                if (Exchanges->fcExchange[i].type == ELS_PDISC || Exchanges->fcExchange[i].type == ELS_PLOGI || Exchanges->fcExchange[i].type == ELS_PRLI) {
1145                                                        // ABORT the exchange!
1146#ifdef IMQ_DEBUG
1147                                                        printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n", i, Exchanges->fcExchange[i].type, Exchanges->fcExchange[i].fchs.d_id);
1148#endif
1149
1150                                                        Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
1151                                                        cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, i);       // abort on LDn
1152                                                }
1153                                        }
1154
1155                                }
1156                                // ################   LINK UP   ##################
1157                                if (fcChip->Registers.FMstatus.value & 0x200L)  // Link Up bit
1158                                {       // AL_PA could have changed
1159
1160                                        // We need the following code, duplicated from LinkDn condition,
1161                                        // because it's possible for the Tachyon to re-initialize (hard
1162                                        // reset) without ever getting a LinkDn indication.
1163                                        pLoggedInPort = &fcChip->fcPorts;
1164                                        while (pLoggedInPort)   // for all ports which are expecting
1165                                                // PDISC after the next LIP, set the
1166                                                // logoutTimer
1167                                        {
1168                                                if (pLoggedInPort->pdisc)       // expecting PDISC within 2 sec?
1169                                                {
1170                                                        pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
1171                                                        // but Timer granularity
1172                                                        // is 1 second
1173
1174                                                        // suspend any I/O in progress until
1175                                                        // PDISC received...
1176
1177                                                }
1178                                                pLoggedInPort = pLoggedInPort->pNextPort;
1179                                        }       // ... all Previously known ports checked
1180
1181                                        // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
1182                                        fcChip->Registers.rcv_al_pa.value = readl(fcChip->Registers.rcv_al_pa.address);
1183
1184                                        // Now, if our acquired address is DIFFERENT from our
1185                                        // previous one, we are not allow to do PDISC - we
1186                                        // must go back to PLOGI, which will terminate I/O in
1187                                        // progress for ALL logged in FC devices...
1188                                        // (This is highly unlikely).
1189
1190                                        if ((fcChip->Registers.my_al_pa & 0xFF) != ((fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF)) {
1191
1192//        printk(" #our HBA port_id changed!# "); // FC port_id changed!!       
1193
1194                                                pLoggedInPort = &fcChip->fcPorts;
1195                                                while (pLoggedInPort)   // for all ports which are expecting
1196                                                        // PDISC after the next LIP, set the
1197                                                        // logoutTimer
1198                                                {
1199                                                        pLoggedInPort->pdisc = FALSE;
1200                                                        pLoggedInPort->prli = FALSE;
1201                                                        pLoggedInPort = pLoggedInPort->pNextPort;
1202                                                }       // ... all Previously known ports checked
1203
1204                                                // when the port_id changes, we must terminate
1205                                                // all open exchanges.
1206                                                cpqfcTSTerminateExchange(cpqfcHBAdata, NULL, PORTID_CHANGED);
1207
1208                                        }
1209                                        // Replace the entire 24-bit port_id.  We only know the
1210                                        // lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
1211                                        // we'll get the upper 16-bits from the FLOGI ACC frame.
1212                                        // If someone plugs into Fabric switch, we'll do FLOGI and
1213                                        // get full 24-bit port_id; someone could then remove and
1214                                        // hot-plug us into a dumb hub.  If we send a 24-bit PLOGI
1215                                        // to a "private" loop device, it might blow up.
1216                                        // Consequently, we force the upper 16-bits of port_id to
1217                                        // be re-set on every LinkUp transition
1218                                        fcChip->Registers.my_al_pa = (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
1219
1220
1221                                        // copy frame manager status to unused u32 slot
1222                                        fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] = fcChip->Registers.my_al_pa;   // (for debugging)
1223
1224                                        // for TachLite, we need to write the acquired al_pa
1225                                        // back into the FMconfig register, because after
1226                                        // first initialization, the AQ (prev. acq.) bit gets
1227                                        // set, causing TL FM to use the AL_PA field in FMconfig.
1228                                        // (In Tachyon, FM writes the acquired AL_PA for us.)
1229                                        ulBuff = readl(fcChip->Registers.FMconfig.address);
1230                                        ulBuff &= 0x00ffffffL;  // mask out current al_pa
1231                                        ulBuff |= (fcChip->Registers.my_al_pa << 24);   // or in acq. al_pa
1232                                        fcChip->Registers.FMconfig.value = ulBuff;      // copy it back
1233                                        writel(fcChip->Registers.FMconfig.value,        // put in TachLite
1234                                               fcChip->Registers.FMconfig.address);
1235
1236
1237#ifdef IMQ_DEBUG
1238                                        printk("#LUp %Xh, FMstat 0x%08X#", fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
1239#endif
1240
1241                                        // also set the WRITE-ONLY My_ID Register (for Fabric
1242                                        // initialization)
1243                                        writel(fcChip->Registers.my_al_pa, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
1244
1245
1246                                        fcChip->fcStats.linkUp++;
1247
1248                                        // reset TL statistics counters
1249                                        // (we ignore these error counters
1250                                        // while link is down)
1251                                        ulBuff =        // just reset TL's counter
1252                                            readl(fcChip->Registers.FMLinkStatus1.address);
1253
1254                                        ulBuff =        // just reset TL's counter
1255                                            readl(fcChip->Registers.FMLinkStatus2.address);
1256
1257                                        // for initiator, need to start verifying ports (e.g. PDISC)
1258
1259
1260
1261
1262
1263
1264                                        CpqTsUnFreezeTachlite(fcChip, 2);       // unfreeze Tachlite, if Link OK
1265
1266                                        // Tachyon creates an interesting problem for us on LILP frames.
1267                                        // Instead of writing the incoming LILP frame into the SFQ before
1268                                        // indicating LINK UP (the actual order of events), Tachyon tells
1269                                        // us LINK UP, and later us the LILP.  So we delay, then examine the
1270                                        // IMQ for an Inbound CM (x04); if found, we can set
1271                                        // LINKACTIVE after processing the LILP.  Otherwise, just proceed.
1272                                        // Since Tachyon imposes this time delay (and doesn't tell us
1273                                        // what it is), we have to impose a delay before "Peeking" the IMQ
1274                                        // for Tach hardware (DMA) delivery.
1275                                        // Processing LILP is required by SANMark
1276                                        udelay(1000);   // microsec delay waiting for LILP (if it comes)
1277                                        if (PeekIMQEntry(fcChip, ELS_LILP_FRAME)) {     // found SFQ LILP, which will post LINKACTIVE          
1278//        printk("skipping LINKACTIVE post\n");
1279
1280                                        } else
1281                                                cpqfcTSPutLinkQue(cpqfcHBAdata, LINKACTIVE, ulFibreFrame);
1282                                }
1283
1284
1285                                // ******* Set Fabric Login indication ********
1286                                if (fcChip->Registers.FMstatus.value & 0x2000) {
1287                                        printk(" #Fabric# ");
1288                                        fcChip->Options.fabric = 1;
1289                                } else
1290                                        fcChip->Options.fabric = 0;
1291
1292
1293
1294                                // ******* LIP(F8,x) or BAD AL_PA? ********
1295                                if (fcChip->Registers.FMstatus.value & 0x30000L) {
1296                                        // copy the error AL_PAs
1297                                        fcChip->Registers.rcv_al_pa.value = readl(fcChip->Registers.rcv_al_pa.address);
1298
1299                                        // Bad AL_PA?
1300                                        if (fcChip->Registers.FMstatus.value & 0x10000L) {
1301                                                PFC_LOGGEDIN_PORT pLoggedInPort;
1302
1303                                                // copy "BAD" al_pa field
1304                                                fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] = (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
1305
1306                                                pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,        // DON'T search Scsi Nexus
1307                                                                                   fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1],     // port id
1308                                                                                   NULL,        // DON'T search linked list for FC WWN
1309                                                                                   NULL);       // DON'T care about end of list
1310
1311                                                if (pLoggedInPort) {
1312                                                        // Just in case we got this BAD_ALPA because a device
1313                                                        // quietly disappeared (can happen on non-managed hubs such 
1314                                                        // as the Vixel Rapport 1000),
1315                                                        // do an Implicit Logout.  We never expect this on a Logged
1316                                                        // in port (but do expect it on port discovery).
1317                                                        // (As a reasonable alternative, this could be changed to 
1318                                                        // simply start the implicit logout timer, giving the device
1319                                                        // several seconds to "come back".)
1320                                                        // 
1321                                                        printk(" #BAD alpa %Xh# ", fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
1322                                                        cpqfcTSImplicitLogout(cpqfcHBAdata, pLoggedInPort);
1323                                                }
1324                                        }
1325                                        // LIP(f8,x)?
1326                                        if (fcChip->Registers.FMstatus.value & 0x20000L) {
1327                                                // for debugging, copy al_pa field
1328                                                fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] = (fcChip->Registers.rcv_al_pa.value & 0xffL);
1329                                                // get the other port's al_pa
1330                                                // (one that sent LIP(F8,?) )
1331                                        }
1332                                }
1333                                // Elastic store err
1334                                if (fcChip->Registers.FMstatus.value & 0x400L) {
1335                                        // don't count e-s if loop is down!
1336                                        if (!(u16) (fcChip->Registers.FMstatus.value & 0x80))
1337                                                fcChip->fcStats.e_stores++;
1338
1339                                }
1340                        }
1341                        break;
1342
1343
1344                case INBOUND_FCP_XCHG_COMPLETION:       // 0x0C
1345
1346                        // Remarks:
1347                        // On Tachlite TL/TS, we get this message when the data phase
1348                        // of a SEST inbound transfer is complete.  For example, if a WRITE command
1349                        // was received with OX_ID 0, we might respond with XFER_RDY with
1350                        // RX_ID 8001.  This would start the SEST controlled data phases.  When
1351                        // all data frames are received, we get this inbound completion. This means
1352                        // we should send a status frame to complete the status phase of the 
1353                        // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
1354                        // frames.
1355                        // See Outbound CM discussion of x_IDs
1356                        // Psuedo Code
1357                        //   Get SEST index (x_ID)
1358                        //     x_ID out of range, return (err condition)
1359                        //   set status bits from 2nd dword
1360                        //   free transactionID & SEST entry
1361                        //   call fcComplete with transactionID & status
1362
1363                        ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
1364                        x_ID = ulBuff & 0x7fffL;        // lower 14 bits SEST_Index/Trans_ID
1365                        // (mask out MSB "direction" bit)
1366                        // Range check CM OX/RX_ID value...
1367                        if (x_ID < TACH_SEST_LEN)       // don't go beyond SEST array space
1368                        {
1369
1370//#define FCP_COMPLETION_DBG 1
1371#ifdef FCP_COMPLETION_DBG
1372                                printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n", x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
1373#endif
1374                                if (ulBuff & 0x08000000L)       // RPC -Response Phase Complete - or -
1375                                        // time to send response frame?
1376                                        RPCset = 1;     // (SEST transaction)
1377                                else
1378                                        RPCset = 0;
1379                                // set the status for this Inbound SCSI transaction's ID
1380                                dwStatus = 0L;
1381                                if (ulBuff & 0x70000000L)       // any errs?
1382                                {
1383
1384                                        if (ulBuff & 0x40000000L)
1385                                                dwStatus |= LINKFAIL_RX;
1386
1387                                        if (ulBuff & 0x20000000L)
1388                                                dwStatus |= COUNT_ERROR;
1389
1390                                        if (ulBuff & 0x10000000L)
1391                                                dwStatus |= OVERFLOW;
1392                                }
1393
1394                                // FCP transaction done - copy status
1395                                Exchanges->fcExchange[x_ID].status = dwStatus;
1396
1397
1398                                // Did the exchange get an FCP-RSP response frame?
1399                                // (Note the little endian/big endian FC payload difference)
1400
1401                                if (RPCset)     // SEST transaction Response frame rec'd
1402                                {
1403                                        // complete the command in our driver...
1404                                        cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, x_ID);
1405
1406                                }       // end "RPCset"
1407
1408                                else    // ("target" logic)
1409                                {
1410                                        // Tachlite says all data frames have been received - now it's time
1411                                        // to analyze data transfer (successful?), then send a response 
1412                                        // frame for this exchange
1413
1414                                        ulFibreFrame[0] = x_ID; // copy for later reference
1415
1416                                        // if this was a TWE, we have to send satus response
1417                                        if (Exchanges->fcExchange[x_ID].type == SCSI_TWE) {
1418//            fcPutScsiQue( cpqfcHBAdata, 
1419//                NEED_FCP_RSP, ulFibreFrame);  // (ulFibreFrame not used here)
1420                                        }
1421                                }
1422                        } else  // ERROR CONDITION!  bogus x_ID in completion message
1423                        {
1424                                printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
1425                        }
1426
1427                        break;
1428
1429
1430
1431
1432                case INBOUND_SCSI_DATA_COMMAND:
1433                case BAD_SCSI_FRAME:
1434                case INB_SCSI_STATUS_COMPLETION:
1435                case BUFFER_PROCESSED_COMPLETION:
1436                        break;
1437                }
1438
1439                // Tachyon is producing;
1440                // we are consuming
1441                fcChip->IMQ->consumerIndex++;   // increment OUR consumerIndex
1442                if (fcChip->IMQ->consumerIndex >= IMQ_LEN)      // check for rollover
1443                        fcChip->IMQ->consumerIndex = 0L;        // reset it
1444
1445
1446                if (fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex) { // all Messages are processed -
1447                        iStatus = 0;    // no more messages to process
1448
1449                } else
1450                        iStatus = 1;    // more messages to process
1451
1452                // update TachLite's ConsumerIndex... (clears INTA_L)
1453                // NOTE: according to TL/TS UG, the 
1454                // "host must return completion messages in sequential order".
1455                // Does this mean one at a time, in the order received?  We
1456                // presume so.
1457
1458                writel(fcChip->IMQ->consumerIndex, (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
1459
1460#if IMQ_DEBUG
1461                printk("Process IMQ: writing consumer ndx %d\n ", fcChip->IMQ->consumerIndex);
1462                printk("PI %X, CI %X\n", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex);
1463#endif
1464
1465
1466
1467        } else {
1468                // hmmm... why did we get interrupted/called with no message?
1469                iStatus = -1;   // nothing to process
1470#if IMQ_DEBUG
1471                printk("Process IMQ: no message PI %Xh  CI %Xh", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex);
1472#endif
1473        }
1474
1475        LEAVE("ProcessIMQEntry");
1476
1477        return iStatus;
1478}
1479
1480
1481
1482
1483
1484// This routine initializes Tachyon according to the following
1485// options (opcode1):
1486// 1 - RESTART Tachyon, simulate power on condition by shutting
1487//     down laser, resetting the hardware, de-allocating all buffers;
1488//     continue
1489// 2 - Config Tachyon / PCI registers;
1490//     continue
1491// 3 - Allocating memory and setting Tachyon queues (write Tachyon regs);
1492//     continue
1493// 4 - Config frame manager registers, initialize, turn on laser
1494//
1495// Returns:
1496//  -1 on fatal error
1497//   0 on success
1498
1499int CpqTsInitializeTachLite(void *pHBA, int opcode1, int opcode2)
1500{
1501        CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
1502        PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1503        u32 ulBuff;
1504        u8 bBuff;
1505        int iStatus = -1;       // assume failure
1506
1507        ENTER("InitializeTachLite");
1508
1509        // verify board's base address (sanity check)
1510
1511        if (!fcChip->Registers.ReMapMemBase)    // NULL address for card?
1512                return -1;      // FATAL error!
1513
1514
1515
1516        switch (opcode1) {
1517        case 1:         // restore hardware to power-on (hard) restart
1518
1519
1520                iStatus = fcChip->ResetTachyon(cpqfcHBAdata, opcode2);  // laser off, reset hardware
1521                // de-allocate aligned buffers
1522
1523
1524/* TBD      // reset FC link Q (producer and consumer = 0)
1525      fcLinkQReset(cpqfcHBAdata); 
1526
1527*/
1528
1529                if (iStatus)
1530                        break;
1531
1532        case 2:         // Config PCI/Tachyon registers
1533                // NOTE: For Tach TL/TS, bit 31 must be set to 1.  For TS chips, a read
1534                // of bit 31 indicates state of M66EN signal; if 1, chip may run at 
1535                // 33-66MHz  (see TL/TS UG, pg 159)
1536
1537                ulBuff = 0x80000000;    // TachLite Configuration Register
1538
1539                writel(ulBuff, fcChip->Registers.TYconfig.address);
1540//      ulBuff = 0x0147L;  // CpqTs PCI CFGCMD register
1541//      WritePCIConfiguration( fcChip->Backplane.bus,
1542//                           fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4);
1543//      ulBuff = 0x0L;  // test!
1544//      ReadPCIConfiguration( fcChip->Backplane.bus,
1545//                           fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4);
1546
1547                // read back for reference...
1548                fcChip->Registers.TYconfig.value = readl(fcChip->Registers.TYconfig.address);
1549
1550                // what is the PCI bus width?
1551                pci_read_config_byte(cpqfcHBAdata->PciDev, 0x43,        // PCIMCTR offset
1552                                     &bBuff);
1553
1554                fcChip->Registers.PCIMCTR = bBuff;
1555
1556                // set string identifying the chip on the circuit board
1557
1558                fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
1559
1560                {
1561// Now that we are supporting multiple boards, we need to change
1562// this logic to check for PCI vendor/device IDs...
1563// for now, quick & dirty is simply checking Chip rev
1564
1565                        u32 RevId = (fcChip->Registers.TYstatus.value & 0x3E0) >> 5;
1566                        u8 Minor = (u8) (RevId & 0x3);
1567                        u8 Major = (u8) ((RevId & 0x1C) >> 2);
1568
1569                        printk("  HBA Tachyon RevId %d.%d\n", Major, Minor);
1570                        if ((Major == 1) && (Minor == 2)) {
1571                                sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
1572
1573                        } else if ((Major == 1) && (Minor == 3)) {
1574                                sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
1575                        } else if ((Major == 2) && (Minor == 1)) {
1576                                sprintf(cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
1577                        } else
1578                                sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
1579                }
1580
1581
1582
1583        case 3:         // allocate mem, set Tachyon Que registers
1584                iStatus = CpqTsCreateTachLiteQues(cpqfcHBAdata, opcode2);
1585
1586                if (iStatus)
1587                        break;
1588
1589                // now that the Queues exist, Tach can DMA to them, so
1590                // we can begin processing INTs
1591                // INTEN register - enable INT (TachLite interrupt)
1592                writeb(0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
1593
1594                // Fall through
1595        case 4:         // Config Fame Manager, Init Loop Command, laser on
1596
1597                // L_PORT or loopback
1598                // depending on Options
1599                iStatus = CpqTsInitializeFrameManager(fcChip, 0);
1600                if (iStatus) {
1601                        // failed to initialize Frame Manager
1602                        break;
1603                }
1604
1605        default:
1606                break;
1607        }
1608        LEAVE("InitializeTachLite");
1609
1610        return iStatus;
1611}
1612
1613
1614
1615
1616// Depending on the type of platform memory allocation (e.g. dynamic),
1617// it's probably best to free memory in opposite order as it was allocated.
1618// Order of allocation: see other function
1619
1620
1621int CpqTsDestroyTachLiteQues(void *pHBA, int opcode)
1622{
1623        CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
1624        PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1625        u16 i, iStatus = 0;
1626        void *vPtr;             // mem Align manager sets this to the freed address on success
1627        unsigned long ulPtr;    // for 64-bit pointer cast (e.g. Alpa machine)
1628        FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1629        PSGPAGES j, next;
1630
1631        ENTER("DestroyTachLiteQues");
1632
1633        if (fcChip->SEST) {
1634                // search out and free Pool for Extended S/G list pages
1635
1636                for (i = 0; i < TACH_SEST_LEN; i++)     // for each exchange
1637                {
1638                        // It's possible that extended S/G pages were allocated, mapped, and
1639                        // not cleared due to error conditions or O/S driver termination.
1640                        // Make sure they're all gone.
1641                        if (Exchanges->fcExchange[i].Cmnd != NULL)
1642                                cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd, fcChip, i);        // undo DMA mappings.
1643
1644                        for (j = fcChip->SEST->sgPages[i]; j != NULL; j = next) {
1645                                next = j->next;
1646                                kfree(j);
1647                        }
1648                        fcChip->SEST->sgPages[i] = NULL;
1649                }
1650                ulPtr = (unsigned long) fcChip->SEST;
1651                vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);      // 'free' mem
1652                fcChip->SEST = 0L;      // null invalid ptr
1653                if (!vPtr) {
1654                        printk("SEST mem not freed\n");
1655                        iStatus = -1;
1656                }
1657        }
1658
1659        if (fcChip->SFQ) {
1660
1661                ulPtr = (unsigned long) fcChip->SFQ;
1662                vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);      // 'free' mem
1663                fcChip->SFQ = 0L;       // null invalid ptr
1664                if (!vPtr) {
1665                        printk("SFQ mem not freed\n");
1666                        iStatus = -2;
1667                }
1668        }
1669
1670
1671        if (fcChip->IMQ) {
1672                // clear Indexes to show empty Queue
1673                fcChip->IMQ->producerIndex = 0;
1674                fcChip->IMQ->consumerIndex = 0;
1675
1676                ulPtr = (unsigned long) fcChip->IMQ;
1677                vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);      // 'free' mem
1678                fcChip->IMQ = 0L;       // null invalid ptr
1679                if (!vPtr) {
1680                        printk("IMQ mem not freed\n");
1681                        iStatus = -3;
1682                }
1683        }
1684
1685        if (fcChip->ERQ)        // release memory blocks used by the queues
1686        {
1687                ulPtr = (unsigned long) fcChip->ERQ;
1688                vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);      // 'free' mem
1689                fcChip->ERQ = 0L;       // null invalid ptr
1690                if (!vPtr) {
1691                        printk("ERQ mem not freed\n");
1692                        iStatus = -4;
1693                }
1694        }
1695        // free up the primary EXCHANGES struct and Link Q
1696        cpqfc_free_dma_consistent(cpqfcHBAdata);
1697
1698        LEAVE("DestroyTachLiteQues");
1699
1700        return iStatus;         // non-zero (failed) if any memory not freed
1701}
1702
1703
1704
1705
1706
1707// The SFQ is an array with SFQ_LEN length, each element (QEntry)
1708// with eight 32-bit words.  TachLite places incoming FC frames (i.e.
1709// a valid FC frame with our AL_PA ) in contiguous SFQ entries
1710// and sends a completion message telling the host where the frame is
1711// in the que.
1712// This function copies the current (or oldest not-yet-processed) QEntry to
1713// a caller's contiguous buffer and updates the Tachyon chip's consumer index
1714//
1715// NOTE:
1716//   An FC frame may consume one or many SFQ entries.  We know the total
1717//   length from the completion message.  The caller passes a buffer large
1718//   enough for the complete message (max 2k).
1719
1720static void CpqTsGetSFQEntry(PTACHYON fcChip, u16 producerNdx, u32 * ulDestPtr, // contiguous destination buffer
1721                             u8 UpdateChip)
1722{
1723        u32 total_bytes = 0;
1724        u32 consumerIndex = fcChip->SFQ->consumerIndex;
1725
1726        // check passed copy of SFQ producer index -
1727        // is a new message waiting for us?
1728        // equal indexes means SFS is copied
1729
1730        while (producerNdx != consumerIndex) {  // need to process message
1731                total_bytes += 64;      // maintain count to prevent writing past buffer
1732                // don't allow copies over Fibre Channel defined length!
1733                if (total_bytes <= 2048) {
1734                        memcpy(ulDestPtr, &fcChip->SFQ->QEntry[consumerIndex], 64);     // each SFQ entry is 64 bytes
1735                        ulDestPtr += 16;        // advance pointer to next 64 byte block
1736                }
1737                // Tachyon is producing,
1738                // and we are consuming
1739
1740                if (++consumerIndex >= SFQ_LEN) // check for rollover
1741                        consumerIndex = 0L;     // reset it
1742        }
1743
1744        // if specified, update the Tachlite chip ConsumerIndex...
1745        if (UpdateChip) {
1746                fcChip->SFQ->consumerIndex = consumerIndex;
1747                writel(fcChip->SFQ->consumerIndex, fcChip->Registers.SFQconsumerIndex.address);
1748        }
1749}
1750
1751
1752
1753// TachLite routinely freezes it's core ques - Outbound FIFO, Inbound FIFO,
1754// and Exchange Request Queue (ERQ) on error recover - 
1755// (e.g. whenever a LIP occurs).  Here
1756// we routinely RESUME by clearing these bits, but only if the loop is up
1757// to avoid ERROR IDLE messages forever.
1758
1759void CpqTsUnFreezeTachlite(void *pChip, int type)
1760{
1761        PTACHYON fcChip = (PTACHYON) pChip;
1762        fcChip->Registers.TYcontrol.value = readl(fcChip->Registers.TYcontrol.address);
1763
1764        // (bit 4 of value is GBIC LASER)
1765        // if we 'unfreeze' the core machines before the loop is healthy
1766        // (i.e. FLT, OS, LS failure bits set in FMstatus)
1767        // we can get 'error idle' messages forever.  Verify that
1768        // FMstatus (Link Status) is OK before unfreezing.
1769
1770        if (!(fcChip->Registers.FMstatus.value & 0x07000000L) &&        // bits clear?
1771            !(fcChip->Registers.FMstatus.value & 0x80)) // Active LPSM?
1772        {
1773                fcChip->Registers.TYcontrol.value &= ~0x300L;   // clear FEQ, FFA
1774                if (type == 1)  // unfreeze ERQ only
1775                {
1776//      printk("Unfreezing ERQ\n");
1777                        fcChip->Registers.TYcontrol.value |= 0x10000L;  // set REQ
1778                } else          // unfreeze both ERQ and FCP-ASSIST (SEST)
1779                {
1780//      printk("Unfreezing ERQ & FCP-ASSIST\n");
1781
1782                        // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
1783                        fcChip->Registers.TYcontrol.value |= 0x70000L;  // set ROF, RIF, REQ
1784                }
1785
1786                writel(fcChip->Registers.TYcontrol.value, fcChip->Registers.TYcontrol.address);
1787
1788        }
1789        // readback for verify (TachLite still frozen?)
1790        fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
1791}
1792
1793
1794// Whenever an FC Exchange Abort is required, we must manipulate the
1795// Host/Tachyon shared memory SEST table.  Before doing this, we
1796// must freeze Tachyon, which flushes certain buffers and ensure we
1797// can manipulate the SEST without contention.
1798// This freeze function will result in FCP & ERQ FROZEN completion
1799// messages (per argument "type").
1800
1801void CpqTsFreezeTachlite(void *pChip, int type)
1802{
1803        PTACHYON fcChip = (PTACHYON) pChip;
1804        fcChip->Registers.TYcontrol.value = readl(fcChip->Registers.TYcontrol.address);
1805
1806        //set FFA, FEQ - freezes SCSI assist and ERQ
1807        if (type == 1)          // freeze ERQ only
1808                fcChip->Registers.TYcontrol.value |= 0x100L;    // (bit 4 is laser)
1809        else                    // freeze both FCP assists (SEST) and ERQ
1810                fcChip->Registers.TYcontrol.value |= 0x300L;    // (bit 4 is laser)
1811
1812        writel(fcChip->Registers.TYcontrol.value, fcChip->Registers.TYcontrol.address);
1813
1814}
1815
1816
1817
1818
1819// TL has two Frame Manager Link Status Registers, with three 8-bit
1820// fields each. These eight bit counters are cleared after each read,
1821// so we define six 32-bit accumulators for these TL counters. This
1822// function breaks out each 8-bit field and adds the value to the existing
1823// sum.  (s/w counters cleared independently)
1824
1825void fcParseLinkStatusCounters(PTACHYON fcChip)
1826{
1827        u8 bBuff;
1828        u32 ulBuff;
1829
1830
1831// The BB0 timer usually increments when TL is initialized, resulting
1832// in an initially bogus count.  If our own counter is ZERO, it means we
1833// are reading this thing for the first time, so we ignore the first count.
1834// Also, reading the register does not clear it, so we have to keep an
1835// additional static counter to detect rollover (yuk).
1836
1837        if (fcChip->fcStats.lastBB0timer == 0L) // TL was reset? (ignore 1st values)
1838        {
1839                // get TL's register counter - the "last" count
1840                fcChip->fcStats.lastBB0timer = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
1841        } else                  // subsequent pass - check for rollover
1842        {
1843                // "this" count
1844                ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
1845                if (fcChip->fcStats.lastBB0timer > ulBuff)      // rollover happened
1846                {
1847                        // counter advanced to max...
1848                        fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
1849                        fcChip->fcStats.BB0_Timer += ulBuff;    // plus some more
1850
1851
1852                } else          // no rollover -- more counts or no change
1853                {
1854                        fcChip->fcStats.BB0_Timer += (ulBuff - fcChip->fcStats.lastBB0timer);
1855
1856                }
1857
1858                fcChip->fcStats.lastBB0timer = ulBuff;
1859        }
1860
1861
1862
1863        bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 24);
1864        fcChip->fcStats.LossofSignal += bBuff;
1865
1866        bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 16);
1867        fcChip->fcStats.BadRXChar += bBuff;
1868
1869        bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 8);
1870        fcChip->fcStats.LossofSync += bBuff;
1871
1872
1873        bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 24);
1874        fcChip->fcStats.Rx_EOFa += bBuff;
1875
1876        bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 16);
1877        fcChip->fcStats.Dis_Frm += bBuff;
1878
1879        bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 8);
1880        fcChip->fcStats.Bad_CRC += bBuff;
1881}
1882
1883
1884void cpqfcTSClearLinkStatusCounters(PTACHYON fcChip)
1885{
1886        ENTER("ClearLinkStatusCounters");
1887        memset(&fcChip->fcStats, 0, sizeof(FCSTATS));
1888        LEAVE("ClearLinkStatusCounters");
1889
1890}
1891
1892
1893
1894
1895// The following function reads the I2C hardware to get the adapter's
1896// World Wide Name (WWN).
1897// If the WWN is "500805f1fadb43e8" (as printed on the card), the
1898// Tachyon WWN_hi (32-bit) register is 500805f1, and WWN_lo register
1899// is fadb43e8.
1900// In the NVRAM, the bytes appear as:
1901// [2d] ..
1902// [2e] .. 
1903// [2f] 50
1904// [30] 08
1905// [31] 05
1906// [32] f1
1907// [33] fa
1908// [34] db
1909// [35] 43
1910// [36] e8
1911//
1912// In the Fibre Channel (Big Endian) format, the FC-AL LISM frame will
1913// be correctly loaded by Tachyon silicon.  In the login payload, bytes
1914// must be correctly swapped for Big Endian format.
1915
1916int CpqTsReadWriteWWN(void * pChip, int Read)
1917{
1918        PTACHYON fcChip = (PTACHYON) pChip;
1919#define NVRAM_SIZE 512
1920        unsigned short i, count = NVRAM_SIZE;
1921        u8 nvRam[NVRAM_SIZE], WWNbuf[8];
1922        u32 ulBuff;
1923        int iStatus = -1;       // assume failure
1924        int WWNoffset;
1925
1926        ENTER("ReadWriteWWN");
1927        // Now try to read the WWN from the adapter's NVRAM
1928
1929        if (Read)               // READing NVRAM WWN?
1930        {
1931                ulBuff = cpqfcTS_ReadNVRAM(fcChip->Registers.TYstatus.address, fcChip->Registers.TYcontrol.address, count, &nvRam[0]);
1932
1933                if (ulBuff)     // NVRAM read successful?
1934                {
1935                        iStatus = 0;    // success!
1936
1937                        // for engineering/ prototype boards, the data may be
1938                        // invalid (GIGO, usually all "FF"); this prevents the
1939                        // parse routine from working correctly, which means
1940                        // nothing will be written to our passed buffer.
1941
1942                        WWNoffset = cpqfcTS_GetNVRAM_data(WWNbuf, nvRam);
1943
1944                        if (!WWNoffset) // uninitialized NVRAM -- copy bytes directly
1945                        {
1946                                printk("CAUTION: Copying NVRAM data on fcChip\n");
1947                                for (i = 0; i < 8; i++)
1948                                        WWNbuf[i] = nvRam[i + 0x2f];    // dangerous! some formats won't work
1949                        }
1950
1951                        fcChip->Registers.wwn_hi = 0L;
1952                        fcChip->Registers.wwn_lo = 0L;
1953                        for (i = 0; i < 4; i++) // WWN bytes are big endian in NVRAM
1954                        {
1955                                ulBuff = 0L;
1956                                ulBuff = (u32) (WWNbuf[i]) << (8 * (3 - i));
1957                                fcChip->Registers.wwn_hi |= ulBuff;
1958                        }
1959                        for (i = 0; i < 4; i++) // WWN bytes are big endian in NVRAM
1960                        {
1961                                ulBuff = 0L;
1962                                ulBuff = (u32) (WWNbuf[i + 4]) << (8 * (3 - i));
1963                                fcChip->Registers.wwn_lo |= ulBuff;
1964                        }
1965                }               // done reading
1966                else {
1967
1968                        printk("cpqfcTS: NVRAM read failed\n");
1969
1970                }
1971        }
1972
1973        else                    // WRITE
1974        {
1975
1976                // NOTE: WRITE not supported & not used in released driver.
1977
1978
1979                printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
1980        }
1981
1982        LEAVE("ReadWriteWWN");
1983        return iStatus;
1984}
1985
1986
1987
1988
1989
1990// The following function reads or writes the entire "NVRAM" contents of 
1991// the I2C hardware (i.e. the NM24C03).  Note that HP's 5121A (TS 66Mhz)
1992// adapter does not use the NM24C03 chip, so this function only works on
1993// Compaq's adapters.
1994
1995int CpqTsReadWriteNVRAM(void * pChip, void * buf, int Read)
1996{
1997        PTACHYON fcChip = (PTACHYON) pChip;
1998#define NVRAM_SIZE 512
1999        u32 ulBuff;
2000        u8 *ucPtr = buf;        // cast caller's void ptr to u8 array
2001        int iStatus = -1;       // assume failure
2002
2003
2004        if (Read)               // READing NVRAM?
2005        {
2006                ulBuff = cpqfcTS_ReadNVRAM(     // TRUE on success
2007                                                  fcChip->Registers.TYstatus.address, fcChip->Registers.TYcontrol.address, 256, // bytes to write
2008                                                  ucPtr);       // source ptr
2009
2010
2011                if (ulBuff)
2012                        iStatus = 0;    // success
2013                else {
2014#ifdef DBG
2015                        printk("CAUTION: NVRAM read failed\n");
2016#endif
2017                }
2018        }                       // done reading
2019
2020        else                    // WRITING NVRAM 
2021        {
2022
2023                printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");
2024        }
2025
2026        return iStatus;
2027}
2028
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.