1 /* Copyright 2000, Compaq Computer Corporation
2 * Fibre Channel Host Bus Adapter
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
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
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
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
27 "HP HPFC-5100/5166 Tachyon TL/TS ICs User Guide", August 16, 1999, 1st Ed.
28 Hewlitt Packard Manual Part Number 5968-1083E.
31 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
33 #include <linux/blkdev.h>
34 #include <linux/kernel.h>
35 #include <linux/string.h>
36 #include <linux/ioport.h> // request_region() prototype
37 #include <linux/sched.h>
38 #include <linux/slab.h> // need "kfree" for ext. S/G pages
39 #include <linux/types.h>
40 #include <linux/pci.h>
41 #include <linux/delay.h>
42 #include <linux/unistd.h>
43 #include <asm/io.h> // struct pt_regs for IRQ handler & Port I/O
45 #include <linux/spinlock.h>
48 #include <scsi/scsi_host.h> // Scsi_Host definition for INT handler
49 #include "cpqfcTSchip.h"
50 #include "cpqfcTSstructs.h"
54 static void fcParseLinkStatusCounters(TACHYON * fcChip);
55 static void CpqTsGetSFQEntry(TACHYON * fcChip,
56 USHORT pi, ULONG * buffr, BOOLEAN UpdateChip);
59 cpqfc_free_dma_consistent(CPQFCHBA *cpqfcHBAdata)
61 // free up the primary EXCHANGES struct and Link Q
62 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
64 if (fcChip->Exchanges != NULL)
65 pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES),
66 fcChip->Exchanges, fcChip->exch_dma_handle);
67 fcChip->Exchanges = NULL;
68 if (cpqfcHBAdata->fcLQ != NULL)
69 pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE),
70 cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle);
71 cpqfcHBAdata->fcLQ = NULL;
74 // Note special requirements for Q alignment! (TL/TS UG pg. 190)
75 // We place critical index pointers at end of QUE elements to assist
76 // in non-symbolic (i.e. memory dump) debugging
77 // opcode defines placement of Queues (e.g. local/external RAM)
79 int CpqTsCreateTachLiteQues( void* pHBA, int opcode)
81 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
82 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
86 dma_addr_t ERQdma, IMQdma, SPQdma, SESTdma;
89 // NOTE! fcMemManager() will return system virtual addresses.
90 // System (kernel) virtual addresses, though non-paged, still
91 // aren't physical addresses. Convert to PHYSICAL_ADDRESS for Tachyon's
93 ENTER("CreateTachLiteQues");
96 // Allocate primary EXCHANGES array...
97 fcChip->Exchanges = NULL;
98 cpqfcHBAdata->fcLQ = NULL;
100 /* printk("Allocating %u for %u Exchanges ",
101 (ULONG)sizeof(FC_EXCHANGES), TACH_MAX_XID); */
102 fcChip->Exchanges = pci_alloc_consistent(cpqfcHBAdata->PciDev,
103 sizeof(FC_EXCHANGES), &fcChip->exch_dma_handle);
104 /* printk("@ %p\n", fcChip->Exchanges); */
106 if( fcChip->Exchanges == NULL ) // fatal error!!
108 printk("pci_alloc_consistent failure on Exchanges: fatal error\n");
111 // zero out the entire EXCHANGE space
112 memset( fcChip->Exchanges, 0, sizeof( FC_EXCHANGES));
115 /* printk("Allocating %u for LinkQ ", (ULONG)sizeof(FC_LINK_QUE)); */
116 cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev,
117 sizeof( FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle);
118 /* printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH); */
120 if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!!
122 cpqfc_free_dma_consistent(cpqfcHBAdata);
123 printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
126 // zero out the entire EXCHANGE space
127 memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));
129 // Verify that basic Tach I/O registers are not NULL
130 if( !fcChip->Registers.ReMapMemBase )
132 cpqfc_free_dma_consistent(cpqfcHBAdata);
133 printk("HBA base address NULL: fatal error\n");
138 // Initialize the fcMemManager memory pairs (stores allocated/aligned
139 // pairs for future freeing)
140 memset( cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
143 // Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
145 fcChip->ERQ = fcMemManager( cpqfcHBAdata->PciDev,
146 &cpqfcHBAdata->dynamic_mem[0],
147 sizeof( TachLiteERQ ), 32*(ERQ_LEN), 0L, &ERQdma);
150 cpqfc_free_dma_consistent(cpqfcHBAdata);
151 printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
154 fcChip->ERQ->length = ERQ_LEN-1;
155 ulAddr = (ULONG) ERQdma;
156 #if BITS_PER_LONG > 32
159 cpqfc_free_dma_consistent(cpqfcHBAdata);
160 printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n",
165 fcChip->ERQ->base = (ULONG)ulAddr; // copy for quick reference
168 // Allocate Tach's Inbound Message Queue (32 bytes per entry)
170 fcChip->IMQ = fcMemManager( cpqfcHBAdata->PciDev,
171 &cpqfcHBAdata->dynamic_mem[0],
172 sizeof( TachyonIMQ ), 32*(IMQ_LEN), 0L, &IMQdma );
175 cpqfc_free_dma_consistent(cpqfcHBAdata);
176 printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
179 fcChip->IMQ->length = IMQ_LEN-1;
182 #if BITS_PER_LONG > 32
185 cpqfc_free_dma_consistent(cpqfcHBAdata);
186 printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
191 fcChip->IMQ->base = (ULONG)ulAddr; // copy for quick reference
194 // Allocate Tach's Single Frame Queue (64 bytes per entry)
195 fcChip->SFQ = fcMemManager( cpqfcHBAdata->PciDev,
196 &cpqfcHBAdata->dynamic_mem[0],
197 sizeof( TachLiteSFQ ), 64*(SFQ_LEN),0L, &SPQdma );
200 cpqfc_free_dma_consistent(cpqfcHBAdata);
201 printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
204 fcChip->SFQ->length = SFQ_LEN-1; // i.e. Que length [# entries -
205 // min. 32; max. 4096 (0xffff)]
208 #if BITS_PER_LONG > 32
211 cpqfc_free_dma_consistent(cpqfcHBAdata);
212 printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
217 fcChip->SFQ->base = (ULONG)ulAddr; // copy for quick reference
220 // Allocate SCSI Exchange State Table; aligned nearest @sizeof
221 // power-of-2 boundary
222 // LIVE DANGEROUSLY! Assume the boundary for SEST mem will
223 // be on physical page (e.g. 4k) boundary.
224 /* printk("Allocating %u for TachSEST for %u Exchanges\n",
225 (ULONG)sizeof(TachSEST), TACH_SEST_LEN); */
226 fcChip->SEST = fcMemManager( cpqfcHBAdata->PciDev,
227 &cpqfcHBAdata->dynamic_mem[0],
228 sizeof(TachSEST), 4, 0L, &SESTdma );
229 // sizeof(TachSEST), 64*TACH_SEST_LEN, 0L );
232 cpqfc_free_dma_consistent(cpqfcHBAdata);
233 printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
237 for( i=0; i < TACH_SEST_LEN; i++) // for each exchange
238 fcChip->SEST->sgPages[i] = NULL;
240 fcChip->SEST->length = TACH_SEST_LEN; // e.g. DON'T subtract one
241 // (TL/TS UG, pg 153)
244 #if BITS_PER_LONG > 32
247 cpqfc_free_dma_consistent(cpqfcHBAdata);
248 printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
253 fcChip->SEST->base = (ULONG)ulAddr; // copy for quick reference
256 // Now that structures are defined,
257 // fill in Tachyon chip registers...
259 // EEEEEEEE EXCHANGE REQUEST QUEUE
261 writel( fcChip->ERQ->base,
262 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
264 writel( fcChip->ERQ->length,
265 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
268 fcChip->ERQ->producerIndex = 0L;
269 writel( fcChip->ERQ->producerIndex,
270 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
273 // NOTE! write consumer index last, since the write
274 // causes Tachyon to process the other registers
276 ulAddr = ((unsigned long)&fcChip->ERQ->consumerIndex -
277 (unsigned long)fcChip->ERQ) + (unsigned long) ERQdma;
279 // NOTE! Tachyon DMAs to the ERQ consumer Index host
280 // address; must be correctly aligned
281 writel( (ULONG)ulAddr,
282 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
286 // IIIIIIIIIIIII INBOUND MESSAGE QUEUE
287 // Tell Tachyon where the Que starts
289 // set the Host's pointer for Tachyon to access
291 /* printk(" cpqfcTS: writing IMQ BASE %Xh ", fcChip->IMQ->base ); */
292 writel( fcChip->IMQ->base,
293 (fcChip->Registers.ReMapMemBase + IMQ_BASE));
295 writel( fcChip->IMQ->length,
296 (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
298 writel( fcChip->IMQ->consumerIndex,
299 (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
302 // NOTE: TachLite DMAs to the producerIndex host address
303 // must be correctly aligned with address bits 1-0 cleared
304 // Writing the BASE register clears the PI register, so write it last
305 ulAddr = ((unsigned long)&fcChip->IMQ->producerIndex -
306 (unsigned long)fcChip->IMQ) + (unsigned long) IMQdma;
308 #if BITS_PER_LONG > 32
311 cpqfc_free_dma_consistent(cpqfcHBAdata);
312 printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
318 printk(" PI %Xh\n", (ULONG)ulAddr );
320 writel( (ULONG)ulAddr,
321 (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
325 // SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
326 // Tell TachLite where the Que starts
328 writel( fcChip->SFQ->base,
329 (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
331 writel( fcChip->SFQ->length,
332 (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
335 // tell TachLite where SEST table is & how long
336 writel( fcChip->SEST->base,
337 (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
339 /* printk(" cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n",
340 fcChip->SEST, fcChip->SEST->base,
341 fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE); */
343 writel( fcChip->SEST->length,
344 (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
346 writel( (TL_EXT_SG_PAGE_COUNT-1),
347 (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
350 LEAVE("CreateTachLiteQues");
357 // function to return TachLite to Power On state
358 // 1st - reset tachyon ('SOFT' reset)
361 int CpqTsResetTachLite(void *pHBA, int type)
363 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
364 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
366 int ret_status=0; // def. success
375 // in case he was running previously, mask Tach's interrupt
376 writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
378 // de-allocate mem for any Logged in ports
379 // (e.g., our module is unloading)
380 // search the forward linked list, de-allocating
381 // the memory we allocated when the port was initially logged in
383 PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
384 PFC_LOGGEDIN_PORT ptr;
385 // printk("checking for allocated LoggedInPorts...\n");
387 while( pLoggedInPort )
390 pLoggedInPort = ptr->pNextPort;
391 // printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
392 // ptr, ptr->port_id);
396 // (continue resetting hardware...)
398 case 1: // RESTART Tachyon (power-up state)
400 // in case he was running previously, mask Tach's interrupt
401 writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
402 // turn OFF laser (NOTE: laser is turned
403 // off during reset, because GPIO4 is cleared
404 // to 0 by reset action - see TLUM, sec 7.22)
405 // However, CPQ 64-bit HBAs have a "health
406 // circuit" which keeps laser ON for a brief
407 // period after it is turned off ( < 1s)
409 fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 0);
413 // soft reset timing constraints require:
415 // 2. read SOFTRST register
416 // (128 times per R. Callison code)
420 (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
422 for( i=0; i<128; i++)
423 ulBuff = readl( fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
425 // clear the soft reset
427 writel( 0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
431 // clear out our copy of Tach regs,
432 // because they must be invalid now,
433 // since TachLite reset all his regs.
434 CpqTsDestroyTachLiteQues(cpqfcHBAdata,0); // remove Host-based Que structs
435 cpqfcTSClearLinkStatusCounters(fcChip); // clear our s/w accumulators
436 // lower bits give GBIC info
437 fcChip->Registers.TYstatus.value =
438 readl( fcChip->Registers.TYstatus.address );
442 case 2: // freeze SCSI
443 case 3: // reset Outbound command que (ERQ)
444 case 4: // unfreeze OSM (Outbound Seq. Man.) 'er'
445 case 5: // report status
450 ret_status = -1; // invalid option passed to RESET function
462 // 'addrBase' is IOBaseU for both TachLite and (older) Tachyon
463 int CpqTsLaserControl( void* addrBase, int opcode )
467 dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL) ); // read TL Control reg
468 // (change only bit 4)
470 dwBuff |= ~0xffffffefL; // set - ON
472 dwBuff &= 0xffffffefL; // clear - OFF
473 writel( dwBuff, (addrBase + TL_MEM_TACH_CONTROL)); // write TL Control reg
481 // Use controller's "Options" field to determine loopback mode (if any)
482 // internal loopback (silicon - no GBIC)
483 // external loopback (GBIC - no FC loop)
484 // no loopback: L_PORT, external cable from GBIC required
486 int CpqTsInitializeFrameManager( void *pChip, int opcode)
490 ULONG wwnLo, wwnHi; // for readback verification
492 ENTER("InitializeFrameManager");
493 fcChip = (PTACHYON)pChip;
494 if( !fcChip->Registers.ReMapMemBase ) // undefined controller?
498 // 0x0065 = 100ms for RT_TOV
499 // 0x01f5 = 500ms for ED_TOV
501 fcChip->Registers.ed_tov.value = 0x006507D1;
502 writel( fcChip->Registers.ed_tov.value,
503 (fcChip->Registers.ed_tov.address));
506 // Set LP_TOV to the FC-AL2 specified 2 secs.
508 writel( 0x07d00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
511 // Now try to read the WWN from the adapter's NVRAM
512 iStatus = CpqTsReadWriteWWN( fcChip, 1); // '1' for READ
514 if( iStatus ) // NVRAM read failed?
516 printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
517 // make up a WWN. If NULL or duplicated on loop, FC loop may hang!
520 fcChip->Registers.wwn_hi = (__u32)jiffies;
521 fcChip->Registers.wwn_hi |= 0x50000000L;
522 fcChip->Registers.wwn_lo = 0x44556677L;
526 writel( fcChip->Registers.wwn_hi,
527 fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
529 writel( fcChip->Registers.wwn_lo,
530 fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
533 // readback for verification:
534 wwnHi = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI );
536 wwnLo = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
537 // test for correct chip register WRITE/READ
538 DEBUG_PCI( printk(" WWN %08X%08X\n",
539 fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo ) );
541 if( wwnHi != fcChip->Registers.wwn_hi ||
542 wwnLo != fcChip->Registers.wwn_lo )
544 printk( "cpqfcTS: WorldWideName register load failed\n");
545 return -1; // FAILED!
550 // set Frame Manager Initialize command
551 fcChip->Registers.FMcontrol.value = 0x06;
553 // Note: for test/debug purposes, we may use "Hard" address,
554 // but we completely support "soft" addressing, including
555 // dynamically changing our address.
556 if( fcChip->Options.intLoopback == 1 ) // internal loopback
557 fcChip->Registers.FMconfig.value = 0x0f002080L;
558 else if( fcChip->Options.extLoopback == 1 ) // internal loopback
559 fcChip->Registers.FMconfig.value = 0x0f004080L;
561 fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
562 // fcChip->Registers.FMconfig.value = 0x01000080L; // soft address (can't pick)
563 // fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
565 // write config to FM
567 if( !fcChip->Options.intLoopback && !fcChip->Options.extLoopback )
568 // (also need LASER for real LOOP)
569 fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 1); // turn on LASER
571 writel( fcChip->Registers.FMconfig.value,
572 fcChip->Registers.FMconfig.address);
575 // issue INITIALIZE command to FM - ACTION!
576 writel( fcChip->Registers.FMcontrol.value,
577 fcChip->Registers.FMcontrol.address);
579 LEAVE("InitializeFrameManager");
588 // This "look ahead" function examines the IMQ for occurrence of
589 // "type". Returns 1 if found, 0 if not.
590 static int PeekIMQEntry( PTACHYON fcChip, ULONG type)
592 ULONG CI = fcChip->IMQ->consumerIndex;
593 ULONG PI = fcChip->IMQ->producerIndex; // snapshot of IMQ indexes
596 { // proceed with search
597 if( (++CI) >= IMQ_LEN ) CI = 0; // rollover check
603 // first, we need to find an Inbound Completion message,
604 // If we find it, check the incoming frame payload (1st word)
606 if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104 )
608 TachFCHDR_GCMND* fchs;
609 #error This is too much stack
610 ULONG ulFibreFrame[2048/4]; // max DWORDS in incoming FC Frame
611 USHORT SFQpi = (USHORT)(fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
613 CpqTsGetSFQEntry( fcChip,
614 SFQpi, // SFQ producer ndx
615 ulFibreFrame, // contiguous dest. buffer
616 FALSE); // DON'T update chip--this is a "lookahead"
618 fchs = (TachFCHDR_GCMND*)&ulFibreFrame;
619 if( fchs->pl[0] == ELS_LILP_FRAME)
621 return 1; // found the LILP frame!
631 case OUTBOUND_COMPLETION:
632 if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00 )
636 if( fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L )
637 return 1; // found OCM error
647 return 0; // failed to find "type"
651 static void SetTachTOV( CPQFCHBA* cpqfcHBAdata)
653 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
656 // 0x0065 = 100ms for RT_TOV
657 // 0x01f5 = 500ms for ED_TOV
658 // 0x07d1 = 2000ms for ED_TOV
660 // SANMark Level 1 requires an "initialization backoff"
661 // (See "SANMark Test Suite Level 1":
662 // initialization_timeout.fcal.SANMark-1.fc)
663 // We have to use 2sec, 24sec, then 128sec when login/
664 // port discovery processes fail to complete.
666 // when port discovery completes (logins done), we set
667 // ED_TOV to 500ms -- this is the normal operational case
668 // On the first Link Down, we'll move to 2 secs (7D1 ms)
669 if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x1f5)
670 fcChip->Registers.ed_tov.value = 0x006507D1;
672 // If we get another LST after we moved TOV to 2 sec,
673 // increase to 24 seconds (5DC1 ms) per SANMark!
674 else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x7D1)
675 fcChip->Registers.ed_tov.value = 0x00655DC1;
677 // If we get still another LST, set the max TOV (Tachyon
678 // has only 16 bits for ms timer, so the max is 65.5 sec)
679 else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x5DC1)
680 fcChip->Registers.ed_tov.value = 0x0065FFFF;
682 writel( fcChip->Registers.ed_tov.value,
683 (fcChip->Registers.ed_tov.address));
684 // keep the same 2sec LP_TOV
685 writel( 0x07D00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
689 // The IMQ is an array with IMQ_LEN length, each element (QEntry)
690 // with eight 32-bit words. Tachyon PRODUCES a QEntry with each
691 // message it wants to send to the host. The host CONSUMES IMQ entries
693 // This function copies the current
694 // (or oldest not-yet-processed) QEntry to
695 // the caller, clears/ re-enables the interrupt, and updates the
696 // (Host) Consumer Index.
698 // 0 message processed, none remain (producer and consumer
700 // 1 message processed, more messages remain
701 // -1 no message processed - none were available to process
703 // TL/TS UG specifices that the following actions for
705 // 1. read PCI Interrupt Status register (0xff)
706 // 2. all IMQ messages should be processed before writing the
707 // IMQ consumer index.
710 int CpqTsProcessIMQEntry(void *host)
712 struct Scsi_Host *HostAdapter = (struct Scsi_Host *)host;
713 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
714 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
715 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
717 USHORT i, RPCset, DPCset;
719 ULONG ulBuff, dwStatus;
720 TachFCHDR_GCMND* fchs;
721 #error This is too much stack
722 ULONG ulFibreFrame[2048/4]; // max number of DWORDS in incoming Fibre Frame
723 UCHAR ucInboundMessageType; // Inbound CM, dword 3 "type" field
725 ENTER("ProcessIMQEntry");
728 // check TachLite's IMQ producer index -
729 // is a new message waiting for us?
730 // equal indexes means empty que
732 if( fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex )
733 { // need to process message
737 printk("PI %X, CI %X type: %X\n",
738 fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex,
739 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
741 // Examine Completion Messages in IMQ
743 switch( (UCHAR)(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type
746 case OUTBOUND_COMPLETION:
749 // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
750 // (starting at 0), and SFS entries (starting at
751 // SEST_LEN -- outside the SEST space).
753 // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
754 // range check - x_ID
755 // if x_ID outside 'Transactions' length, error - exit
756 // if any OCM error, copy error status to Exchange slot
757 // if FCP ASSIST transaction (x_ID within SEST),
758 // call fcComplete (to App)
762 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
763 x_ID = ulBuff & 0x7fffL; // lower 14 bits SEST_Index/Trans_ID
764 // Range check CM OX/RX_ID value...
765 if( x_ID < TACH_MAX_XID ) // don't go beyond array space
769 if( ulBuff & 0x20000000L ) // RPC -Response Phase Complete?
770 RPCset = 1; // (SEST transactions only)
774 if( ulBuff & 0x40000000L ) // DPC -Data Phase Complete?
775 DPCset = 1; // (SEST transactions only)
778 // set the status for this Outbound transaction's ID
780 if( ulBuff & 0x10000000L ) // SPE? (SEST Programming Error)
781 dwStatus |= SESTPROG_ERR;
783 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
784 if( ulBuff & 0x7a000000L ) // any other errs?
786 if( ulBuff & 0x40000000L )
787 dwStatus |= INV_ENTRY;
788 if( ulBuff & 0x20000000L )
789 dwStatus |= FRAME_TO; // FTO
790 if( ulBuff & 0x10000000L )
791 dwStatus |= HOSTPROG_ERR;
792 if( ulBuff & 0x08000000L )
793 dwStatus |= LINKFAIL_TX;
794 if( ulBuff & 0x02000000L )
795 dwStatus |= ABORTSEQ_NOTIFY; // ASN
799 if( dwStatus ) // any errors?
801 // set the Outbound Completion status
802 Exchanges->fcExchange[ x_ID ].status |= dwStatus;
804 // if this Outbound frame was for a SEST entry, automatically
805 // reque it in the case of LINKFAIL (it will restart on PDISC)
806 if( x_ID < TACH_SEST_LEN )
809 printk(" #OCM error %Xh x_ID %X# ",
812 Exchanges->fcExchange[x_ID].timeOut = 30000; // seconds default
815 // We Q ABTS for each exchange.
816 // NOTE: We can get FRAME_TO on bad alpa (device gone). Since
817 // bad alpa is reported before FRAME_TO, examine the status
818 // flags to see if the device is removed. If so, DON'T
819 // post an ABTS, since it will be terminated by the bad alpa
821 if( dwStatus & FRAME_TO ) // check for device removed...
823 if( !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) )
825 // presumes device is still there: send ABTS.
827 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
830 else // Abort all other errors
832 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
835 // if the HPE bit is set, we have to CLose the LOOP
836 // (see TL/TS UG, pg. 239)
838 if( dwStatus &= HOSTPROG_ERR )
839 // set CL bit (see TL/TS UG, pg. 172)
840 writel( 4, fcChip->Registers.FMcontrol.address);
843 // NOTE: we don't necessarily care about ALL completion messages...
844 // SCSI resp. complete OR
845 if( ((x_ID < TACH_SEST_LEN) && RPCset)||
846 (x_ID >= TACH_SEST_LEN) ) // non-SCSI command
848 // exchange done; complete to upper levels with status
849 // (if necessary) and free the exchange slot
852 if( x_ID >= TACH_SEST_LEN ) // Link Service Outbound frame?
853 // A Request or Reply has been sent
854 { // signal waiting WorkerThread
856 up( cpqfcHBAdata->TYOBcomplete); // frame is OUT of Tach
858 // WorkerThread will complete Xchng
860 else // X_ID is for FCP assist (SEST)
863 // fcCompleteExchange( fcChip, x_ID); // TRE completed
867 else // ERROR CONDITION! bogus x_ID in completion message
870 printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
876 // Load the Frame Manager's error counters. We check them here
877 // because presumably the link is up and healthy enough for the
878 // counters to be meaningful (i.e., don't check them while loop
880 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
881 readl(fcChip->Registers.FMLinkStatus1.address);
883 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
884 readl(fcChip->Registers.FMLinkStatus2.address);
887 fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
892 case ERROR_IDLE_COMPLETION: // TachLite Error Idle...
894 // We usually get this when the link goes down during heavy traffic.
895 // For now, presume that if SEST Exchanges are open, we will
896 // get this as our cue to INVALIDATE all SEST entries
897 // (and we OWN all the SEST entries).
898 // See TL/TS UG, pg. 53
900 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
903 // Does this VALid SEST entry need to be invalidated for Abort?
904 fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
907 CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachyon, if Link OK
912 case INBOUND_SFS_COMPLETION: //0x04
913 // NOTE! we must process this SFQ message to avoid SFQ filling
914 // up and stopping TachLite. Incoming commands are placed here,
915 // as well as 'unknown' frames (e.g. LIP loop position data)
916 // write this CM's producer index to global...
918 // Type: 0 - reserved
919 // 1 - Unassisted FCP
925 fcChip->SFQ->producerIndex = (USHORT)
926 (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
929 ucInboundMessageType = 0; // default to useless frame
931 // we can only process two Types: 1, Unassisted FCP, and 3, Unknown
932 // Also, we aren't interested in processing frame fragments
933 // so don't Que anything with 'LKF' bit set
934 if( !(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2]
935 & 0x40000000) ) // 'LKF' link failure bit clear?
937 ucInboundMessageType = (UCHAR) // ICM DWord3, "Type"
938 (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
942 fcChip->fcStats.linkFailRX++;
943 // printk("LKF (link failure) bit set on inbound message\n");
946 // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
948 fcChip, // i.e. this Device Object
949 (USHORT)fcChip->SFQ->producerIndex, // SFQ producer ndx
950 ulFibreFrame, TRUE); // contiguous destination buffer, update chip
952 // analyze the incoming frame outside the INT handler...
955 if( ucInboundMessageType == 1 )
957 fchs = (TachFCHDR_GCMND*)ulFibreFrame; // cast to examine IB frame
958 // don't fill up our Q with garbage - only accept FCP-CMND
960 if( (fchs->d_id & 0xFF000000) == 0x06000000 ) // CMND
962 // someone sent us a SCSI command
964 // fcPutScsiQue( cpqfcHBAdata,
965 // SFQ_UNASSISTED_FCP, ulFibreFrame);
967 else if( ((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status)
968 (fchs->d_id & 0xFF000000) == 0x05000000 ) // XRDY
971 // Unfortunately, ABTS requires a Freeze on the chip so
972 // we can modify the shared memory SEST. When frozen,
973 // any received Exchange frames cannot be processed by
974 // Tachyon, so they will be dumped in here. It is too
975 // complex to attempt the reconstruct these frames in
976 // the correct Exchange context, so we simply seek to
977 // find status or transfer ready frames, and cause the
978 // exchange to complete with errors before the timeout
979 // expires. We use a Linux Scsi Cmnd result code that
980 // causes immediate retry.
983 // Do we have an open exchange that matches this s_id
985 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
987 if( (fchs->s_id & 0xFFFFFF) ==
988 (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF)
990 (fchs->ox_rx_id & 0xFFFF0000) ==
991 (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000) )
993 // printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
994 // simulate the anticipated error - since the
995 // SEST was frozen, frames were lost...
996 Exchanges->fcExchange[ x_ID ].status |= SFQ_FRAME;
998 // presumes device is still there: send ABTS.
999 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
1007 else if( ucInboundMessageType == 3)
1009 // FC Link Service frames (e.g. PLOGI, ACC) come in here.
1010 cpqfcTSPutLinkQue( cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame);
1014 else if( ucInboundMessageType == 2 ) // "bad FCP"?
1017 printk("Bad FCP incoming frame discarded\n");
1021 else // don't know this type
1024 printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
1028 // Check the Frame Manager's error counters. We check them here
1029 // because presumably the link is up and healthy enough for the
1030 // counters to be meaningful (i.e., don't check them while loop
1031 // is initializing).
1032 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
1033 readl(fcChip->Registers.FMLinkStatus1.address);
1036 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
1037 readl(fcChip->Registers.FMLinkStatus2.address);
1045 // We get this CM because we issued a freeze
1046 // command to stop outbound frames. We issue the
1047 // freeze command at Link Up time; when this message
1048 // is received, the ERQ base can be switched and PDISC
1049 // frames can be sent.
1052 case ERQ_FROZEN_COMPLETION: // note: expect ERQ followed immediately
1053 // by FCP when freezing TL
1054 fcChip->Registers.TYstatus.value = // read what's frozen
1055 readl(fcChip->Registers.TYstatus.address);
1056 // (do nothing; wait for FCP frozen message)
1058 case FCP_FROZEN_COMPLETION:
1060 fcChip->Registers.TYstatus.value = // read what's frozen
1061 readl(fcChip->Registers.TYstatus.address);
1063 // Signal the kernel thread to proceed with SEST modification
1064 up( cpqfcHBAdata->TachFrozen);
1070 case INBOUND_C1_TIMEOUT:
1079 // In older Tachyons, we 'clear' the internal 'core' interrupt state
1080 // by reading the FMstatus register. In newer TachLite (Tachyon),
1081 // we must WRITE the register
1082 // to clear the condition (TL/TS UG, pg 179)
1083 case FRAME_MGR_INTERRUPT:
1085 PFC_LOGGEDIN_PORT pLoggedInPort;
1087 fcChip->Registers.FMstatus.value =
1088 readl( fcChip->Registers.FMstatus.address );
1090 // PROBLEM: It is possible, especially with "dumb" hubs that
1091 // don't automatically LIP on by-pass of ports that are going
1092 // away, for the hub by-pass process to destroy critical
1093 // ordered sets of a frame. The result of this is a hung LPSM
1094 // (Loop Port State Machine), which on Tachyon results in a
1095 // (default 2 sec) Loop State Timeout (LST) FM message. We
1096 // want to avoid this relatively huge timeout by detecting
1097 // likely scenarios which will result in LST.
1098 // To do this, we could examine FMstatus for Loss of Synchronization
1099 // and/or Elastic Store (ES) errors. Of these, Elastic Store is better
1100 // because we get this indication more quickly than the LOS.
1101 // Not all ES errors are harmfull, so we don't want to LIP on every
1102 // ES. Instead, on every ES, detect whether our LPSM in in one
1103 // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
1104 // or RECEIVED CLOSE. (See TL/TS UG, pg. 181)
1105 // If any of these LPSM states are detected
1106 // in combination with the LIP while LDn is not set,
1107 // send an FM init (LIP F7,F7 for loops)!
1108 // It is critical to the physical link stability NOT to reset (LIP)
1109 // more than absolutely necessary; this is a basic premise of the
1110 // SANMark level 1 spec.
1112 ULONG Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >>4;
1114 if( (fcChip->Registers.FMstatus.value & 0x400) // ElasticStore?
1116 !(fcChip->Registers.FMstatus.value & 0x100) // NOT LDn
1118 !(fcChip->Registers.FMstatus.value & 0x1000)) // NOT LF
1120 if( (Lpsm != 0) || // not MONITORING? or
1121 !(Lpsm & 0x8) )// not already offline?
1123 // now check the particular LST states...
1124 if( (Lpsm == ARBITRATING) || (Lpsm == OPEN) ||
1125 (Lpsm == OPENED) || (Lpsm == XMITTD_CLOSE) ||
1126 (Lpsm == RCVD_CLOSE) )
1128 // re-init the loop before it hangs itself!
1129 printk(" #req FMinit on E-S: LPSM %Xh# ",Lpsm);
1132 fcChip->fcStats.FMinits++;
1133 writel( 6, fcChip->Registers.FMcontrol.address); // LIP
1137 else if( fcChip->Registers.FMstatus.value & 0x40000 ) // LST?
1139 printk(" #req FMinit on LST, LPSM %Xh# ",Lpsm);
1141 fcChip->fcStats.FMinits++;
1142 writel( 6, fcChip->Registers.FMcontrol.address); // LIP
1147 // clear only the 'interrupting' type bits for this REG read
1148 writel( (fcChip->Registers.FMstatus.value & 0xff3fff00L),
1149 fcChip->Registers.FMstatus.address);
1152 // copy frame manager status to unused ULONG slot
1153 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] =
1154 fcChip->Registers.FMstatus.value; // (for debugging)
1157 // Load the Frame Manager's error counters. We check them here
1158 // because presumably the link is up and healthy enough for the
1159 // counters to be meaningful (i.e., don't check them while loop
1160 // is initializing).
1161 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
1162 readl(fcChip->Registers.FMLinkStatus1.address);
1164 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
1165 readl(fcChip->Registers.FMLinkStatus2.address);
1167 // Get FM BB_Credit Zero Reg - does not clear on READ
1168 fcChip->Registers.FMBB_CreditZero.value = // get TL's counter
1169 readl(fcChip->Registers.FMBB_CreditZero.address);
1173 fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
1178 if( fcChip->Registers.FMstatus.value & 0x100L ) // Link DOWN bit
1186 fcChip->fcStats.linkDown++;
1188 SetTachTOV( cpqfcHBAdata); // must set according to SANMark
1190 // Check the ERQ - force it to be "empty" to prevent Tach
1191 // from sending out frames before we do logins.
1194 if( fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex)
1196 // printk("#ERQ PI != CI#");
1197 CpqTsFreezeTachlite( fcChip, 1); // freeze ERQ only
1198 fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
1199 writel( fcChip->ERQ->base,
1200 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
1201 // re-writing base forces ERQ PI to equal CI
1205 // link down transition occurred -- port_ids can change
1206 // on next LinkUp, so we must invalidate current logins
1207 // (and any I/O in progress) until PDISC or PLOGI/PRLI
1210 pLoggedInPort = &fcChip->fcPorts;
1211 while( pLoggedInPort ) // for all ports which are expecting
1212 // PDISC after the next LIP, set the
1216 if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
1218 pLoggedInPort->LOGO_timer = 3; // we want 2 seconds
1219 // but Timer granularity
1222 // suspend any I/O in progress until
1223 // PDISC received...
1224 pLoggedInPort->prli = FALSE; // block FCP-SCSI commands
1226 pLoggedInPort = pLoggedInPort->pNextPort;
1227 } // ... all Previously known ports checked
1230 // since any hot plugging device may NOT support LILP frames
1231 // (such as early Tachyon chips), clear this flag indicating
1232 // we shouldn't use (our copy of) a LILP map.
1233 // If we receive an LILP frame, we'll set it again.
1234 fcChip->Options.LILPin = 0; // our LILPmap is invalid
1235 cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports!
1237 // also, we want to invalidate (i.e. INITIATOR_ABORT) any
1238 // open Login exchanges, in case the LinkDown happened in the
1239 // middle of logins. It's possible that some ports already
1240 // ACCepted login commands which we have not processed before
1241 // another LinkDown occurred. Any accepted Login exhanges are
1242 // invalidated by LinkDown, even before they are acknowledged.
1243 // It's also possible for a port to have a Queued Reply or Request
1244 // for login which was interrupted by LinkDown; it may come later,
1245 // but it will be unacceptable to us.
1247 // we must scan the entire exchange space, find every Login type
1248 // originated by us, and abort it. This is NOT an abort due to
1249 // timeout, so we don't actually send abort to the other port -
1250 // we just complete it to free up the fcExchange slot.
1252 for( i=TACH_SEST_LEN; i< TACH_MAX_XID; i++)
1253 { // looking for Extended Link Serv.Exchanges
1254 if( Exchanges->fcExchange[i].type == ELS_PDISC ||
1255 Exchanges->fcExchange[i].type == ELS_PLOGI ||
1256 Exchanges->fcExchange[i].type == ELS_PRLI )
1258 // ABORT the exchange!
1260 printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n",
1261 i, Exchanges->fcExchange[i].type,
1262 Exchanges->fcExchange[i].fchs.d_id);
1265 Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
1266 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // abort on LDn
1272 // ################ LINK UP ##################
1273 if( fcChip->Registers.FMstatus.value & 0x200L ) // Link Up bit
1274 { // AL_PA could have changed
1276 // We need the following code, duplicated from LinkDn condition,
1277 // because it's possible for the Tachyon to re-initialize (hard
1278 // reset) without ever getting a LinkDn indication.
1279 pLoggedInPort = &fcChip->fcPorts;
1280 while( pLoggedInPort ) // for all ports which are expecting
1281 // PDISC after the next LIP, set the
1284 if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
1286 pLoggedInPort->LOGO_timer = 3; // we want 2 seconds
1287 // but Timer granularity
1290 // suspend any I/O in progress until
1291 // PDISC received...
1294 pLoggedInPort = pLoggedInPort->pNextPort;
1295 } // ... all Previously known ports checked
1297 // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
1298 fcChip->Registers.rcv_al_pa.value =
1299 readl(fcChip->Registers.rcv_al_pa.address);
1301 // Now, if our acquired address is DIFFERENT from our
1302 // previous one, we are not allow to do PDISC - we
1303 // must go back to PLOGI, which will terminate I/O in
1304 // progress for ALL logged in FC devices...
1305 // (This is highly unlikely).
1307 if( (fcChip->Registers.my_al_pa & 0xFF) !=
1308 ((fcChip->Registers.rcv_al_pa.value >> 16) &0xFF) )
1311 // printk(" #our HBA port_id changed!# "); // FC port_id changed!!
1313 pLoggedInPort = &fcChip->fcPorts;
1314 while( pLoggedInPort ) // for all ports which are expecting
1315 // PDISC after the next LIP, set the
1318 pLoggedInPort->pdisc = FALSE;
1319 pLoggedInPort->prli = FALSE;
1320 pLoggedInPort = pLoggedInPort->pNextPort;
1321 } // ... all Previously known ports checked
1323 // when the port_id changes, we must terminate
1324 // all open exchanges.
1325 cpqfcTSTerminateExchange( cpqfcHBAdata, NULL, PORTID_CHANGED);
1329 // Replace the entire 24-bit port_id. We only know the
1330 // lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
1331 // we'll get the upper 16-bits from the FLOGI ACC frame.
1332 // If someone plugs into Fabric switch, we'll do FLOGI and
1333 // get full 24-bit port_id; someone could then remove and
1334 // hot-plug us into a dumb hub. If we send a 24-bit PLOGI
1335 // to a "private" loop device, it might blow up.
1336 // Consequently, we force the upper 16-bits of port_id to
1337 // be re-set on every LinkUp transition
1338 fcChip->Registers.my_al_pa =
1339 (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
1342 // copy frame manager status to unused ULONG slot
1343 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
1344 fcChip->Registers.my_al_pa; // (for debugging)
1346 // for TachLite, we need to write the acquired al_pa
1347 // back into the FMconfig register, because after
1348 // first initialization, the AQ (prev. acq.) bit gets
1349 // set, causing TL FM to use the AL_PA field in FMconfig.
1350 // (In Tachyon, FM writes the acquired AL_PA for us.)
1351 ulBuff = readl( fcChip->Registers.FMconfig.address);
1352 ulBuff &= 0x00ffffffL; // mask out current al_pa
1353 ulBuff |= ( fcChip->Registers.my_al_pa << 24 ); // or in acq. al_pa
1354 fcChip->Registers.FMconfig.value = ulBuff; // copy it back
1355 writel( fcChip->Registers.FMconfig.value, // put in TachLite
1356 fcChip->Registers.FMconfig.address);
1360 printk("#LUp %Xh, FMstat 0x%08X#",
1361 fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
1364 // also set the WRITE-ONLY My_ID Register (for Fabric
1366 writel( fcChip->Registers.my_al_pa,
1367 fcChip->Registers.ReMapMemBase +TL_MEM_TACH_My_ID);
1370 fcChip->fcStats.linkUp++;
1372 // reset TL statistics counters
1373 // (we ignore these error counters
1374 // while link is down)
1375 ulBuff = // just reset TL's counter
1376 readl( fcChip->Registers.FMLinkStatus1.address);
1378 ulBuff = // just reset TL's counter
1379 readl( fcChip->Registers.FMLinkStatus2.address);
1381 // for initiator, need to start verifying ports (e.g. PDISC)
1388 CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachlite, if Link OK
1390 // Tachyon creates an interesting problem for us on LILP frames.
1391 // Instead of writing the incoming LILP frame into the SFQ before
1392 // indicating LINK UP (the actual order of events), Tachyon tells
1393 // us LINK UP, and later us the LILP. So we delay, then examine the
1394 // IMQ for an Inbound CM (x04); if found, we can set
1395 // LINKACTIVE after processing the LILP. Otherwise, just proceed.
1396 // Since Tachyon imposes this time delay (and doesn't tell us
1397 // what it is), we have to impose a delay before "Peeking" the IMQ
1398 // for Tach hardware (DMA) delivery.
1399 // Processing LILP is required by SANMark
1400 udelay( 1000); // microsec delay waiting for LILP (if it comes)
1401 if( PeekIMQEntry( fcChip, ELS_LILP_FRAME) )
1402 { // found SFQ LILP, which will post LINKACTIVE
1403 // printk("skipping LINKACTIVE post\n");
1407 cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, ulFibreFrame);
1412 // ******* Set Fabric Login indication ********
1413 if( fcChip->Registers.FMstatus.value & 0x2000 )
1415 printk(" #Fabric# ");
1416 fcChip->Options.fabric = 1;
1419 fcChip->Options.fabric = 0;
1423 // ******* LIP(F8,x) or BAD AL_PA? ********
1424 if( fcChip->Registers.FMstatus.value & 0x30000L )
1426 // copy the error AL_PAs
1427 fcChip->Registers.rcv_al_pa.value =
1428 readl(fcChip->Registers.rcv_al_pa.address);
1431 if( fcChip->Registers.FMstatus.value & 0x10000L )
1433 PFC_LOGGEDIN_PORT pLoggedInPort;
1435 // copy "BAD" al_pa field
1436 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
1437 (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
1439 pLoggedInPort = fcFindLoggedInPort( fcChip,
1440 NULL, // DON'T search Scsi Nexus
1441 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1], // port id
1442 NULL, // DON'T search linked list for FC WWN
1443 NULL); // DON'T care about end of list
1447 // Just in case we got this BAD_ALPA because a device
1448 // quietly disappeared (can happen on non-managed hubs such
1449 // as the Vixel Rapport 1000),
1450 // do an Implicit Logout. We never expect this on a Logged
1451 // in port (but do expect it on port discovery).
1452 // (As a reasonable alternative, this could be changed to
1453 // simply start the implicit logout timer, giving the device
1454 // several seconds to "come back".)
1456 printk(" #BAD alpa %Xh# ",
1457 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
1458 cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
1462 if( fcChip->Registers.FMstatus.value & 0x20000L )
1464 // for debugging, copy al_pa field
1465 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] =
1466 (fcChip->Registers.rcv_al_pa.value & 0xffL);
1467 // get the other port's al_pa
1468 // (one that sent LIP(F8,?) )
1472 // Elastic store err
1473 if( fcChip->Registers.FMstatus.value & 0x400L )
1475 // don't count e-s if loop is down!
1476 if( !(USHORT)(fcChip->Registers.FMstatus.value & 0x80) )
1477 fcChip->fcStats.e_stores++;
1484 case INBOUND_FCP_XCHG_COMPLETION: // 0x0C
1487 // On Tachlite TL/TS, we get this message when the data phase
1488 // of a SEST inbound transfer is complete. For example, if a WRITE command
1489 // was received with OX_ID 0, we might respond with XFER_RDY with
1490 // RX_ID 8001. This would start the SEST controlled data phases. When
1491 // all data frames are received, we get this inbound completion. This means
1492 // we should send a status frame to complete the status phase of the
1493 // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
1495 // See Outbound CM discussion of x_IDs
1497 // Get SEST index (x_ID)
1498 // x_ID out of range, return (err condition)
1499 // set status bits from 2nd dword
1500 // free transactionID & SEST entry
1501 // call fcComplete with transactionID & status
1503 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
1504 x_ID = ulBuff & 0x7fffL; // lower 14 bits SEST_Index/Trans_ID
1505 // (mask out MSB "direction" bit)
1506 // Range check CM OX/RX_ID value...
1507 if( x_ID < TACH_SEST_LEN ) // don't go beyond SEST array space
1510 //#define FCP_COMPLETION_DBG 1
1511 #ifdef FCP_COMPLETION_DBG
1512 printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n",
1513 x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
1515 if( ulBuff & 0x08000000L ) // RPC -Response Phase Complete - or -
1516 // time to send response frame?
1517 RPCset = 1; // (SEST transaction)
1520 // set the status for this Inbound SCSI transaction's ID
1522 if( ulBuff & 0x70000000L ) // any errs?
1525 if( ulBuff & 0x40000000L )
1526 dwStatus |= LINKFAIL_RX;
1528 if( ulBuff & 0x20000000L )
1529 dwStatus |= COUNT_ERROR;
1531 if( ulBuff & 0x10000000L )
1532 dwStatus |= OVERFLOW;
1536 // FCP transaction done - copy status
1537 Exchanges->fcExchange[ x_ID ].status = dwStatus;
1540 // Did the exchange get an FCP-RSP response frame?
1541 // (Note the little endian/big endian FC payload difference)
1543 if( RPCset ) // SEST transaction Response frame rec'd
1545 // complete the command in our driver...
1546 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev,fcChip, x_ID);
1550 else // ("target" logic)
1552 // Tachlite says all data frames have been received - now it's time
1553 // to analyze data transfer (successful?), then send a response
1554 // frame for this exchange
1556 ulFibreFrame[0] = x_ID; // copy for later reference
1558 // if this was a TWE, we have to send satus response
1559 if( Exchanges->fcExchange[ x_ID].type == SCSI_TWE )
1561 // fcPutScsiQue( cpqfcHBAdata,
1562 // NEED_FCP_RSP, ulFibreFrame); // (ulFibreFrame not used here)
1566 else // ERROR CONDITION! bogus x_ID in completion message
1568 printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
1576 case INBOUND_SCSI_DATA_COMMAND:
1577 case BAD_SCSI_FRAME:
1578 case INB_SCSI_STATUS_COMPLETION:
1579 case BUFFER_PROCESSED_COMPLETION:
1583 // Tachyon is producing;
1585 fcChip->IMQ->consumerIndex++; // increment OUR consumerIndex
1586 if( fcChip->IMQ->consumerIndex >= IMQ_LEN)// check for rollover
1587 fcChip->IMQ->consumerIndex = 0L; // reset it
1590 if( fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex )
1591 { // all Messages are processed -
1592 iStatus = 0; // no more messages to process
1596 iStatus = 1; // more messages to process
1598 // update TachLite's ConsumerIndex... (clears INTA_L)
1599 // NOTE: according to TL/TS UG, the
1600 // "host must return completion messages in sequential order".
1601 // Does this mean one at a time, in the order received? We
1604 writel( fcChip->IMQ->consumerIndex,
1605 (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
1608 printk("Process IMQ: writing consumer ndx %d\n ",
1609 fcChip->IMQ->consumerIndex);
1610 printk("PI %X, CI %X\n",
1611 fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex );
1619 // hmmm... why did we get interrupted/called with no message?
1620 iStatus = -1; // nothing to process
1622 printk("Process IMQ: no message PI %Xh CI %Xh",
1623 fcChip->IMQ->producerIndex,
1624 fcChip->IMQ->consumerIndex);
1628 LEAVE("ProcessIMQEntry");
1637 // This routine initializes Tachyon according to the following
1638 // options (opcode1):
1639 // 1 - RESTART Tachyon, simulate power on condition by shutting
1640 // down laser, resetting the hardware, de-allocating all buffers;
1642 // 2 - Config Tachyon / PCI registers;
1644 // 3 - Allocating memory and setting Tachyon queues (write Tachyon regs);
1646 // 4 - Config frame manager registers, initialize, turn on laser
1649 // -1 on fatal error
1652 int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2)
1654 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
1655 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1658 int iStatus=-1; // assume failure
1660 ENTER("InitializeTachLite");
1662 // verify board's base address (sanity check)
1664 if( !fcChip->Registers.ReMapMemBase) // NULL address for card?
1665 return -1; // FATAL error!
1671 case 1: // restore hardware to power-on (hard) restart
1674 iStatus = fcChip->ResetTachyon(
1675 cpqfcHBAdata, opcode2); // laser off, reset hardware
1676 // de-allocate aligned buffers
1679 /* TBD // reset FC link Q (producer and consumer = 0)
1680 fcLinkQReset(cpqfcHBAdata);
1687 case 2: // Config PCI/Tachyon registers
1688 // NOTE: For Tach TL/TS, bit 31 must be set to 1. For TS chips, a read
1689 // of bit 31 indicates state of M66EN signal; if 1, chip may run at
1690 // 33-66MHz (see TL/TS UG, pg 159)
1692 ulBuff = 0x80000000; // TachLite Configuration Register
1694 writel( ulBuff, fcChip->Registers.TYconfig.address);
1695 // ulBuff = 0x0147L; // CpqTs PCI CFGCMD register
1696 // WritePCIConfiguration( fcChip->Backplane.bus,
1697 // fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4);
1698 // ulBuff = 0x0L; // test!
1699 // ReadPCIConfiguration( fcChip->Backplane.bus,
1700 // fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4);
1702 // read back for reference...
1703 fcChip->Registers.TYconfig.value =
1704 readl( fcChip->Registers.TYconfig.address );
1706 // what is the PCI bus width?
1707 pci_read_config_byte( cpqfcHBAdata->PciDev,
1708 0x43, // PCIMCTR offset
1711 fcChip->Registers.PCIMCTR = bBuff;
1713 // set string identifying the chip on the circuit board
1715 fcChip->Registers.TYstatus.value =
1716 readl( fcChip->Registers.TYstatus.address);
1719 // Now that we are supporting multiple boards, we need to change
1720 // this logic to check for PCI vendor/device IDs...
1721 // for now, quick & dirty is simply checking Chip rev
1723 ULONG RevId = (fcChip->Registers.TYstatus.value &0x3E0)>>5;
1724 UCHAR Minor = (UCHAR)(RevId & 0x3);
1725 UCHAR Major = (UCHAR)((RevId & 0x1C) >>2);
1727 /* printk(" HBA Tachyon RevId %d.%d\n", Major, Minor); */
1728 if( (Major == 1) && (Minor == 2) )
1730 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
1733 else if( (Major == 1) && (Minor == 3) )
1735 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
1737 else if( (Major == 2) && (Minor == 1) )
1739 sprintf( cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
1742 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
1747 case 3: // allocate mem, set Tachyon Que registers
1748 iStatus = CpqTsCreateTachLiteQues( cpqfcHBAdata, opcode2);
1753 // now that the Queues exist, Tach can DMA to them, so
1754 // we can begin processing INTs
1755 // INTEN register - enable INT (TachLite interrupt)
1756 writeb( 0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
1759 case 4: // Config Fame Manager, Init Loop Command, laser on
1761 // L_PORT or loopback
1762 // depending on Options
1763 iStatus = CpqTsInitializeFrameManager( fcChip,0 );
1766 // failed to initialize Frame Manager
1773 LEAVE("InitializeTachLite");
1781 // Depending on the type of platform memory allocation (e.g. dynamic),
1782 // it's probably best to free memory in opposite order as it was allocated.
1783 // Order of allocation: see other function
1786 int CpqTsDestroyTachLiteQues( void *pHBA, int opcode)
1788 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
1789 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1790 USHORT i, iStatus=0;
1791 void* vPtr; // mem Align manager sets this to the freed address on success
1792 unsigned long ulPtr; // for 64-bit pointer cast (e.g. Alpa machine)
1793 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1796 ENTER("DestroyTachLiteQues");
1800 // search out and free Pool for Extended S/G list pages
1802 for( i=0; i < TACH_SEST_LEN; i++) // for each exchange
1804 // It's possible that extended S/G pages were allocated, mapped, and
1805 // not cleared due to error conditions or O/S driver termination.
1806 // Make sure they're all gone.
1807 if (Exchanges->fcExchange[i].Cmnd != NULL)
1808 cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd,
1809 fcChip, i); // undo DMA mappings.
1811 for (j=fcChip->SEST->sgPages[i] ; j != NULL ; j = next) {
1815 fcChip->SEST->sgPages[i] = NULL;
1817 ulPtr = (unsigned long)fcChip->SEST;
1818 vPtr = fcMemManager( cpqfcHBAdata->PciDev,
1819 &cpqfcHBAdata->dynamic_mem[0],
1820 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1821 fcChip->SEST = 0L; // null invalid ptr
1824 printk("SEST mem not freed\n");
1832 ulPtr = (unsigned long)fcChip->SFQ;
1833 vPtr = fcMemManager( cpqfcHBAdata->PciDev,
1834 &cpqfcHBAdata->dynamic_mem[0],
1835 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1836 fcChip->SFQ = 0L; // null invalid ptr
1839 printk("SFQ mem not freed\n");
1847 // clear Indexes to show empty Queue
1848 fcChip->IMQ->producerIndex = 0;
1849 fcChip->IMQ->consumerIndex = 0;
1851 ulPtr = (unsigned long)fcChip->IMQ;
1852 vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
1853 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1854 fcChip->IMQ = 0L; // null invalid ptr
1857 printk("IMQ mem not freed\n");
1862 if( fcChip->ERQ ) // release memory blocks used by the queues
1864 ulPtr = (unsigned long)fcChip->ERQ;
1865 vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
1866 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1867 fcChip->ERQ = 0L; // null invalid ptr
1870 printk("ERQ mem not freed\n");
1875 // free up the primary EXCHANGES struct and Link Q
1876 cpqfc_free_dma_consistent(cpqfcHBAdata);
1878 LEAVE("DestroyTachLiteQues");
1880 return iStatus; // non-zero (failed) if any memory not freed
1887 // The SFQ is an array with SFQ_LEN length, each element (QEntry)
1888 // with eight 32-bit words. TachLite places incoming FC frames (i.e.
1889 // a valid FC frame with our AL_PA ) in contiguous SFQ entries
1890 // and sends a completion message telling the host where the frame is
1892 // This function copies the current (or oldest not-yet-processed) QEntry to
1893 // a caller's contiguous buffer and updates the Tachyon chip's consumer index
1896 // An FC frame may consume one or many SFQ entries. We know the total
1897 // length from the completion message. The caller passes a buffer large
1898 // enough for the complete message (max 2k).
1900 static void CpqTsGetSFQEntry(
1903 ULONG *ulDestPtr, // contiguous destination buffer
1906 ULONG total_bytes=0;
1907 ULONG consumerIndex = fcChip->SFQ->consumerIndex;
1909 // check passed copy of SFQ producer index -
1910 // is a new message waiting for us?
1911 // equal indexes means SFS is copied
1913 while( producerNdx != consumerIndex )
1914 { // need to process message
1915 total_bytes += 64; // maintain count to prevent writing past buffer
1916 // don't allow copies over Fibre Channel defined length!
1917 if( total_bytes <= 2048 )
1920 &fcChip->SFQ->QEntry[consumerIndex],
1921 64 ); // each SFQ entry is 64 bytes
1922 ulDestPtr += 16; // advance pointer to next 64 byte block
1924 // Tachyon is producing,
1925 // and we are consuming
1927 if( ++consumerIndex >= SFQ_LEN)// check for rollover
1928 consumerIndex = 0L; // reset it
1931 // if specified, update the Tachlite chip ConsumerIndex...
1934 fcChip->SFQ->consumerIndex = consumerIndex;
1935 writel( fcChip->SFQ->consumerIndex,
1936 fcChip->Registers.SFQconsumerIndex.address);
1942 // TachLite routinely freezes it's core ques - Outbound FIFO, Inbound FIFO,
1943 // and Exchange Request Queue (ERQ) on error recover -
1944 // (e.g. whenever a LIP occurs). Here
1945 // we routinely RESUME by clearing these bits, but only if the loop is up
1946 // to avoid ERROR IDLE messages forever.
1948 void CpqTsUnFreezeTachlite( void *pChip, int type )
1950 PTACHYON fcChip = (PTACHYON)pChip;
1951 fcChip->Registers.TYcontrol.value =
1952 readl(fcChip->Registers.TYcontrol.address);
1954 // (bit 4 of value is GBIC LASER)
1955 // if we 'unfreeze' the core machines before the loop is healthy
1956 // (i.e. FLT, OS, LS failure bits set in FMstatus)
1957 // we can get 'error idle' messages forever. Verify that
1958 // FMstatus (Link Status) is OK before unfreezing.
1960 if( !(fcChip->Registers.FMstatus.value & 0x07000000L) && // bits clear?
1961 !(fcChip->Registers.FMstatus.value & 0x80 )) // Active LPSM?
1963 fcChip->Registers.TYcontrol.value &= ~0x300L; // clear FEQ, FFA
1964 if( type == 1 ) // unfreeze ERQ only
1966 // printk("Unfreezing ERQ\n");
1967 fcChip->Registers.TYcontrol.value |= 0x10000L; // set REQ
1969 else // unfreeze both ERQ and FCP-ASSIST (SEST)
1971 // printk("Unfreezing ERQ & FCP-ASSIST\n");
1973 // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
1974 fcChip->Registers.TYcontrol.value |= 0x70000L; // set ROF, RIF, REQ
1977 writel( fcChip->Registers.TYcontrol.value,
1978 fcChip->Registers.TYcontrol.address);
1981 // readback for verify (TachLite still frozen?)
1982 fcChip->Registers.TYstatus.value =
1983 readl(fcChip->Registers.TYstatus.address);
1987 // Whenever an FC Exchange Abort is required, we must manipulate the
1988 // Host/Tachyon shared memory SEST table. Before doing this, we
1989 // must freeze Tachyon, which flushes certain buffers and ensure we
1990 // can manipulate the SEST without contention.
1991 // This freeze function will result in FCP & ERQ FROZEN completion
1992 // messages (per argument "type").
1994 void CpqTsFreezeTachlite( void *pChip, int type )
1996 PTACHYON fcChip = (PTACHYON)pChip;
1997 fcChip->Registers.TYcontrol.value =
1998 readl(fcChip->Registers.TYcontrol.address);
2000 //set FFA, FEQ - freezes SCSI assist and ERQ
2001 if( type == 1) // freeze ERQ only
2002 fcChip->Registers.TYcontrol.value |= 0x100L; // (bit 4 is laser)
2003 else // freeze both FCP assists (SEST) and ERQ
2004 fcChip->Registers.TYcontrol.value |= 0x300L; // (bit 4 is laser)
2006 writel( fcChip->Registers.TYcontrol.value,
2007 fcChip->Registers.TYcontrol.address);
2014 // TL has two Frame Manager Link Status Registers, with three 8-bit
2015 // fields each. These eight bit counters are cleared after each read,
2016 // so we define six 32-bit accumulators for these TL counters. This
2017 // function breaks out each 8-bit field and adds the value to the existing
2018 // sum. (s/w counters cleared independently)
2020 void fcParseLinkStatusCounters(PTACHYON fcChip)
2026 // The BB0 timer usually increments when TL is initialized, resulting
2027 // in an initially bogus count. If our own counter is ZERO, it means we
2028 // are reading this thing for the first time, so we ignore the first count.
2029 // Also, reading the register does not clear it, so we have to keep an
2030 // additional static counter to detect rollover (yuk).
2032 if( fcChip->fcStats.lastBB0timer == 0L) // TL was reset? (ignore 1st values)
2034 // get TL's register counter - the "last" count
2035 fcChip->fcStats.lastBB0timer =
2036 fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
2038 else // subsequent pass - check for rollover
2041 ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
2042 if( fcChip->fcStats.lastBB0timer > ulBuff ) // rollover happened
2044 // counter advanced to max...
2045 fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
2046 fcChip->fcStats.BB0_Timer += ulBuff; // plus some more
2050 else // no rollover -- more counts or no change
2052 fcChip->fcStats.BB0_Timer += (ulBuff - fcChip->fcStats.lastBB0timer);
2056 fcChip->fcStats.lastBB0timer = ulBuff;
2061 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 24);
2062 fcChip->fcStats.LossofSignal += bBuff;
2064 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 16);
2065 fcChip->fcStats.BadRXChar += bBuff;
2067 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 8);
2068 fcChip->fcStats.LossofSync += bBuff;
2071 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 24);
2072 fcChip->fcStats.Rx_EOFa += bBuff;
2074 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 16);
2075 fcChip->fcStats.Dis_Frm += bBuff;
2077 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 8);
2078 fcChip->fcStats.Bad_CRC += bBuff;
2082 void cpqfcTSClearLinkStatusCounters(PTACHYON fcChip)
2084 ENTER("ClearLinkStatusCounters");
2085 memset( &fcChip->fcStats, 0, sizeof( FCSTATS));
2086 LEAVE("ClearLinkStatusCounters");
2093 // The following function reads the I2C hardware to get the adapter's
2094 // World Wide Name (WWN).
2095 // If the WWN is "500805f1fadb43e8" (as printed on the card), the
2096 // Tachyon WWN_hi (32-bit) register is 500805f1, and WWN_lo register
2098 // In the NVRAM, the bytes appear as:
2110 // In the Fibre Channel (Big Endian) format, the FC-AL LISM frame will
2111 // be correctly loaded by Tachyon silicon. In the login payload, bytes
2112 // must be correctly swapped for Big Endian format.
2114 int CpqTsReadWriteWWN( PVOID pChip, int Read)
2116 PTACHYON fcChip = (PTACHYON)pChip;
2117 #define NVRAM_SIZE 512
2118 unsigned short i, count = NVRAM_SIZE;
2119 UCHAR nvRam[NVRAM_SIZE], WWNbuf[8];
2121 int iStatus=-1; // assume failure
2124 ENTER("ReadWriteWWN");
2125 // Now try to read the WWN from the adapter's NVRAM
2127 if( Read ) // READing NVRAM WWN?
2129 ulBuff = cpqfcTS_ReadNVRAM( fcChip->Registers.TYstatus.address,
2130 fcChip->Registers.TYcontrol.address,
2133 if( ulBuff ) // NVRAM read successful?
2135 iStatus = 0; // success!
2137 // for engineering/ prototype boards, the data may be
2138 // invalid (GIGO, usually all "FF"); this prevents the
2139 // parse routine from working correctly, which means
2140 // nothing will be written to our passed buffer.
2142 WWNoffset = cpqfcTS_GetNVRAM_data( WWNbuf, nvRam );
2144 if( !WWNoffset ) // uninitialized NVRAM -- copy bytes directly
2146 printk( "CAUTION: Copying NVRAM data on fcChip\n");
2147 for( i= 0; i < 8; i++)
2148 WWNbuf[i] = nvRam[i +0x2f]; // dangerous! some formats won't work
2151 fcChip->Registers.wwn_hi = 0L;
2152 fcChip->Registers.wwn_lo = 0L;
2153 for( i=0; i<4; i++) // WWN bytes are big endian in NVRAM
2156 ulBuff = (ULONG)(WWNbuf[i]) << (8 * (3-i));
2157 fcChip->Registers.wwn_hi |= ulBuff;
2159 for( i=0; i<4; i++) // WWN bytes are big endian in NVRAM
2162 ulBuff = (ULONG)(WWNbuf[i+4]) << (8 * (3-i));
2163 fcChip->Registers.wwn_lo |= ulBuff;
2169 printk( "cpqfcTS: NVRAM read failed\n");
2177 // NOTE: WRITE not supported & not used in released driver.
2180 printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
2183 LEAVE("ReadWriteWWN");
2191 // The following function reads or writes the entire "NVRAM" contents of
2192 // the I2C hardware (i.e. the NM24C03). Note that HP's 5121A (TS 66Mhz)
2193 // adapter does not use the NM24C03 chip, so this function only works on
2194 // Compaq's adapters.
2196 int CpqTsReadWriteNVRAM( PVOID pChip, PVOID buf, int Read)
2198 PTACHYON fcChip = (PTACHYON)pChip;
2199 #define NVRAM_SIZE 512
2201 UCHAR *ucPtr = buf; // cast caller's void ptr to UCHAR array
2202 int iStatus=-1; // assume failure
2205 if( Read ) // READing NVRAM?
2207 ulBuff = cpqfcTS_ReadNVRAM( // TRUE on success
2208 fcChip->Registers.TYstatus.address,
2209 fcChip->Registers.TYcontrol.address,
2210 256, // bytes to write
2211 ucPtr ); // source ptr
2215 iStatus = 0; // success
2219 printk( "CAUTION: NVRAM read failed\n");
2224 else // WRITING NVRAM
2227 printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");