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 "hosts.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); */
119 memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));
121 if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!!
123 cpqfc_free_dma_consistent(cpqfcHBAdata);
124 printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
127 // zero out the entire EXCHANGE space
128 memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));
130 // Verify that basic Tach I/O registers are not NULL
131 if( !fcChip->Registers.ReMapMemBase )
133 cpqfc_free_dma_consistent(cpqfcHBAdata);
134 printk("HBA base address NULL: fatal error\n");
139 // Initialize the fcMemManager memory pairs (stores allocated/aligned
140 // pairs for future freeing)
141 memset( cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
144 // Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
146 fcChip->ERQ = fcMemManager( cpqfcHBAdata->PciDev,
147 &cpqfcHBAdata->dynamic_mem[0],
148 sizeof( TachLiteERQ ), 32*(ERQ_LEN), 0L, &ERQdma);
151 cpqfc_free_dma_consistent(cpqfcHBAdata);
152 printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
155 fcChip->ERQ->length = ERQ_LEN-1;
156 ulAddr = (ULONG) ERQdma;
157 #if BITS_PER_LONG > 32
160 cpqfc_free_dma_consistent(cpqfcHBAdata);
161 printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n",
166 fcChip->ERQ->base = (ULONG)ulAddr; // copy for quick reference
169 // Allocate Tach's Inbound Message Queue (32 bytes per entry)
171 fcChip->IMQ = fcMemManager( cpqfcHBAdata->PciDev,
172 &cpqfcHBAdata->dynamic_mem[0],
173 sizeof( TachyonIMQ ), 32*(IMQ_LEN), 0L, &IMQdma );
176 cpqfc_free_dma_consistent(cpqfcHBAdata);
177 printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
180 fcChip->IMQ->length = IMQ_LEN-1;
183 #if BITS_PER_LONG > 32
186 cpqfc_free_dma_consistent(cpqfcHBAdata);
187 printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
192 fcChip->IMQ->base = (ULONG)ulAddr; // copy for quick reference
195 // Allocate Tach's Single Frame Queue (64 bytes per entry)
196 fcChip->SFQ = fcMemManager( cpqfcHBAdata->PciDev,
197 &cpqfcHBAdata->dynamic_mem[0],
198 sizeof( TachLiteSFQ ), 64*(SFQ_LEN),0L, &SPQdma );
201 cpqfc_free_dma_consistent(cpqfcHBAdata);
202 printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
205 fcChip->SFQ->length = SFQ_LEN-1; // i.e. Que length [# entries -
206 // min. 32; max. 4096 (0xffff)]
209 #if BITS_PER_LONG > 32
212 cpqfc_free_dma_consistent(cpqfcHBAdata);
213 printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
218 fcChip->SFQ->base = (ULONG)ulAddr; // copy for quick reference
221 // Allocate SCSI Exchange State Table; aligned nearest @sizeof
222 // power-of-2 boundary
223 // LIVE DANGEROUSLY! Assume the boundary for SEST mem will
224 // be on physical page (e.g. 4k) boundary.
225 /* printk("Allocating %u for TachSEST for %u Exchanges\n",
226 (ULONG)sizeof(TachSEST), TACH_SEST_LEN); */
227 fcChip->SEST = fcMemManager( cpqfcHBAdata->PciDev,
228 &cpqfcHBAdata->dynamic_mem[0],
229 sizeof(TachSEST), 4, 0L, &SESTdma );
230 // sizeof(TachSEST), 64*TACH_SEST_LEN, 0L );
233 cpqfc_free_dma_consistent(cpqfcHBAdata);
234 printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
238 for( i=0; i < TACH_SEST_LEN; i++) // for each exchange
239 fcChip->SEST->sgPages[i] = NULL;
241 fcChip->SEST->length = TACH_SEST_LEN; // e.g. DON'T subtract one
242 // (TL/TS UG, pg 153)
245 #if BITS_PER_LONG > 32
248 cpqfc_free_dma_consistent(cpqfcHBAdata);
249 printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
254 fcChip->SEST->base = (ULONG)ulAddr; // copy for quick reference
257 // Now that structures are defined,
258 // fill in Tachyon chip registers...
260 // EEEEEEEE EXCHANGE REQUEST QUEUE
262 writel( fcChip->ERQ->base,
263 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
265 writel( fcChip->ERQ->length,
266 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
269 fcChip->ERQ->producerIndex = 0L;
270 writel( fcChip->ERQ->producerIndex,
271 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
274 // NOTE! write consumer index last, since the write
275 // causes Tachyon to process the other registers
277 ulAddr = ((unsigned long)&fcChip->ERQ->consumerIndex -
278 (unsigned long)fcChip->ERQ) + (unsigned long) ERQdma;
280 // NOTE! Tachyon DMAs to the ERQ consumer Index host
281 // address; must be correctly aligned
282 writel( (ULONG)ulAddr,
283 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
287 // IIIIIIIIIIIII INBOUND MESSAGE QUEUE
288 // Tell Tachyon where the Que starts
290 // set the Host's pointer for Tachyon to access
292 /* printk(" cpqfcTS: writing IMQ BASE %Xh ", fcChip->IMQ->base ); */
293 writel( fcChip->IMQ->base,
294 (fcChip->Registers.ReMapMemBase + IMQ_BASE));
296 writel( fcChip->IMQ->length,
297 (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
299 writel( fcChip->IMQ->consumerIndex,
300 (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
303 // NOTE: TachLite DMAs to the producerIndex host address
304 // must be correctly aligned with address bits 1-0 cleared
305 // Writing the BASE register clears the PI register, so write it last
306 ulAddr = ((unsigned long)&fcChip->IMQ->producerIndex -
307 (unsigned long)fcChip->IMQ) + (unsigned long) IMQdma;
309 #if BITS_PER_LONG > 32
312 cpqfc_free_dma_consistent(cpqfcHBAdata);
313 printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
319 printk(" PI %Xh\n", (ULONG)ulAddr );
321 writel( (ULONG)ulAddr,
322 (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
326 // SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
327 // Tell TachLite where the Que starts
329 writel( fcChip->SFQ->base,
330 (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
332 writel( fcChip->SFQ->length,
333 (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
336 // tell TachLite where SEST table is & how long
337 writel( fcChip->SEST->base,
338 (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
340 /* printk(" cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n",
341 fcChip->SEST, fcChip->SEST->base,
342 fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE); */
344 writel( fcChip->SEST->length,
345 (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
347 writel( (TL_EXT_SG_PAGE_COUNT-1),
348 (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
351 LEAVE("CreateTachLiteQues");
358 // function to return TachLite to Power On state
359 // 1st - reset tachyon ('SOFT' reset)
362 int CpqTsResetTachLite(void *pHBA, int type)
364 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
365 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
367 int ret_status=0; // def. success
376 // in case he was running previously, mask Tach's interrupt
377 writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
379 // de-allocate mem for any Logged in ports
380 // (e.g., our module is unloading)
381 // search the forward linked list, de-allocating
382 // the memory we allocated when the port was initially logged in
384 PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
385 PFC_LOGGEDIN_PORT ptr;
386 // printk("checking for allocated LoggedInPorts...\n");
388 while( pLoggedInPort )
391 pLoggedInPort = ptr->pNextPort;
392 // printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
393 // ptr, ptr->port_id);
397 // (continue resetting hardware...)
399 case 1: // RESTART Tachyon (power-up state)
401 // in case he was running previously, mask Tach's interrupt
402 writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
403 // turn OFF laser (NOTE: laser is turned
404 // off during reset, because GPIO4 is cleared
405 // to 0 by reset action - see TLUM, sec 7.22)
406 // However, CPQ 64-bit HBAs have a "health
407 // circuit" which keeps laser ON for a brief
408 // period after it is turned off ( < 1s)
410 fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 0);
414 // soft reset timing constraints require:
416 // 2. read SOFTRST register
417 // (128 times per R. Callison code)
421 (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
423 for( i=0; i<128; i++)
424 ulBuff = readl( fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
426 // clear the soft reset
428 writel( 0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
432 // clear out our copy of Tach regs,
433 // because they must be invalid now,
434 // since TachLite reset all his regs.
435 CpqTsDestroyTachLiteQues(cpqfcHBAdata,0); // remove Host-based Que structs
436 cpqfcTSClearLinkStatusCounters(fcChip); // clear our s/w accumulators
437 // lower bits give GBIC info
438 fcChip->Registers.TYstatus.value =
439 readl( fcChip->Registers.TYstatus.address );
443 case 2: // freeze SCSI
444 case 3: // reset Outbound command que (ERQ)
445 case 4: // unfreeze OSM (Outbound Seq. Man.) 'er'
446 case 5: // report status
451 ret_status = -1; // invalid option passed to RESET function
463 // 'addrBase' is IOBaseU for both TachLite and (older) Tachyon
464 int CpqTsLaserControl( void* addrBase, int opcode )
468 dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL) ); // read TL Control reg
469 // (change only bit 4)
471 dwBuff |= ~0xffffffefL; // set - ON
473 dwBuff &= 0xffffffefL; // clear - OFF
474 writel( dwBuff, (addrBase + TL_MEM_TACH_CONTROL)); // write TL Control reg
482 // Use controller's "Options" field to determine loopback mode (if any)
483 // internal loopback (silicon - no GBIC)
484 // external loopback (GBIC - no FC loop)
485 // no loopback: L_PORT, external cable from GBIC required
487 int CpqTsInitializeFrameManager( void *pChip, int opcode)
491 ULONG wwnLo, wwnHi; // for readback verification
493 ENTER("InitializeFrameManager");
494 fcChip = (PTACHYON)pChip;
495 if( !fcChip->Registers.ReMapMemBase ) // undefined controller?
499 // 0x0065 = 100ms for RT_TOV
500 // 0x01f5 = 500ms for ED_TOV
502 fcChip->Registers.ed_tov.value = 0x006507D1;
503 writel( fcChip->Registers.ed_tov.value,
504 (fcChip->Registers.ed_tov.address));
507 // Set LP_TOV to the FC-AL2 specified 2 secs.
509 writel( 0x07d00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
512 // Now try to read the WWN from the adapter's NVRAM
513 iStatus = CpqTsReadWriteWWN( fcChip, 1); // '1' for READ
515 if( iStatus ) // NVRAM read failed?
517 printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
518 // make up a WWN. If NULL or duplicated on loop, FC loop may hang!
521 fcChip->Registers.wwn_hi = (__u32)jiffies;
522 fcChip->Registers.wwn_hi |= 0x50000000L;
523 fcChip->Registers.wwn_lo = 0x44556677L;
527 writel( fcChip->Registers.wwn_hi,
528 fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
530 writel( fcChip->Registers.wwn_lo,
531 fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
534 // readback for verification:
535 wwnHi = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI );
537 wwnLo = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
538 // test for correct chip register WRITE/READ
539 DEBUG_PCI( printk(" WWN %08X%08X\n",
540 fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo ) );
542 if( wwnHi != fcChip->Registers.wwn_hi ||
543 wwnLo != fcChip->Registers.wwn_lo )
545 printk( "cpqfcTS: WorldWideName register load failed\n");
546 return -1; // FAILED!
551 // set Frame Manager Initialize command
552 fcChip->Registers.FMcontrol.value = 0x06;
554 // Note: for test/debug purposes, we may use "Hard" address,
555 // but we completely support "soft" addressing, including
556 // dynamically changing our address.
557 if( fcChip->Options.intLoopback == 1 ) // internal loopback
558 fcChip->Registers.FMconfig.value = 0x0f002080L;
559 else if( fcChip->Options.extLoopback == 1 ) // internal loopback
560 fcChip->Registers.FMconfig.value = 0x0f004080L;
562 fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
563 // fcChip->Registers.FMconfig.value = 0x01000080L; // soft address (can't pick)
564 // fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
566 // write config to FM
568 if( !fcChip->Options.intLoopback && !fcChip->Options.extLoopback )
569 // (also need LASER for real LOOP)
570 fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 1); // turn on LASER
572 writel( fcChip->Registers.FMconfig.value,
573 fcChip->Registers.FMconfig.address);
576 // issue INITIALIZE command to FM - ACTION!
577 writel( fcChip->Registers.FMcontrol.value,
578 fcChip->Registers.FMcontrol.address);
580 LEAVE("InitializeFrameManager");
589 // This "look ahead" function examines the IMQ for occurrence of
590 // "type". Returns 1 if found, 0 if not.
591 static int PeekIMQEntry( PTACHYON fcChip, ULONG type)
593 ULONG CI = fcChip->IMQ->consumerIndex;
594 ULONG PI = fcChip->IMQ->producerIndex; // snapshot of IMQ indexes
597 { // proceed with search
598 if( (++CI) >= IMQ_LEN ) CI = 0; // rollover check
604 // first, we need to find an Inbound Completion message,
605 // If we find it, check the incoming frame payload (1st word)
607 if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104 )
609 TachFCHDR_GCMND* fchs;
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 ULONG ulFibreFrame[2048/4]; // max number of DWORDS in incoming Fibre Frame
722 UCHAR ucInboundMessageType; // Inbound CM, dword 3 "type" field
724 ENTER("ProcessIMQEntry");
727 // check TachLite's IMQ producer index -
728 // is a new message waiting for us?
729 // equal indexes means empty que
731 if( fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex )
732 { // need to process message
736 printk("PI %X, CI %X type: %X\n",
737 fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex,
738 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
740 // Examine Completion Messages in IMQ
742 switch( (UCHAR)(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type
745 case OUTBOUND_COMPLETION:
748 // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
749 // (starting at 0), and SFS entries (starting at
750 // SEST_LEN -- outside the SEST space).
752 // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
753 // range check - x_ID
754 // if x_ID outside 'Transactions' length, error - exit
755 // if any OCM error, copy error status to Exchange slot
756 // if FCP ASSIST transaction (x_ID within SEST),
757 // call fcComplete (to App)
761 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
762 x_ID = ulBuff & 0x7fffL; // lower 14 bits SEST_Index/Trans_ID
763 // Range check CM OX/RX_ID value...
764 if( x_ID < TACH_MAX_XID ) // don't go beyond array space
768 if( ulBuff & 0x20000000L ) // RPC -Response Phase Complete?
769 RPCset = 1; // (SEST transactions only)
773 if( ulBuff & 0x40000000L ) // DPC -Data Phase Complete?
774 DPCset = 1; // (SEST transactions only)
777 // set the status for this Outbound transaction's ID
779 if( ulBuff & 0x10000000L ) // SPE? (SEST Programming Error)
780 dwStatus |= SESTPROG_ERR;
782 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
783 if( ulBuff & 0x7a000000L ) // any other errs?
785 if( ulBuff & 0x40000000L )
786 dwStatus |= INV_ENTRY;
787 if( ulBuff & 0x20000000L )
788 dwStatus |= FRAME_TO; // FTO
789 if( ulBuff & 0x10000000L )
790 dwStatus |= HOSTPROG_ERR;
791 if( ulBuff & 0x08000000L )
792 dwStatus |= LINKFAIL_TX;
793 if( ulBuff & 0x02000000L )
794 dwStatus |= ABORTSEQ_NOTIFY; // ASN
798 if( dwStatus ) // any errors?
800 // set the Outbound Completion status
801 Exchanges->fcExchange[ x_ID ].status |= dwStatus;
803 // if this Outbound frame was for a SEST entry, automatically
804 // reque it in the case of LINKFAIL (it will restart on PDISC)
805 if( x_ID < TACH_SEST_LEN )
808 printk(" #OCM error %Xh x_ID %X# ",
811 Exchanges->fcExchange[x_ID].timeOut = 30000; // seconds default
814 // We Q ABTS for each exchange.
815 // NOTE: We can get FRAME_TO on bad alpa (device gone). Since
816 // bad alpa is reported before FRAME_TO, examine the status
817 // flags to see if the device is removed. If so, DON'T
818 // post an ABTS, since it will be terminated by the bad alpa
820 if( dwStatus & FRAME_TO ) // check for device removed...
822 if( !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) )
824 // presumes device is still there: send ABTS.
826 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
829 else // Abort all other errors
831 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
834 // if the HPE bit is set, we have to CLose the LOOP
835 // (see TL/TS UG, pg. 239)
837 if( dwStatus &= HOSTPROG_ERR )
838 // set CL bit (see TL/TS UG, pg. 172)
839 writel( 4, fcChip->Registers.FMcontrol.address);
842 // NOTE: we don't necessarily care about ALL completion messages...
843 // SCSI resp. complete OR
844 if( ((x_ID < TACH_SEST_LEN) && RPCset)||
845 (x_ID >= TACH_SEST_LEN) ) // non-SCSI command
847 // exchange done; complete to upper levels with status
848 // (if necessary) and free the exchange slot
851 if( x_ID >= TACH_SEST_LEN ) // Link Service Outbound frame?
852 // A Request or Reply has been sent
853 { // signal waiting WorkerThread
855 up( cpqfcHBAdata->TYOBcomplete); // frame is OUT of Tach
857 // WorkerThread will complete Xchng
859 else // X_ID is for FCP assist (SEST)
862 // fcCompleteExchange( fcChip, x_ID); // TRE completed
866 else // ERROR CONDITION! bogus x_ID in completion message
869 printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
875 // Load the Frame Manager's error counters. We check them here
876 // because presumably the link is up and healthy enough for the
877 // counters to be meaningful (i.e., don't check them while loop
879 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
880 readl(fcChip->Registers.FMLinkStatus1.address);
882 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
883 readl(fcChip->Registers.FMLinkStatus2.address);
886 fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
891 case ERROR_IDLE_COMPLETION: // TachLite Error Idle...
893 // We usually get this when the link goes down during heavy traffic.
894 // For now, presume that if SEST Exchanges are open, we will
895 // get this as our cue to INVALIDATE all SEST entries
896 // (and we OWN all the SEST entries).
897 // See TL/TS UG, pg. 53
899 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
902 // Does this VALid SEST entry need to be invalidated for Abort?
903 fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
906 CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachyon, if Link OK
911 case INBOUND_SFS_COMPLETION: //0x04
912 // NOTE! we must process this SFQ message to avoid SFQ filling
913 // up and stopping TachLite. Incoming commands are placed here,
914 // as well as 'unknown' frames (e.g. LIP loop position data)
915 // write this CM's producer index to global...
917 // Type: 0 - reserved
918 // 1 - Unassisted FCP
924 fcChip->SFQ->producerIndex = (USHORT)
925 (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
928 ucInboundMessageType = 0; // default to useless frame
930 // we can only process two Types: 1, Unassisted FCP, and 3, Unknown
931 // Also, we aren't interested in processing frame fragments
932 // so don't Que anything with 'LKF' bit set
933 if( !(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2]
934 & 0x40000000) ) // 'LKF' link failure bit clear?
936 ucInboundMessageType = (UCHAR) // ICM DWord3, "Type"
937 (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
941 fcChip->fcStats.linkFailRX++;
942 // printk("LKF (link failure) bit set on inbound message\n");
945 // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
947 fcChip, // i.e. this Device Object
948 (USHORT)fcChip->SFQ->producerIndex, // SFQ producer ndx
949 ulFibreFrame, TRUE); // contiguous destination buffer, update chip
951 // analyze the incoming frame outside the INT handler...
954 if( ucInboundMessageType == 1 )
956 fchs = (TachFCHDR_GCMND*)ulFibreFrame; // cast to examine IB frame
957 // don't fill up our Q with garbage - only accept FCP-CMND
959 if( (fchs->d_id & 0xFF000000) == 0x06000000 ) // CMND
961 // someone sent us a SCSI command
963 // fcPutScsiQue( cpqfcHBAdata,
964 // SFQ_UNASSISTED_FCP, ulFibreFrame);
966 else if( ((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status)
967 (fchs->d_id & 0xFF000000) == 0x05000000 ) // XRDY
970 // Unfortunately, ABTS requires a Freeze on the chip so
971 // we can modify the shared memory SEST. When frozen,
972 // any received Exchange frames cannot be processed by
973 // Tachyon, so they will be dumped in here. It is too
974 // complex to attempt the reconstruct these frames in
975 // the correct Exchange context, so we simply seek to
976 // find status or transfer ready frames, and cause the
977 // exchange to complete with errors before the timeout
978 // expires. We use a Linux Scsi Cmnd result code that
979 // causes immediate retry.
982 // Do we have an open exchange that matches this s_id
984 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
986 if( (fchs->s_id & 0xFFFFFF) ==
987 (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF)
989 (fchs->ox_rx_id & 0xFFFF0000) ==
990 (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000) )
992 // printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
993 // simulate the anticipated error - since the
994 // SEST was frozen, frames were lost...
995 Exchanges->fcExchange[ x_ID ].status |= SFQ_FRAME;
997 // presumes device is still there: send ABTS.
998 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
1006 else if( ucInboundMessageType == 3)
1008 // FC Link Service frames (e.g. PLOGI, ACC) come in here.
1009 cpqfcTSPutLinkQue( cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame);
1013 else if( ucInboundMessageType == 2 ) // "bad FCP"?
1016 printk("Bad FCP incoming frame discarded\n");
1020 else // don't know this type
1023 printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
1027 // Check the Frame Manager's error counters. We check them here
1028 // because presumably the link is up and healthy enough for the
1029 // counters to be meaningful (i.e., don't check them while loop
1030 // is initializing).
1031 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
1032 readl(fcChip->Registers.FMLinkStatus1.address);
1035 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
1036 readl(fcChip->Registers.FMLinkStatus2.address);
1044 // We get this CM because we issued a freeze
1045 // command to stop outbound frames. We issue the
1046 // freeze command at Link Up time; when this message
1047 // is received, the ERQ base can be switched and PDISC
1048 // frames can be sent.
1051 case ERQ_FROZEN_COMPLETION: // note: expect ERQ followed immediately
1052 // by FCP when freezing TL
1053 fcChip->Registers.TYstatus.value = // read what's frozen
1054 readl(fcChip->Registers.TYstatus.address);
1055 // (do nothing; wait for FCP frozen message)
1057 case FCP_FROZEN_COMPLETION:
1059 fcChip->Registers.TYstatus.value = // read what's frozen
1060 readl(fcChip->Registers.TYstatus.address);
1062 // Signal the kernel thread to proceed with SEST modification
1063 up( cpqfcHBAdata->TachFrozen);
1069 case INBOUND_C1_TIMEOUT:
1078 // In older Tachyons, we 'clear' the internal 'core' interrupt state
1079 // by reading the FMstatus register. In newer TachLite (Tachyon),
1080 // we must WRITE the register
1081 // to clear the condition (TL/TS UG, pg 179)
1082 case FRAME_MGR_INTERRUPT:
1084 PFC_LOGGEDIN_PORT pLoggedInPort;
1086 fcChip->Registers.FMstatus.value =
1087 readl( fcChip->Registers.FMstatus.address );
1089 // PROBLEM: It is possible, especially with "dumb" hubs that
1090 // don't automatically LIP on by-pass of ports that are going
1091 // away, for the hub by-pass process to destroy critical
1092 // ordered sets of a frame. The result of this is a hung LPSM
1093 // (Loop Port State Machine), which on Tachyon results in a
1094 // (default 2 sec) Loop State Timeout (LST) FM message. We
1095 // want to avoid this relatively huge timeout by detecting
1096 // likely scenarios which will result in LST.
1097 // To do this, we could examine FMstatus for Loss of Synchronization
1098 // and/or Elastic Store (ES) errors. Of these, Elastic Store is better
1099 // because we get this indication more quickly than the LOS.
1100 // Not all ES errors are harmfull, so we don't want to LIP on every
1101 // ES. Instead, on every ES, detect whether our LPSM in in one
1102 // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
1103 // or RECEIVED CLOSE. (See TL/TS UG, pg. 181)
1104 // If any of these LPSM states are detected
1105 // in combination with the LIP while LDn is not set,
1106 // send an FM init (LIP F7,F7 for loops)!
1107 // It is critical to the physical link stability NOT to reset (LIP)
1108 // more than absolutely necessary; this is a basic premise of the
1109 // SANMark level 1 spec.
1111 ULONG Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >>4;
1113 if( (fcChip->Registers.FMstatus.value & 0x400) // ElasticStore?
1115 !(fcChip->Registers.FMstatus.value & 0x100) // NOT LDn
1117 !(fcChip->Registers.FMstatus.value & 0x1000)) // NOT LF
1119 if( (Lpsm != 0) || // not MONITORING? or
1120 !(Lpsm & 0x8) )// not already offline?
1122 // now check the particular LST states...
1123 if( (Lpsm == ARBITRATING) || (Lpsm == OPEN) ||
1124 (Lpsm == OPENED) || (Lpsm == XMITTD_CLOSE) ||
1125 (Lpsm == RCVD_CLOSE) )
1127 // re-init the loop before it hangs itself!
1128 printk(" #req FMinit on E-S: LPSM %Xh# ",Lpsm);
1131 fcChip->fcStats.FMinits++;
1132 writel( 6, fcChip->Registers.FMcontrol.address); // LIP
1136 else if( fcChip->Registers.FMstatus.value & 0x40000 ) // LST?
1138 printk(" #req FMinit on LST, LPSM %Xh# ",Lpsm);
1140 fcChip->fcStats.FMinits++;
1141 writel( 6, fcChip->Registers.FMcontrol.address); // LIP
1146 // clear only the 'interrupting' type bits for this REG read
1147 writel( (fcChip->Registers.FMstatus.value & 0xff3fff00L),
1148 fcChip->Registers.FMstatus.address);
1151 // copy frame manager status to unused ULONG slot
1152 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] =
1153 fcChip->Registers.FMstatus.value; // (for debugging)
1156 // Load the Frame Manager's error counters. We check them here
1157 // because presumably the link is up and healthy enough for the
1158 // counters to be meaningful (i.e., don't check them while loop
1159 // is initializing).
1160 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
1161 readl(fcChip->Registers.FMLinkStatus1.address);
1163 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
1164 readl(fcChip->Registers.FMLinkStatus2.address);
1166 // Get FM BB_Credit Zero Reg - does not clear on READ
1167 fcChip->Registers.FMBB_CreditZero.value = // get TL's counter
1168 readl(fcChip->Registers.FMBB_CreditZero.address);
1172 fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
1177 if( fcChip->Registers.FMstatus.value & 0x100L ) // Link DOWN bit
1185 fcChip->fcStats.linkDown++;
1187 SetTachTOV( cpqfcHBAdata); // must set according to SANMark
1189 // Check the ERQ - force it to be "empty" to prevent Tach
1190 // from sending out frames before we do logins.
1193 if( fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex)
1195 // printk("#ERQ PI != CI#");
1196 CpqTsFreezeTachlite( fcChip, 1); // freeze ERQ only
1197 fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
1198 writel( fcChip->ERQ->base,
1199 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
1200 // re-writing base forces ERQ PI to equal CI
1204 // link down transition occurred -- port_ids can change
1205 // on next LinkUp, so we must invalidate current logins
1206 // (and any I/O in progress) until PDISC or PLOGI/PRLI
1209 pLoggedInPort = &fcChip->fcPorts;
1210 while( pLoggedInPort ) // for all ports which are expecting
1211 // PDISC after the next LIP, set the
1215 if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
1217 pLoggedInPort->LOGO_timer = 3; // we want 2 seconds
1218 // but Timer granularity
1221 // suspend any I/O in progress until
1222 // PDISC received...
1223 pLoggedInPort->prli = FALSE; // block FCP-SCSI commands
1225 pLoggedInPort = pLoggedInPort->pNextPort;
1226 } // ... all Previously known ports checked
1229 // since any hot plugging device may NOT support LILP frames
1230 // (such as early Tachyon chips), clear this flag indicating
1231 // we shouldn't use (our copy of) a LILP map.
1232 // If we receive an LILP frame, we'll set it again.
1233 fcChip->Options.LILPin = 0; // our LILPmap is invalid
1234 cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports!
1236 // also, we want to invalidate (i.e. INITIATOR_ABORT) any
1237 // open Login exchanges, in case the LinkDown happened in the
1238 // middle of logins. It's possible that some ports already
1239 // ACCepted login commands which we have not processed before
1240 // another LinkDown occurred. Any accepted Login exhanges are
1241 // invalidated by LinkDown, even before they are acknowledged.
1242 // It's also possible for a port to have a Queued Reply or Request
1243 // for login which was interrupted by LinkDown; it may come later,
1244 // but it will be unacceptable to us.
1246 // we must scan the entire exchange space, find every Login type
1247 // originated by us, and abort it. This is NOT an abort due to
1248 // timeout, so we don't actually send abort to the other port -
1249 // we just complete it to free up the fcExchange slot.
1251 for( i=TACH_SEST_LEN; i< TACH_MAX_XID; i++)
1252 { // looking for Extended Link Serv.Exchanges
1253 if( Exchanges->fcExchange[i].type == ELS_PDISC ||
1254 Exchanges->fcExchange[i].type == ELS_PLOGI ||
1255 Exchanges->fcExchange[i].type == ELS_PRLI )
1257 // ABORT the exchange!
1259 printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n",
1260 i, Exchanges->fcExchange[i].type,
1261 Exchanges->fcExchange[i].fchs.d_id);
1264 Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
1265 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // abort on LDn
1271 // ################ LINK UP ##################
1272 if( fcChip->Registers.FMstatus.value & 0x200L ) // Link Up bit
1273 { // AL_PA could have changed
1275 // We need the following code, duplicated from LinkDn condition,
1276 // because it's possible for the Tachyon to re-initialize (hard
1277 // reset) without ever getting a LinkDn indication.
1278 pLoggedInPort = &fcChip->fcPorts;
1279 while( pLoggedInPort ) // for all ports which are expecting
1280 // PDISC after the next LIP, set the
1283 if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
1285 pLoggedInPort->LOGO_timer = 3; // we want 2 seconds
1286 // but Timer granularity
1289 // suspend any I/O in progress until
1290 // PDISC received...
1293 pLoggedInPort = pLoggedInPort->pNextPort;
1294 } // ... all Previously known ports checked
1296 // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
1297 fcChip->Registers.rcv_al_pa.value =
1298 readl(fcChip->Registers.rcv_al_pa.address);
1300 // Now, if our acquired address is DIFFERENT from our
1301 // previous one, we are not allow to do PDISC - we
1302 // must go back to PLOGI, which will terminate I/O in
1303 // progress for ALL logged in FC devices...
1304 // (This is highly unlikely).
1306 if( (fcChip->Registers.my_al_pa & 0xFF) !=
1307 ((fcChip->Registers.rcv_al_pa.value >> 16) &0xFF) )
1310 // printk(" #our HBA port_id changed!# "); // FC port_id changed!!
1312 pLoggedInPort = &fcChip->fcPorts;
1313 while( pLoggedInPort ) // for all ports which are expecting
1314 // PDISC after the next LIP, set the
1317 pLoggedInPort->pdisc = FALSE;
1318 pLoggedInPort->prli = FALSE;
1319 pLoggedInPort = pLoggedInPort->pNextPort;
1320 } // ... all Previously known ports checked
1322 // when the port_id changes, we must terminate
1323 // all open exchanges.
1324 cpqfcTSTerminateExchange( cpqfcHBAdata, NULL, PORTID_CHANGED);
1328 // Replace the entire 24-bit port_id. We only know the
1329 // lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
1330 // we'll get the upper 16-bits from the FLOGI ACC frame.
1331 // If someone plugs into Fabric switch, we'll do FLOGI and
1332 // get full 24-bit port_id; someone could then remove and
1333 // hot-plug us into a dumb hub. If we send a 24-bit PLOGI
1334 // to a "private" loop device, it might blow up.
1335 // Consequently, we force the upper 16-bits of port_id to
1336 // be re-set on every LinkUp transition
1337 fcChip->Registers.my_al_pa =
1338 (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
1341 // copy frame manager status to unused ULONG slot
1342 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
1343 fcChip->Registers.my_al_pa; // (for debugging)
1345 // for TachLite, we need to write the acquired al_pa
1346 // back into the FMconfig register, because after
1347 // first initialization, the AQ (prev. acq.) bit gets
1348 // set, causing TL FM to use the AL_PA field in FMconfig.
1349 // (In Tachyon, FM writes the acquired AL_PA for us.)
1350 ulBuff = readl( fcChip->Registers.FMconfig.address);
1351 ulBuff &= 0x00ffffffL; // mask out current al_pa
1352 ulBuff |= ( fcChip->Registers.my_al_pa << 24 ); // or in acq. al_pa
1353 fcChip->Registers.FMconfig.value = ulBuff; // copy it back
1354 writel( fcChip->Registers.FMconfig.value, // put in TachLite
1355 fcChip->Registers.FMconfig.address);
1359 printk("#LUp %Xh, FMstat 0x%08X#",
1360 fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
1363 // also set the WRITE-ONLY My_ID Register (for Fabric
1365 writel( fcChip->Registers.my_al_pa,
1366 fcChip->Registers.ReMapMemBase +TL_MEM_TACH_My_ID);
1369 fcChip->fcStats.linkUp++;
1371 // reset TL statistics counters
1372 // (we ignore these error counters
1373 // while link is down)
1374 ulBuff = // just reset TL's counter
1375 readl( fcChip->Registers.FMLinkStatus1.address);
1377 ulBuff = // just reset TL's counter
1378 readl( fcChip->Registers.FMLinkStatus2.address);
1380 // for initiator, need to start verifying ports (e.g. PDISC)
1387 CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachlite, if Link OK
1389 // Tachyon creates an interesting problem for us on LILP frames.
1390 // Instead of writing the incoming LILP frame into the SFQ before
1391 // indicating LINK UP (the actual order of events), Tachyon tells
1392 // us LINK UP, and later us the LILP. So we delay, then examine the
1393 // IMQ for an Inbound CM (x04); if found, we can set
1394 // LINKACTIVE after processing the LILP. Otherwise, just proceed.
1395 // Since Tachyon imposes this time delay (and doesn't tell us
1396 // what it is), we have to impose a delay before "Peeking" the IMQ
1397 // for Tach hardware (DMA) delivery.
1398 // Processing LILP is required by SANMark
1399 udelay( 1000); // microsec delay waiting for LILP (if it comes)
1400 if( PeekIMQEntry( fcChip, ELS_LILP_FRAME) )
1401 { // found SFQ LILP, which will post LINKACTIVE
1402 // printk("skipping LINKACTIVE post\n");
1406 cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, ulFibreFrame);
1411 // ******* Set Fabric Login indication ********
1412 if( fcChip->Registers.FMstatus.value & 0x2000 )
1414 printk(" #Fabric# ");
1415 fcChip->Options.fabric = 1;
1418 fcChip->Options.fabric = 0;
1422 // ******* LIP(F8,x) or BAD AL_PA? ********
1423 if( fcChip->Registers.FMstatus.value & 0x30000L )
1425 // copy the error AL_PAs
1426 fcChip->Registers.rcv_al_pa.value =
1427 readl(fcChip->Registers.rcv_al_pa.address);
1430 if( fcChip->Registers.FMstatus.value & 0x10000L )
1432 PFC_LOGGEDIN_PORT pLoggedInPort;
1434 // copy "BAD" al_pa field
1435 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
1436 (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
1438 pLoggedInPort = fcFindLoggedInPort( fcChip,
1439 NULL, // DON'T search Scsi Nexus
1440 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1], // port id
1441 NULL, // DON'T search linked list for FC WWN
1442 NULL); // DON'T care about end of list
1446 // Just in case we got this BAD_ALPA because a device
1447 // quietly disappeared (can happen on non-managed hubs such
1448 // as the Vixel Rapport 1000),
1449 // do an Implicit Logout. We never expect this on a Logged
1450 // in port (but do expect it on port discovery).
1451 // (As a reasonable alternative, this could be changed to
1452 // simply start the implicit logout timer, giving the device
1453 // several seconds to "come back".)
1455 printk(" #BAD alpa %Xh# ",
1456 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
1457 cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
1461 if( fcChip->Registers.FMstatus.value & 0x20000L )
1463 // for debugging, copy al_pa field
1464 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] =
1465 (fcChip->Registers.rcv_al_pa.value & 0xffL);
1466 // get the other port's al_pa
1467 // (one that sent LIP(F8,?) )
1471 // Elastic store err
1472 if( fcChip->Registers.FMstatus.value & 0x400L )
1474 // don't count e-s if loop is down!
1475 if( !(USHORT)(fcChip->Registers.FMstatus.value & 0x80) )
1476 fcChip->fcStats.e_stores++;
1483 case INBOUND_FCP_XCHG_COMPLETION: // 0x0C
1486 // On Tachlite TL/TS, we get this message when the data phase
1487 // of a SEST inbound transfer is complete. For example, if a WRITE command
1488 // was received with OX_ID 0, we might respond with XFER_RDY with
1489 // RX_ID 8001. This would start the SEST controlled data phases. When
1490 // all data frames are received, we get this inbound completion. This means
1491 // we should send a status frame to complete the status phase of the
1492 // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
1494 // See Outbound CM discussion of x_IDs
1496 // Get SEST index (x_ID)
1497 // x_ID out of range, return (err condition)
1498 // set status bits from 2nd dword
1499 // free transactionID & SEST entry
1500 // call fcComplete with transactionID & status
1502 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
1503 x_ID = ulBuff & 0x7fffL; // lower 14 bits SEST_Index/Trans_ID
1504 // (mask out MSB "direction" bit)
1505 // Range check CM OX/RX_ID value...
1506 if( x_ID < TACH_SEST_LEN ) // don't go beyond SEST array space
1509 //#define FCP_COMPLETION_DBG 1
1510 #ifdef FCP_COMPLETION_DBG
1511 printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n",
1512 x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
1514 if( ulBuff & 0x08000000L ) // RPC -Response Phase Complete - or -
1515 // time to send response frame?
1516 RPCset = 1; // (SEST transaction)
1519 // set the status for this Inbound SCSI transaction's ID
1521 if( ulBuff & 0x70000000L ) // any errs?
1524 if( ulBuff & 0x40000000L )
1525 dwStatus |= LINKFAIL_RX;
1527 if( ulBuff & 0x20000000L )
1528 dwStatus |= COUNT_ERROR;
1530 if( ulBuff & 0x10000000L )
1531 dwStatus |= OVERFLOW;
1535 // FCP transaction done - copy status
1536 Exchanges->fcExchange[ x_ID ].status = dwStatus;
1539 // Did the exchange get an FCP-RSP response frame?
1540 // (Note the little endian/big endian FC payload difference)
1542 if( RPCset ) // SEST transaction Response frame rec'd
1544 // complete the command in our driver...
1545 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev,fcChip, x_ID);
1549 else // ("target" logic)
1551 // Tachlite says all data frames have been received - now it's time
1552 // to analyze data transfer (successful?), then send a response
1553 // frame for this exchange
1555 ulFibreFrame[0] = x_ID; // copy for later reference
1557 // if this was a TWE, we have to send satus response
1558 if( Exchanges->fcExchange[ x_ID].type == SCSI_TWE )
1560 // fcPutScsiQue( cpqfcHBAdata,
1561 // NEED_FCP_RSP, ulFibreFrame); // (ulFibreFrame not used here)
1565 else // ERROR CONDITION! bogus x_ID in completion message
1567 printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
1575 case INBOUND_SCSI_DATA_COMMAND:
1576 case BAD_SCSI_FRAME:
1577 case INB_SCSI_STATUS_COMPLETION:
1578 case BUFFER_PROCESSED_COMPLETION:
1582 // Tachyon is producing;
1584 fcChip->IMQ->consumerIndex++; // increment OUR consumerIndex
1585 if( fcChip->IMQ->consumerIndex >= IMQ_LEN)// check for rollover
1586 fcChip->IMQ->consumerIndex = 0L; // reset it
1589 if( fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex )
1590 { // all Messages are processed -
1591 iStatus = 0; // no more messages to process
1595 iStatus = 1; // more messages to process
1597 // update TachLite's ConsumerIndex... (clears INTA_L)
1598 // NOTE: according to TL/TS UG, the
1599 // "host must return completion messages in sequential order".
1600 // Does this mean one at a time, in the order received? We
1603 writel( fcChip->IMQ->consumerIndex,
1604 (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
1607 printk("Process IMQ: writing consumer ndx %d\n ",
1608 fcChip->IMQ->consumerIndex);
1609 printk("PI %X, CI %X\n",
1610 fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex );
1618 // hmmm... why did we get interrupted/called with no message?
1619 iStatus = -1; // nothing to process
1621 printk("Process IMQ: no message PI %Xh CI %Xh",
1622 fcChip->IMQ->producerIndex,
1623 fcChip->IMQ->consumerIndex);
1627 LEAVE("ProcessIMQEntry");
1636 // This routine initializes Tachyon according to the following
1637 // options (opcode1):
1638 // 1 - RESTART Tachyon, simulate power on condition by shutting
1639 // down laser, resetting the hardware, de-allocating all buffers;
1641 // 2 - Config Tachyon / PCI registers;
1643 // 3 - Allocating memory and setting Tachyon queues (write Tachyon regs);
1645 // 4 - Config frame manager registers, initialize, turn on laser
1648 // -1 on fatal error
1651 int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2)
1653 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
1654 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1657 int iStatus=-1; // assume failure
1659 ENTER("InitializeTachLite");
1661 // verify board's base address (sanity check)
1663 if( !fcChip->Registers.ReMapMemBase) // NULL address for card?
1664 return -1; // FATAL error!
1670 case 1: // restore hardware to power-on (hard) restart
1673 iStatus = fcChip->ResetTachyon(
1674 cpqfcHBAdata, opcode2); // laser off, reset hardware
1675 // de-allocate aligned buffers
1678 /* TBD // reset FC link Q (producer and consumer = 0)
1679 fcLinkQReset(cpqfcHBAdata);
1686 case 2: // Config PCI/Tachyon registers
1687 // NOTE: For Tach TL/TS, bit 31 must be set to 1. For TS chips, a read
1688 // of bit 31 indicates state of M66EN signal; if 1, chip may run at
1689 // 33-66MHz (see TL/TS UG, pg 159)
1691 ulBuff = 0x80000000; // TachLite Configuration Register
1693 writel( ulBuff, fcChip->Registers.TYconfig.address);
1694 // ulBuff = 0x0147L; // CpqTs PCI CFGCMD register
1695 // WritePCIConfiguration( fcChip->Backplane.bus,
1696 // fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4);
1697 // ulBuff = 0x0L; // test!
1698 // ReadPCIConfiguration( fcChip->Backplane.bus,
1699 // fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4);
1701 // read back for reference...
1702 fcChip->Registers.TYconfig.value =
1703 readl( fcChip->Registers.TYconfig.address );
1705 // what is the PCI bus width?
1706 pci_read_config_byte( cpqfcHBAdata->PciDev,
1707 0x43, // PCIMCTR offset
1710 fcChip->Registers.PCIMCTR = bBuff;
1712 // set string identifying the chip on the circuit board
1714 fcChip->Registers.TYstatus.value =
1715 readl( fcChip->Registers.TYstatus.address);
1718 // Now that we are supporting multiple boards, we need to change
1719 // this logic to check for PCI vendor/device IDs...
1720 // for now, quick & dirty is simply checking Chip rev
1722 ULONG RevId = (fcChip->Registers.TYstatus.value &0x3E0)>>5;
1723 UCHAR Minor = (UCHAR)(RevId & 0x3);
1724 UCHAR Major = (UCHAR)((RevId & 0x1C) >>2);
1726 /* printk(" HBA Tachyon RevId %d.%d\n", Major, Minor); */
1727 if( (Major == 1) && (Minor == 2) )
1729 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
1732 else if( (Major == 1) && (Minor == 3) )
1734 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
1736 else if( (Major == 2) && (Minor == 1) )
1738 sprintf( cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
1741 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
1746 case 3: // allocate mem, set Tachyon Que registers
1747 iStatus = CpqTsCreateTachLiteQues( cpqfcHBAdata, opcode2);
1752 // now that the Queues exist, Tach can DMA to them, so
1753 // we can begin processing INTs
1754 // INTEN register - enable INT (TachLite interrupt)
1755 writeb( 0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
1758 case 4: // Config Fame Manager, Init Loop Command, laser on
1760 // L_PORT or loopback
1761 // depending on Options
1762 iStatus = CpqTsInitializeFrameManager( fcChip,0 );
1765 // failed to initialize Frame Manager
1772 LEAVE("InitializeTachLite");
1780 // Depending on the type of platform memory allocation (e.g. dynamic),
1781 // it's probably best to free memory in opposite order as it was allocated.
1782 // Order of allocation: see other function
1785 int CpqTsDestroyTachLiteQues( void *pHBA, int opcode)
1787 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
1788 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1789 USHORT i, iStatus=0;
1790 void* vPtr; // mem Align manager sets this to the freed address on success
1791 unsigned long ulPtr; // for 64-bit pointer cast (e.g. Alpa machine)
1792 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1795 ENTER("DestroyTachLiteQues");
1799 // search out and free Pool for Extended S/G list pages
1801 for( i=0; i < TACH_SEST_LEN; i++) // for each exchange
1803 // It's possible that extended S/G pages were allocated, mapped, and
1804 // not cleared due to error conditions or O/S driver termination.
1805 // Make sure they're all gone.
1806 if (Exchanges->fcExchange[i].Cmnd != NULL)
1807 cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd,
1808 fcChip, i); // undo DMA mappings.
1810 for (j=fcChip->SEST->sgPages[i] ; j != NULL ; j = next) {
1814 fcChip->SEST->sgPages[i] = NULL;
1816 ulPtr = (unsigned long)fcChip->SEST;
1817 vPtr = fcMemManager( cpqfcHBAdata->PciDev,
1818 &cpqfcHBAdata->dynamic_mem[0],
1819 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1820 fcChip->SEST = 0L; // null invalid ptr
1823 printk("SEST mem not freed\n");
1831 ulPtr = (unsigned long)fcChip->SFQ;
1832 vPtr = fcMemManager( cpqfcHBAdata->PciDev,
1833 &cpqfcHBAdata->dynamic_mem[0],
1834 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1835 fcChip->SFQ = 0L; // null invalid ptr
1838 printk("SFQ mem not freed\n");
1846 // clear Indexes to show empty Queue
1847 fcChip->IMQ->producerIndex = 0;
1848 fcChip->IMQ->consumerIndex = 0;
1850 ulPtr = (unsigned long)fcChip->IMQ;
1851 vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
1852 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1853 fcChip->IMQ = 0L; // null invalid ptr
1856 printk("IMQ mem not freed\n");
1861 if( fcChip->ERQ ) // release memory blocks used by the queues
1863 ulPtr = (unsigned long)fcChip->ERQ;
1864 vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
1865 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1866 fcChip->ERQ = 0L; // null invalid ptr
1869 printk("ERQ mem not freed\n");
1874 // free up the primary EXCHANGES struct and Link Q
1875 cpqfc_free_dma_consistent(cpqfcHBAdata);
1877 LEAVE("DestroyTachLiteQues");
1879 return iStatus; // non-zero (failed) if any memory not freed
1886 // The SFQ is an array with SFQ_LEN length, each element (QEntry)
1887 // with eight 32-bit words. TachLite places incoming FC frames (i.e.
1888 // a valid FC frame with our AL_PA ) in contiguous SFQ entries
1889 // and sends a completion message telling the host where the frame is
1891 // This function copies the current (or oldest not-yet-processed) QEntry to
1892 // a caller's contiguous buffer and updates the Tachyon chip's consumer index
1895 // An FC frame may consume one or many SFQ entries. We know the total
1896 // length from the completion message. The caller passes a buffer large
1897 // enough for the complete message (max 2k).
1899 static void CpqTsGetSFQEntry(
1902 ULONG *ulDestPtr, // contiguous destination buffer
1905 ULONG total_bytes=0;
1906 ULONG consumerIndex = fcChip->SFQ->consumerIndex;
1908 // check passed copy of SFQ producer index -
1909 // is a new message waiting for us?
1910 // equal indexes means SFS is copied
1912 while( producerNdx != consumerIndex )
1913 { // need to process message
1914 total_bytes += 64; // maintain count to prevent writing past buffer
1915 // don't allow copies over Fibre Channel defined length!
1916 if( total_bytes <= 2048 )
1919 &fcChip->SFQ->QEntry[consumerIndex],
1920 64 ); // each SFQ entry is 64 bytes
1921 ulDestPtr += 16; // advance pointer to next 64 byte block
1923 // Tachyon is producing,
1924 // and we are consuming
1926 if( ++consumerIndex >= SFQ_LEN)// check for rollover
1927 consumerIndex = 0L; // reset it
1930 // if specified, update the Tachlite chip ConsumerIndex...
1933 fcChip->SFQ->consumerIndex = consumerIndex;
1934 writel( fcChip->SFQ->consumerIndex,
1935 fcChip->Registers.SFQconsumerIndex.address);
1941 // TachLite routinely freezes it's core ques - Outbound FIFO, Inbound FIFO,
1942 // and Exchange Request Queue (ERQ) on error recover -
1943 // (e.g. whenever a LIP occurs). Here
1944 // we routinely RESUME by clearing these bits, but only if the loop is up
1945 // to avoid ERROR IDLE messages forever.
1947 void CpqTsUnFreezeTachlite( void *pChip, int type )
1949 PTACHYON fcChip = (PTACHYON)pChip;
1950 fcChip->Registers.TYcontrol.value =
1951 readl(fcChip->Registers.TYcontrol.address);
1953 // (bit 4 of value is GBIC LASER)
1954 // if we 'unfreeze' the core machines before the loop is healthy
1955 // (i.e. FLT, OS, LS failure bits set in FMstatus)
1956 // we can get 'error idle' messages forever. Verify that
1957 // FMstatus (Link Status) is OK before unfreezing.
1959 if( !(fcChip->Registers.FMstatus.value & 0x07000000L) && // bits clear?
1960 !(fcChip->Registers.FMstatus.value & 0x80 )) // Active LPSM?
1962 fcChip->Registers.TYcontrol.value &= ~0x300L; // clear FEQ, FFA
1963 if( type == 1 ) // unfreeze ERQ only
1965 // printk("Unfreezing ERQ\n");
1966 fcChip->Registers.TYcontrol.value |= 0x10000L; // set REQ
1968 else // unfreeze both ERQ and FCP-ASSIST (SEST)
1970 // printk("Unfreezing ERQ & FCP-ASSIST\n");
1972 // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
1973 fcChip->Registers.TYcontrol.value |= 0x70000L; // set ROF, RIF, REQ
1976 writel( fcChip->Registers.TYcontrol.value,
1977 fcChip->Registers.TYcontrol.address);
1980 // readback for verify (TachLite still frozen?)
1981 fcChip->Registers.TYstatus.value =
1982 readl(fcChip->Registers.TYstatus.address);
1986 // Whenever an FC Exchange Abort is required, we must manipulate the
1987 // Host/Tachyon shared memory SEST table. Before doing this, we
1988 // must freeze Tachyon, which flushes certain buffers and ensure we
1989 // can manipulate the SEST without contention.
1990 // This freeze function will result in FCP & ERQ FROZEN completion
1991 // messages (per argument "type").
1993 void CpqTsFreezeTachlite( void *pChip, int type )
1995 PTACHYON fcChip = (PTACHYON)pChip;
1996 fcChip->Registers.TYcontrol.value =
1997 readl(fcChip->Registers.TYcontrol.address);
1999 //set FFA, FEQ - freezes SCSI assist and ERQ
2000 if( type == 1) // freeze ERQ only
2001 fcChip->Registers.TYcontrol.value |= 0x100L; // (bit 4 is laser)
2002 else // freeze both FCP assists (SEST) and ERQ
2003 fcChip->Registers.TYcontrol.value |= 0x300L; // (bit 4 is laser)
2005 writel( fcChip->Registers.TYcontrol.value,
2006 fcChip->Registers.TYcontrol.address);
2013 // TL has two Frame Manager Link Status Registers, with three 8-bit
2014 // fields each. These eight bit counters are cleared after each read,
2015 // so we define six 32-bit accumulators for these TL counters. This
2016 // function breaks out each 8-bit field and adds the value to the existing
2017 // sum. (s/w counters cleared independently)
2019 void fcParseLinkStatusCounters(PTACHYON fcChip)
2025 // The BB0 timer usually increments when TL is initialized, resulting
2026 // in an initially bogus count. If our own counter is ZERO, it means we
2027 // are reading this thing for the first time, so we ignore the first count.
2028 // Also, reading the register does not clear it, so we have to keep an
2029 // additional static counter to detect rollover (yuk).
2031 if( fcChip->fcStats.lastBB0timer == 0L) // TL was reset? (ignore 1st values)
2033 // get TL's register counter - the "last" count
2034 fcChip->fcStats.lastBB0timer =
2035 fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
2037 else // subsequent pass - check for rollover
2040 ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
2041 if( fcChip->fcStats.lastBB0timer > ulBuff ) // rollover happened
2043 // counter advanced to max...
2044 fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
2045 fcChip->fcStats.BB0_Timer += ulBuff; // plus some more
2049 else // no rollover -- more counts or no change
2051 fcChip->fcStats.BB0_Timer += (ulBuff - fcChip->fcStats.lastBB0timer);
2055 fcChip->fcStats.lastBB0timer = ulBuff;
2060 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 24);
2061 fcChip->fcStats.LossofSignal += bBuff;
2063 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 16);
2064 fcChip->fcStats.BadRXChar += bBuff;
2066 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 8);
2067 fcChip->fcStats.LossofSync += bBuff;
2070 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 24);
2071 fcChip->fcStats.Rx_EOFa += bBuff;
2073 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 16);
2074 fcChip->fcStats.Dis_Frm += bBuff;
2076 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 8);
2077 fcChip->fcStats.Bad_CRC += bBuff;
2081 void cpqfcTSClearLinkStatusCounters(PTACHYON fcChip)
2083 ENTER("ClearLinkStatusCounters");
2084 memset( &fcChip->fcStats, 0, sizeof( FCSTATS));
2085 LEAVE("ClearLinkStatusCounters");
2092 // The following function reads the I2C hardware to get the adapter's
2093 // World Wide Name (WWN).
2094 // If the WWN is "500805f1fadb43e8" (as printed on the card), the
2095 // Tachyon WWN_hi (32-bit) register is 500805f1, and WWN_lo register
2097 // In the NVRAM, the bytes appear as:
2109 // In the Fibre Channel (Big Endian) format, the FC-AL LISM frame will
2110 // be correctly loaded by Tachyon silicon. In the login payload, bytes
2111 // must be correctly swapped for Big Endian format.
2113 int CpqTsReadWriteWWN( PVOID pChip, int Read)
2115 PTACHYON fcChip = (PTACHYON)pChip;
2116 #define NVRAM_SIZE 512
2117 unsigned short i, count = NVRAM_SIZE;
2118 UCHAR nvRam[NVRAM_SIZE], WWNbuf[8];
2120 int iStatus=-1; // assume failure
2123 ENTER("ReadWriteWWN");
2124 // Now try to read the WWN from the adapter's NVRAM
2126 if( Read ) // READing NVRAM WWN?
2128 ulBuff = cpqfcTS_ReadNVRAM( fcChip->Registers.TYstatus.address,
2129 fcChip->Registers.TYcontrol.address,
2132 if( ulBuff ) // NVRAM read successful?
2134 iStatus = 0; // success!
2136 // for engineering/ prototype boards, the data may be
2137 // invalid (GIGO, usually all "FF"); this prevents the
2138 // parse routine from working correctly, which means
2139 // nothing will be written to our passed buffer.
2141 WWNoffset = cpqfcTS_GetNVRAM_data( WWNbuf, nvRam );
2143 if( !WWNoffset ) // uninitialized NVRAM -- copy bytes directly
2145 printk( "CAUTION: Copying NVRAM data on fcChip\n");
2146 for( i= 0; i < 8; i++)
2147 WWNbuf[i] = nvRam[i +0x2f]; // dangerous! some formats won't work
2150 fcChip->Registers.wwn_hi = 0L;
2151 fcChip->Registers.wwn_lo = 0L;
2152 for( i=0; i<4; i++) // WWN bytes are big endian in NVRAM
2155 ulBuff = (ULONG)(WWNbuf[i]) << (8 * (3-i));
2156 fcChip->Registers.wwn_hi |= ulBuff;
2158 for( i=0; i<4; i++) // WWN bytes are big endian in NVRAM
2161 ulBuff = (ULONG)(WWNbuf[i+4]) << (8 * (3-i));
2162 fcChip->Registers.wwn_lo |= ulBuff;
2168 printk( "cpqfcTS: NVRAM read failed\n");
2176 // NOTE: WRITE not supported & not used in released driver.
2179 printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
2182 LEAVE("ReadWriteWWN");
2190 // The following function reads or writes the entire "NVRAM" contents of
2191 // the I2C hardware (i.e. the NM24C03). Note that HP's 5121A (TS 66Mhz)
2192 // adapter does not use the NM24C03 chip, so this function only works on
2193 // Compaq's adapters.
2195 int CpqTsReadWriteNVRAM( PVOID pChip, PVOID buf, int Read)
2197 PTACHYON fcChip = (PTACHYON)pChip;
2198 #define NVRAM_SIZE 512
2200 UCHAR *ucPtr = buf; // cast caller's void ptr to UCHAR array
2201 int iStatus=-1; // assume failure
2204 if( Read ) // READing NVRAM?
2206 ulBuff = cpqfcTS_ReadNVRAM( // TRUE on success
2207 fcChip->Registers.TYstatus.address,
2208 fcChip->Registers.TYcontrol.address,
2209 256, // bytes to write
2210 ucPtr ); // source ptr
2214 iStatus = 0; // success
2218 printk( "CAUTION: NVRAM read failed\n");
2223 else // WRITING NVRAM
2226 printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");