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 #error This is too much stack
611 ULONG ulFibreFrame[2048/4]; // max DWORDS in incoming FC Frame
612 USHORT SFQpi = (USHORT)(fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
614 CpqTsGetSFQEntry( fcChip,
615 SFQpi, // SFQ producer ndx
616 ulFibreFrame, // contiguous dest. buffer
617 FALSE); // DON'T update chip--this is a "lookahead"
619 fchs = (TachFCHDR_GCMND*)&ulFibreFrame;
620 if( fchs->pl[0] == ELS_LILP_FRAME)
622 return 1; // found the LILP frame!
632 case OUTBOUND_COMPLETION:
633 if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00 )
637 if( fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L )
638 return 1; // found OCM error
648 return 0; // failed to find "type"
652 static void SetTachTOV( CPQFCHBA* cpqfcHBAdata)
654 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
657 // 0x0065 = 100ms for RT_TOV
658 // 0x01f5 = 500ms for ED_TOV
659 // 0x07d1 = 2000ms for ED_TOV
661 // SANMark Level 1 requires an "initialization backoff"
662 // (See "SANMark Test Suite Level 1":
663 // initialization_timeout.fcal.SANMark-1.fc)
664 // We have to use 2sec, 24sec, then 128sec when login/
665 // port discovery processes fail to complete.
667 // when port discovery completes (logins done), we set
668 // ED_TOV to 500ms -- this is the normal operational case
669 // On the first Link Down, we'll move to 2 secs (7D1 ms)
670 if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x1f5)
671 fcChip->Registers.ed_tov.value = 0x006507D1;
673 // If we get another LST after we moved TOV to 2 sec,
674 // increase to 24 seconds (5DC1 ms) per SANMark!
675 else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x7D1)
676 fcChip->Registers.ed_tov.value = 0x00655DC1;
678 // If we get still another LST, set the max TOV (Tachyon
679 // has only 16 bits for ms timer, so the max is 65.5 sec)
680 else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x5DC1)
681 fcChip->Registers.ed_tov.value = 0x0065FFFF;
683 writel( fcChip->Registers.ed_tov.value,
684 (fcChip->Registers.ed_tov.address));
685 // keep the same 2sec LP_TOV
686 writel( 0x07D00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
690 // The IMQ is an array with IMQ_LEN length, each element (QEntry)
691 // with eight 32-bit words. Tachyon PRODUCES a QEntry with each
692 // message it wants to send to the host. The host CONSUMES IMQ entries
694 // This function copies the current
695 // (or oldest not-yet-processed) QEntry to
696 // the caller, clears/ re-enables the interrupt, and updates the
697 // (Host) Consumer Index.
699 // 0 message processed, none remain (producer and consumer
701 // 1 message processed, more messages remain
702 // -1 no message processed - none were available to process
704 // TL/TS UG specifices that the following actions for
706 // 1. read PCI Interrupt Status register (0xff)
707 // 2. all IMQ messages should be processed before writing the
708 // IMQ consumer index.
711 int CpqTsProcessIMQEntry(void *host)
713 struct Scsi_Host *HostAdapter = (struct Scsi_Host *)host;
714 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
715 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
716 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
718 USHORT i, RPCset, DPCset;
720 ULONG ulBuff, dwStatus;
721 TachFCHDR_GCMND* fchs;
722 #error This is too much stack
723 ULONG ulFibreFrame[2048/4]; // max number of DWORDS in incoming Fibre Frame
724 UCHAR ucInboundMessageType; // Inbound CM, dword 3 "type" field
726 ENTER("ProcessIMQEntry");
729 // check TachLite's IMQ producer index -
730 // is a new message waiting for us?
731 // equal indexes means empty que
733 if( fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex )
734 { // need to process message
738 printk("PI %X, CI %X type: %X\n",
739 fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex,
740 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
742 // Examine Completion Messages in IMQ
744 switch( (UCHAR)(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type
747 case OUTBOUND_COMPLETION:
750 // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
751 // (starting at 0), and SFS entries (starting at
752 // SEST_LEN -- outside the SEST space).
754 // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
755 // range check - x_ID
756 // if x_ID outside 'Transactions' length, error - exit
757 // if any OCM error, copy error status to Exchange slot
758 // if FCP ASSIST transaction (x_ID within SEST),
759 // call fcComplete (to App)
763 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
764 x_ID = ulBuff & 0x7fffL; // lower 14 bits SEST_Index/Trans_ID
765 // Range check CM OX/RX_ID value...
766 if( x_ID < TACH_MAX_XID ) // don't go beyond array space
770 if( ulBuff & 0x20000000L ) // RPC -Response Phase Complete?
771 RPCset = 1; // (SEST transactions only)
775 if( ulBuff & 0x40000000L ) // DPC -Data Phase Complete?
776 DPCset = 1; // (SEST transactions only)
779 // set the status for this Outbound transaction's ID
781 if( ulBuff & 0x10000000L ) // SPE? (SEST Programming Error)
782 dwStatus |= SESTPROG_ERR;
784 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
785 if( ulBuff & 0x7a000000L ) // any other errs?
787 if( ulBuff & 0x40000000L )
788 dwStatus |= INV_ENTRY;
789 if( ulBuff & 0x20000000L )
790 dwStatus |= FRAME_TO; // FTO
791 if( ulBuff & 0x10000000L )
792 dwStatus |= HOSTPROG_ERR;
793 if( ulBuff & 0x08000000L )
794 dwStatus |= LINKFAIL_TX;
795 if( ulBuff & 0x02000000L )
796 dwStatus |= ABORTSEQ_NOTIFY; // ASN
800 if( dwStatus ) // any errors?
802 // set the Outbound Completion status
803 Exchanges->fcExchange[ x_ID ].status |= dwStatus;
805 // if this Outbound frame was for a SEST entry, automatically
806 // reque it in the case of LINKFAIL (it will restart on PDISC)
807 if( x_ID < TACH_SEST_LEN )
810 printk(" #OCM error %Xh x_ID %X# ",
813 Exchanges->fcExchange[x_ID].timeOut = 30000; // seconds default
816 // We Q ABTS for each exchange.
817 // NOTE: We can get FRAME_TO on bad alpa (device gone). Since
818 // bad alpa is reported before FRAME_TO, examine the status
819 // flags to see if the device is removed. If so, DON'T
820 // post an ABTS, since it will be terminated by the bad alpa
822 if( dwStatus & FRAME_TO ) // check for device removed...
824 if( !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) )
826 // presumes device is still there: send ABTS.
828 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
831 else // Abort all other errors
833 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
836 // if the HPE bit is set, we have to CLose the LOOP
837 // (see TL/TS UG, pg. 239)
839 if( dwStatus &= HOSTPROG_ERR )
840 // set CL bit (see TL/TS UG, pg. 172)
841 writel( 4, fcChip->Registers.FMcontrol.address);
844 // NOTE: we don't necessarily care about ALL completion messages...
845 // SCSI resp. complete OR
846 if( ((x_ID < TACH_SEST_LEN) && RPCset)||
847 (x_ID >= TACH_SEST_LEN) ) // non-SCSI command
849 // exchange done; complete to upper levels with status
850 // (if necessary) and free the exchange slot
853 if( x_ID >= TACH_SEST_LEN ) // Link Service Outbound frame?
854 // A Request or Reply has been sent
855 { // signal waiting WorkerThread
857 up( cpqfcHBAdata->TYOBcomplete); // frame is OUT of Tach
859 // WorkerThread will complete Xchng
861 else // X_ID is for FCP assist (SEST)
864 // fcCompleteExchange( fcChip, x_ID); // TRE completed
868 else // ERROR CONDITION! bogus x_ID in completion message
871 printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
877 // Load the Frame Manager's error counters. We check them here
878 // because presumably the link is up and healthy enough for the
879 // counters to be meaningful (i.e., don't check them while loop
881 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
882 readl(fcChip->Registers.FMLinkStatus1.address);
884 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
885 readl(fcChip->Registers.FMLinkStatus2.address);
888 fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
893 case ERROR_IDLE_COMPLETION: // TachLite Error Idle...
895 // We usually get this when the link goes down during heavy traffic.
896 // For now, presume that if SEST Exchanges are open, we will
897 // get this as our cue to INVALIDATE all SEST entries
898 // (and we OWN all the SEST entries).
899 // See TL/TS UG, pg. 53
901 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
904 // Does this VALid SEST entry need to be invalidated for Abort?
905 fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
908 CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachyon, if Link OK
913 case INBOUND_SFS_COMPLETION: //0x04
914 // NOTE! we must process this SFQ message to avoid SFQ filling
915 // up and stopping TachLite. Incoming commands are placed here,
916 // as well as 'unknown' frames (e.g. LIP loop position data)
917 // write this CM's producer index to global...
919 // Type: 0 - reserved
920 // 1 - Unassisted FCP
926 fcChip->SFQ->producerIndex = (USHORT)
927 (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
930 ucInboundMessageType = 0; // default to useless frame
932 // we can only process two Types: 1, Unassisted FCP, and 3, Unknown
933 // Also, we aren't interested in processing frame fragments
934 // so don't Que anything with 'LKF' bit set
935 if( !(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2]
936 & 0x40000000) ) // 'LKF' link failure bit clear?
938 ucInboundMessageType = (UCHAR) // ICM DWord3, "Type"
939 (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
943 fcChip->fcStats.linkFailRX++;
944 // printk("LKF (link failure) bit set on inbound message\n");
947 // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
949 fcChip, // i.e. this Device Object
950 (USHORT)fcChip->SFQ->producerIndex, // SFQ producer ndx
951 ulFibreFrame, TRUE); // contiguous destination buffer, update chip
953 // analyze the incoming frame outside the INT handler...
956 if( ucInboundMessageType == 1 )
958 fchs = (TachFCHDR_GCMND*)ulFibreFrame; // cast to examine IB frame
959 // don't fill up our Q with garbage - only accept FCP-CMND
961 if( (fchs->d_id & 0xFF000000) == 0x06000000 ) // CMND
963 // someone sent us a SCSI command
965 // fcPutScsiQue( cpqfcHBAdata,
966 // SFQ_UNASSISTED_FCP, ulFibreFrame);
968 else if( ((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status)
969 (fchs->d_id & 0xFF000000) == 0x05000000 ) // XRDY
972 // Unfortunately, ABTS requires a Freeze on the chip so
973 // we can modify the shared memory SEST. When frozen,
974 // any received Exchange frames cannot be processed by
975 // Tachyon, so they will be dumped in here. It is too
976 // complex to attempt the reconstruct these frames in
977 // the correct Exchange context, so we simply seek to
978 // find status or transfer ready frames, and cause the
979 // exchange to complete with errors before the timeout
980 // expires. We use a Linux Scsi Cmnd result code that
981 // causes immediate retry.
984 // Do we have an open exchange that matches this s_id
986 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
988 if( (fchs->s_id & 0xFFFFFF) ==
989 (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF)
991 (fchs->ox_rx_id & 0xFFFF0000) ==
992 (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000) )
994 // printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
995 // simulate the anticipated error - since the
996 // SEST was frozen, frames were lost...
997 Exchanges->fcExchange[ x_ID ].status |= SFQ_FRAME;
999 // presumes device is still there: send ABTS.
1000 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
1008 else if( ucInboundMessageType == 3)
1010 // FC Link Service frames (e.g. PLOGI, ACC) come in here.
1011 cpqfcTSPutLinkQue( cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame);
1015 else if( ucInboundMessageType == 2 ) // "bad FCP"?
1018 printk("Bad FCP incoming frame discarded\n");
1022 else // don't know this type
1025 printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
1029 // Check the Frame Manager's error counters. We check them here
1030 // because presumably the link is up and healthy enough for the
1031 // counters to be meaningful (i.e., don't check them while loop
1032 // is initializing).
1033 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
1034 readl(fcChip->Registers.FMLinkStatus1.address);
1037 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
1038 readl(fcChip->Registers.FMLinkStatus2.address);
1046 // We get this CM because we issued a freeze
1047 // command to stop outbound frames. We issue the
1048 // freeze command at Link Up time; when this message
1049 // is received, the ERQ base can be switched and PDISC
1050 // frames can be sent.
1053 case ERQ_FROZEN_COMPLETION: // note: expect ERQ followed immediately
1054 // by FCP when freezing TL
1055 fcChip->Registers.TYstatus.value = // read what's frozen
1056 readl(fcChip->Registers.TYstatus.address);
1057 // (do nothing; wait for FCP frozen message)
1059 case FCP_FROZEN_COMPLETION:
1061 fcChip->Registers.TYstatus.value = // read what's frozen
1062 readl(fcChip->Registers.TYstatus.address);
1064 // Signal the kernel thread to proceed with SEST modification
1065 up( cpqfcHBAdata->TachFrozen);
1071 case INBOUND_C1_TIMEOUT:
1080 // In older Tachyons, we 'clear' the internal 'core' interrupt state
1081 // by reading the FMstatus register. In newer TachLite (Tachyon),
1082 // we must WRITE the register
1083 // to clear the condition (TL/TS UG, pg 179)
1084 case FRAME_MGR_INTERRUPT:
1086 PFC_LOGGEDIN_PORT pLoggedInPort;
1088 fcChip->Registers.FMstatus.value =
1089 readl( fcChip->Registers.FMstatus.address );
1091 // PROBLEM: It is possible, especially with "dumb" hubs that
1092 // don't automatically LIP on by-pass of ports that are going
1093 // away, for the hub by-pass process to destroy critical
1094 // ordered sets of a frame. The result of this is a hung LPSM
1095 // (Loop Port State Machine), which on Tachyon results in a
1096 // (default 2 sec) Loop State Timeout (LST) FM message. We
1097 // want to avoid this relatively huge timeout by detecting
1098 // likely scenarios which will result in LST.
1099 // To do this, we could examine FMstatus for Loss of Synchronization
1100 // and/or Elastic Store (ES) errors. Of these, Elastic Store is better
1101 // because we get this indication more quickly than the LOS.
1102 // Not all ES errors are harmfull, so we don't want to LIP on every
1103 // ES. Instead, on every ES, detect whether our LPSM in in one
1104 // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
1105 // or RECEIVED CLOSE. (See TL/TS UG, pg. 181)
1106 // If any of these LPSM states are detected
1107 // in combination with the LIP while LDn is not set,
1108 // send an FM init (LIP F7,F7 for loops)!
1109 // It is critical to the physical link stability NOT to reset (LIP)
1110 // more than absolutely necessary; this is a basic premise of the
1111 // SANMark level 1 spec.
1113 ULONG Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >>4;
1115 if( (fcChip->Registers.FMstatus.value & 0x400) // ElasticStore?
1117 !(fcChip->Registers.FMstatus.value & 0x100) // NOT LDn
1119 !(fcChip->Registers.FMstatus.value & 0x1000)) // NOT LF
1121 if( (Lpsm != 0) || // not MONITORING? or
1122 !(Lpsm & 0x8) )// not already offline?
1124 // now check the particular LST states...
1125 if( (Lpsm == ARBITRATING) || (Lpsm == OPEN) ||
1126 (Lpsm == OPENED) || (Lpsm == XMITTD_CLOSE) ||
1127 (Lpsm == RCVD_CLOSE) )
1129 // re-init the loop before it hangs itself!
1130 printk(" #req FMinit on E-S: LPSM %Xh# ",Lpsm);
1133 fcChip->fcStats.FMinits++;
1134 writel( 6, fcChip->Registers.FMcontrol.address); // LIP
1138 else if( fcChip->Registers.FMstatus.value & 0x40000 ) // LST?
1140 printk(" #req FMinit on LST, LPSM %Xh# ",Lpsm);
1142 fcChip->fcStats.FMinits++;
1143 writel( 6, fcChip->Registers.FMcontrol.address); // LIP
1148 // clear only the 'interrupting' type bits for this REG read
1149 writel( (fcChip->Registers.FMstatus.value & 0xff3fff00L),
1150 fcChip->Registers.FMstatus.address);
1153 // copy frame manager status to unused ULONG slot
1154 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] =
1155 fcChip->Registers.FMstatus.value; // (for debugging)
1158 // Load the Frame Manager's error counters. We check them here
1159 // because presumably the link is up and healthy enough for the
1160 // counters to be meaningful (i.e., don't check them while loop
1161 // is initializing).
1162 fcChip->Registers.FMLinkStatus1.value = // get TL's counter
1163 readl(fcChip->Registers.FMLinkStatus1.address);
1165 fcChip->Registers.FMLinkStatus2.value = // get TL's counter
1166 readl(fcChip->Registers.FMLinkStatus2.address);
1168 // Get FM BB_Credit Zero Reg - does not clear on READ
1169 fcChip->Registers.FMBB_CreditZero.value = // get TL's counter
1170 readl(fcChip->Registers.FMBB_CreditZero.address);
1174 fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
1179 if( fcChip->Registers.FMstatus.value & 0x100L ) // Link DOWN bit
1187 fcChip->fcStats.linkDown++;
1189 SetTachTOV( cpqfcHBAdata); // must set according to SANMark
1191 // Check the ERQ - force it to be "empty" to prevent Tach
1192 // from sending out frames before we do logins.
1195 if( fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex)
1197 // printk("#ERQ PI != CI#");
1198 CpqTsFreezeTachlite( fcChip, 1); // freeze ERQ only
1199 fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
1200 writel( fcChip->ERQ->base,
1201 (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
1202 // re-writing base forces ERQ PI to equal CI
1206 // link down transition occurred -- port_ids can change
1207 // on next LinkUp, so we must invalidate current logins
1208 // (and any I/O in progress) until PDISC or PLOGI/PRLI
1211 pLoggedInPort = &fcChip->fcPorts;
1212 while( pLoggedInPort ) // for all ports which are expecting
1213 // PDISC after the next LIP, set the
1217 if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
1219 pLoggedInPort->LOGO_timer = 3; // we want 2 seconds
1220 // but Timer granularity
1223 // suspend any I/O in progress until
1224 // PDISC received...
1225 pLoggedInPort->prli = FALSE; // block FCP-SCSI commands
1227 pLoggedInPort = pLoggedInPort->pNextPort;
1228 } // ... all Previously known ports checked
1231 // since any hot plugging device may NOT support LILP frames
1232 // (such as early Tachyon chips), clear this flag indicating
1233 // we shouldn't use (our copy of) a LILP map.
1234 // If we receive an LILP frame, we'll set it again.
1235 fcChip->Options.LILPin = 0; // our LILPmap is invalid
1236 cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports!
1238 // also, we want to invalidate (i.e. INITIATOR_ABORT) any
1239 // open Login exchanges, in case the LinkDown happened in the
1240 // middle of logins. It's possible that some ports already
1241 // ACCepted login commands which we have not processed before
1242 // another LinkDown occurred. Any accepted Login exhanges are
1243 // invalidated by LinkDown, even before they are acknowledged.
1244 // It's also possible for a port to have a Queued Reply or Request
1245 // for login which was interrupted by LinkDown; it may come later,
1246 // but it will be unacceptable to us.
1248 // we must scan the entire exchange space, find every Login type
1249 // originated by us, and abort it. This is NOT an abort due to
1250 // timeout, so we don't actually send abort to the other port -
1251 // we just complete it to free up the fcExchange slot.
1253 for( i=TACH_SEST_LEN; i< TACH_MAX_XID; i++)
1254 { // looking for Extended Link Serv.Exchanges
1255 if( Exchanges->fcExchange[i].type == ELS_PDISC ||
1256 Exchanges->fcExchange[i].type == ELS_PLOGI ||
1257 Exchanges->fcExchange[i].type == ELS_PRLI )
1259 // ABORT the exchange!
1261 printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n",
1262 i, Exchanges->fcExchange[i].type,
1263 Exchanges->fcExchange[i].fchs.d_id);
1266 Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
1267 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // abort on LDn
1273 // ################ LINK UP ##################
1274 if( fcChip->Registers.FMstatus.value & 0x200L ) // Link Up bit
1275 { // AL_PA could have changed
1277 // We need the following code, duplicated from LinkDn condition,
1278 // because it's possible for the Tachyon to re-initialize (hard
1279 // reset) without ever getting a LinkDn indication.
1280 pLoggedInPort = &fcChip->fcPorts;
1281 while( pLoggedInPort ) // for all ports which are expecting
1282 // PDISC after the next LIP, set the
1285 if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
1287 pLoggedInPort->LOGO_timer = 3; // we want 2 seconds
1288 // but Timer granularity
1291 // suspend any I/O in progress until
1292 // PDISC received...
1295 pLoggedInPort = pLoggedInPort->pNextPort;
1296 } // ... all Previously known ports checked
1298 // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
1299 fcChip->Registers.rcv_al_pa.value =
1300 readl(fcChip->Registers.rcv_al_pa.address);
1302 // Now, if our acquired address is DIFFERENT from our
1303 // previous one, we are not allow to do PDISC - we
1304 // must go back to PLOGI, which will terminate I/O in
1305 // progress for ALL logged in FC devices...
1306 // (This is highly unlikely).
1308 if( (fcChip->Registers.my_al_pa & 0xFF) !=
1309 ((fcChip->Registers.rcv_al_pa.value >> 16) &0xFF) )
1312 // printk(" #our HBA port_id changed!# "); // FC port_id changed!!
1314 pLoggedInPort = &fcChip->fcPorts;
1315 while( pLoggedInPort ) // for all ports which are expecting
1316 // PDISC after the next LIP, set the
1319 pLoggedInPort->pdisc = FALSE;
1320 pLoggedInPort->prli = FALSE;
1321 pLoggedInPort = pLoggedInPort->pNextPort;
1322 } // ... all Previously known ports checked
1324 // when the port_id changes, we must terminate
1325 // all open exchanges.
1326 cpqfcTSTerminateExchange( cpqfcHBAdata, NULL, PORTID_CHANGED);
1330 // Replace the entire 24-bit port_id. We only know the
1331 // lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
1332 // we'll get the upper 16-bits from the FLOGI ACC frame.
1333 // If someone plugs into Fabric switch, we'll do FLOGI and
1334 // get full 24-bit port_id; someone could then remove and
1335 // hot-plug us into a dumb hub. If we send a 24-bit PLOGI
1336 // to a "private" loop device, it might blow up.
1337 // Consequently, we force the upper 16-bits of port_id to
1338 // be re-set on every LinkUp transition
1339 fcChip->Registers.my_al_pa =
1340 (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
1343 // copy frame manager status to unused ULONG slot
1344 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
1345 fcChip->Registers.my_al_pa; // (for debugging)
1347 // for TachLite, we need to write the acquired al_pa
1348 // back into the FMconfig register, because after
1349 // first initialization, the AQ (prev. acq.) bit gets
1350 // set, causing TL FM to use the AL_PA field in FMconfig.
1351 // (In Tachyon, FM writes the acquired AL_PA for us.)
1352 ulBuff = readl( fcChip->Registers.FMconfig.address);
1353 ulBuff &= 0x00ffffffL; // mask out current al_pa
1354 ulBuff |= ( fcChip->Registers.my_al_pa << 24 ); // or in acq. al_pa
1355 fcChip->Registers.FMconfig.value = ulBuff; // copy it back
1356 writel( fcChip->Registers.FMconfig.value, // put in TachLite
1357 fcChip->Registers.FMconfig.address);
1361 printk("#LUp %Xh, FMstat 0x%08X#",
1362 fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
1365 // also set the WRITE-ONLY My_ID Register (for Fabric
1367 writel( fcChip->Registers.my_al_pa,
1368 fcChip->Registers.ReMapMemBase +TL_MEM_TACH_My_ID);
1371 fcChip->fcStats.linkUp++;
1373 // reset TL statistics counters
1374 // (we ignore these error counters
1375 // while link is down)
1376 ulBuff = // just reset TL's counter
1377 readl( fcChip->Registers.FMLinkStatus1.address);
1379 ulBuff = // just reset TL's counter
1380 readl( fcChip->Registers.FMLinkStatus2.address);
1382 // for initiator, need to start verifying ports (e.g. PDISC)
1389 CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachlite, if Link OK
1391 // Tachyon creates an interesting problem for us on LILP frames.
1392 // Instead of writing the incoming LILP frame into the SFQ before
1393 // indicating LINK UP (the actual order of events), Tachyon tells
1394 // us LINK UP, and later us the LILP. So we delay, then examine the
1395 // IMQ for an Inbound CM (x04); if found, we can set
1396 // LINKACTIVE after processing the LILP. Otherwise, just proceed.
1397 // Since Tachyon imposes this time delay (and doesn't tell us
1398 // what it is), we have to impose a delay before "Peeking" the IMQ
1399 // for Tach hardware (DMA) delivery.
1400 // Processing LILP is required by SANMark
1401 udelay( 1000); // microsec delay waiting for LILP (if it comes)
1402 if( PeekIMQEntry( fcChip, ELS_LILP_FRAME) )
1403 { // found SFQ LILP, which will post LINKACTIVE
1404 // printk("skipping LINKACTIVE post\n");
1408 cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, ulFibreFrame);
1413 // ******* Set Fabric Login indication ********
1414 if( fcChip->Registers.FMstatus.value & 0x2000 )
1416 printk(" #Fabric# ");
1417 fcChip->Options.fabric = 1;
1420 fcChip->Options.fabric = 0;
1424 // ******* LIP(F8,x) or BAD AL_PA? ********
1425 if( fcChip->Registers.FMstatus.value & 0x30000L )
1427 // copy the error AL_PAs
1428 fcChip->Registers.rcv_al_pa.value =
1429 readl(fcChip->Registers.rcv_al_pa.address);
1432 if( fcChip->Registers.FMstatus.value & 0x10000L )
1434 PFC_LOGGEDIN_PORT pLoggedInPort;
1436 // copy "BAD" al_pa field
1437 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
1438 (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
1440 pLoggedInPort = fcFindLoggedInPort( fcChip,
1441 NULL, // DON'T search Scsi Nexus
1442 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1], // port id
1443 NULL, // DON'T search linked list for FC WWN
1444 NULL); // DON'T care about end of list
1448 // Just in case we got this BAD_ALPA because a device
1449 // quietly disappeared (can happen on non-managed hubs such
1450 // as the Vixel Rapport 1000),
1451 // do an Implicit Logout. We never expect this on a Logged
1452 // in port (but do expect it on port discovery).
1453 // (As a reasonable alternative, this could be changed to
1454 // simply start the implicit logout timer, giving the device
1455 // several seconds to "come back".)
1457 printk(" #BAD alpa %Xh# ",
1458 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
1459 cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
1463 if( fcChip->Registers.FMstatus.value & 0x20000L )
1465 // for debugging, copy al_pa field
1466 fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] =
1467 (fcChip->Registers.rcv_al_pa.value & 0xffL);
1468 // get the other port's al_pa
1469 // (one that sent LIP(F8,?) )
1473 // Elastic store err
1474 if( fcChip->Registers.FMstatus.value & 0x400L )
1476 // don't count e-s if loop is down!
1477 if( !(USHORT)(fcChip->Registers.FMstatus.value & 0x80) )
1478 fcChip->fcStats.e_stores++;
1485 case INBOUND_FCP_XCHG_COMPLETION: // 0x0C
1488 // On Tachlite TL/TS, we get this message when the data phase
1489 // of a SEST inbound transfer is complete. For example, if a WRITE command
1490 // was received with OX_ID 0, we might respond with XFER_RDY with
1491 // RX_ID 8001. This would start the SEST controlled data phases. When
1492 // all data frames are received, we get this inbound completion. This means
1493 // we should send a status frame to complete the status phase of the
1494 // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
1496 // See Outbound CM discussion of x_IDs
1498 // Get SEST index (x_ID)
1499 // x_ID out of range, return (err condition)
1500 // set status bits from 2nd dword
1501 // free transactionID & SEST entry
1502 // call fcComplete with transactionID & status
1504 ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
1505 x_ID = ulBuff & 0x7fffL; // lower 14 bits SEST_Index/Trans_ID
1506 // (mask out MSB "direction" bit)
1507 // Range check CM OX/RX_ID value...
1508 if( x_ID < TACH_SEST_LEN ) // don't go beyond SEST array space
1511 //#define FCP_COMPLETION_DBG 1
1512 #ifdef FCP_COMPLETION_DBG
1513 printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n",
1514 x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
1516 if( ulBuff & 0x08000000L ) // RPC -Response Phase Complete - or -
1517 // time to send response frame?
1518 RPCset = 1; // (SEST transaction)
1521 // set the status for this Inbound SCSI transaction's ID
1523 if( ulBuff & 0x70000000L ) // any errs?
1526 if( ulBuff & 0x40000000L )
1527 dwStatus |= LINKFAIL_RX;
1529 if( ulBuff & 0x20000000L )
1530 dwStatus |= COUNT_ERROR;
1532 if( ulBuff & 0x10000000L )
1533 dwStatus |= OVERFLOW;
1537 // FCP transaction done - copy status
1538 Exchanges->fcExchange[ x_ID ].status = dwStatus;
1541 // Did the exchange get an FCP-RSP response frame?
1542 // (Note the little endian/big endian FC payload difference)
1544 if( RPCset ) // SEST transaction Response frame rec'd
1546 // complete the command in our driver...
1547 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev,fcChip, x_ID);
1551 else // ("target" logic)
1553 // Tachlite says all data frames have been received - now it's time
1554 // to analyze data transfer (successful?), then send a response
1555 // frame for this exchange
1557 ulFibreFrame[0] = x_ID; // copy for later reference
1559 // if this was a TWE, we have to send satus response
1560 if( Exchanges->fcExchange[ x_ID].type == SCSI_TWE )
1562 // fcPutScsiQue( cpqfcHBAdata,
1563 // NEED_FCP_RSP, ulFibreFrame); // (ulFibreFrame not used here)
1567 else // ERROR CONDITION! bogus x_ID in completion message
1569 printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
1577 case INBOUND_SCSI_DATA_COMMAND:
1578 case BAD_SCSI_FRAME:
1579 case INB_SCSI_STATUS_COMPLETION:
1580 case BUFFER_PROCESSED_COMPLETION:
1584 // Tachyon is producing;
1586 fcChip->IMQ->consumerIndex++; // increment OUR consumerIndex
1587 if( fcChip->IMQ->consumerIndex >= IMQ_LEN)// check for rollover
1588 fcChip->IMQ->consumerIndex = 0L; // reset it
1591 if( fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex )
1592 { // all Messages are processed -
1593 iStatus = 0; // no more messages to process
1597 iStatus = 1; // more messages to process
1599 // update TachLite's ConsumerIndex... (clears INTA_L)
1600 // NOTE: according to TL/TS UG, the
1601 // "host must return completion messages in sequential order".
1602 // Does this mean one at a time, in the order received? We
1605 writel( fcChip->IMQ->consumerIndex,
1606 (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
1609 printk("Process IMQ: writing consumer ndx %d\n ",
1610 fcChip->IMQ->consumerIndex);
1611 printk("PI %X, CI %X\n",
1612 fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex );
1620 // hmmm... why did we get interrupted/called with no message?
1621 iStatus = -1; // nothing to process
1623 printk("Process IMQ: no message PI %Xh CI %Xh",
1624 fcChip->IMQ->producerIndex,
1625 fcChip->IMQ->consumerIndex);
1629 LEAVE("ProcessIMQEntry");
1638 // This routine initializes Tachyon according to the following
1639 // options (opcode1):
1640 // 1 - RESTART Tachyon, simulate power on condition by shutting
1641 // down laser, resetting the hardware, de-allocating all buffers;
1643 // 2 - Config Tachyon / PCI registers;
1645 // 3 - Allocating memory and setting Tachyon queues (write Tachyon regs);
1647 // 4 - Config frame manager registers, initialize, turn on laser
1650 // -1 on fatal error
1653 int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2)
1655 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
1656 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1659 int iStatus=-1; // assume failure
1661 ENTER("InitializeTachLite");
1663 // verify board's base address (sanity check)
1665 if( !fcChip->Registers.ReMapMemBase) // NULL address for card?
1666 return -1; // FATAL error!
1672 case 1: // restore hardware to power-on (hard) restart
1675 iStatus = fcChip->ResetTachyon(
1676 cpqfcHBAdata, opcode2); // laser off, reset hardware
1677 // de-allocate aligned buffers
1680 /* TBD // reset FC link Q (producer and consumer = 0)
1681 fcLinkQReset(cpqfcHBAdata);
1688 case 2: // Config PCI/Tachyon registers
1689 // NOTE: For Tach TL/TS, bit 31 must be set to 1. For TS chips, a read
1690 // of bit 31 indicates state of M66EN signal; if 1, chip may run at
1691 // 33-66MHz (see TL/TS UG, pg 159)
1693 ulBuff = 0x80000000; // TachLite Configuration Register
1695 writel( ulBuff, fcChip->Registers.TYconfig.address);
1696 // ulBuff = 0x0147L; // CpqTs PCI CFGCMD register
1697 // WritePCIConfiguration( fcChip->Backplane.bus,
1698 // fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4);
1699 // ulBuff = 0x0L; // test!
1700 // ReadPCIConfiguration( fcChip->Backplane.bus,
1701 // fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4);
1703 // read back for reference...
1704 fcChip->Registers.TYconfig.value =
1705 readl( fcChip->Registers.TYconfig.address );
1707 // what is the PCI bus width?
1708 pci_read_config_byte( cpqfcHBAdata->PciDev,
1709 0x43, // PCIMCTR offset
1712 fcChip->Registers.PCIMCTR = bBuff;
1714 // set string identifying the chip on the circuit board
1716 fcChip->Registers.TYstatus.value =
1717 readl( fcChip->Registers.TYstatus.address);
1720 // Now that we are supporting multiple boards, we need to change
1721 // this logic to check for PCI vendor/device IDs...
1722 // for now, quick & dirty is simply checking Chip rev
1724 ULONG RevId = (fcChip->Registers.TYstatus.value &0x3E0)>>5;
1725 UCHAR Minor = (UCHAR)(RevId & 0x3);
1726 UCHAR Major = (UCHAR)((RevId & 0x1C) >>2);
1728 /* printk(" HBA Tachyon RevId %d.%d\n", Major, Minor); */
1729 if( (Major == 1) && (Minor == 2) )
1731 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
1734 else if( (Major == 1) && (Minor == 3) )
1736 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
1738 else if( (Major == 2) && (Minor == 1) )
1740 sprintf( cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
1743 sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
1748 case 3: // allocate mem, set Tachyon Que registers
1749 iStatus = CpqTsCreateTachLiteQues( cpqfcHBAdata, opcode2);
1754 // now that the Queues exist, Tach can DMA to them, so
1755 // we can begin processing INTs
1756 // INTEN register - enable INT (TachLite interrupt)
1757 writeb( 0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
1760 case 4: // Config Fame Manager, Init Loop Command, laser on
1762 // L_PORT or loopback
1763 // depending on Options
1764 iStatus = CpqTsInitializeFrameManager( fcChip,0 );
1767 // failed to initialize Frame Manager
1774 LEAVE("InitializeTachLite");
1782 // Depending on the type of platform memory allocation (e.g. dynamic),
1783 // it's probably best to free memory in opposite order as it was allocated.
1784 // Order of allocation: see other function
1787 int CpqTsDestroyTachLiteQues( void *pHBA, int opcode)
1789 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
1790 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1791 USHORT i, iStatus=0;
1792 void* vPtr; // mem Align manager sets this to the freed address on success
1793 unsigned long ulPtr; // for 64-bit pointer cast (e.g. Alpa machine)
1794 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1797 ENTER("DestroyTachLiteQues");
1801 // search out and free Pool for Extended S/G list pages
1803 for( i=0; i < TACH_SEST_LEN; i++) // for each exchange
1805 // It's possible that extended S/G pages were allocated, mapped, and
1806 // not cleared due to error conditions or O/S driver termination.
1807 // Make sure they're all gone.
1808 if (Exchanges->fcExchange[i].Cmnd != NULL)
1809 cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd,
1810 fcChip, i); // undo DMA mappings.
1812 for (j=fcChip->SEST->sgPages[i] ; j != NULL ; j = next) {
1816 fcChip->SEST->sgPages[i] = NULL;
1818 ulPtr = (unsigned long)fcChip->SEST;
1819 vPtr = fcMemManager( cpqfcHBAdata->PciDev,
1820 &cpqfcHBAdata->dynamic_mem[0],
1821 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1822 fcChip->SEST = 0L; // null invalid ptr
1825 printk("SEST mem not freed\n");
1833 ulPtr = (unsigned long)fcChip->SFQ;
1834 vPtr = fcMemManager( cpqfcHBAdata->PciDev,
1835 &cpqfcHBAdata->dynamic_mem[0],
1836 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1837 fcChip->SFQ = 0L; // null invalid ptr
1840 printk("SFQ mem not freed\n");
1848 // clear Indexes to show empty Queue
1849 fcChip->IMQ->producerIndex = 0;
1850 fcChip->IMQ->consumerIndex = 0;
1852 ulPtr = (unsigned long)fcChip->IMQ;
1853 vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
1854 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1855 fcChip->IMQ = 0L; // null invalid ptr
1858 printk("IMQ mem not freed\n");
1863 if( fcChip->ERQ ) // release memory blocks used by the queues
1865 ulPtr = (unsigned long)fcChip->ERQ;
1866 vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
1867 0,0, (ULONG)ulPtr, NULL ); // 'free' mem
1868 fcChip->ERQ = 0L; // null invalid ptr
1871 printk("ERQ mem not freed\n");
1876 // free up the primary EXCHANGES struct and Link Q
1877 cpqfc_free_dma_consistent(cpqfcHBAdata);
1879 LEAVE("DestroyTachLiteQues");
1881 return iStatus; // non-zero (failed) if any memory not freed
1888 // The SFQ is an array with SFQ_LEN length, each element (QEntry)
1889 // with eight 32-bit words. TachLite places incoming FC frames (i.e.
1890 // a valid FC frame with our AL_PA ) in contiguous SFQ entries
1891 // and sends a completion message telling the host where the frame is
1893 // This function copies the current (or oldest not-yet-processed) QEntry to
1894 // a caller's contiguous buffer and updates the Tachyon chip's consumer index
1897 // An FC frame may consume one or many SFQ entries. We know the total
1898 // length from the completion message. The caller passes a buffer large
1899 // enough for the complete message (max 2k).
1901 static void CpqTsGetSFQEntry(
1904 ULONG *ulDestPtr, // contiguous destination buffer
1907 ULONG total_bytes=0;
1908 ULONG consumerIndex = fcChip->SFQ->consumerIndex;
1910 // check passed copy of SFQ producer index -
1911 // is a new message waiting for us?
1912 // equal indexes means SFS is copied
1914 while( producerNdx != consumerIndex )
1915 { // need to process message
1916 total_bytes += 64; // maintain count to prevent writing past buffer
1917 // don't allow copies over Fibre Channel defined length!
1918 if( total_bytes <= 2048 )
1921 &fcChip->SFQ->QEntry[consumerIndex],
1922 64 ); // each SFQ entry is 64 bytes
1923 ulDestPtr += 16; // advance pointer to next 64 byte block
1925 // Tachyon is producing,
1926 // and we are consuming
1928 if( ++consumerIndex >= SFQ_LEN)// check for rollover
1929 consumerIndex = 0L; // reset it
1932 // if specified, update the Tachlite chip ConsumerIndex...
1935 fcChip->SFQ->consumerIndex = consumerIndex;
1936 writel( fcChip->SFQ->consumerIndex,
1937 fcChip->Registers.SFQconsumerIndex.address);
1943 // TachLite routinely freezes it's core ques - Outbound FIFO, Inbound FIFO,
1944 // and Exchange Request Queue (ERQ) on error recover -
1945 // (e.g. whenever a LIP occurs). Here
1946 // we routinely RESUME by clearing these bits, but only if the loop is up
1947 // to avoid ERROR IDLE messages forever.
1949 void CpqTsUnFreezeTachlite( void *pChip, int type )
1951 PTACHYON fcChip = (PTACHYON)pChip;
1952 fcChip->Registers.TYcontrol.value =
1953 readl(fcChip->Registers.TYcontrol.address);
1955 // (bit 4 of value is GBIC LASER)
1956 // if we 'unfreeze' the core machines before the loop is healthy
1957 // (i.e. FLT, OS, LS failure bits set in FMstatus)
1958 // we can get 'error idle' messages forever. Verify that
1959 // FMstatus (Link Status) is OK before unfreezing.
1961 if( !(fcChip->Registers.FMstatus.value & 0x07000000L) && // bits clear?
1962 !(fcChip->Registers.FMstatus.value & 0x80 )) // Active LPSM?
1964 fcChip->Registers.TYcontrol.value &= ~0x300L; // clear FEQ, FFA
1965 if( type == 1 ) // unfreeze ERQ only
1967 // printk("Unfreezing ERQ\n");
1968 fcChip->Registers.TYcontrol.value |= 0x10000L; // set REQ
1970 else // unfreeze both ERQ and FCP-ASSIST (SEST)
1972 // printk("Unfreezing ERQ & FCP-ASSIST\n");
1974 // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
1975 fcChip->Registers.TYcontrol.value |= 0x70000L; // set ROF, RIF, REQ
1978 writel( fcChip->Registers.TYcontrol.value,
1979 fcChip->Registers.TYcontrol.address);
1982 // readback for verify (TachLite still frozen?)
1983 fcChip->Registers.TYstatus.value =
1984 readl(fcChip->Registers.TYstatus.address);
1988 // Whenever an FC Exchange Abort is required, we must manipulate the
1989 // Host/Tachyon shared memory SEST table. Before doing this, we
1990 // must freeze Tachyon, which flushes certain buffers and ensure we
1991 // can manipulate the SEST without contention.
1992 // This freeze function will result in FCP & ERQ FROZEN completion
1993 // messages (per argument "type").
1995 void CpqTsFreezeTachlite( void *pChip, int type )
1997 PTACHYON fcChip = (PTACHYON)pChip;
1998 fcChip->Registers.TYcontrol.value =
1999 readl(fcChip->Registers.TYcontrol.address);
2001 //set FFA, FEQ - freezes SCSI assist and ERQ
2002 if( type == 1) // freeze ERQ only
2003 fcChip->Registers.TYcontrol.value |= 0x100L; // (bit 4 is laser)
2004 else // freeze both FCP assists (SEST) and ERQ
2005 fcChip->Registers.TYcontrol.value |= 0x300L; // (bit 4 is laser)
2007 writel( fcChip->Registers.TYcontrol.value,
2008 fcChip->Registers.TYcontrol.address);
2015 // TL has two Frame Manager Link Status Registers, with three 8-bit
2016 // fields each. These eight bit counters are cleared after each read,
2017 // so we define six 32-bit accumulators for these TL counters. This
2018 // function breaks out each 8-bit field and adds the value to the existing
2019 // sum. (s/w counters cleared independently)
2021 void fcParseLinkStatusCounters(PTACHYON fcChip)
2027 // The BB0 timer usually increments when TL is initialized, resulting
2028 // in an initially bogus count. If our own counter is ZERO, it means we
2029 // are reading this thing for the first time, so we ignore the first count.
2030 // Also, reading the register does not clear it, so we have to keep an
2031 // additional static counter to detect rollover (yuk).
2033 if( fcChip->fcStats.lastBB0timer == 0L) // TL was reset? (ignore 1st values)
2035 // get TL's register counter - the "last" count
2036 fcChip->fcStats.lastBB0timer =
2037 fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
2039 else // subsequent pass - check for rollover
2042 ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
2043 if( fcChip->fcStats.lastBB0timer > ulBuff ) // rollover happened
2045 // counter advanced to max...
2046 fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
2047 fcChip->fcStats.BB0_Timer += ulBuff; // plus some more
2051 else // no rollover -- more counts or no change
2053 fcChip->fcStats.BB0_Timer += (ulBuff - fcChip->fcStats.lastBB0timer);
2057 fcChip->fcStats.lastBB0timer = ulBuff;
2062 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 24);
2063 fcChip->fcStats.LossofSignal += bBuff;
2065 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 16);
2066 fcChip->fcStats.BadRXChar += bBuff;
2068 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 8);
2069 fcChip->fcStats.LossofSync += bBuff;
2072 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 24);
2073 fcChip->fcStats.Rx_EOFa += bBuff;
2075 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 16);
2076 fcChip->fcStats.Dis_Frm += bBuff;
2078 bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 8);
2079 fcChip->fcStats.Bad_CRC += bBuff;
2083 void cpqfcTSClearLinkStatusCounters(PTACHYON fcChip)
2085 ENTER("ClearLinkStatusCounters");
2086 memset( &fcChip->fcStats, 0, sizeof( FCSTATS));
2087 LEAVE("ClearLinkStatusCounters");
2094 // The following function reads the I2C hardware to get the adapter's
2095 // World Wide Name (WWN).
2096 // If the WWN is "500805f1fadb43e8" (as printed on the card), the
2097 // Tachyon WWN_hi (32-bit) register is 500805f1, and WWN_lo register
2099 // In the NVRAM, the bytes appear as:
2111 // In the Fibre Channel (Big Endian) format, the FC-AL LISM frame will
2112 // be correctly loaded by Tachyon silicon. In the login payload, bytes
2113 // must be correctly swapped for Big Endian format.
2115 int CpqTsReadWriteWWN( PVOID pChip, int Read)
2117 PTACHYON fcChip = (PTACHYON)pChip;
2118 #define NVRAM_SIZE 512
2119 unsigned short i, count = NVRAM_SIZE;
2120 UCHAR nvRam[NVRAM_SIZE], WWNbuf[8];
2122 int iStatus=-1; // assume failure
2125 ENTER("ReadWriteWWN");
2126 // Now try to read the WWN from the adapter's NVRAM
2128 if( Read ) // READing NVRAM WWN?
2130 ulBuff = cpqfcTS_ReadNVRAM( fcChip->Registers.TYstatus.address,
2131 fcChip->Registers.TYcontrol.address,
2134 if( ulBuff ) // NVRAM read successful?
2136 iStatus = 0; // success!
2138 // for engineering/ prototype boards, the data may be
2139 // invalid (GIGO, usually all "FF"); this prevents the
2140 // parse routine from working correctly, which means
2141 // nothing will be written to our passed buffer.
2143 WWNoffset = cpqfcTS_GetNVRAM_data( WWNbuf, nvRam );
2145 if( !WWNoffset ) // uninitialized NVRAM -- copy bytes directly
2147 printk( "CAUTION: Copying NVRAM data on fcChip\n");
2148 for( i= 0; i < 8; i++)
2149 WWNbuf[i] = nvRam[i +0x2f]; // dangerous! some formats won't work
2152 fcChip->Registers.wwn_hi = 0L;
2153 fcChip->Registers.wwn_lo = 0L;
2154 for( i=0; i<4; i++) // WWN bytes are big endian in NVRAM
2157 ulBuff = (ULONG)(WWNbuf[i]) << (8 * (3-i));
2158 fcChip->Registers.wwn_hi |= ulBuff;
2160 for( i=0; i<4; i++) // WWN bytes are big endian in NVRAM
2163 ulBuff = (ULONG)(WWNbuf[i+4]) << (8 * (3-i));
2164 fcChip->Registers.wwn_lo |= ulBuff;
2170 printk( "cpqfcTS: NVRAM read failed\n");
2178 // NOTE: WRITE not supported & not used in released driver.
2181 printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
2184 LEAVE("ReadWriteWWN");
2192 // The following function reads or writes the entire "NVRAM" contents of
2193 // the I2C hardware (i.e. the NM24C03). Note that HP's 5121A (TS 66Mhz)
2194 // adapter does not use the NM24C03 chip, so this function only works on
2195 // Compaq's adapters.
2197 int CpqTsReadWriteNVRAM( PVOID pChip, PVOID buf, int Read)
2199 PTACHYON fcChip = (PTACHYON)pChip;
2200 #define NVRAM_SIZE 512
2202 UCHAR *ucPtr = buf; // cast caller's void ptr to UCHAR array
2203 int iStatus=-1; // assume failure
2206 if( Read ) // READing NVRAM?
2208 ulBuff = cpqfcTS_ReadNVRAM( // TRUE on success
2209 fcChip->Registers.TYstatus.address,
2210 fcChip->Registers.TYcontrol.address,
2211 256, // bytes to write
2212 ucPtr ); // source ptr
2216 iStatus = 0; // success
2220 printk( "CAUTION: NVRAM read failed\n");
2225 else // WRITING NVRAM
2228 printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");