aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/cpqfcTScontrol.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/cpqfcTScontrol.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/scsi/cpqfcTScontrol.c')
-rw-r--r--drivers/scsi/cpqfcTScontrol.c2231
1 files changed, 2231 insertions, 0 deletions
diff --git a/drivers/scsi/cpqfcTScontrol.c b/drivers/scsi/cpqfcTScontrol.c
new file mode 100644
index 000000000000..bd94c70f473d
--- /dev/null
+++ b/drivers/scsi/cpqfcTScontrol.c
@@ -0,0 +1,2231 @@
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
54static void fcParseLinkStatusCounters(TACHYON * fcChip);
55static void CpqTsGetSFQEntry(TACHYON * fcChip,
56 USHORT pi, ULONG * buffr, BOOLEAN UpdateChip);
57
58static void
59cpqfc_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
79int 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
361int 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
463int 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
486int 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.
590static 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
651static 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
710int 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
1652int 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
1786int 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
1900static 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
1948void 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
1994void 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
2020void 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
2082void 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
2114int 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
2196int 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}