~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/scsi/cpqfcTScontrol.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.