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