File: /usr/src/linux/drivers/scsi/cpqfcTSworker.c

1     /* Copyright(c) 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     
22     #include <linux/sched.h>
23     #include <linux/timer.h>
24     #include <linux/string.h>
25     #include <linux/slab.h>
26     #include <linux/ioport.h>
27     #include <linux/kernel.h>
28     #include <linux/stat.h>
29     #include <linux/blk.h>
30     #include <linux/interrupt.h>
31     #include <linux/delay.h>
32     #include <linux/smp_lock.h>
33     
34     #define __KERNEL_SYSCALLS__
35     
36     #define SHUTDOWN_SIGS	(sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
37     
38     #include <linux/unistd.h>
39     
40     #include <asm/system.h>
41     #include <asm/irq.h>
42     #include <asm/dma.h>
43     
44     
45     
46     #include "sd.h"
47     #include "hosts.h"   // struct Scsi_Host definition for T handler
48     #include "cpqfcTSchip.h"
49     #include "cpqfcTSstructs.h"
50     #include "cpqfcTStrigger.h"
51     
52     //#define LOGIN_DBG 1
53     
54     // REMARKS:
55     // Since Tachyon chips may be permitted to wait from 500ms up to 2 sec
56     // to empty an outgoing frame from its FIFO to the Fibre Channel stream,
57     // we cannot do everything we need to in the interrupt handler.  Specifically,
58     // every time a link re-init (e.g. LIP) takes place, all SCSI I/O has to be
59     // suspended until the login sequences have been completed.  Login commands
60     // are frames just like SCSI commands are frames; they are subject to the same
61     // timeout issues and delays.  Also, various specs provide up to 2 seconds for
62     // devices to log back in (i.e. respond with ACC to a login frame), so I/O to
63     // that device has to be suspended.
64     // A serious problem here occurs on highly loaded FC-AL systems.  If our FC port
65     // has a low priority (e.g. high arbitrated loop physical address, alpa), and
66     // some other device is hogging bandwidth (permissible under FC-AL), we might
67     // time out thinking the link is hung, when it's simply busy.  Many such
68     // considerations complicate the design.  Although Tachyon assumes control
69     // (in silicon) for many link-specific issues, the Linux driver is left with the
70     // rest, which turns out to be a difficult, time critical chore.
71     
72     // These "worker" functions will handle things like FC Logins; all
73     // processes with I/O to our device must wait for the Login to complete
74     // and (if successful) I/O to resume.  In the event of a malfunctioning or  
75     // very busy loop, it may take hundreds of millisecs or even seconds to complete
76     // a frame send.  We don't want to hang up the entire server (and all
77     // processes which don't depend on Fibre) during this wait.
78     
79     // The Tachyon chip can have around 30,000 I/O operations ("exchanges")
80     // open at one time.  However, each exchange must be initiated 
81     // synchronously (i.e. each of the 30k I/O had to be started one at a
82     // time by sending a starting frame via Tachyon's outbound que).  
83     
84     // To accomodate kernel "module" build, this driver limits the exchanges
85     // to 256, because of the contiguous physical memory limitation of 128M.
86     
87     // Typical FC Exchanges are opened presuming the FC frames start without errors,
88     // while Exchange completion is handled in the interrupt handler.  This
89     // optimizes performance for the "everything's working" case.
90     // However, when we have FC related errors or hot plugging of FC ports, we pause
91     // I/O and handle FC-specific tasks in the worker thread.  These FC-specific
92     // functions will handle things like FC Logins and Aborts.  As the Login sequence
93     // completes to each and every target, I/O can resume to that target.  
94     
95     // Our kernel "worker thread" must share the HBA with threads calling 
96     // "queuecommand".  We define a "BoardLock" semaphore which indicates
97     // to "queuecommand" that the HBA is unavailable, and Cmnds are added to a
98     // board lock Q.  When the worker thread finishes with the board, the board
99     // lock Q commands are completed with status causing immediate retry.
100     // Typically, the board is locked while Logins are in progress after an
101     // FC Link Down condition.  When Cmnds are re-queued after board lock, the
102     // particular Scsi channel/target may or may not have logged back in.  When
103     // the device is waiting for login, the "prli" flag is clear, in which case
104     // commands are passed to a Link Down Q.  Whenever the login finally completes,
105     // the LinkDown Q is completed, again with status causing immediate retry.
106     // When FC devices are logged in, we build and start FC commands to the
107     // devices.
108     
109     // NOTE!! As of May 2000, kernel 2.2.14, the error recovery logic for devices 
110     // that never log back in (e.g. physically removed) is NOT completely
111     // understood.  I've still seen instances of system hangs on failed Write 
112     // commands (possibly from the ext2 layer?) on device removal.  Such special
113     // cases need to be evaluated from a system/application view - e.g., how
114     // exactly does the system want me to complete commands when the device is
115     // physically removed??
116     
117     // local functions
118     
119     static void SetLoginFields(
120       PFC_LOGGEDIN_PORT pLoggedInPort,
121       TachFCHDR_GCMND* fchs,
122       BOOLEAN PDisc,
123       BOOLEAN Originator);
124     
125     static void AnalyzeIncomingFrame( 
126            CPQFCHBA *cpqfcHBAdata,
127            ULONG QNdx );
128     
129     static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
130     
131     static int verify_PLOGI( PTACHYON fcChip,
132           TachFCHDR_GCMND* fchs, ULONG* reject_explain);
133     static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
134     
135     static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
136     static void BuildLinkServicePayload( 
137                   PTACHYON fcChip, ULONG type, void* payload);
138     
139     static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
140             PFC_LOGGEDIN_PORT pLoggedInPort);
141     
142     static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
143     
144     static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
145     
146     static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
147     		        PFC_LOGGEDIN_PORT pLoggedInPort);
148     
149     static void IssueReportLunsCommand( 
150                   CPQFCHBA* cpqfcHBAdata, 
151     	      TachFCHDR_GCMND* fchs);
152     
153     // (see scsi_error.c comments on kernel task creation)
154     
155     void cpqfcTSWorkerThread( void *host)
156     {
157       struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
158       CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; 
159     #ifdef PCI_KERNEL_TRACE
160       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
161     #endif
162       struct fs_struct *fs;
163       DECLARE_MUTEX_LOCKED(fcQueReady);
164       DECLARE_MUTEX_LOCKED(fcTYOBcomplete); 
165       DECLARE_MUTEX_LOCKED(TachFrozen);  
166       DECLARE_MUTEX_LOCKED(BoardLock);  
167     
168       ENTER("WorkerThread");
169     
170       lock_kernel();
171     	/*
172     	 * If we were started as result of loading a module, close all of the
173     	 * user space pages.  We don't need them, and if we didn't close them
174     	 * they would be locked into memory.
175     	 */
176       exit_mm(current);
177     
178       current->session = 1;
179       current->pgrp = 1;
180     	
181       /* Become as one with the init task */
182     	
183       exit_fs(current);	/* current->fs->count--; */
184       fs = init_task.fs;
185       // Some kernels compiled for SMP, while actually running
186       // on a uniproc machine, will return NULL for this call
187       if( !fs)
188       {
189         printk(" cpqfcTS FATAL: fs is NULL! Is this an SMP kernel on uniproc machine?\n ");
190       }
191      
192       else
193       { 
194         current->fs = fs;
195         atomic_inc(&fs->count);
196       }
197     
198       siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
199     
200     
201       /*
202        * Set the name of this process.
203        */
204       sprintf(current->comm, "cpqfcTS_wt_%d", HostAdapter->host_no);
205     
206       cpqfcHBAdata->fcQueReady = &fcQueReady;  // primary wait point
207       cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
208       cpqfcHBAdata->TachFrozen = &TachFrozen;
209         
210      
211       cpqfcHBAdata->worker_thread = current;
212       
213       unlock_kernel();
214     
215       if( cpqfcHBAdata->notify_wt != NULL )
216         up( cpqfcHBAdata->notify_wt); // OK to continue
217     
218       while(1)
219       {
220         unsigned long flags;
221     
222         down_interruptible( &fcQueReady);  // wait for something to do
223     
224         if (signal_pending(current) )
225           break;
226         
227         PCI_TRACE( 0x90)
228         // first, take the IO lock so the SCSI upper layers can't call
229         // into our _quecommand function (this also disables INTs)
230         spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
231         PCI_TRACE( 0x90)
232              
233         CPQ_SPINLOCK_HBA( cpqfcHBAdata)
234         // next, set this pointer to indicate to the _quecommand function
235         // that the board is in use, so it should que the command and 
236         // immediately return (we don't actually require the semaphore function
237         // in this driver rev)
238     
239         cpqfcHBAdata->BoardLock = &BoardLock;
240     
241         PCI_TRACE( 0x90)
242     
243         // release the IO lock (and re-enable interrupts)
244         spin_unlock_irqrestore( &io_request_lock, flags);
245     
246         // disable OUR HBA interrupt (keep them off as much as possible
247         // during error recovery)
248         disable_irq( cpqfcHBAdata->HostAdapter->irq);
249     
250         // OK, let's process the Fibre Channel Link Q and do the work
251         cpqfcTS_WorkTask( HostAdapter);
252     
253         // hopefully, no more "work" to do;
254         // re-enable our INTs for "normal" completion processing
255         enable_irq( cpqfcHBAdata->HostAdapter->irq);
256      
257     
258         cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
259         CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
260     
261     
262         // Now, complete any Cmnd we Q'd up while BoardLock was held
263     
264         CompleteBoardLockCmnd( cpqfcHBAdata);
265       
266     
267       }
268       // hopefully, the signal was for our module exit...
269       if( cpqfcHBAdata->notify_wt != NULL )
270         up( cpqfcHBAdata->notify_wt); // yep, we're outta here
271     }
272     
273     
274     // Freeze Tachyon routine.
275     // If Tachyon is already frozen, return FALSE
276     // If Tachyon is not frozen, call freeze function, return TRUE
277     //
278     static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
279     {
280       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
281       BOOLEAN FrozeTach = FALSE;
282       // It's possible that the chip is already frozen; if so,
283       // "Freezing" again will NOT! generate another Freeze
284       // Completion Message.
285     
286       if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
287       {  // (need to freeze...)
288         fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
289     
290         // 2. Get Tach freeze confirmation
291         // (synchronize SEST manipulation with Freeze Completion Message)
292         // we need INTs on so semaphore can be set.	
293         enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
294         down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
295         // can we TIMEOUT semaphore wait?? TBD
296         disable_irq( cpqfcHBAdata->HostAdapter->irq); 
297     
298         FrozeTach = TRUE;
299       }  // (else, already frozen)
300      
301       return FrozeTach;
302     }  
303     
304     
305     
306     
307     // This is the kernel worker thread task, which processes FC
308     // tasks which were queued by the Interrupt handler or by
309     // other WorkTask functions.
310     
311     #define DBG 1
312     //#undef DBG
313     void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
314     {
315       CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
316       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
317       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
318       ULONG QconsumerNdx;
319       LONG ExchangeID;
320       ULONG ulStatus=0;
321       TachFCHDR_GCMND fchs;
322       PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
323     
324       ENTER("WorkTask");
325     
326       // copy current index to work on
327       QconsumerNdx = fcLQ->consumer;
328     
329       PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
330       
331     
332       // NOTE: when this switch completes, we will "consume" the Que item
333     //  printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
334       switch( fcLQ->Qitem[QconsumerNdx].Type )
335       {
336           // incoming frame - link service (ACC, UNSOL REQ, etc.)
337           // or FCP-SCSI command
338         case SFQ_UNKNOWN:  
339           AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
340     
341           break;
342       
343         
344         
345         case EXCHANGE_QUEUED:  // an Exchange (i.e. FCP-SCSI) was previously
346                                // Queued because the link was down.  The  
347                                // heartbeat timer detected it and Queued it here.
348                                // We attempt to start it again, and if
349                                // successful we clear the EXCHANGE_Q flag.
350                                // If the link doesn't come up, the Exchange
351                                // will eventually time-out.
352     
353           ExchangeID = (LONG)  // x_ID copied from DPC timeout function
354                        fcLQ->Qitem[QconsumerNdx].ulBuff[0];
355     
356           // It's possible that a Q'd exchange could have already
357           // been started by other logic (e.g. ABTS process)
358           // Don't start if already started (Q'd flag clear)
359     
360           if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
361           {
362     //        printk(" *Start Q'd x_ID %Xh: type %Xh ", 
363     //          ExchangeID, Exchanges->fcExchange[ExchangeID].type);
364           
365             ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
366             if( !ulStatus )
367             {
368     //          printk("success* ");
369             }	
370             else
371             {
372     #ifdef DBG
373           
374               if( ulStatus == EXCHANGE_QUEUED)
375                 printk("Queued* ");
376               else
377                 printk("failed* ");
378     		
379     #endif
380     	} 
381           }
382           break;
383     
384     
385         case LINKDOWN:  
386           // (lots of things already done in INT handler) future here?
387           break;
388         
389         
390         case LINKACTIVE:   // Tachyon set the Lup bit in FM status
391                            // NOTE: some misbehaving FC ports (like Tach2.1)
392                            // can re-LIP immediately after a LIP completes.
393           
394           // if "initiator", need to verify LOGs with ports
395     //      printk("\n*LNKUP* ");
396     
397           if( fcChip->Options.initiator )
398             SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
399                       // if SendLogins successfully completes, PortDiscDone
400                       // will be set.
401           
402           
403           // If SendLogins was successful, then we expect to get incoming
404           // ACCepts or REJECTs, which are handled below.
405     
406           break;
407     
408         // LinkService and Fabric request/reply processing
409         case ELS_FDISC:      // need to send Fabric Discovery (Login)
410         case ELS_FLOGI:      // need to send Fabric Login
411         case ELS_SCR:        // need to send State Change Registration
412         case FCS_NSR:        // need to send Name Service Request
413         case ELS_PLOGI:      // need to send PLOGI
414         case ELS_ACC:        // send generic ACCept
415         case ELS_PLOGI_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
416         case ELS_PRLI_ACC:   // need to send ELS ACCept frame to recv'd PRLI
417         case ELS_LOGO:      // need to send ELS LOGO (logout)
418         case ELS_LOGO_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
419         case ELS_RJT:         // ReJecT reply
420         case ELS_PRLI:       // need to send ELS PRLI
421      
422         
423     //      printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
424           // if PortDiscDone is not set, it means the SendLogins routine
425           // failed to complete -- assume that LDn occurred, so login frames
426           // are invalid
427           if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
428           {
429             printk("Discard Q'd ELS login frame\n");
430             break;  
431           }
432     
433           ulStatus = cpqfcTSBuildExchange(
434               cpqfcHBAdata,
435               fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
436               (TachFCHDR_GCMND*)
437                 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
438               NULL,         // no data (no scatter/gather list)
439               &ExchangeID );// fcController->fcExchanges index, -1 if failed
440     
441           if( !ulStatus ) // Exchange setup?
442           {
443             ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
444             if( !ulStatus )
445             {
446               // submitted to Tach's Outbound Que (ERQ PI incremented)
447               // waited for completion for ELS type (Login frames issued
448               // synchronously)
449             }
450             else
451               // check reason for Exchange not being started - we might
452               // want to Queue and start later, or fail with error
453             {
454     
455             }
456           }
457     
458           else   // Xchange setup failed...
459             printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
460     
461           break;
462     
463         case SCSI_REPORT_LUNS:
464           // pass the incoming frame (actually, it's a PRLI frame)
465           // so we can send REPORT_LUNS, in order to determine VSA/PDU
466           // FCP-SCSI Lun address mode
467           IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
468                 fcLQ->Qitem[QconsumerNdx].ulBuff); 
469     
470           break;
471           
472     
473     
474     
475         case BLS_ABTS:       // need to ABORT one or more exchanges
476         {
477           LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
478           BOOLEAN FrozeTach = FALSE;   
479          
480           if( x_ID > TACH_SEST_LEN )  // (in)sanity check
481           {
482     //	printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
483     	break;
484           }
485     
486     
487           if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
488           {
489     //	printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
490     	
491            break;  // nothing to abort!
492           }
493     
494     //#define ABTS_DBG
495     #ifdef ABTS_DBG
496           printk("INV SEST[%X] ", x_ID); 
497           if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
498           {
499             printk("FC2TO");
500           }
501           if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
502           {
503             printk("IA");
504           }
505           if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
506           {
507             printk("PORTID");
508           }
509           if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
510           {
511             printk("DEVRM");
512           }
513           if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
514           {
515             printk("LKF");
516           }
517           if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
518           {
519             printk("FRMTO");
520           }
521           if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
522           {
523             printk("ABSQ");
524           }
525           if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
526           {
527             printk("SFQFR");
528           }
529     
530           if( Exchanges->fcExchange[ x_ID].type == 0x2000)
531             printk(" WR");
532           else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
533             printk(" RD");
534           else if( Exchanges->fcExchange[ x_ID].type == 0x10)
535             printk(" ABTS");
536           else
537             printk(" %Xh", Exchanges->fcExchange[ x_ID].type); 
538     
539           if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
540           {
541     	printk(" Cmd %p, ", 
542               Exchanges->fcExchange[ x_ID].Cmnd);
543     
544             printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n", 
545               cpqfcHBAdata->HBAnum,
546               Exchanges->fcExchange[ x_ID].Cmnd->channel,
547               Exchanges->fcExchange[ x_ID].Cmnd->target,
548               Exchanges->fcExchange[ x_ID].Cmnd->lun,
549               Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
550           }
551           else  // assume that Cmnd ptr is invalid on _abort()
552           {
553     	printk(" Cmd ptr invalid\n");
554           }
555          
556     #endif      
557     
558           
559           // Steps to ABORT a SEST exchange:
560           // 1. Freeze TL SCSI assists & ERQ (everything)
561           // 2. Receive FROZEN inbound CM (must succeed!)
562           // 3. Invalidate x_ID SEST entry 
563           // 4. Resume TL SCSI assists & ERQ (everything)
564           // 5. Build/start on exchange - change "type" to BLS_ABTS,
565           //    timeout to X sec (RA_TOV from PLDA is actually 0)
566           // 6. Set Exchange Q'd status if ABTS cannot be started,
567           //    or simply complete Exchange in "Terminate" condition
568     
569       PCI_TRACEO( x_ID, 0xB4)
570           
571           // 1 & 2 . Freeze Tach & get confirmation of freeze
572           FrozeTach = FreezeTach( cpqfcHBAdata);
573     
574           // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
575           // FC2_TIMEOUT means we are originating the abort, while
576           // TARGET_ABORT means we are ACCepting an abort.
577           // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are 
578           // all from Tachyon:
579           // Exchange was corrupted by LDn or other FC physical failure
580           // INITIATOR_ABORT means the upper layer driver/application
581           // requested the abort.
582     
583     
584     	  
585           // clear bit 31 (VALid), to invalidate & take control from TL
586           fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
587     
588     
589           // examine and Tach's "Linked List" for IWEs that 
590           // received (nearly) simultaneous transfer ready (XRDY) 
591           // repair linked list if necessary (TBD!)
592           // (If we ignore the "Linked List", we will time out
593           // WRITE commands where we received the FCP-SCSI XFRDY
594           // frame (because Tachyon didn't processes it).  Linked List
595           // management should be done as an optimization.
596     
597     //       readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
598     
599     
600           
601     
602           // 4. Resume all Tachlite functions (for other open Exchanges)
603           // as quickly as possible to allow other exchanges to other ports
604           // to resume.  Freezing Tachyon may cause cascading errors, because
605           // any received SEST frame cannot be processed by the SEST.
606           // Don't "unfreeze" unless Link is operational
607           if( FrozeTach )  // did we just freeze it (above)?
608             fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
609           
610     
611       PCI_TRACEO( x_ID, 0xB4)
612     
613           // Note there is no confirmation that the chip is "unfrozen".  Also,
614           // if the Link is down when unfreeze is called, it has no effect.
615           // Chip will unfreeze when the Link is back up.
616     
617           // 5. Now send out Abort commands if possible
618           // Some Aborts can't be "sent" (Port_id changed or gone);
619           // if the device is gone, there is no port_id to send the ABTS to.
620     
621           if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
622     			  &&
623               !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
624           {
625             Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
626             fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
627             ulStatus = cpqfcTSBuildExchange(
628               cpqfcHBAdata,
629               BLS_ABTS,
630               &fchs,        // (uses only s_id)
631               NULL,         // (no scatter/gather list for ABTS)
632               &x_ID );// ABTS on this Exchange ID
633     
634             if( !ulStatus ) // Exchange setup build OK?
635             {
636     
637                 // ABTS may be needed because an Exchange was corrupted
638                 // by a Link disruption.  If the Link is UP, we can
639     	    // presume that this ABTS can start immediately; otherwise,
640     	    // set Que'd status so the Login functions
641                 // can restart it when the FC physical Link is restored
642               if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
643               {			    
644     //                printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
645                     Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
646               }
647     
648               else  // what FC device (port_id) does the Cmd belong to?
649               {
650                 PFC_LOGGEDIN_PORT pLoggedInPort = 
651                   Exchanges->fcExchange[ x_ID].pLoggedInPort;
652                 
653                 // if Port is logged in, we might start the abort.
654     	
655                 if( (pLoggedInPort != NULL) 
656     			      &&
657                     (pLoggedInPort->prli == TRUE) ) 
658                 {
659                   // it's possible that an Exchange has already been Queued
660                   // to start after Login completes.  Check and don't
661     	      // start it (again) here if Q'd status set
662     //	    printk(" ABTS xchg %Xh ", x_ID);            
663      	      if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
664     	      {
665     //		    printk("already Q'd ");
666     	      }
667     	      else
668     	      {
669     //	            printk("starting ");
670     		
671                     fcChip->fcStats.FC2aborted++; 
672                     ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
673                     if( !ulStatus )
674                     {
675                         // OK
676                         // submitted to Tach's Outbound Que (ERQ PI incremented)
677                     }
678                     else
679                     {
680     /*                   printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
681                             ulStatus, x_ID);
682     */
683                     } 
684     	      }
685     	    }
686     	    else
687     	    {
688     /*         	  printk(" ABTS NOT starting xchg %Xh, %p ",
689     			       x_ID, pLoggedInPort);
690     	          if( pLoggedInPort )
691     	            printk("prli %d ", pLoggedInPort->prli);
692     */
693     	    }		
694      	  }
695             }
696             else  // what the #@!
697             {  // how do we fail to build an Exchange for ABTS??
698                   printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
699                     ulStatus, x_ID);
700             }
701           }
702           else   // abort without ABTS -- just complete exchange/Cmnd to Linux
703           {
704     //            printk(" *Terminating x_ID %Xh on %Xh* ", 
705     //		    x_ID, Exchanges->fcExchange[x_ID].status);
706             cpqfcTSCompleteExchange( fcChip, x_ID);
707     
708     
709           }
710         } // end of ABTS case
711           break;
712     
713     
714     
715         case BLS_ABTS_ACC:   // need to ACCept one ABTS
716                              // (NOTE! this code not updated for Linux yet..)
717           
718     
719           printk(" *ABTS_ACC* ");
720           // 1. Freeze TL
721     
722           fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
723     
724           memcpy(  // copy the incoming ABTS frame
725             &fchs,
726             fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
727             sizeof( fchs));
728     
729           // 3. OK, Tachyon is frozen so we can invalidate SEST entry 
730           // (if necessary)
731           // Status FC2_TIMEOUT means we are originating the abort, while
732           // TARGET_ABORT means we are ACCepting an abort
733           
734           ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
735     //      printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
736     
737     
738           // sanity check on received ExchangeID
739           if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
740           {
741               // clear bit 31 (VALid), to invalidate & take control from TL
742     //          printk("Invalidating SEST exchange %Xh\n", ExchangeID);
743               fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
744           }
745     
746     
747           // 4. Resume all Tachlite functions (for other open Exchanges)
748           // as quickly as possible to allow other exchanges to other ports
749           // to resume.  Freezing Tachyon for too long may royally screw
750           // up everything!
751           fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
752           
753           // Note there is no confirmation that the chip is "unfrozen".  Also,
754           // if the Link is down when unfreeze is called, it has no effect.
755           // Chip will unfreeze when the Link is back up.
756     
757           // 5. Now send out Abort ACC reply for this exchange
758           Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
759           
760           fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
761           ulStatus = cpqfcTSBuildExchange(
762                 cpqfcHBAdata,
763                 BLS_ABTS_ACC,
764                 &fchs,
765                 NULL,         // no data (no scatter/gather list)
766                 &ExchangeID );// fcController->fcExchanges index, -1 if failed
767     
768           if( !ulStatus ) // Exchange setup?
769           {
770             ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
771             if( !ulStatus )
772             {
773               // submitted to Tach's Outbound Que (ERQ PI incremented)
774               // waited for completion for ELS type (Login frames issued
775               // synchronously)
776             }
777             else
778               // check reason for Exchange not being started - we might
779               // want to Queue and start later, or fail with error
780             {
781     
782             } 
783           }
784           break;
785     
786     
787         case BLS_ABTS_RJT:   // need to ReJecT one ABTS; reject implies the
788                              // exchange doesn't exist in the TARGET context.
789                              // ExchangeID has to come from LinkService space.
790     
791           printk(" *ABTS_RJT* ");
792           ulStatus = cpqfcTSBuildExchange(
793                 cpqfcHBAdata,
794                 BLS_ABTS_RJT,
795                 (TachFCHDR_GCMND*)
796                   fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
797                 NULL,         // no data (no scatter/gather list)
798                 &ExchangeID );// fcController->fcExchanges index, -1 if failed
799     
800           if( !ulStatus ) // Exchange setup OK?
801           {
802             ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
803             // If it fails, we aren't required to retry.
804           }
805           if( ulStatus )
806           {
807             printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
808           }
809           else
810           {
811             printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
812           
813           }
814     
815           break;
816     
817     
818     
819         default:
820           break;
821       }                   // end switch
822     //doNothing:
823         // done with this item - now set the NEXT index
824     
825       if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
826       {
827         fcLQ->consumer = 0;
828       }
829       else
830       { 
831         fcLQ->consumer++;
832       }
833     
834       PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
835     
836       LEAVE("WorkTask");
837       return;
838     }
839     
840     
841     
842     
843     // When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login)
844     // commands come in, post to the LinkQ so that action can be taken outside the
845     // interrupt handler.  
846     // This circular Q works like Tachyon's que - the producer points to the next
847     // (unused) entry.  Called by Interrupt handler, WorkerThread, Timer
848     // sputlinkq
849     void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
850       int Type, 
851       void *QueContent)
852     {
853       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
854     //  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
855       PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
856       ULONG ndx;
857       
858       ENTER("cpqfcTSPutLinkQ");
859     
860       ndx = fcLQ->producer;
861       
862       ndx += 1;  // test for Que full
863     
864     
865       
866       if( ndx >= FC_LINKQ_DEPTH ) // rollover test
867         ndx = 0;
868     
869       if( ndx == fcLQ->consumer )   // QUE full test
870       {
871                            // QUE was full! lost LK command (fatal to logic)
872         fcChip->fcStats.lnkQueFull++;
873     
874         printk("*LinkQ Full!*");
875         TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
876     /*
877         {
878           int i;
879           printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
880             fcLQ->consumer);
881     		      
882           for( i=0; i< FC_LINKQ_DEPTH; )
883           {
884     	printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
885     	if( (++i %8) == 0) printk("\n");
886           }
887       
888         }
889     */    
890         printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
891       }
892       else                        // QUE next element
893       {
894         // Prevent certain multiple (back-to-back) requests.
895         // This is important in that we don't want to issue multiple
896         // ABTS for the same Exchange, or do multiple FM inits, etc.
897         // We can never be sure of the timing of events reported to
898         // us by Tach's IMQ, which can depend on system/bus speeds,
899         // FC physical link circumstances, etc.
900          
901         if( (fcLQ->producer != fcLQ->consumer)
902     	    && 
903             (Type == FMINIT)  )
904         {
905           LONG lastNdx;  // compute previous producer index
906           if( fcLQ->producer)
907             lastNdx = fcLQ->producer- 1;
908           else
909     	lastNdx = FC_LINKQ_DEPTH-1;
910     
911     
912           if( fcLQ->Qitem[lastNdx].Type == FMINIT)
913           {
914     //        printk(" *skip FMINIT Q post* ");
915     //        goto DoneWithPutQ;
916           }
917     
918         }
919     
920         // OK, add the Q'd item...
921         
922         fcLQ->Qitem[fcLQ->producer].Type = Type;
923        
924         memcpy(
925             fcLQ->Qitem[fcLQ->producer].ulBuff,
926             QueContent, 
927             sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
928     
929         fcLQ->producer = ndx;  // increment Que producer
930     
931         // set semaphore to wake up Kernel (worker) thread
932         // 
933         up( cpqfcHBAdata->fcQueReady );
934       }
935     
936     //DoneWithPutQ:
937     
938       LEAVE("cpqfcTSPutLinkQ");
939     }
940     
941     
942     
943     
944     // reset device ext FC link Q
945     void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
946        
947     {
948       PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
949       fcLQ->producer = 0;
950       fcLQ->consumer = 0;
951     
952     }
953     
954     
955     
956     
957     
958     // When Tachyon gets an unassisted FCP-SCSI frame, post here so
959     // an arbitrary context thread (e.g. IOCTL loopback test function)
960     // can process it.
961     
962     // (NOTE: Not revised for Linux)
963     // This Q works like Tachyon's que - the producer points to the next
964     // (unused) entry.
965     void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
966       int Type, 
967       void *QueContent)
968     {
969     //  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
970     //  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
971     
972     //  ULONG ndx;
973     
974     //  ULONG *pExchangeID;
975     //  LONG ExchangeID;
976     
977     /*
978       KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
979       ndx = pDevExt->fcScsiQue.producer + 1;  // test for Que full
980     
981       if( ndx >= FC_SCSIQ_DEPTH ) // rollover test
982         ndx = 0;
983     
984       if( ndx == pDevExt->fcScsiQue.consumer )   // QUE full test
985       {
986                            // QUE was full! lost LK command (fatal to logic)
987         fcChip->fcStats.ScsiQueFull++;
988     #ifdef DBG
989         printk( "fcPutScsiQue - FULL!\n");
990     #endif
991     
992       }
993       else                        // QUE next element
994       {
995         pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].Type = Type;
996         
997         if( Type == FCP_RSP )
998         {
999           // this TL inbound message type means that a TL SEST exchange has
1000           // copied an FCP response frame into a buffer pointed to by the SEST
1001           // entry.  That buffer is allocated in the SEST structure at ->RspHDR.
1002           // Copy the RspHDR for use by the Que handler.
1003           pExchangeID = (ULONG *)QueContent;
1004           
1005           memcpy(
1006     	      pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
1007             &fcChip->SEST->RspHDR[ *pExchangeID ],
1008     	      sizeof(pDevExt->fcScsiQue.Qitem[0].ulBuff)); // (any element for size)
1009           
1010         }
1011         else
1012         {
1013           memcpy(
1014     	      pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
1015             QueContent, 
1016     	      sizeof(pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff));
1017         }
1018           
1019         pDevExt->fcScsiQue.producer = ndx;  // increment Que
1020     
1021     
1022         KeSetEvent( &pDevExt->TYIBscsi,  // signal any waiting thread
1023            0,                    // no priority boost
1024     		   FALSE );              // no waiting later for this event
1025       }
1026       KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
1027     */
1028     }
1029     
1030     
1031     
1032     
1033     
1034     
1035     
1036     static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
1037     
1038     static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
1039     
1040     static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
1041     
1042     void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
1043     		PFC_LOGGEDIN_PORT pFcPort)
1044     {
1045       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1046     
1047       if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
1048       {
1049         fcChip->fcStats.logouts++;
1050         printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", 
1051             (ULONG)pFcPort->u.liWWN,
1052             (ULONG)(pFcPort->u.liWWN >>32),
1053     	pFcPort->port_id);
1054     
1055       // Terminate I/O with this (Linux) Scsi target
1056         cpqfcTSTerminateExchange( cpqfcHBAdata, 
1057                                 &pFcPort->ScsiNexus,
1058     	                    DEVICE_REMOVED);
1059       }
1060     			
1061       // Do an "implicit logout" - we can't really Logout the device
1062       // (i.e. with LOGOut Request) because of port_id confusion
1063       // (i.e. the Other port has no port_id).
1064       // A new login for that WWN will have to re-write port_id (0 invalid)
1065       pFcPort->port_id = 0;  // invalid!
1066       pFcPort->pdisc = FALSE;
1067       pFcPort->prli = FALSE;
1068       pFcPort->plogi = FALSE;
1069       pFcPort->flogi = FALSE;
1070       pFcPort->LOGO_timer = 0;
1071       pFcPort->device_blocked = TRUE; // block Scsi Requests
1072       pFcPort->ScsiNexus.VolumeSetAddressing=0;	
1073     }
1074     
1075       
1076     // On FC-AL, there is a chance that a previously known device can
1077     // be quietly removed (e.g. with non-managed hub), 
1078     // while a NEW device (with different WWN) took the same alpa or
1079     // even 24-bit port_id.  This chance is unlikely but we must always
1080     // check for it.
1081     static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
1082     		PFC_LOGGEDIN_PORT pLoggedInPort)
1083     {
1084       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1085       // set "other port" at beginning of fcPorts list
1086       PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
1087       while( pOtherPortWithPortId ) 
1088       {
1089         if( (pOtherPortWithPortId->port_id == 
1090              pLoggedInPort->port_id) 
1091     		    &&
1092              (pOtherPortWithPortId != pLoggedInPort) )
1093         {
1094           // trouble!  (Implicitly) Log the other guy out
1095           printk(" *port_id %Xh is duplicated!* ", 
1096             pOtherPortWithPortId->port_id);
1097           cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId); 
1098        }
1099         pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
1100       }
1101     }
1102     
1103     
1104     
1105     
1106     
1107     
1108     // Dynamic Memory Allocation for newly discovered FC Ports.
1109     // For simplicity, maintain fcPorts structs for ALL
1110     // for discovered devices, including those we never do I/O with
1111     // (e.g. Fabric addresses)
1112     
1113     static PFC_LOGGEDIN_PORT CreateFcPort( 
1114     	  CPQFCHBA* cpqfcHBAdata, 
1115     	  PFC_LOGGEDIN_PORT pLastLoggedInPort, 
1116     	  TachFCHDR_GCMND* fchs,
1117     	  LOGIN_PAYLOAD* plogi)
1118     {
1119       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1120       PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
1121       int i;
1122     
1123     
1124       printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
1125       for( i=3; i>=0; i--)   // copy the LOGIN port's WWN
1126         printk("%02X", plogi->port_name[i]);
1127       for( i=7; i>3; i--)   // copy the LOGIN port's WWN
1128         printk("%02X", plogi->port_name[i]);
1129     
1130     
1131       // allocate mem for new port
1132       // (these are small and rare allocations...)
1133       pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
1134     
1135         
1136       // allocation succeeded?  Fill out NEW PORT
1137       if( pNextLoggedInPort )
1138       {    
1139                                   // clear out any garbage (sometimes exists)
1140         memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
1141     
1142     
1143         // If we login to a Fabric, we don't want to treat it
1144         // as a SCSI device...
1145         if( (fchs->s_id & 0xFFF000) != 0xFFF000)
1146         {
1147           int i;
1148           
1149           // create a unique "virtual" SCSI Nexus (for now, just a
1150           // new target ID) -- we will update channel/target on REPORT_LUNS
1151           // special case for very first SCSI target...
1152           if( cpqfcHBAdata->HostAdapter->max_id == 0)
1153           {
1154             pNextLoggedInPort->ScsiNexus.target = 0;
1155             fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
1156           }
1157           else
1158           {
1159             pNextLoggedInPort->ScsiNexus.target =
1160               cpqfcHBAdata->HostAdapter->max_id;
1161           }
1162     
1163           // initialize the lun[] Nexus struct for lun masking      
1164           for( i=0; i< CPQFCTS_MAX_LUN; i++)
1165             pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
1166           
1167           pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
1168           
1169           printk(" SCSI Chan/Trgt %d/%d", 
1170               pNextLoggedInPort->ScsiNexus.channel,
1171               pNextLoggedInPort->ScsiNexus.target);
1172      
1173           // tell Scsi layers about the new target...
1174           cpqfcHBAdata->HostAdapter->max_id++; 
1175     //    printk("HostAdapter->max_id = %d\n",
1176     //      cpqfcHBAdata->HostAdapter->max_id);		    
1177         }                          
1178         else
1179         {
1180           // device is NOT SCSI (in case of Fabric)
1181           pNextLoggedInPort->ScsiNexus.target = -1;  // invalid
1182         }
1183     
1184     	  // create forward link to new port
1185         pLastLoggedInPort->pNextPort = pNextLoggedInPort;
1186         printk("\n");
1187     
1188       }     
1189       return pNextLoggedInPort;  // NULL on allocation failure
1190     }   // end NEW PORT (WWN) logic
1191     
1192     
1193     
1194     // For certain cases, we want to terminate exchanges without
1195     // sending ABTS to the device.  Examples include when an FC
1196     // device changed it's port_id after Loop re-init, or when
1197     // the device sent us a logout.  In the case of changed port_id,
1198     // we want to complete the command and return SOFT_ERROR to
1199     // force a re-try.  In the case of LOGOut, we might return
1200     // BAD_TARGET if the device is really gone.
1201     // Since we must ensure that Tachyon is not operating on the
1202     // exchange, we have to freeze the chip
1203     // sterminateex
1204     void cpqfcTSTerminateExchange( 
1205       CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
1206     {
1207       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1208       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1209       ULONG x_ID;
1210     
1211       if( ScsiNexus )
1212       {
1213     //    printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
1214     //		    ScsiNexus->channel, ScsiNexus->target);
1215     
1216       } 
1217       
1218       for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
1219       {
1220         if( Exchanges->fcExchange[x_ID].type )  // in use?
1221         {
1222           if( ScsiNexus == NULL ) // our HBA changed - term. all
1223           {
1224     	Exchanges->fcExchange[x_ID].status = TerminateStatus;
1225             cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); 
1226           }
1227           else
1228           {
1229     	// If a device, according to WWN, has been removed, it's
1230     	// port_id may be used by another working device, so we
1231     	// have to terminate by SCSI target, NOT port_id.
1232             if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
1233     	{	                 
1234     	  if( (Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
1235     			&&
1236                 (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel)) 
1237               {
1238                 Exchanges->fcExchange[x_ID].status = TerminateStatus;
1239                 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
1240               }
1241     	}
1242     
1243     	// (in case we ever need it...)
1244     	// all SEST structures have a remote node ID at SEST DWORD 2
1245             //          if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
1246             //                ==  port_id)
1247           } 
1248         }
1249       }
1250     }
1251     
1252     
1253     static void ProcessELS_Request( 
1254                   CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1255     {
1256       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1257     //  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1258     //  ULONG ox_id = (fchs->ox_rx_id >>16);
1259       PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
1260       BOOLEAN NeedReject = FALSE;
1261       ULONG ls_reject_code = 0; // default don'n know??
1262     
1263     
1264       // Check the incoming frame for a supported ELS type
1265       switch( fchs->pl[0] & 0xFFFF)
1266       {
1267       case 0x0050: //  PDISC?
1268     
1269         // Payload for PLOGI and PDISC is identical (request & reply)
1270         if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1271         {
1272           LOGIN_PAYLOAD logi;       // FC-PH Port Login
1273           
1274           // PDISC payload OK. If critical login fields
1275           // (e.g. WWN) matches last login for this port_id,
1276           // we may resume any prior exchanges
1277           // with the other port
1278     
1279           
1280           BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1281        
1282           pLoggedInPort = fcFindLoggedInPort( 
1283                  fcChip, 
1284     	     NULL,     // don't search Scsi Nexus
1285     	     0,        // don't search linked list for port_id
1286                  &logi.port_name[0],     // search linked list for WWN
1287                  &pLastLoggedInPort);  // must return non-NULL; when a port_id
1288                                        // is not found, this pointer marks the
1289                                        // end of the singly linked list
1290         
1291           if( pLoggedInPort != NULL)   // WWN found (prior login OK)
1292           { 
1293                
1294      	if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1295     	{
1296               // Yes.  We were expecting PDISC?
1297               if( pLoggedInPort->pdisc )
1298     	  {
1299     	    // Yes; set fields accordingly.     (PDISC, not Originator)
1300                 SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
1301            
1302                 // send 'ACC' reply 
1303                 cpqfcTSPutLinkQue( cpqfcHBAdata, 
1304                               ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1305                               fchs );
1306     
1307     	    // OK to resume I/O...
1308     	  }
1309     	  else
1310      	  {
1311     	    printk("Not expecting PDISC (pdisc=FALSE)\n");
1312     	    NeedReject = TRUE;
1313     	    // set reject reason code 
1314                 ls_reject_code = 
1315                   LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1316     	  }
1317     	}
1318     	else
1319     	{
1320     	  if( pLoggedInPort->port_id != 0)
1321     	  {
1322       	    printk("PDISC PortID change: old %Xh, new %Xh\n",
1323                   pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1324     	  }
1325               NeedReject = TRUE;
1326               // set reject reason code 
1327               ls_reject_code = 
1328     	    LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1329     		  
1330     	}
1331           }
1332           else
1333           {
1334     	printk("PDISC Request from unknown WWN\n");
1335             NeedReject = TRUE;
1336               
1337     	// set reject reason code 
1338             ls_reject_code = 
1339               LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
1340           }
1341     
1342         }
1343         else // Payload unacceptable
1344         {
1345           printk("payload unacceptable\n");
1346           NeedReject = TRUE;  // reject code already set
1347           
1348         }
1349     
1350         if( NeedReject)
1351         {
1352           ULONG port_id;
1353           // The PDISC failed.  Set login struct flags accordingly,
1354           // terminate any I/O to this port, and Q a PLOGI
1355           if( pLoggedInPort )
1356           {
1357             pLoggedInPort->pdisc = FALSE;
1358             pLoggedInPort->prli = FALSE;
1359             pLoggedInPort->plogi = FALSE;
1360     	
1361             cpqfcTSTerminateExchange( cpqfcHBAdata, 
1362               &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1363     	port_id = pLoggedInPort->port_id;
1364           }
1365           else
1366           {
1367     	port_id = fchs->s_id &0xFFFFFF;
1368           }
1369           fchs->reserved = ls_reject_code; // borrow this (unused) field
1370           cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1371         }
1372        
1373         break;
1374     
1375     
1376     
1377       case 0x0003: //  PLOGI?
1378     
1379         // Payload for PLOGI and PDISC is identical (request & reply)
1380         if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1381         {
1382           LOGIN_PAYLOAD logi;       // FC-PH Port Login
1383           BOOLEAN NeedReject = FALSE;
1384           
1385           // PDISC payload OK. If critical login fields
1386           // (e.g. WWN) matches last login for this port_id,
1387           // we may resume any prior exchanges
1388           // with the other port
1389     
1390           
1391           BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1392        
1393           pLoggedInPort = fcFindLoggedInPort( 
1394                  fcChip, 
1395     	     NULL,       // don't search Scsi Nexus
1396     	     0,        // don't search linked list for port_id
1397                  &logi.port_name[0],     // search linked list for WWN
1398                  &pLastLoggedInPort);  // must return non-NULL; when a port_id
1399                                        // is not found, this pointer marks the
1400                                        // end of the singly linked list
1401         
1402           if( pLoggedInPort == NULL)   // WWN not found -New Port
1403           { 
1404           	pLoggedInPort = CreateFcPort( 
1405     			  cpqfcHBAdata, 
1406     			  pLastLoggedInPort, 
1407     			  fchs,
1408     			  &logi);
1409             if( pLoggedInPort == NULL )
1410             {
1411               printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1412               // Now Q a LOGOut Request, since we won't be talking to that device
1413     	
1414               NeedReject = TRUE;  
1415     	  
1416               // set reject reason code 
1417               ls_reject_code = 
1418                 LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
1419     	    
1420     	}
1421           }
1422           if( !NeedReject )
1423           {
1424           
1425             // OK - we have valid fcPort ptr; set fields accordingly.   
1426     	//                         (not PDISC, not Originator)
1427             SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); 
1428     
1429             // send 'ACC' reply 
1430             cpqfcTSPutLinkQue( cpqfcHBAdata, 
1431                           ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1432                           fchs );
1433           }
1434         }
1435         else // Payload unacceptable
1436         {
1437           printk("payload unacceptable\n");
1438           NeedReject = TRUE;  // reject code already set
1439         }
1440     
1441         if( NeedReject)
1442         {
1443           // The PDISC failed.  Set login struct flags accordingly,
1444           // terminate any I/O to this port, and Q a PLOGI
1445           pLoggedInPort->pdisc = FALSE;
1446           pLoggedInPort->prli = FALSE;
1447           pLoggedInPort->plogi = FALSE;
1448     	
1449           fchs->reserved = ls_reject_code; // borrow this (unused) field
1450     
1451           // send 'RJT' reply 
1452           cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1453         }
1454        
1455         // terminate any exchanges with this device...
1456         if( pLoggedInPort )
1457         {
1458           cpqfcTSTerminateExchange( cpqfcHBAdata, 
1459             &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1460         }
1461         break;
1462     
1463     
1464     
1465       case 0x1020:  // PRLI?
1466       {
1467         BOOLEAN NeedReject = TRUE;
1468         pLoggedInPort = fcFindLoggedInPort( 
1469                fcChip, 
1470                NULL,       // don't search Scsi Nexus
1471     	   (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
1472                NULL,     // DON'T search linked list for WWN
1473                NULL);    // don't care
1474           
1475         if( pLoggedInPort == NULL ) 
1476         {
1477           // huh?
1478           printk(" Unexpected PRLI Request -not logged in!\n");
1479     
1480           // set reject reason code 
1481           ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1482           
1483           // Q a LOGOut here?
1484         }
1485         else
1486         {
1487           // verify the PRLI ACC payload
1488           if( !verify_PRLI( fchs, &ls_reject_code) )
1489           {
1490             // PRLI Reply is acceptable; were we expecting it?
1491             if( pLoggedInPort->plogi ) 
1492             { 
1493       	  // yes, we expected the PRLI ACC  (not PDISC; not Originator)
1494               SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1495     
1496               // Q an ACCept Reply
1497     	  cpqfcTSPutLinkQue( cpqfcHBAdata,
1498                             ELS_PRLI_ACC, 
1499                             fchs );   
1500     	  
1501     	  NeedReject = FALSE;
1502     	}
1503             else
1504             {
1505               // huh?
1506               printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
1507     
1508               // set reject reason code 
1509               ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1510         
1511         	  // Q a LOGOut here?
1512     	  
1513             }
1514           }
1515           else
1516           {
1517             printk(" PRLI REQUEST payload failed verify\n");
1518             // (reject code set by "verify")
1519     
1520             // Q a LOGOut here?
1521           }
1522         }
1523     
1524         if( NeedReject )
1525         {
1526           // Q a ReJecT Reply with reason code
1527           fchs->reserved = ls_reject_code;
1528           cpqfcTSPutLinkQue( cpqfcHBAdata,
1529                         ELS_RJT, // Q Type
1530                         fchs );  
1531         }
1532       }
1533         break;
1534      
1535     
1536         
1537     
1538       case  0x0005:  // LOGOut?
1539       {
1540       // was this LOGOUT because we sent a ELS_PDISC to an FC device
1541       // with changed (or new) port_id, or does the port refuse 
1542       // to communicate to us?
1543       // We maintain a logout counter - if we get 3 consecutive LOGOuts,
1544       // give up!
1545         LOGOUT_PAYLOAD logo;
1546         BOOLEAN GiveUpOnDevice = FALSE;
1547         ULONG ls_reject_code = 0;
1548         
1549         BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
1550     
1551         pLoggedInPort = fcFindLoggedInPort( 
1552                fcChip, 
1553                NULL,     // don't search Scsi Nexus
1554     	   0,        // don't search linked list for port_id
1555                &logo.port_name[0],     // search linked list for WWN
1556                NULL);    // don't care about end of list
1557         
1558         if( pLoggedInPort ) // found the device?
1559         {
1560           // Q an ACC reply 
1561           cpqfcTSPutLinkQue( cpqfcHBAdata,
1562                         ELS_LOGO_ACC, // Q Type
1563                         fchs );       // device to respond to
1564     
1565           // set login struct fields (LOGO_counter increment)
1566           SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1567           
1568           // are we an Initiator?
1569           if( fcChip->Options.initiator)  
1570           {
1571             // we're an Initiator, so check if we should 
1572     	// try (another?) login
1573     
1574     	// Fabrics routinely log out from us after
1575     	// getting device info - don't try to log them
1576     	// back in.
1577     	if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
1578     	{
1579     	  ; // do nothing
1580     	}
1581     	else if( pLoggedInPort->LOGO_counter <= 3)
1582     	{
1583     	  // try (another) login (PLOGI request)
1584     	  
1585               cpqfcTSPutLinkQue( cpqfcHBAdata,
1586                         ELS_PLOGI, // Q Type
1587                         fchs );  
1588     	
1589     	  // Terminate I/O with "retry" potential
1590     	  cpqfcTSTerminateExchange( cpqfcHBAdata, 
1591     			            &pLoggedInPort->ScsiNexus,
1592     				    PORTID_CHANGED);
1593     	}
1594     	else
1595     	{
1596     	  printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
1597     			  fchs->s_id &&0xFFFFFF);
1598     	  GiveUpOnDevice = TRUE;
1599     	}
1600           }
1601           else
1602           {
1603     	GiveUpOnDevice = TRUE;
1604           }
1605     
1606     
1607           if( GiveUpOnDevice == TRUE )
1608           {
1609             cpqfcTSTerminateExchange( cpqfcHBAdata, 
1610     	                          &pLoggedInPort->ScsiNexus,
1611     		                  DEVICE_REMOVED);
1612           }
1613         }  
1614         else  // we don't know this WWN!
1615         {
1616           // Q a ReJecT Reply with reason code
1617           fchs->reserved = ls_reject_code;
1618           cpqfcTSPutLinkQue( cpqfcHBAdata,
1619                         ELS_RJT, // Q Type
1620                         fchs );  
1621         }
1622       }
1623         break;
1624     
1625     
1626     
1627     
1628       // FABRIC only case
1629       case 0x0461:  // ELS RSCN (Registered State Change Notification)?
1630       {
1631         int Ports;
1632         int i;
1633         __u32 Buff;
1634         // Typically, one or more devices have been added to or dropped
1635         // from the Fabric.
1636         // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
1637         // The first 32-bit word has a 2-byte Payload Length, which
1638         // includes the 4 bytes of the first word.  Consequently,
1639         // this PL len must never be less than 4, must be a multiple of 4,
1640         // and has a specified max value 256.
1641         // (Endianess!)
1642         Ports = ((fchs->pl[0] >>24) - 4) / 4;
1643         Ports = Ports > 63 ? 63 : Ports;
1644         
1645         printk(" RSCN ports: %d\n", Ports);
1646         if( Ports <= 0 )  // huh?
1647         {
1648           // ReJecT the command
1649           fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
1650         
1651           cpqfcTSPutLinkQue( cpqfcHBAdata,
1652                         ELS_RJT, // Q Type
1653                         fchs ); 
1654           
1655           break;
1656         }
1657         else  // Accept the command
1658         {
1659            cpqfcTSPutLinkQue( cpqfcHBAdata,
1660                         ELS_ACC, // Q Type
1661                         fchs ); 
1662         }
1663         
1664           // Check the "address format" to determine action.
1665           // We have 3 cases:
1666           // 0 = Port Address; 24-bit address of affected device
1667           // 1 = Area Address; MS 16 bits valid
1668           // 2 = Domain Address; MS 8 bits valid
1669         for( i=0; i<Ports; i++)
1670         { 
1671           BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
1672           switch( Buff & 0xFF000000)
1673           {
1674     
1675           case 0:  // Port Address?
1676     	
1677           case 0x01000000: // Area Domain?
1678           case 0x02000000: // Domain Address
1679             // For example, "port_id" 0x201300 
1680     	// OK, let's try a Name Service Request (Query)
1681           fchs->s_id = 0xFFFFFC;  // Name Server Address
1682           cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
1683     
1684           break;
1685     	
1686     	
1687           default:  // huh? new value on version change?
1688           break;
1689           }
1690         }
1691       }    
1692       break;    
1693     
1694     
1695     
1696         
1697       default:  // don't support this request (yet)
1698         // set reject reason code 
1699         fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 
1700     		                    REQUEST_NOT_SUPPORTED);
1701         
1702         cpqfcTSPutLinkQue( cpqfcHBAdata,
1703                         ELS_RJT, // Q Type
1704                         fchs );     
1705         break;  
1706       }
1707     }
1708     
1709     
1710     static void ProcessELS_Reply( 
1711     		CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1712     {
1713       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1714       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1715       ULONG ox_id = (fchs->ox_rx_id >>16);
1716       ULONG ls_reject_code;
1717       PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
1718       
1719       // If this is a valid reply, then we MUST have sent a request.
1720       // Verify that we can find a valid request OX_ID corresponding to
1721       // this reply
1722     
1723       
1724       if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
1725       {
1726         printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", 
1727     		    ox_id, fchs->ox_rx_id & 0xffff);
1728         goto Quit;  // exit this routine
1729       }
1730     
1731     
1732       // Is the reply a RJT (reject)?
1733       if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
1734       {
1735     //  ******  REJECT REPLY  ********
1736         switch( Exchanges->fcExchange[ox_id].type )
1737         {
1738     	  
1739         case ELS_FDISC:  // we sent out Fabric Discovery
1740         case ELS_FLOGI:  // we sent out FLOGI
1741     
1742           printk("RJT received on Fabric Login from %Xh, reason %Xh\n", 
1743             fchs->s_id, fchs->pl[1]);    
1744     
1745         break;
1746     
1747         default:
1748         break;
1749         }
1750           
1751         goto Done;
1752       }
1753     
1754       // OK, we have an ACCept...
1755       // What's the ACC type? (according to what we sent)
1756       switch( Exchanges->fcExchange[ox_id].type )
1757       {
1758     	  
1759       case ELS_PLOGI:  // we sent out PLOGI
1760         if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1761         {
1762           LOGIN_PAYLOAD logi;       // FC-PH Port Login
1763           
1764           // login ACC payload acceptable; search for WWN in our list
1765           // of fcPorts
1766           
1767           BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1768        
1769           pLoggedInPort = fcFindLoggedInPort( 
1770                  fcChip, 
1771     	     NULL,     // don't search Scsi Nexus
1772     	     0,        // don't search linked list for port_id
1773                  &logi.port_name[0],     // search linked list for WWN
1774                  &pLastLoggedInPort);  // must return non-NULL; when a port_id
1775                                        // is not found, this pointer marks the
1776                                        // end of the singly linked list
1777         
1778           if( pLoggedInPort == NULL)         // WWN not found - new port
1779           {
1780     
1781     	pLoggedInPort = CreateFcPort( 
1782     			  cpqfcHBAdata, 
1783     			  pLastLoggedInPort, 
1784     			  fchs,
1785     			  &logi);
1786     
1787             if( pLoggedInPort == NULL )
1788             {
1789               printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1790               // Now Q a LOGOut Request, since we won't be talking to that device
1791     	
1792               goto Done;  // exit with error! dropped login frame
1793     	}
1794           }
1795           else      // WWN was already known.  Ensure that any open
1796     	        // exchanges for this WWN are terminated.
1797           	// NOTE: It's possible that a device can change its 
1798     	// 24-bit port_id after a Link init or Fabric change 
1799     	// (e.g. LIP or Fabric RSCN).  In that case, the old
1800     	// 24-bit port_id may be duplicated, or no longer exist.
1801           {
1802     
1803             cpqfcTSTerminateExchange( cpqfcHBAdata, 
1804               &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1805           }
1806     
1807           // We have an fcPort struct - set fields accordingly
1808                                         // not PDISC, originator 
1809           SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1810     			
1811           // We just set a "port_id"; is it duplicated?
1812           TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1813     
1814           // For Fabric operation, we issued PLOGI to 0xFFFFFC
1815           // so we can send SCR (State Change Registration) 
1816           // Check for this special case...
1817           if( fchs->s_id == 0xFFFFFC ) 
1818           {
1819             // PLOGI ACC was a Fabric response... issue SCR
1820     	fchs->s_id = 0xFFFFFD;  // address for SCR
1821             cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
1822           }
1823     
1824           else
1825           {
1826           // Now we need a PRLI to enable FCP-SCSI operation
1827           // set flags and Q up a ELS_PRLI
1828             cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
1829           }
1830         }
1831         else
1832         {
1833           // login payload unacceptable - reason in ls_reject_code
1834           // Q up a Logout Request
1835           printk("Login Payload unacceptable\n");
1836     
1837         }
1838         break;
1839     
1840     
1841       // PDISC logic very similar to PLOGI, except we never want
1842       // to allocate mem for "new" port, and we set flags differently
1843       // (might combine later with PLOGI logic for efficiency)  
1844       case ELS_PDISC:  // we sent out PDISC
1845         if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1846         {
1847           LOGIN_PAYLOAD logi;       // FC-PH Port Login
1848           BOOLEAN NeedLogin = FALSE;
1849           
1850           // login payload acceptable; search for WWN in our list
1851           // of (previously seen) fcPorts
1852           
1853           BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1854        
1855           pLoggedInPort = fcFindLoggedInPort( 
1856                  fcChip, 
1857     	     NULL,     // don't search Scsi Nexus
1858     	     0,        // don't search linked list for port_id
1859                  &logi.port_name[0],     // search linked list for WWN
1860                  &pLastLoggedInPort);  // must return non-NULL; when a port_id
1861                                        // is not found, this pointer marks the
1862                                        // end of the singly linked list
1863         
1864           if( pLoggedInPort != NULL)   // WWN found?
1865           {
1866             // WWN has same port_id as last login?  (Of course, a properly
1867     	// working FC device should NEVER ACCept a PDISC if it's
1868     	// port_id changed, but check just in case...)
1869     	if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1870     	{
1871               // Yes.  We were expecting PDISC?
1872               if( pLoggedInPort->pdisc )
1873     	  {
1874                 int i;
1875     	    
1876     	    
1877     	    // PDISC expected -- set fields.  (PDISC, Originator)
1878                 SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
1879     
1880     	    // We are ready to resume FCP-SCSI to this device...
1881                 // Do we need to start anything that was Queued?
1882     
1883                 for( i=0; i< TACH_SEST_LEN; i++)
1884                 {
1885                   // see if any exchange for this PDISC'd port was queued
1886                   if( ((fchs->s_id &0xFFFFFF) == 
1887                        (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
1888                           &&
1889                       (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
1890                   {
1891                     fchs->reserved = i; // copy ExchangeID
1892     //                printk(" *Q x_ID %Xh after PDISC* ",i);
1893     
1894                     cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
1895                   }
1896                 }
1897     
1898     	    // Complete commands Q'd while we were waiting for Login
1899     
1900     	    UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
1901     	  }
1902     	  else
1903     	  {
1904     	    printk("Not expecting PDISC (pdisc=FALSE)\n");
1905     	    NeedLogin = TRUE;
1906     	  }
1907     	}
1908     	else
1909     	{
1910     	  printk("PDISC PortID change: old %Xh, new %Xh\n",
1911                 pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1912               NeedLogin = TRUE;
1913     		  
1914     	}
1915           }
1916           else
1917           {
1918     	printk("PDISC ACC from unknown WWN\n");
1919             NeedLogin = TRUE;
1920           }
1921     
1922           if( NeedLogin)
1923           {
1924     	
1925             // The PDISC failed.  Set login struct flags accordingly,
1926     	// terminate any I/O to this port, and Q a PLOGI
1927     	if( pLoggedInPort )  // FC device previously known?
1928     	{
1929     
1930               cpqfcTSPutLinkQue( cpqfcHBAdata,
1931                         ELS_LOGO, // Q Type
1932                         fchs );   // has port_id to send to 
1933     
1934     	  // There are a variety of error scenarios which can result
1935       	  // in PDISC failure, so as a catchall, add the check for
1936     	  // duplicate port_id.
1937     	  TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1938     
1939     //    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
1940               pLoggedInPort->pdisc = FALSE;
1941               pLoggedInPort->prli = FALSE;
1942               pLoggedInPort->plogi = FALSE;
1943     	
1944               cpqfcTSTerminateExchange( cpqfcHBAdata, 
1945     	    &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1946             }
1947             cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
1948           }
1949         }
1950         else
1951         {
1952           // login payload unacceptable - reason in ls_reject_code
1953           // Q up a Logout Request
1954           printk("ERROR: Login Payload unacceptable!\n");
1955     
1956         }
1957        
1958         break;
1959         
1960     
1961     
1962       case ELS_PRLI:  // we sent out PRLI
1963     
1964     
1965         pLoggedInPort = fcFindLoggedInPort( 
1966                fcChip, 
1967                NULL,       // don't search Scsi Nexus
1968     	   (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
1969                NULL,     // DON'T search linked list for WWN
1970                NULL);    // don't care
1971           
1972         if( pLoggedInPort == NULL ) 
1973         {
1974           // huh?
1975           printk(" Unexpected PRLI ACCept frame!\n");
1976     
1977           // Q a LOGOut here?
1978     
1979           goto Done;
1980         }
1981     
1982         // verify the PRLI ACC payload
1983         if( !verify_PRLI( fchs, &ls_reject_code) )
1984         {
1985           // PRLI Reply is acceptable; were we expecting it?
1986           if( pLoggedInPort->plogi ) 
1987           { 
1988     	// yes, we expected the PRLI ACC  (not PDISC; Originator)
1989     	SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1990     
1991             // OK, let's send a REPORT_LUNS command to determine
1992     	// whether VSA or PDA FCP-LUN addressing is used.
1993     	
1994             cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
1995     	
1996     	// It's possible that a device we were talking to changed 
1997     	// port_id, and has logged back in.  This function ensures
1998     	// that I/O will resume.
1999             UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
2000     
2001           }
2002           else
2003           {
2004             // huh?
2005             printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
2006     
2007             // Q a LOGOut here?
2008             goto Done;
2009           }
2010         }
2011         else
2012         {
2013           printk(" PRLI ACCept payload failed verify\n");
2014     
2015           // Q a LOGOut here?
2016         }
2017     
2018         break;
2019      
2020       case ELS_FLOGI:  // we sent out FLOGI (Fabric Login)
2021     
2022         // update the upper 16 bits of our port_id in Tachyon
2023         // the switch adds those upper 16 bits when responding
2024         // to us (i.e. we are the destination_id)
2025         fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
2026         writel( fcChip->Registers.my_al_pa,  
2027           fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
2028     
2029         // now send out a PLOGI to the well known port_id 0xFFFFFC
2030         fchs->s_id = 0xFFFFFC;
2031         cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
2032       
2033        break; 
2034     
2035     
2036       case ELS_FDISC:  // we sent out FDISC (Fabric Discovery (Login))
2037     
2038        printk( " ELS_FDISC success ");
2039        break;
2040        
2041     
2042       case ELS_SCR:  // we sent out State Change Registration
2043         // now we can issue Name Service Request to find any
2044         // Fabric-connected devices we might want to login to.
2045        
2046     	
2047         fchs->s_id = 0xFFFFFC;  // Name Server Address
2048         cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
2049         
2050     
2051         break;
2052     
2053         
2054       default:
2055         printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", 
2056        		    ox_id, fchs->ox_rx_id & 0xffff);
2057         break;
2058       }
2059     
2060       
2061     Done:
2062       // Regardless of whether the Reply is valid or not, the
2063       // the exchange is done - complete
2064       cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete
2065     	  
2066     Quit:    
2067       return;
2068     }
2069     
2070     
2071     
2072     
2073     
2074     
2075     // ****************  Fibre Channel Services  **************
2076     // This is where we process the Directory (Name) Service Reply
2077     // to know which devices are on the Fabric
2078     
2079     static void ProcessFCS_Reply( 
2080     	CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
2081     {
2082       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2083       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2084       ULONG ox_id = (fchs->ox_rx_id >>16);
2085     //  ULONG ls_reject_code;
2086     //  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
2087       
2088       // If this is a valid reply, then we MUST have sent a request.
2089       // Verify that we can find a valid request OX_ID corresponding to
2090       // this reply
2091     
2092       if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
2093       {
2094         printk(" *Discarding Reply frame, xID %04X/%04X* ", 
2095     		    ox_id, fchs->ox_rx_id & 0xffff);
2096         goto Quit;  // exit this routine
2097       }
2098     
2099     
2100       // OK, we were expecting it.  Now check to see if it's a
2101       // "Name Service" Reply, and if so force a re-validation of
2102       // Fabric device logins (i.e. Start the login timeout and
2103       // send PDISC or PLOGI)
2104       // (Endianess Byte Swap?)
2105       if( fchs->pl[1] == 0x02FC )  // Name Service
2106       {
2107         // got a new (or NULL) list of Fabric attach devices... 
2108         // Invalidate current logins
2109         
2110         PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
2111         while( pLoggedInPort ) // for all ports which are expecting
2112                                // PDISC after the next LIP, set the
2113                                // logoutTimer
2114         {
2115     
2116           if( (pLoggedInPort->port_id & 0xFFFF00)  // Fabric device?
2117     		      &&
2118               (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
2119           {
2120             pLoggedInPort->LOGO_timer = 6;  // what's the Fabric timeout??
2121                                     // suspend any I/O in progress until
2122                                     // PDISC received...
2123             pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
2124           }
2125     	    
2126           pLoggedInPort = pLoggedInPort->pNextPort;
2127         }
2128         
2129         if( fchs->pl[2] == 0x0280)  // ACCept?
2130         {
2131           // Send PLOGI or PDISC to these Fabric devices
2132           SendLogins( cpqfcHBAdata, &fchs->pl[4] );  
2133         }
2134     
2135     
2136         // As of this writing, the only reason to reject is because NO
2137         // devices are left on the Fabric.  We already started
2138         // "logged out" timers; if the device(s) don't come
2139         // back, we'll do the implicit logout in the heart beat 
2140         // timer routine
2141         else  // ReJecT
2142         {
2143           // this just means no Fabric device is visible at this instant
2144         } 
2145       }
2146     
2147       // Regardless of whether the Reply is valid or not, the
2148       // the exchange is done - complete
2149       cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete
2150     	  
2151     Quit:    
2152       return;
2153     }
2154     
2155     
2156     
2157     
2158     
2159     
2160     
2161     static void AnalyzeIncomingFrame( 
2162             CPQFCHBA *cpqfcHBAdata,
2163             ULONG QNdx )
2164     {
2165       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2166       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2167       PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
2168       TachFCHDR_GCMND* fchs = 
2169         (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
2170     //  ULONG ls_reject_code;  // reason for rejecting login
2171       LONG ExchangeID;
2172     //  FC_LOGGEDIN_PORT *pLoggedInPort;
2173       BOOLEAN AbortAccept;  
2174     
2175       ENTER("AnalyzeIncomingFrame");
2176     
2177     
2178     
2179       switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
2180       {
2181     
2182       case SFQ_UNKNOWN:  // unknown frame (e.g. LIP position frame, NOP, etc.)
2183      
2184     
2185           // *********  FC-4 Device Data/ Fibre Channel Service *************
2186         if( ((fchs->d_id &0xF0000000) == 0)   // R_CTL (upper nibble) 0x0?
2187                     &&   
2188           (fchs->f_ctl & 0x20000000) )  // TYPE 20h is Fibre Channel Service
2189         {
2190     
2191           // ************** FCS Reply **********************
2192     
2193           if( (fchs->d_id & 0xff000000L) == 0x03000000L)  // (31:23 R_CTL)
2194           {
2195     	ProcessFCS_Reply( cpqfcHBAdata, fchs );
2196     
2197           }  // end of  FCS logic
2198     
2199         }
2200         
2201     
2202           // ***********  Extended Link Service **************
2203     
2204         else if( fchs->d_id & 0x20000000   // R_CTL 0x2?
2205                       &&   
2206           (fchs->f_ctl & 0x01000000) )  // TYPE = 1
2207         {
2208     
2209                                // these frames are either a response to
2210                                // something we sent (0x23) or "unsolicited"
2211                                // frames (0x22).
2212     
2213     
2214           // **************Extended Link REPLY **********************
2215                                // R_CTL Solicited Control Reply
2216     
2217           if( (fchs->d_id & 0xff000000L) == 0x23000000L)  // (31:23 R_CTL)
2218           {
2219     
2220     	ProcessELS_Reply( cpqfcHBAdata, fchs );
2221     
2222           }  // end of  "R_CTL Solicited Control Reply"
2223     
2224     
2225     
2226     
2227            // **************Extended Link REQUEST **********************
2228            // (unsolicited commands from another port or task...)
2229     
2230                                // R_CTL Ext Link REQUEST
2231           else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2232                   (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
2233           {
2234     
2235     
2236     
2237     	ProcessELS_Request( cpqfcHBAdata, fchs );
2238     
2239           }
2240     
2241     
2242     
2243             // ************** LILP **********************
2244           else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2245                    (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
2246     
2247           {
2248             // SANMark specifies that when available, we must use
2249     	// the LILP frame to determine which ALPAs to send Port Discovery
2250     	// to...
2251     
2252             if( fchs->pl[0] == 0x0711L) //  ELS_PLOGI?
2253     	{
2254     //	  UCHAR *ptr = (UCHAR*)&fchs->pl[1];
2255     //	  printk(" %d ALPAs found\n", *ptr);
2256     	  memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
2257     	  fcChip->Options.LILPin = 1; // our LILPmap is valid!
2258     	  // now post to make Port Discovery happen...
2259               cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);  
2260     	}
2261           }
2262         }
2263     
2264          
2265         // *****************  BASIC LINK SERVICE *****************
2266         
2267         else if( fchs->d_id & 0x80000000  // R_CTL:
2268                         &&           // Basic Link Service Request
2269                !(fchs->f_ctl & 0xFF000000) )  // type=0 for BLS
2270         {
2271     
2272           // Check for ABTS (Abort Sequence)
2273           if( (fchs->d_id & 0x8F000000) == 0x81000000)
2274           {
2275             // look for OX_ID, S_ID pair that matches in our
2276             // fcExchanges table; if found, reply with ACCept and complete
2277             // the exchange
2278     
2279             // Per PLDA, an ABTS is sent by an initiator; therefore
2280             // assume that if we have an exhange open to the port who
2281             // sent ABTS, it will be the d_id of what we sent.  
2282             for( ExchangeID = 0, AbortAccept=FALSE;
2283                  ExchangeID < TACH_SEST_LEN; ExchangeID++)
2284             {
2285                 // Valid "target" exchange 24-bit port_id matches? 
2286                 // NOTE: For the case of handling Intiator AND Target
2287                 // functions on the same chip, we can have TWO Exchanges
2288                 // with the same OX_ID -- OX_ID/FFFF for the CMND, and
2289                 // OX_ID/RX_ID for the XRDY or DATA frame(s).  Ideally,
2290                 // we would like to support ABTS from Initiators or Targets,
2291                 // but it's not clear that can be supported on Tachyon for
2292                 // all cases (requires more investigation).
2293                 
2294               if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
2295                    Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
2296                       &&
2297                  ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2298                  (fchs->s_id & 0xFFFFFF)) )
2299               {
2300                   
2301                   // target xchnge port_id matches -- how about OX_ID?
2302                 if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
2303                         == (fchs->ox_rx_id & 0xFFFF0000) )
2304                         // yes! post ACCept response; will be completed by fcStart
2305                 {
2306                   Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
2307                     
2308                     // copy (add) rx_id field for simplified ACCept reply
2309                   fchs->ox_rx_id = 
2310                     Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
2311                     
2312                   cpqfcTSPutLinkQue( cpqfcHBAdata,
2313                                 BLS_ABTS_ACC, // Q Type 
2314                                 fchs );    // void QueContent
2315                   AbortAccept = TRUE;
2316           printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", 
2317                  fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
2318                   break;      // ABTS can affect only ONE exchange -exit loop
2319                 }
2320               }
2321             }  // end of FOR loop
2322             if( !AbortAccept ) // can't ACCept ABTS - send Reject
2323             {
2324           printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", 
2325                 fchs->ox_rx_id);
2326               if( Exchanges->fcExchange[ ExchangeID].type 
2327                     &&
2328                   !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
2329                    & 0x80000000))
2330               {
2331                 cpqfcTSCompleteExchange( fcChip, ExchangeID);
2332               }
2333               else
2334               {
2335                 printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", 
2336                   ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
2337               }
2338             }
2339           }
2340     
2341           // Check for BLS {ABTS? (Abort Sequence)} ACCept
2342           else if( (fchs->d_id & 0x8F000000) == 0x84000000)
2343           {
2344             // target has responded with ACC for our ABTS;
2345     	// complete the indicated exchange with ABORTED status 
2346             // Make no checks for correct RX_ID, since
2347     	// all we need to conform ABTS ACC is the OX_ID.
2348             // Verify that the d_id matches!
2349      
2350             ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2351     //	printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n", 
2352     //          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
2353     //          Exchanges->fcExchange[ExchangeID].status);
2354     
2355     
2356     	
2357             if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2358             {
2359                 // Does "target" exchange 24-bit port_id match? 
2360                 // (See "NOTE" above for handling Intiator AND Target in
2361                 // the same device driver)
2362                 // First, if this is a target response, then we originated
2363     	    // (initiated) it with BLS_ABTS:
2364     	  
2365               if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2366     
2367                       &&
2368     	    // Second, does the source of this ACC match the destination
2369                 // of who we originally sent it to?
2370                  ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2371                  (fchs->s_id & 0xFFFFFF)) )
2372               {
2373                 cpqfcTSCompleteExchange( fcChip, ExchangeID );
2374     	  }
2375             }              
2376           }
2377           // Check for BLS {ABTS? (Abort Sequence)} ReJecT
2378           else if( (fchs->d_id & 0x8F000000) == 0x85000000)
2379           {
2380             // target has responded with RJT for our ABTS;
2381     	// complete the indicated exchange with ABORTED status 
2382             // Make no checks for correct RX_ID, since
2383     	// all we need to conform ABTS ACC is the OX_ID.
2384             // Verify that the d_id matches!
2385      
2386             ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2387     //	printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n", 
2388     //          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
2389     
2390             if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2391     	{  
2392                 // Does "target" exchange 24-bit port_id match? 
2393                 // (See "NOTE" above for handling Intiator AND Target in
2394                 // the same device driver)
2395                 // First, if this is a target response, then we originated
2396     	    // (initiated) it with BLS_ABTS:
2397     		  
2398               if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2399     
2400                       &&
2401     	    // Second, does the source of this ACC match the destination
2402                 // of who we originally sent it to?
2403                  ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2404                  (fchs->s_id & 0xFFFFFF)) )
2405               {
2406     	    // YES! NOTE: There is a bug in CPQ's RA-4000 box 
2407     	    // where the "reason code" isn't returned in the payload
2408     	    // For now, simply presume the reject is because the target
2409     	    // already completed the exchange...
2410     	    
2411     //            printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
2412                 cpqfcTSCompleteExchange( fcChip, ExchangeID );
2413     	  }
2414     	} 
2415           }  // end of ABTS check
2416         }  // end of Basic Link Service Request
2417         break;
2418       
2419         default:
2420           printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
2421             fcLQ->Qitem[QNdx].Type,
2422             fcLQ->Qitem[QNdx].Type);
2423         break;
2424       }
2425     }
2426     
2427     
2428     // Function for Port Discovery necessary after every FC 
2429     // initialization (e.g. LIP).
2430     // Also may be called if from Fabric Name Service logic.
2431     
2432     static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
2433     {
2434       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2435       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2436       ULONG ulStatus=0;
2437       TachFCHDR_GCMND fchs;  // copy fields for transmission
2438       int i;
2439       ULONG loginType;
2440       LONG ExchangeID;
2441       PFC_LOGGEDIN_PORT pLoggedInPort;
2442       __u32 PortIds[ number_of_al_pa];
2443       int NumberOfPorts=0;
2444     
2445       // We're going to presume (for now) that our limit of Fabric devices
2446       // is the same as the number of alpa on a private loop (126 devices).
2447       // (Of course this could be changed to support however many we have
2448       // memory for).
2449       memset( &PortIds[0], 0, sizeof(PortIds));
2450        
2451       // First, check if this login is for our own Link Initialization
2452       // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
2453       // from a switch.  If we are logging into Fabric devices, we'll
2454       // have a non-NULL FabricPortId pointer
2455       
2456       if( FabricPortIds != NULL) // may need logins
2457       {
2458         int LastPort=FALSE;
2459         i = 0;
2460         while( !LastPort)
2461         {
2462           // port IDs From NSR payload; byte swap needed?
2463           BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
2464      
2465     //      printk("FPortId[%d] %Xh ", i, PortIds[i]);
2466           if( PortIds[i] & 0x80000000)
2467     	LastPort = TRUE;
2468           
2469           PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
2470           // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
2471           // erroneously use ALPA 0.
2472           if( PortIds[i]  ) // need non-zero port_id...
2473             i++;
2474           
2475           if( i >= number_of_al_pa ) // (in)sanity check
2476     	break;
2477           FabricPortIds++;  // next...
2478         }
2479     
2480         NumberOfPorts = i;
2481     //    printk("NumberOf Fabric ports %d", NumberOfPorts);
2482       }
2483       
2484       else  // need to send logins on our "local" link
2485       {
2486       
2487         // are we a loop port?  If so, check for reception of LILP frame,
2488         // and if received use it (SANMark requirement)
2489         if( fcChip->Options.LILPin )
2490         {
2491           int j=0;
2492           // sanity check on number of ALPAs from LILP frame...
2493           // For format of LILP frame, see FC-AL specs or 
2494           // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
2495           // First byte is number of ALPAs
2496           i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
2497           NumberOfPorts = i;
2498     //      printk(" LILP alpa count %d ", i);
2499           while( i > 0)
2500           {
2501     	PortIds[j] = fcChip->LILPmap[1+ j];
2502     	j++; i--;
2503           }
2504         }
2505         else  // have to send login to everybody
2506         {
2507           int j=0;
2508           i = number_of_al_pa;
2509           NumberOfPorts = i;
2510           while( i > 0)
2511           {
2512             PortIds[j] = valid_al_pa[j]; // all legal ALPAs
2513     	j++; i--;
2514           }
2515         }
2516       }
2517     
2518     
2519       // Now we have a copy of the port_ids (and how many)...
2520       for( i = 0; i < NumberOfPorts; i++)
2521       {
2522         // 24-bit FC Port ID
2523         fchs.s_id = PortIds[i];  // note: only 8-bits used for ALPA
2524     
2525     
2526         // don't log into ourselves (Linux Scsi disk scan will stop on
2527         // no TARGET support error on us, and quit trying for rest of devices)
2528         if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
2529           continue;
2530     
2531         // fabric login needed?
2532         if( (fchs.s_id == 0) || 
2533             (fcChip->Options.fabric == 1) )
2534         {
2535           fcChip->Options.flogi = 1;  // fabric needs longer for login
2536           // Do we need FLOGI or FDISC?
2537           pLoggedInPort = fcFindLoggedInPort( 
2538                  fcChip, 
2539                  NULL,           // don't search SCSI Nexus
2540                  0xFFFFFC,       // search linked list for Fabric port_id
2541                  NULL,           // don't search WWN
2542                  NULL);          // (don't care about end of list)
2543     
2544           if( pLoggedInPort )    // If found, we have prior experience with
2545                                  // this port -- check whether PDISC is needed
2546           {
2547             if( pLoggedInPort->flogi )
2548     	{
2549     	  // does the switch support FDISC?? (FLOGI for now...)
2550               loginType = ELS_FLOGI;  // prior FLOGI still valid
2551     	}
2552             else
2553               loginType = ELS_FLOGI;  // expired FLOGI
2554           }
2555           else                      // first FLOGI?
2556             loginType = ELS_FLOGI;  
2557     
2558     
2559           fchs.s_id = 0xFFFFFE;   // well known F_Port address
2560     
2561           // Fabrics are not required to support FDISC, and
2562           // it's not clear if that helps us anyway, since
2563           // we'll want a Name Service Request to re-verify
2564           // visible devices...
2565           // Consequently, we always want our upper 16 bit
2566           // port_id to be zero (we'll be rejected if we
2567           // use our prior port_id if we've been plugged into
2568           // a different switch port).
2569           // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
2570           // If our ALPA is 55h for instance, we want the FC frame
2571           // s_id to be 0x000055, while Tach's my_al_pa register
2572           // must be 0x000155, to force an OPN at ALPA 0 
2573           // (the Fabric port)
2574           fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
2575           writel( fcChip->Registers.my_al_pa | 0x0100,  
2576             fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
2577         }
2578     
2579         else // not FLOGI...
2580         {
2581           // should we send PLOGI or PDISC?  Check if any prior port_id
2582           // (e.g. alpa) completed a PLOGI/PRLI exchange by checking 
2583           // the pdisc flag.
2584     
2585           pLoggedInPort = fcFindLoggedInPort( 
2586                  fcChip, 
2587                  NULL,           // don't search SCSI Nexus
2588                  fchs.s_id,      // search linked list for al_pa
2589                  NULL,           // don't search WWN
2590                  NULL);          // (don't care about end of list)
2591     
2592                  
2593     
2594           if( pLoggedInPort )      // If found, we have prior experience with
2595                                  // this port -- check whether PDISC is needed
2596           {
2597             if( pLoggedInPort->pdisc )
2598     	{
2599               loginType = ELS_PDISC;  // prior PLOGI and PRLI maybe still valid
2600                
2601     	}
2602             else
2603               loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
2604           }
2605           else                      // never talked to this port_id before
2606             loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
2607         }
2608     
2609     
2610         
2611         ulStatus = cpqfcTSBuildExchange(
2612               cpqfcHBAdata,
2613               loginType,            // e.g. PLOGI
2614               &fchs,        // no incoming frame (we are originator)
2615               NULL,         // no data (no scatter/gather list)
2616               &ExchangeID );// fcController->fcExchanges index, -1 if failed
2617     
2618         if( !ulStatus ) // Exchange setup OK?
2619         {
2620           ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
2621           if( !ulStatus )
2622           {
2623               // submitted to Tach's Outbound Que (ERQ PI incremented)
2624               // waited for completion for ELS type (Login frames issued
2625               // synchronously)
2626     
2627     	if( loginType == ELS_PDISC )
2628     	{
2629     	  // now, we really shouldn't Revalidate SEST exchanges until
2630     	  // we get an ACC reply from our target and verify that
2631     	  // the target address/WWN is unchanged.  However, when a fast
2632     	  // target gets the PDISC, they can send SEST Exchange data
2633     	  // before we even get around to processing the PDISC ACC.
2634     	  // Consequently, we lose the I/O.
2635     	  // To avoid this, go ahead and Revalidate when the PDISC goes
2636     	  // out, anticipating that the ACC will be truly acceptable
2637     	  // (this happens 99.9999....% of the time).
2638     	  // If we revalidate a SEST write, and write data goes to a
2639     	  // target that is NOT the one we originated the WRITE to,
2640     	  // that target is required (FCP-SCSI specs, etc) to discard 
2641     	  // our WRITE data.
2642     
2643               // Re-validate SEST entries (Tachyon hardware assists)
2644               RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort); 
2645         //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
2646     	}
2647           }
2648           else  // give up immediately on error
2649           {
2650     #ifdef LOGIN_DBG
2651             printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
2652     #endif
2653             break;
2654           }
2655     
2656                   
2657           if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
2658           {
2659             ulStatus = LNKDWN_OSLS;
2660     #ifdef LOGIN_DBG
2661             printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
2662     #endif
2663             break;
2664           }
2665             // Check the exchange for bad status (i.e. FrameTimeOut),
2666             // and complete on bad status (most likely due to BAD_ALPA)
2667             // on LDn, DPC function may already complete (ABORT) a started
2668             // exchange, so check type first (type = 0 on complete).
2669           if( Exchanges->fcExchange[ExchangeID].status )
2670           {
2671     #ifdef LOGIN_DBG 
2672      	printk("completing x_ID %X on status %Xh\n", 
2673               ExchangeID, Exchanges->fcExchange[ExchangeID].status);
2674     #endif
2675             cpqfcTSCompleteExchange( fcChip, ExchangeID);
2676           }
2677         }
2678         else   // Xchange setup failed...
2679         {
2680     #ifdef LOGIN_DBG
2681           printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
2682     #endif
2683           break;
2684         }
2685       }
2686       if( !ulStatus )
2687       {
2688         // set the event signifying that all ALPAs were sent out.
2689     #ifdef LOGIN_DBG
2690         printk("SendLogins: PortDiscDone\n");
2691     #endif
2692         cpqfcHBAdata->PortDiscDone = 1;
2693     
2694     
2695         // TL/TS UG, pg. 184
2696         // 0x0065 = 100ms for RT_TOV
2697         // 0x01f5 = 500ms for ED_TOV
2698         fcChip->Registers.ed_tov.value = 0x006501f5L; 
2699         writel( fcChip->Registers.ed_tov.value,
2700           (fcChip->Registers.ed_tov.address));
2701     
2702         // set the LP_TOV back to ED_TOV (i.e. 500 ms)
2703         writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
2704       }
2705       else
2706       {
2707         printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", 
2708           ExchangeID, fchs.s_id, ulStatus);
2709       }
2710       LEAVE("SendLogins");
2711     
2712     }
2713     
2714     
2715     // for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
2716     // D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
2717     static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
2718     {
2719       struct Scsi_Host *HostAdapter = Cmnd->host;
2720       CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
2721       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2722       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2723       PFC_LOGGEDIN_PORT pLoggedInPort; 
2724       int LunListLen=0;
2725       int i;
2726       ULONG x_ID = 0xFFFFFFFF;
2727       UCHAR *ucBuff = Cmnd->request_buffer;
2728     
2729     //  printk("cpqfcTS: ReportLunsDone \n");
2730       // first, we need to find the Exchange for this command,
2731       // so we can find the fcPort struct to make the indicated
2732       // changes.
2733       for( i=0; i< TACH_SEST_LEN; i++)
2734       {
2735         if( Exchanges->fcExchange[i].type   // exchange defined?
2736                        &&
2737            (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
2738     	      
2739         {
2740           x_ID = i;  // found exchange!
2741           break;
2742         }
2743       }
2744       if( x_ID == 0xFFFFFFFF)
2745       {
2746     //    printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
2747         goto Done;  // Report Luns FC Exchange gone; 
2748                     // exchange probably Terminated by Implicit logout
2749       }
2750     
2751     
2752       // search linked list for the port_id we sent INQUIRY to
2753       pLoggedInPort = fcFindLoggedInPort( fcChip,
2754         NULL,     // DON'T search Scsi Nexus (we will set it)
2755         Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
2756         NULL,     // DON'T search linked list for FC WWN
2757         NULL);    // DON'T care about end of list
2758      
2759       if( !pLoggedInPort )
2760       {
2761     //    printk("cpqfcTS: ReportLuns failed - device gone\n");
2762         goto Done; // error! can't find logged in Port
2763       }    
2764       LunListLen = ucBuff[3];
2765       LunListLen += ucBuff[2]>>8;
2766     
2767       if( !LunListLen )  // failed
2768       {
2769         // generically speaking, a soft error means we should retry...
2770         if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
2771         {
2772           if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
2773     	        (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
2774           {
2775             TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
2776           // did we fail because of "check condition, device reset?"
2777           // e.g. the device was reset (i.e., at every power up)
2778           // retry the Report Luns
2779           
2780           // who are we sending it to?
2781           // we know this because we have a copy of the command
2782           // frame from the original Report Lun command -
2783           // switch the d_id/s_id fields, because the Exchange Build
2784           // context is "reply to source".
2785           
2786             fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
2787             cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
2788           }
2789         }
2790         else  // probably, the device doesn't support Report Luns
2791           pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;  
2792       }
2793       else  // we have LUN info - check VSA mode
2794       {
2795         // for now, assume all LUNs will have same addr mode
2796         // for VSA, payload byte 8 will be 0x40; otherwise, 0
2797         pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];  
2798           
2799         // Since we got a Report Luns answer, set lun masking flag
2800         pLoggedInPort->ScsiNexus.LunMasking = 1;
2801     
2802         if( LunListLen > 8*CPQFCTS_MAX_LUN)   // We expect CPQFCTS_MAX_LUN max
2803           LunListLen = 8*CPQFCTS_MAX_LUN;
2804     
2805     /*   
2806         printk("Device WWN %08X%08X Reports Luns @: ", 
2807               (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
2808               (ULONG)(pLoggedInPort->u.liWWN>>32));
2809     	    
2810         for( i=8; i<LunListLen+8; i+=8)
2811         {  
2812           printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
2813         }
2814         printk("\n");
2815     */
2816         
2817         // Since the device was kind enough to tell us where the
2818         // LUNs are, lets ensure they are contiguous for Linux's
2819         // SCSI driver scan, which expects them to start at 0.
2820         // Since Linux only supports 8 LUNs, only copy the first
2821         // eight from the report luns command
2822     
2823         // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
2824         // LUNs 4001, 4004, etc., because other LUNs are masked from
2825         // this HBA (owned by someone else).  We'll make those appear as
2826         // LUN 0, 1... to Linux
2827         {
2828           int j;
2829           int AppendLunList = 0;
2830           // Walk through the LUN list.  The 'j' array number is
2831           // Linux's lun #, while the value of .lun[j] is the target's
2832           // lun #.
2833           // Once we build a LUN list, it's possible for a known device 
2834           // to go offline while volumes (LUNs) are added.  Later,
2835           // the device will do another PLOGI ... Report Luns command,
2836           // and we must not alter the existing Linux Lun map.
2837           // (This will be very rare).
2838           for( j=0; j < CPQFCTS_MAX_LUN; j++)
2839           {
2840             if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
2841     	{
2842     	  AppendLunList = 1;
2843     	  break;
2844     	}
2845           }
2846           if( AppendLunList )
2847           {
2848     	int k;
2849             int FreeLunIndex;
2850     //        printk("cpqfcTS: AppendLunList\n");
2851     
2852     	// If we get a new Report Luns, we cannot change
2853     	// any existing LUN mapping! (Only additive entry)
2854     	// For all LUNs in ReportLun list
2855     	// if RL lun != ScsiNexus lun
2856     	//   if RL lun present in ScsiNexus lun[], continue
2857     	//   else find ScsiNexus lun[]==FF and add, continue
2858     	
2859             for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2860     	{
2861               if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
2862     	  {
2863     	    // something changed from the last Report Luns
2864     	    printk(" cpqfcTS: Report Lun change!\n");
2865     	    for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN; 
2866                      k < CPQFCTS_MAX_LUN; k++)
2867                 {
2868     	      if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
2869     	      {
2870     		FreeLunIndex = k;
2871     		break;
2872     	      }
2873                   if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
2874     		break; // we already masked this lun
2875     	    }
2876     	    if( k >= CPQFCTS_MAX_LUN )
2877     	    {
2878     	      printk(" no room for new LUN %d\n", ucBuff[i+1]);
2879     	    }
2880     	    else if( k == FreeLunIndex )  // need to add LUN
2881     	    {
2882     	      pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
2883     //	      printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
2884     	      
2885     	    }
2886     	    else
2887     	    {
2888     	      // lun already known
2889     	    }
2890     	    break;
2891     	  }
2892     	}
2893     	// print out the new list...
2894     	for( j=0; j< CPQFCTS_MAX_LUN; j++)
2895     	{
2896     	  if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
2897     	    break; // done
2898     //	  printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2899     	}
2900           }
2901           else
2902           {
2903     //	  printk("Linux SCSI LUNs[] -> Device LUNs: ");
2904     	// first time - this is easy
2905             for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2906     	{
2907               pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
2908     //	  printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2909     	}
2910     //	printk("\n");
2911           }
2912         }
2913       }
2914     
2915     Done:  
2916     }
2917     
2918     // After successfully getting a "Process Login" (PRLI) from an
2919     // FC port, we want to Discover the LUNs so that we know the
2920     // addressing type (e.g., FCP-SCSI Volume Set Address, Peripheral
2921     // Unit Device), and whether SSP (Selective Storage Presentation or
2922     // Lun Masking) has made the LUN numbers non-zero based or 
2923     // non-contiguous.  To remain backward compatible with the SCSI-2
2924     // driver model, which expects a contiguous LUNs starting at 0,
2925     // will use the ReportLuns info to map from "device" to "Linux" 
2926     // LUNs.
2927     static void IssueReportLunsCommand( 
2928                   CPQFCHBA* cpqfcHBAdata, 
2929     	      TachFCHDR_GCMND* fchs)
2930     {
2931       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2932       PFC_LOGGEDIN_PORT pLoggedInPort; 
2933       Scsi_Cmnd *Cmnd;
2934       LONG x_ID;
2935       ULONG ulStatus;
2936       UCHAR *ucBuff;
2937     
2938       if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
2939       {
2940         printk("Discard Q'd ReportLun command\n");
2941         goto Done;
2942       }
2943     
2944       // find the device (from port_id) we're talking to
2945       pLoggedInPort = fcFindLoggedInPort( fcChip,
2946             NULL,     // DON'T search Scsi Nexus 
2947       	fchs->s_id & 0xFFFFFF,        
2948     	NULL,     // DON'T search linked list for FC WWN
2949             NULL);    // DON'T care about end of list
2950       if( pLoggedInPort ) // we'd BETTER find it!
2951       {
2952     
2953     
2954         if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
2955           goto Done;  // forget it - FC device not a "target"
2956     
2957         // now use the port's Scsi Command buffer for the 
2958         // Report Luns Command
2959      
2960         Cmnd = &pLoggedInPort->ScsiCmnd; 
2961         ucBuff = pLoggedInPort->ReportLunsPayload;
2962         
2963         memset( Cmnd, 0, sizeof(Scsi_Cmnd));
2964         memset( ucBuff, 0, REPORT_LUNS_PL);
2965         
2966         Cmnd->scsi_done = ScsiReportLunsDone;
2967         Cmnd->host = cpqfcHBAdata->HostAdapter;
2968     
2969         Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload; 
2970         Cmnd->request_bufflen = REPORT_LUNS_PL; 
2971     	    
2972         Cmnd->cmnd[0] = 0xA0;
2973         Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
2974         Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL;
2975         Cmnd->cmd_len = 12;
2976     
2977         Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
2978         Cmnd->target = pLoggedInPort->ScsiNexus.target;
2979     
2980     	    
2981         ulStatus = cpqfcTSBuildExchange(
2982           cpqfcHBAdata,
2983           SCSI_IRE, 
2984           fchs,
2985           Cmnd,         // buffer for Report Lun data
2986           &x_ID );// fcController->fcExchanges index, -1 if failed
2987     
2988         if( !ulStatus ) // Exchange setup?
2989         {
2990           ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
2991           if( !ulStatus )
2992           {
2993             // submitted to Tach's Outbound Que (ERQ PI incremented)
2994             // waited for completion for ELS type (Login frames issued
2995             // synchronously)
2996           }
2997           else
2998             // check reason for Exchange not being started - we might
2999             // want to Queue and start later, or fail with error
3000           {
3001       
3002           }
3003         }
3004     
3005         else   // Xchange setup failed...
3006           printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
3007       }
3008       else     // like, we just got a PRLI ACC, and now the port is gone?
3009       {
3010         printk(" can't send ReportLuns - no login for port_id %Xh\n",
3011     	    fchs->s_id & 0xFFFFFF);
3012       }
3013     
3014     
3015     
3016     Done:
3017     
3018     }
3019     
3020     
3021     
3022     
3023     
3024     
3025     
3026     static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata)
3027     {
3028       int i;
3029       for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--)
3030       {
3031         if( cpqfcHBAdata->BoardLockCmnd[i] != NULL )
3032         {
3033           Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i];
3034           cpqfcHBAdata->BoardLockCmnd[i] = NULL;
3035           Cmnd->result = (DID_SOFT_ERROR << 16);  // ask for retry
3036     //      printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
3037     //        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
3038           if( Cmnd->scsi_done != NULL)
3039             (*Cmnd->scsi_done)(Cmnd);
3040         }
3041       }
3042     }
3043     
3044     
3045     
3046     
3047     
3048     
3049     // runs every 1 second for FC exchange timeouts and implicit FC device logouts
3050     
3051     void cpqfcTSheartbeat( unsigned long ptr )
3052     {
3053       CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr;
3054       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
3055       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3056       PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
3057       ULONG i;
3058       unsigned long flags;
3059       DECLARE_MUTEX_LOCKED(BoardLock);
3060       
3061       PCI_TRACE( 0xA8)
3062     
3063       if( cpqfcHBAdata->BoardLock) // Worker Task Running?
3064         goto Skip;
3065     
3066       spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
3067     
3068       PCI_TRACE( 0xA8)
3069     
3070     
3071       cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
3072       
3073       // release the IO lock (and re-enable interrupts)
3074       spin_unlock_irqrestore( &io_request_lock, flags);
3075       
3076       // Ensure no contention from  _quecommand or Worker process 
3077       CPQ_SPINLOCK_HBA( cpqfcHBAdata)
3078       
3079       PCI_TRACE( 0xA8)
3080       
3081     
3082       disable_irq( cpqfcHBAdata->HostAdapter->irq);  // our IRQ
3083     
3084       // Complete the "bad target" commands (normally only used during
3085       // initialization, since we aren't supposed to call "scsi_done"
3086       // inside the queuecommand() function).
3087     
3088       for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
3089       {
3090         if( cpqfcHBAdata->BadTargetCmnd[i] )
3091         {
3092           Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
3093           cpqfcHBAdata->BadTargetCmnd[i] = NULL;
3094           Cmnd->result = (DID_BAD_TARGET << 16);
3095           if( Cmnd->scsi_done != NULL)
3096             (*Cmnd->scsi_done)(Cmnd);
3097         }
3098         else
3099           break;
3100       }
3101     
3102       
3103       // logged in ports -- re-login check (ports required to verify login with
3104       // PDISC after LIP within 2 secs)
3105     
3106       // prevent contention
3107       while( pLoggedInPort ) // for all ports which are expecting
3108                              // PDISC after the next LIP, check to see if
3109                              // time is up!
3110       {
3111           // Important: we only detect "timeout" condition on TRANSITION
3112           // from non-zero to zero
3113         if( pLoggedInPort->LOGO_timer )  // time-out "armed"?
3114         {
3115           if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0?
3116           {
3117               // LOGOUT time!  Per PLDA, PDISC hasn't complete in 2 secs, so
3118               // issue LOGO request and destroy all I/O with other FC port(s).
3119             
3120     /*          
3121             printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
3122             printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n", 
3123             pLoggedInPort->ScsiNexus.channel, 
3124             pLoggedInPort->ScsiNexus.target, 
3125     	pLoggedInPort->port_id,
3126               (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
3127               (ULONG)(pLoggedInPort->u.liWWN>>32));
3128     
3129     */
3130             cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
3131     
3132           }
3133           // else simply decremented - maybe next time...
3134         }
3135         pLoggedInPort = pLoggedInPort->pNextPort;
3136       }
3137     
3138     
3139     
3140       
3141       
3142       // ************  FC EXCHANGE TIMEOUT CHECK **************
3143       
3144       for( i=0; i< TACH_MAX_XID; i++)
3145       {
3146         if( Exchanges->fcExchange[i].type )  // exchange defined?
3147         {
3148     
3149           if( !Exchanges->fcExchange[i].timeOut ) // time expired
3150           {
3151             // Set Exchange timeout status
3152             Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
3153     
3154             if( i >= TACH_SEST_LEN ) // Link Service Exchange
3155             {
3156               cpqfcTSCompleteExchange( fcChip, i);  // Don't "abort" LinkService
3157             }
3158             
3159             else  // SEST Exchange TO -- may post ABTS to Worker Thread Que
3160             {
3161     	  // (Make sure we don't keep timing it out; let other functions
3162     	  // complete it or set the timeOut as needed)
3163     	  Exchanges->fcExchange[i].timeOut = 30000; // seconds default
3164     
3165               if( Exchanges->fcExchange[i].type 
3166                       & 
3167                   (BLS_ABTS | BLS_ABTS_ACC )  )
3168               {
3169     	    // For BLS_ABTS*, an upper level might still have
3170     	    // an outstanding command waiting for low-level completion.
3171     	    // Also, in the case of a WRITE, we MUST get confirmation
3172     	    // of either ABTS ACC or RJT before re-using the Exchange.
3173     	    // It's possible that the RAID cache algorithm can hang
3174     	    // if we fail to complete a WRITE to a LBA, when a READ
3175     	    // comes later to that same LBA.  Therefore, we must
3176     	    // ensure that the target verifies receipt of ABTS for
3177     	    // the exchange
3178     	   
3179     	    printk("~TO Q'd ABTS (x_ID %Xh)~ ", i); 
3180     //            TriggerHBA( fcChip->Registers.ReMapMemBase);
3181     
3182     	    // On timeout of a ABTS exchange, check to
3183     	    // see if the FC device has a current valid login.
3184     	    // If so, restart it.
3185     	    pLoggedInPort = fcFindLoggedInPort( fcChip,
3186                   Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
3187                   0,        // DON'T search linked list for FC port id
3188     	      NULL,     // DON'T search linked list for FC WWN
3189                   NULL);    // DON'T care about end of list
3190     
3191     	    // device exists?
3192     	    if( pLoggedInPort ) // device exists?
3193     	    {
3194     	      if( pLoggedInPort->prli ) // logged in for FCP-SCSI?
3195     	      {
3196     		// attempt to restart the ABTS
3197     		printk(" ~restarting ABTS~ ");
3198                     cpqfcTSStartExchange( cpqfcHBAdata, i );
3199     
3200     	      }
3201     	    }
3202               }
3203     	  else  // not an ABTS
3204     	  { 
3205                
3206                 // We expect the WorkerThread to change the xchng type to
3207                 // abort and set appropriate timeout.
3208                 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out
3209     	  }
3210             }
3211           }
3212           else  // time not expired...
3213           {
3214             // decrement timeout: 1 or more seconds left
3215             --Exchanges->fcExchange[i].timeOut;
3216           }
3217         }
3218       }
3219     
3220     
3221       enable_irq( cpqfcHBAdata->HostAdapter->irq);
3222      
3223     
3224       CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
3225     
3226       cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued
3227     
3228       // Now, complete any Cmnd we Q'd up while BoardLock was held
3229     
3230       CompleteBoardLockCmnd( cpqfcHBAdata);
3231      
3232     
3233       // restart the timer to run again (1 sec later)
3234     Skip:
3235       mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ);
3236       
3237       PCI_TRACEO( i, 0xA8)
3238       return;
3239     }
3240     
3241     
3242     // put valid FC-AL physical address in spec order
3243     static const UCHAR valid_al_pa[]={
3244         0xef, 0xe8, 0xe4, 0xe2, 
3245         0xe1, 0xE0, 0xDC, 0xDA, 
3246         0xD9, 0xD6, 0xD5, 0xD4, 
3247         0xD3, 0xD2, 0xD1, 0xCe, 
3248         0xCd, 0xCc, 0xCb, 0xCa, 
3249         0xC9, 0xC7, 0xC6, 0xC5, 
3250         0xC3, 0xBc, 0xBa, 0xB9,
3251         0xB6, 0xB5, 0xB4, 0xB3, 
3252         0xB2, 0xB1, 0xae, 0xad,
3253         0xAc, 0xAb, 0xAa, 0xA9, 
3254     
3255         0xA7, 0xA6, 0xA5, 0xA3, 
3256         0x9f, 0x9e, 0x9d, 0x9b, 
3257         0x98, 0x97, 0x90, 0x8f, 
3258         0x88, 0x84, 0x82, 0x81, 
3259         0x80, 0x7c, 0x7a, 0x79, 
3260         0x76, 0x75, 0x74, 0x73, 
3261         0x72, 0x71, 0x6e, 0x6d, 
3262         0x6c, 0x6b, 0x6a, 0x69, 
3263         0x67, 0x66, 0x65, 0x63, 
3264         0x5c, 0x5a, 0x59, 0x56, 
3265         
3266         0x55, 0x54, 0x53, 0x52, 
3267         0x51, 0x4e, 0x4d, 0x4c, 
3268         0x4b, 0x4a, 0x49, 0x47, 
3269         0x46, 0x45, 0x43, 0x3c,
3270         0x3a, 0x39, 0x36, 0x35, 
3271         0x34, 0x33, 0x32, 0x31, 
3272         0x2e, 0x2d, 0x2c, 0x2b, 
3273         0x2a, 0x29, 0x27, 0x26, 
3274         0x25, 0x23, 0x1f, 0x1E,
3275         0x1d, 0x1b, 0x18, 0x17, 
3276     
3277         0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case
3278     
3279     const int number_of_al_pa = (sizeof(valid_al_pa) );
3280     
3281     
3282     
3283     // this function looks up an al_pa from the table of valid al_pa's
3284     // we decrement from the last decimal loop ID, because soft al_pa
3285     // (our typical case) are assigned with highest priority (and high al_pa)
3286     // first.  See "In-Depth FC-AL", R. Kembel pg. 38
3287     // INPUTS:
3288     //   al_pa - 24 bit port identifier (8 bit al_pa on private loop)
3289     // RETURN:
3290     //  Loop ID - serves are index to array of logged in ports
3291     //  -1      - invalid al_pa (not all 8 bit values are legal)
3292     
3293     #if (0)
3294     static int GetLoopID( ULONG al_pa )
3295     {
3296       int i;
3297     
3298       for( i = number_of_al_pa -1; i >= 0; i--)  // dec.
3299       {
3300         if( valid_al_pa[i] == (UCHAR)al_pa )  // take lowest 8 bits
3301           return i;  // success - found valid al_pa; return decimal LoopID
3302       }
3303       return -1; // failed - not found
3304     }
3305     #endif
3306     
3307     
3308     // Search the singly (forward) linked list "fcPorts" looking for 
3309     // either the SCSI target (if != -1), port_id (if not NULL), 
3310     // or WWN (if not null), in that specific order.
3311     // If we find a SCSI nexus (from Cmnd arg), set the SCp.phase
3312     // field according to VSA or PDU
3313     // RETURNS:
3314     //   Ptr to logged in port struct if found
3315     //     (NULL if not found)
3316     //   pLastLoggedInPort - ptr to last struct (for adding new ones)
3317     // 
3318     PFC_LOGGEDIN_PORT  fcFindLoggedInPort( 
3319       PTACHYON fcChip, 
3320       Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
3321       ULONG port_id,   // search linked list for al_pa, or
3322       UCHAR wwn[8],    // search linked list for WWN, or...
3323       PFC_LOGGEDIN_PORT *pLastLoggedInPort )
3324                  
3325     {
3326       PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
3327       BOOLEAN target_id_valid=FALSE;
3328       BOOLEAN port_id_valid=FALSE;
3329       BOOLEAN wwn_valid=FALSE;
3330       int i;
3331     
3332     
3333       if( Cmnd != NULL )
3334         target_id_valid = TRUE;
3335       
3336       else if( port_id ) // note! 24-bit NULL address is illegal
3337         port_id_valid = TRUE;
3338     
3339       else
3340       {
3341         if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
3342         {
3343           for( i=0; i<8; i++)  // valid WWN passed?  NULL WWN invalid
3344           {
3345             if( wwn[i] != 0 )
3346               wwn_valid = TRUE;  // any non-zero byte makes (presumably) valid
3347           }
3348         }
3349       }
3350                     // check other options ...
3351     
3352     
3353       // In case multiple search options are given, we use a priority
3354       // scheme:
3355       // While valid pLoggedIn Ptr
3356       //   If port_id is valid
3357       //     if port_id matches, return Ptr
3358       //   If wwn is valid
3359       //     if wwn matches, return Ptr
3360       //   Next Ptr in list
3361       //
3362       // Return NULL (not found)
3363      
3364           
3365       while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid)
3366       {
3367         if( pLastLoggedInPort ) // caller's pointer valid?
3368           *pLastLoggedInPort = pLoggedInPort;  // end of linked list
3369         
3370         if( target_id_valid )
3371         {
3372           // check Linux Scsi Cmnd for channel/target Nexus match
3373           // (all luns are accessed through matching "pLoggedInPort")
3374           if( (pLoggedInPort->ScsiNexus.target == Cmnd->target)
3375                     &&
3376               (pLoggedInPort->ScsiNexus.channel == Cmnd->channel))
3377           {
3378             // For "passthru" modes, the IOCTL caller is responsible
3379     	// for setting the FCP-LUN addressing
3380     	if( !Cmnd->SCp.sent_command ) // NOT passthru?
3381     	{
3382     	
3383               // set the FCP-LUN addressing type
3384               Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;	
3385     
3386               // set the Device Type we got from the snooped INQUIRY string
3387     	  Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
3388     
3389     	  // handle LUN masking; if not "default" (illegal) lun value,
3390     	  // the use it.  These lun values are set by a successful
3391     	  // Report Luns command
3392               if( pLoggedInPort->ScsiNexus.LunMasking == 1) 
3393     	  {
3394                 // we KNOW all the valid LUNs... 0xFF is invalid!
3395                 Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
3396     	    if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
3397     		return NULL;
3398     	    // printk("xlating lun %d to 0x%02x\n", Cmnd->lun, 
3399                 //	pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
3400     	  }
3401     	  else
3402     	    Cmnd->SCp.have_data_in = Cmnd->lun; // Linux & target luns match
3403     	}
3404     	break; // found it!
3405           }
3406         }
3407         
3408         if( port_id_valid ) // look for alpa first
3409         {
3410           if( pLoggedInPort->port_id == port_id )
3411               break;  // found it!
3412         }
3413         if( wwn_valid ) // look for wwn second
3414         {
3415     
3416           if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
3417           {  
3418                      // all 8 bytes of WWN match
3419             break;   // found it!
3420           }
3421         }
3422                     
3423         pLoggedInPort = pLoggedInPort->pNextPort; // try next port
3424       }
3425     
3426       return pLoggedInPort;
3427     }
3428     
3429     
3430     
3431     
3432     // 
3433     // We need to examine the SEST table and re-validate
3434     // any open Exchanges for this LoggedInPort
3435     // To make Tachyon pay attention, Freeze FCP assists,
3436     // set VAL bits, Unfreeze FCP assists
3437     static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
3438     		        PFC_LOGGEDIN_PORT pLoggedInPort)
3439     {
3440       CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3441       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
3442       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3443       ULONG x_ID;
3444       BOOLEAN TachFroze = FALSE;
3445       
3446       
3447       // re-validate any SEST exchanges that are permitted
3448       // to survive the link down (e.g., good PDISC performed)
3449       for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
3450       {
3451     
3452         // If the SEST entry port_id matches the pLoggedInPort,
3453         // we need to re-validate
3454         if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
3455              || 
3456     	(Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
3457         {
3458     		     
3459           if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF)  // (24-bit port ID)
3460                 == pLoggedInPort->port_id) 
3461           {
3462     //	printk(" re-val xID %Xh ", x_ID);
3463             if( !TachFroze )  // freeze if not already frozen
3464               TachFroze |= FreezeTach( cpqfcHBAdata);
3465             fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
3466           }
3467         } 
3468       }
3469     
3470       if( TachFroze) 
3471       { 
3472         fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
3473       }
3474     } 
3475     
3476     
3477     // Complete an Linux Cmnds that we Queued because
3478     // our FC link was down (cause immediate retry)
3479     
3480     static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
3481     		        PFC_LOGGEDIN_PORT pLoggedInPort)
3482     {
3483     //  Scsi_Device *sdev = HostAdapter->host_queue;
3484       CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3485       Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
3486       Scsi_Cmnd *Cmnd;
3487       int indx;
3488     
3489      
3490       
3491       // if the device was previously "blocked", make sure
3492       // we unblock it so Linux SCSI will resume
3493     
3494       pLoggedInPort->device_blocked = FALSE; // clear our flag
3495     
3496       // check the Link Down command ptr buffer;
3497       // we can complete now causing immediate retry
3498       for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
3499       {
3500         if( *SCptr != NULL ) // scsi command to complete?
3501         {
3502     #ifdef DUMMYCMND_DBG
3503           printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
3504     #endif
3505           Cmnd = *SCptr;
3506     
3507     
3508           // Are there any Q'd commands for this target?
3509           if( (Cmnd->target == pLoggedInPort->ScsiNexus.target)
3510     	       &&
3511               (Cmnd->channel == pLoggedInPort->ScsiNexus.channel) )
3512           {
3513             Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
3514             if( Cmnd->scsi_done != NULL)
3515               (*Cmnd->scsi_done)(Cmnd);
3516             else
3517               printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
3518     		  pLoggedInPort->port_id);
3519             *SCptr = NULL;  // free this slot for next use
3520           }
3521         }
3522       }
3523     }
3524     
3525       
3526     //#define WWN_DBG 1
3527     
3528     static void SetLoginFields(
3529       PFC_LOGGEDIN_PORT pLoggedInPort,
3530       TachFCHDR_GCMND* fchs,
3531       BOOLEAN PDisc,
3532       BOOLEAN Originator)
3533     {
3534       LOGIN_PAYLOAD logi;       // FC-PH Port Login
3535       PRLI_REQUEST prli;  // copy for BIG ENDIAN switch
3536       int i;
3537     #ifdef WWN_DBG
3538       ULONG ulBuff;
3539     #endif
3540     
3541       BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
3542     
3543       pLoggedInPort->Originator = Originator;
3544       pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
3545       
3546       switch( fchs->pl[0] & 0xffff )
3547       {
3548       case 0x00000002:  //  PLOGI or PDISC ACCept?
3549         if( PDisc )     // PDISC accept
3550           goto PDISC_case;
3551     
3552       case 0x00000003:  //  ELS_PLOGI or ELS_PLOGI_ACC
3553     
3554       // Login BB_credit typically 0 for Tachyons
3555         pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
3556     
3557         // e.g. 128, 256, 1024, 2048 per FC-PH spec
3558         // We have to use this when setting up SEST Writes,
3559         // since that determines frame size we send.
3560         pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
3561         pLoggedInPort->plogi = TRUE;
3562         pLoggedInPort->pdisc = FALSE;
3563         pLoggedInPort->prli = FALSE;    // ELS_PLOGI resets
3564         pLoggedInPort->flogi = FALSE;   // ELS_PLOGI resets
3565         pLoggedInPort->logo = FALSE;    // ELS_PLOGI resets
3566         pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
3567         pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
3568     
3569         // was this PLOGI to a Fabric?
3570         if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
3571           pLoggedInPort->flogi = TRUE;
3572     
3573     
3574         for( i=0; i<8; i++)   // copy the LOGIN port's WWN
3575           pLoggedInPort->u.ucWWN[i] = logi.port_name[i];  
3576     
3577     #ifdef WWN_DBG
3578         ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3579         if( pLoggedInPort->Originator)
3580           printk("o");
3581         else
3582           printk("r");
3583         printk("PLOGI port_id %Xh, WWN %08X",
3584           pLoggedInPort->port_id, ulBuff);
3585     
3586         ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3587         printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
3588     #endif
3589         break;
3590     
3591     
3592     
3593       
3594       case 0x00000005:  //  ELS_LOGO (logout)
3595     
3596     
3597         pLoggedInPort->plogi = FALSE;
3598         pLoggedInPort->pdisc = FALSE;
3599         pLoggedInPort->prli = FALSE;   // ELS_PLOGI resets
3600         pLoggedInPort->flogi = FALSE;  // ELS_PLOGI resets
3601         pLoggedInPort->logo = TRUE;    // ELS_PLOGI resets
3602         pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
3603         pLoggedInPort->LOGO_timer = 0;
3604     #ifdef WWN_DBG
3605         ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3606         if( pLoggedInPort->Originator)
3607           printk("o");
3608         else
3609           printk("r");
3610         printk("LOGO port_id %Xh, WWN %08X",
3611           pLoggedInPort->port_id, ulBuff);
3612     
3613         ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3614         printk("%08Xh\n", ulBuff);
3615     #endif
3616         break;
3617     
3618     
3619     
3620     PDISC_case:
3621       case 0x00000050: //  ELS_PDISC or ELS_PDISC_ACC
3622         pLoggedInPort->LOGO_timer = 0;  // stop the time-out
3623           
3624         pLoggedInPort->prli = TRUE;     // ready to accept FCP-SCSI I/O
3625         
3626     
3627           
3628     #ifdef WWN_DBG
3629         ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3630         if( pLoggedInPort->Originator)
3631           printk("o");
3632         else
3633           printk("r");
3634         printk("PDISC port_id %Xh, WWN %08X",
3635           pLoggedInPort->port_id, ulBuff);
3636     
3637         ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3638         printk("%08Xh\n", ulBuff);
3639     #endif
3640     
3641     
3642         
3643         break;
3644     
3645     
3646         
3647       case  0x1020L: //  PRLI?
3648       case  0x1002L: //  PRLI ACCept?
3649         BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
3650     
3651         pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
3652         pLoggedInPort->prli = TRUE;  // PLOGI resets, PDISC doesn't
3653     
3654         pLoggedInPort->pdisc = TRUE;  // expect to send (or receive) PDISC
3655                                       // next time
3656         pLoggedInPort->LOGO_timer = 0;  // will be set next LinkDown
3657     #ifdef WWN_DBG
3658         ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3659         if( pLoggedInPort->Originator)
3660           printk("o");
3661         else
3662           printk("r");
3663         printk("PRLI port_id %Xh, WWN %08X",
3664           pLoggedInPort->port_id, ulBuff);
3665     
3666         ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3667           printk("%08Xh\n", ulBuff);
3668     #endif
3669     
3670         break;
3671     
3672       }
3673     
3674       return;
3675     }
3676     
3677     
3678     
3679     
3680     
3681     
3682     static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
3683     {
3684       LOGIN_PAYLOAD *plogi;  // FC-PH Port Login
3685       LOGIN_PAYLOAD PlogiPayload;   // copy for BIG ENDIAN switch
3686       PRLI_REQUEST  *prli;          // FCP-SCSI Process Login
3687       PRLI_REQUEST  PrliPayload;    // copy for BIG ENDIAN switch
3688       LOGOUT_PAYLOAD  *logo;
3689       LOGOUT_PAYLOAD  LogoutPayload;
3690     //  PRLO_REQUEST  *prlo;
3691     //  PRLO_REQUEST  PrloPayload;
3692       REJECT_MESSAGE rjt, *prjt;
3693     
3694       memset( &PlogiPayload, 0, sizeof( PlogiPayload));
3695       plogi = &PlogiPayload;    // load into stack buffer,
3696                                     // then BIG-ENDIAN switch a copy to caller
3697     
3698     
3699       switch( type )  // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
3700       {
3701         case ELS_FDISC:
3702         case ELS_FLOGI:
3703         case ELS_PLOGI_ACC:   // FC-PH PORT Login Accept
3704         case ELS_PLOGI:   // FC-PH PORT Login
3705         case ELS_PDISC:   // FC-PH2 Port Discovery - same payload as ELS_PLOGI
3706           plogi->login_cmd = LS_PLOGI;
3707           if( type == ELS_PDISC)
3708             plogi->login_cmd = LS_PDISC;
3709           else if( type == ELS_PLOGI_ACC )
3710             plogi->login_cmd = LS_ACC;
3711     
3712           plogi->cmn_services.bb_credit = 0x00;
3713           plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
3714           plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
3715           plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
3716           plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
3717                   RANDOM_RELATIVE_OFFSET;
3718     
3719                  // fill in with World Wide Name based Port Name - 8 UCHARs
3720                  // get from Tach registers WWN hi & lo
3721           LoadWWN( fcChip, plogi->port_name, 0);
3722                  // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
3723                  // get from Tach registers WWN hi & lo
3724           LoadWWN( fcChip, plogi->node_name, 1);
3725     
3726     	// For Seagate Drives.
3727     	//
3728           plogi->cmn_services.common_features |= 0x800;
3729           plogi->cmn_services.rel_offset = 0xFE;
3730           plogi->cmn_services.concurrent_seq = 1;
3731           plogi->class1.service_options = 0x00;
3732           plogi->class2.service_options = 0x00;
3733           plogi->class3.service_options = CLASS_VALID;
3734           plogi->class3.initiator_control = 0x00;
3735           plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
3736           plogi->class3.recipient_control =
3737                  ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
3738           plogi->class3.concurrent_sequences = 1;
3739           plogi->class3.open_sequences = 1;
3740           plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
3741           plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
3742           plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0';
3743           plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0';
3744     
3745     
3746           // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
3747           if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
3748           {
3749             if( type == ELS_FLOGI )
3750       	  plogi->login_cmd = LS_FLOGI;  
3751     	else
3752       	  plogi->login_cmd = LS_FDISC;  
3753     
3754             plogi->cmn_services.lowest_ver = 0x20;
3755             plogi->cmn_services.common_features = 0x0800;
3756             plogi->cmn_services.rel_offset = 0;
3757             plogi->cmn_services.concurrent_seq = 0;
3758     
3759             plogi->class3.service_options = 0x8800;
3760             plogi->class3.rx_data_size = 0;
3761             plogi->class3.recipient_control = 0;
3762             plogi->class3.concurrent_sequences = 0;
3763             plogi->class3.open_sequences = 0;
3764           }
3765           
3766                   // copy back to caller's buff, w/ BIG ENDIAN swap
3767           BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  sizeof(PlogiPayload));
3768           break;
3769     
3770         
3771         case ELS_ACC:       // generic Extended Link Service ACCept	    
3772           plogi->login_cmd = LS_ACC;
3773                   // copy back to caller's buff, w/ BIG ENDIAN swap
3774           BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  4);
3775           break;
3776     
3777     
3778           
3779         case ELS_SCR:    // Fabric State Change Registration
3780         {
3781           SCR_PL scr;     // state change registration
3782     
3783           memset( &scr, 0, sizeof(scr));
3784     
3785           scr.command = LS_SCR;  // 0x62000000
3786                                  // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
3787           scr.function = 3;      // 1 = Events detected by Fabric
3788                                  // 2 = N_Port detected registration
3789                                  // 3 = Full registration
3790           
3791           // copy back to caller's buff, w/ BIG ENDIAN swap
3792           BigEndianSwap( (UCHAR*)&scr, payload,  sizeof(SCR_PL));
3793         }
3794         
3795         break;
3796     
3797         
3798         case FCS_NSR:    // Fabric Name Service Request
3799         {
3800           NSR_PL nsr;    // Name Server Req. payload
3801     
3802           memset( &nsr, 0, sizeof(NSR_PL));
3803     
3804                                  // see Brocade Fabric Programming Guide,
3805                                  // Rev 1.3, pg 4-44
3806           nsr.CT_Rev = 0x01000000;
3807           nsr.FCS_Type = 0xFC020000;
3808           nsr.Command_code = 0x01710000;
3809           nsr.FCP = 8;
3810          
3811           // copy back to caller's buff, w/ BIG ENDIAN swap
3812           BigEndianSwap( (UCHAR*)&nsr, payload,  sizeof(NSR_PL));
3813         }
3814         
3815         break;
3816     
3817     
3818     
3819         
3820         case ELS_LOGO:   // FC-PH PORT LogOut
3821           logo = &LogoutPayload;    // load into stack buffer,
3822                                     // then BIG-ENDIAN switch a copy to caller
3823           logo->cmd = LS_LOGO;
3824                                     // load the 3 UCHARs of the node name
3825                                     // (if private loop, upper two UCHARs 0)
3826           logo->reserved = 0;
3827     
3828           logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
3829           logo->n_port_identifier[1] =
3830                          (UCHAR)(fcChip->Registers.my_al_pa>>8);
3831           logo->n_port_identifier[2] =
3832                          (UCHAR)(fcChip->Registers.my_al_pa>>16);
3833                  // fill in with World Wide Name based Port Name - 8 UCHARs
3834                  // get from Tach registers WWN hi & lo
3835           LoadWWN( fcChip, logo->port_name, 0);
3836     
3837           BigEndianSwap( (UCHAR*)&LogoutPayload,
3838                          payload,  sizeof(LogoutPayload) );  // 16 UCHAR struct
3839           break;
3840     
3841     
3842         case ELS_LOGO_ACC:     // Logout Accept (FH-PH pg 149, table 74)
3843           logo = &LogoutPayload;    // load into stack buffer,
3844                                     // then BIG-ENDIAN switch a copy to caller
3845           logo->cmd = LS_ACC;
3846           BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 );  // 4 UCHAR cmnd
3847           break;
3848           
3849     
3850         case ELS_RJT:          // ELS_RJT link service reject (FH-PH pg 155)
3851     
3852           prjt = (REJECT_MESSAGE*)payload;  // pick up passed data
3853           rjt.command_code = ELS_RJT;
3854                            // reverse fields, because of Swap that follows...
3855           rjt.vendor = prjt->reserved; // vendor specific
3856           rjt.explain = prjt->reason; //
3857           rjt.reason = prjt->explain; //
3858           rjt.reserved = prjt->vendor; //
3859                            // BIG-ENDIAN switch a copy to caller
3860           BigEndianSwap( (UCHAR*)&rjt, payload, 8 );  // 8 UCHAR cmnd
3861           break;
3862     
3863     
3864     
3865     
3866     
3867         case ELS_PRLI_ACC:  // Process Login ACCept
3868         case ELS_PRLI:  // Process Login
3869         case ELS_PRLO:  // Process Logout
3870           memset( &PrliPayload, 0, sizeof( PrliPayload));
3871           prli = &PrliPayload;      // load into stack buffer,
3872     
3873           if( type == ELS_PRLI )
3874             prli->cmd = 0x20;  // Login
3875           else if( type == ELS_PRLO )
3876             prli->cmd = 0x21;  // Logout
3877           else if( type == ELS_PRLI_ACC )
3878           {
3879             prli->cmd = 0x02;  // Login ACCept
3880             prli->valid = REQUEST_EXECUTED;
3881           }
3882     
3883     
3884           prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
3885           prli->fcp_info = READ_XFER_RDY;
3886           prli->page_length = 0x10;
3887           prli->payload_length = 20;
3888                                     // Can be initiator AND target
3889     
3890           if( fcChip->Options.initiator )
3891             prli->fcp_info |= INITIATOR_FUNCTION;
3892           if( fcChip->Options.target )
3893             prli->fcp_info |= TARGET_FUNCTION;
3894     
3895           BigEndianSwap( (UCHAR*)&PrliPayload, payload,  prli->payload_length);
3896           break;
3897     
3898     
3899     
3900         default:  // no can do - programming error
3901           printk(" BuildLinkServicePayload unknown!\n");
3902           break;
3903       }
3904     }
3905     
3906     // loads 8 UCHARs for PORT name or NODE name base on
3907     // controller's WWN.
3908     void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
3909     {
3910       UCHAR* bPtr, i;
3911     
3912       switch( type )
3913       {
3914         case 0:  // Port_Name
3915           bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3916           for( i =0; i<4; i++)
3917             dest[i] = *bPtr++;
3918           bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3919           for( i =4; i<8; i++)
3920             dest[i] = *bPtr++;
3921           break;
3922         case 1:  // Node/Fabric _Name
3923           bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3924           for( i =0; i<4; i++)
3925             dest[i] = *bPtr++;
3926           bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3927           for( i =4; i<8; i++)
3928             dest[i] = *bPtr++;
3929           break;
3930       }
3931       
3932     }
3933     
3934     
3935     
3936     // We check the Port Login payload for required values.  Note that
3937     // ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
3938     
3939     
3940     int verify_PLOGI( PTACHYON fcChip,
3941                       TachFCHDR_GCMND* fchs, 
3942                       ULONG* reject_explain)
3943     {
3944       LOGIN_PAYLOAD	login;
3945     
3946                       // source, dest, len (should be mult. of 4)
3947       BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login,  sizeof(login));
3948     
3949                                 // check FC version
3950                                 // if other port's highest supported version
3951                                 // is less than our lowest, and 
3952                                 // if other port's lowest
3953       if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
3954           login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
3955       {
3956         *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
3957         return LOGICAL_ERROR;
3958       }
3959     
3960                                 // Receive Data Field Size must be >=128
3961                                 // per FC-PH
3962       if (login.cmn_services.bb_rx_size < 128)
3963       {
3964         *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
3965         return LOGICAL_ERROR;
3966       }
3967     
3968                                 // Only check Class 3 params
3969       if( login.class3.service_options & CLASS_VALID)
3970       {
3971         if (login.class3.rx_data_size < 128)
3972         {
3973           *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
3974           return LOGICAL_ERROR;
3975         }
3976         if( login.class3.initiator_control & XID_REQUIRED)
3977         {
3978           *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
3979           return LOGICAL_ERROR;
3980         }
3981       }
3982       return 0;   // success
3983     }
3984     
3985     
3986     
3987     
3988     int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
3989     {
3990       PRLI_REQUEST prli;  // buffer for BIG ENDIAN
3991     
3992                       // source, dest, len (should be mult. of 4)
3993       BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli,  sizeof(prli));
3994     
3995       if( prli.fcp_info == 0 )  // i.e., not target or initiator?
3996       {
3997         *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
3998         return LOGICAL_ERROR;
3999       }
4000     
4001       return 0;  // success
4002     }
4003     
4004     
4005     // SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
4006     // INPUTS:
4007     //   source   - ptr to LITTLE ENDIAN ULONGS
4008     //   cnt      - number of UCHARs to switch (should be mult. of ULONG)
4009     // OUTPUTS:
4010     //   dest     - ptr to BIG ENDIAN copy
4011     // RETURN:
4012     //   none
4013     //
4014     void BigEndianSwap( UCHAR *source, UCHAR *dest,  USHORT cnt)
4015     {
4016       int i,j;
4017     
4018       source+=3;   // start at MSB of 1st ULONG
4019       for( j=0; j < cnt; j+=4, source+=4, dest+=4)  // every ULONG
4020       {
4021         for( i=0; i<4; i++)  // every UCHAR in ULONG
4022               *(dest+i) = *(source-i);
4023       }
4024     }
4025     
4026     
4027     
4028     
4029     // Build FC Exchanges............
4030     
4031     static void  buildFCPstatus( 
4032       PTACHYON fcChip, 
4033       ULONG ExchangeID);
4034     
4035     static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
4036     
4037     static ULONG build_SEST_sgList( 
4038       ULONG *SESTalPairStart,
4039       Scsi_Cmnd *Cmnd,
4040       ULONG *sgPairs,
4041       PSGPAGES sgPages  // link list of TL Ext. S/G pages from O/S Pool
4042     );
4043     
4044     static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
4045       UCHAR* payload, ULONG type, ULONG fcp_dl );
4046     
4047     
4048     /*
4049                                  IRB
4050           ERQ           __________________
4051       |          |   / | Req_A_SFS_Len    |        ____________________
4052       |----------|  /  | Req_A_SFS_Addr   |------->|  Reserved         |
4053       |   IRB    | /   | Req_A_D_ID       |        | SOF EOF TimeStamp |
4054       |-----------/    | Req_A_SEST_Index |-+      | R_CTL |   D_ID    |
4055       |   IRB    |     | Req_B...         | |      | CS_CTL|   S_ID    | 
4056       |-----------\    |                  | |      | TYPE  |   F_CTL   |
4057       |   IRB    | \   |                  | |      | SEQ_ID  | SEQ_CNT |
4058       |-----------  \  |                  | +-->+--| OX_ID   | RX_ID   |
4059       |          |   \ |__________________|     |  |       RO          |
4060                                                 |  | pl (payload/cmnd) |
4061                                                 |  |        .....      |
4062                                                 |  |___________________|
4063                                                 |
4064                                                 |
4065     +-------------------------------------------+
4066     |
4067     |
4068     |                        e.g. IWE    
4069     |    SEST           __________________             for FCP_DATA
4070     | |          |   / |       | Hdr_Len  |        ____________________
4071     | |----------|  /  |  Hdr_Addr_Addr   |------->|  Reserved         |
4072     | |   [0]    | /   |Remote_ID| RSP_Len|        | SOF EOF TimeStamp |
4073     | |-----------/    |   RSP_Addr       |---+    | R_CTL |   D_ID    |
4074     +->   [1]    |     |       | Buff_Off |   |    | CS_CTL|   S_ID    | 
4075       |-----------\    |BuffIndex| Link   |   |    | TYPE  |   F_CTL   |
4076       |   [2]    | \   | Rsvd  |   RX_ID  |   |    | SEQ_ID  | SEQ_CNT |
4077       |-----------  \  |    Data_Len      |   |    | OX_ID   | RX_ID   |
4078       |    ...   |   \ |     Exp_RO       |   |    |       RO          |
4079       |----------|     |   Exp_Byte_Cnt   |   |    |___________________|
4080       | SEST_LEN |  +--|    Len           |   |                                             
4081       |__________|  |  |   Address        |   |                                              
4082                     |  |    ...           |   |         for FCP_RSP  
4083                     |  |__________________|   |    ____________________
4084                     |                         +----|  Reserved         |   
4085                     |                              | SOF EOF TimeStamp |
4086                     |                              | R_CTL |   D_ID    |
4087                     |                              | CS_CTL|   S_ID    | 
4088                     +--- local or extended         |     ....          |
4089                          scatter/gather lists
4090                          defining upper-layer
4091                          data (e.g. from user's App)
4092     
4093     
4094     */
4095     // All TachLite commands must start with a SFS (Single Frame Sequence)
4096     // command.  In the simplest case (a NOP Basic Link command),
4097     // only one frame header and ERQ entry is required.  The most complex
4098     // case is the SCSI assisted command, which requires an ERQ entry,
4099     // SEST entry, and several frame headers and data buffers all
4100     // logically linked together.
4101     // Inputs:
4102     //   cpqfcHBAdata  - controller struct
4103     //   type          - PLOGI, SCSI_IWE, etc.
4104     //   InFCHS        - Incoming Tachlite FCHS which prompted this exchange
4105     //                   (only s_id set if we are originating)
4106     //   Data          - PVOID to data struct consistent with "type"
4107     //   fcExchangeIndex - pointer to OX/RD ID value of built exchange
4108     // Return:
4109     //   fcExchangeIndex - OX/RD ID value if successful
4110     //   0    - success
4111     //  INVALID_ARGS    - NULL/ invalid passed args
4112     //  BAD_ALPA        - Bad source al_pa address
4113     //  LNKDWN_OSLS     - Link Down (according to this controller)
4114     //  OUTQUE_FULL     - Outbound Que full
4115     //  DRIVERQ_FULL    - controller's Exchange array full
4116     //  SEST_FULL       - SEST table full
4117     //
4118     // Remarks:
4119     // Psuedo code:
4120     // Check for NULL pointers / bad args
4121     // Build outgoing FCHS - the header/payload struct
4122     // Build IRB (for ERQ entry)
4123     // if SCSI command, build SEST entry (e.g. IWE, TRE,...)
4124     // return success
4125     
4126     //sbuildex
4127     ULONG cpqfcTSBuildExchange(
4128       CPQFCHBA *cpqfcHBAdata,
4129       ULONG type, // e.g. PLOGI
4130       TachFCHDR_GCMND* InFCHS,  // incoming FCHS
4131       void *Data,               // the CDB, scatter/gather, etc.  
4132       LONG *fcExchangeIndex )   // points to allocated exchange, 
4133     {
4134       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
4135       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
4136       ULONG ulStatus = 0;  // assume OK
4137       USHORT ox_ID, rx_ID=0xFFFF;
4138       ULONG SfsLen=0L;
4139       TachLiteIRB* pIRB;
4140       IRBflags IRB_flags;
4141       UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
4142       TachFCHDR_GCMND* CMDfchs;
4143       TachFCHDR* dataHDR;     // 32 byte HEADER ONLY FCP-DATA buffer
4144       TachFCHDR_RSP* rspHDR;     // 32 byte header + RSP payload
4145       Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data;   // Linux Scsi CDB, S/G, ...
4146       TachLiteIWE* pIWE;
4147       TachLiteIRE* pIRE;
4148       TachLiteTWE* pTWE;
4149       TachLiteTRE* pTRE;
4150       ULONG fcp_dl;           // total byte length of DATA transferred
4151       ULONG fl;               // frame length (FC frame size, 128, 256, 512, 1024)
4152       ULONG sgPairs;          // number of valid scatter/gather pairs
4153       int FCP_SCSI_command;
4154       BA_ACC_PAYLOAD *ba_acc;
4155       BA_RJT_PAYLOAD *ba_rjt;
4156     
4157                               // check passed ARGS
4158       if( !fcChip->ERQ )      // NULL ptr means uninitialized Tachlite chip
4159         return INVALID_ARGS;
4160     
4161     
4162       if( type == SCSI_IRE ||
4163           type == SCSI_TRE ||
4164           type == SCSI_IWE ||
4165           type == SCSI_TWE)
4166         FCP_SCSI_command = 1;
4167     
4168       else
4169         FCP_SCSI_command = 0;
4170     
4171     
4172                          // for commands that pass payload data (e.g. SCSI write)
4173                          // examine command struct - verify that the
4174                          // length of s/g buffers is adequate for total payload
4175                          // length (end of list is NULL address)
4176     
4177       if( FCP_SCSI_command )
4178       {
4179         if( Data )     // must have data descriptor (S/G list -- at least
4180                        // one address with at least 1 byte of data)
4181         {
4182           // something to do (later)?
4183         }
4184     
4185         else
4186           return INVALID_ARGS;  // invalid DATA ptr
4187       }
4188     
4189         
4190     
4191              // we can build an Exchange for later Queuing (on the TL chip)
4192              // if an empty slot is available in the DevExt for this controller
4193              // look for available Exchange slot...
4194     
4195       if( type != FCP_RESPONSE &&
4196           type != BLS_ABTS &&
4197           type != BLS_ABTS_ACC )  // already have Exchange slot!
4198         *fcExchangeIndex = FindFreeExchange( fcChip, type );
4199     
4200       if( *fcExchangeIndex != -1 )   // Exchange is available?
4201       {
4202                          // assign tmp ptr (shorthand)
4203         CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs; 
4204     
4205     
4206         if( Cmnd != NULL ) // (necessary for ABTS cases)
4207         {
4208           Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
4209           Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort = 
4210     	fcFindLoggedInPort( fcChip,
4211               Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
4212               0,        // DON'T search linked list for FC port id
4213     	  NULL,     // DON'T search linked list for FC WWN
4214               NULL);    // DON'T care about end of list
4215     
4216         }
4217     
4218     
4219                          // Build the command frame header (& data) according
4220                          // to command type
4221     
4222                          // fields common for all SFS frame types
4223         CMDfchs->reserved = 0L; // must clear
4224         CMDfchs->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; LCr=0, no TS
4225         
4226                  // get the destination port_id from incoming FCHS
4227                  // (initialized before calling if we're Originator)
4228                  // Frame goes to port it was from - the source_id
4229         
4230         CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
4231         CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4232     
4233     
4234         // now enter command-specific fields
4235         switch( type )
4236         {
4237     
4238         case BLS_NOP:   // FC defined basic link service command NO-OP
4239                     // ensure unique X_IDs! (use tracking function)
4240     
4241           *pIRB_flags = 0;      // clear IRB flags
4242           IRB_flags.SFA = 1;    // send SFS (not SEST index)
4243           SfsLen = *pIRB_flags;
4244     
4245           SfsLen <<= 24;        // shift flags to MSB
4246           SfsLen += 32L;        // add len to LSB (header only - no payload)
4247     
4248                        // TYPE[31-24] 00 Basic Link Service
4249                        // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4250           CMDfchs->d_id |= 0x80000000L;  // R_CTL = 80 for NOP (Basic Link Ser.)
4251           CMDfchs->f_ctl = 0x00310000L;  // xchng originator, 1st seq,....
4252           CMDfchs->seq_cnt = 0x0L;
4253           CMDfchs->ox_rx_id = 0xFFFF;        // RX_ID for now; OX_ID on start
4254           CMDfchs->ro = 0x0L;    // relative offset (n/a)
4255           CMDfchs->pl[0] = 0xaabbccddL;   // words 8-15 frame data payload (n/a)
4256           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
4257                                           // (NOP should complete ~instantly)
4258           break;
4259     
4260     
4261         
4262         
4263         case BLS_ABTS_ACC:  // Abort Sequence ACCept
4264           *pIRB_flags = 0;      // clear IRB flags
4265           IRB_flags.SFA = 1;    // send SFS (not SEST index)
4266           SfsLen = *pIRB_flags;
4267     
4268           SfsLen <<= 24;        // shift flags to MSB
4269           SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
4270     
4271           CMDfchs->d_id |= 0x84000000L;  // R_CTL = 84 for BASIC ACCept
4272                        // TYPE[31-24] 00 Basic Link Service
4273                        // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4274           CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
4275                        // CMDfchs->seq_id & count might be set from DataHdr?
4276           CMDfchs->ro = 0x0L;    // relative offset (n/a)
4277           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4278                             // (Timeout in case of weird error)
4279           
4280           // now set the ACCept payload...
4281           ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
4282           memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
4283           // Since PLDA requires (only) entire Exchange aborts, we don't need
4284           // to worry about what the last sequence was.
4285     
4286           // We expect that a "target" task is accepting the abort, so we
4287           // can use the OX/RX ID pair 
4288           ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
4289      
4290           // source, dest, #bytes
4291           BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
4292     
4293           ba_acc->low_seq_cnt = 0;
4294           ba_acc->high_seq_cnt = 0xFFFF;
4295     
4296     
4297           break;
4298         
4299     
4300         case BLS_ABTS_RJT:  // Abort Sequence ACCept
4301           *pIRB_flags = 0;      // clear IRB flags
4302           IRB_flags.SFA = 1;    // send SFS (not SEST index)
4303           SfsLen = *pIRB_flags;
4304     
4305           SfsLen <<= 24;        // shift flags to MSB
4306           SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
4307     
4308           CMDfchs->d_id |= 0x85000000L;  // R_CTL = 85 for BASIC ReJecT
4309                        // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4310                        // TYPE[31-24] 00 Basic Link Service
4311           CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
4312                        // CMDfchs->seq_id & count might be set from DataHdr?
4313           CMDfchs->ro = 0x0L;    // relative offset (n/a)
4314           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4315                             // (Timeout in case of weird error)
4316           
4317           CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
4318           
4319           // now set the ReJecT payload...
4320           ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
4321           memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
4322     
4323           // We expect that a "target" task couldn't find the Exhange in the
4324           // array of active exchanges, so we use a new LinkService X_ID.
4325           // See Reject payload description in FC-PH (Rev 4.3), pg. 140
4326           ba_rjt->reason_code = 0x09; // "unable to perform command request"
4327           ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
4328     
4329     
4330           break;
4331         
4332         
4333         case BLS_ABTS:   // FC defined basic link service command ABTS 
4334                          // Abort Sequence
4335                          
4336     
4337           *pIRB_flags = 0;      // clear IRB flags
4338           IRB_flags.SFA = 1;    // send SFS (not SEST index)
4339           SfsLen = *pIRB_flags;
4340     
4341           SfsLen <<= 24;        // shift flags to MSB
4342           SfsLen += 32L;        // add len to LSB (header only - no payload)
4343     
4344                        // TYPE[31-24] 00 Basic Link Service
4345                        // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4346           CMDfchs->d_id |= 0x81000000L;  // R_CTL = 81 for ABTS
4347           CMDfchs->f_ctl = 0x00110000L;  // xchnge originator, last seq, xfer SI
4348                        // CMDfchs->seq_id & count might be set from DataHdr?
4349           CMDfchs->ro = 0x0L;    // relative offset (n/a)
4350           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4351                             // (ABTS must timeout when responder is gone)
4352           break;
4353     
4354         
4355         
4356         case FCS_NSR:    // Fabric Name Service Request
4357            Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4358     
4359     
4360           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4361                              // OX_ID, linked to Driver Transaction ID
4362                              // (fix-up at Queing time)
4363           CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4364                                         // OX_ID set at ERQueing time
4365           *pIRB_flags = 0;      // clear IRB flags
4366           IRB_flags.SFA = 1;    // send SFS (not SEST index)
4367           SfsLen = *pIRB_flags;
4368     
4369           SfsLen <<= 24;        // shift flags to MSB
4370           SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
4371     
4372           CMDfchs->d_id |= 0x02000000L;  // R_CTL = 02 for -
4373                                        // Name Service Request: Unsolicited 
4374                        // TYPE[31-24] 01 Extended Link Service
4375                        // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4376           CMDfchs->f_ctl = 0x20210000L;
4377                        // OX_ID will be fixed-up at Tachyon enqueing time
4378           CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4379           CMDfchs->ro = 0x0L;    // relative offset (n/a)
4380     
4381           BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4382     
4383        
4384         
4385         
4386         
4387         
4388           break;
4389         
4390         
4391         
4392         
4393         case ELS_PLOGI:  // FC-PH extended link service command Port Login
4394           // (May, 2000)
4395           // NOTE! This special case facilitates SANMark testing.  The SANMark
4396           // test script for initialization-timeout.fcal.SANMark-1.fc
4397           // "eats" the OPN() primitive without issuing an R_RDY, causing
4398           // Tachyon to report LST (loop state timeout), which causes a
4399           // LIP.  To avoid this, simply send out the frame (i.e. assuming a
4400           // buffer credit of 1) without waiting for R_RDY.  Many FC devices
4401           // (other than Tachyon) have been doing this for years.  We don't
4402           // ever want to do this for non-Link Service frames unless the
4403           // other device really did report non-zero login BB credit (i.e.
4404           // in the PLOGI ACCept frame).
4405     //      CMDfchs->sof_eof |= 0x00000400L;  // LCr=1
4406         
4407         case ELS_FDISC:  // Fabric Discovery (Login)
4408         case ELS_FLOGI:  // Fabric Login
4409         case ELS_SCR:    // Fabric State Change Registration
4410         case ELS_LOGO:   // FC-PH extended link service command Port Logout
4411         case ELS_PDISC:  // FC-PH extended link service cmnd Port Discovery
4412         case ELS_PRLI:   // FC-PH extended link service cmnd Process Login
4413     
4414           Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4415     
4416     
4417           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4418                              // OX_ID, linked to Driver Transaction ID
4419                              // (fix-up at Queing time)
4420           CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4421                                         // OX_ID set at ERQueing time
4422           *pIRB_flags = 0;      // clear IRB flags
4423           IRB_flags.SFA = 1;    // send SFS (not SEST index)
4424           SfsLen = *pIRB_flags;
4425     
4426           SfsLen <<= 24;        // shift flags to MSB
4427           if( type == ELS_LOGO )
4428             SfsLen += (32L + 16L); //  add len (header & PLOGI payload)
4429           else if( type == ELS_PRLI )
4430             SfsLen += (32L + 20L); //  add len (header & PRLI payload)
4431           else if( type == ELS_SCR )
4432             SfsLen += (32L + sizeof(SCR_PL)); //  add len (header & SCR payload)
4433           else
4434             SfsLen += (32L + 116L); //  add len (header & PLOGI payload)
4435     
4436           CMDfchs->d_id |= 0x22000000L;  // R_CTL = 22 for -
4437                                        // Extended Link_Data: Unsolicited Control
4438                        // TYPE[31-24] 01 Extended Link Service
4439                        // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4440           CMDfchs->f_ctl = 0x01210000L;
4441                        // OX_ID will be fixed-up at Tachyon enqueing time
4442           CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4443           CMDfchs->ro = 0x0L;    // relative offset (n/a)
4444     
4445           BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4446     
4447           break;
4448     
4449     
4450     
4451         case ELS_LOGO_ACC: // FC-PH extended link service logout accept
4452         case ELS_RJT:          // extended link service reject (add reason)
4453         case ELS_ACC:      // ext. link service generic accept
4454         case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
4455         case ELS_PRLI_ACC: // ext. link service process login accept
4456     
4457     
4458           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
4459                     // ensure unique X_IDs! (use tracking function)
4460                     // OX_ID from initiator cmd
4461           ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16); 
4462           rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
4463     
4464           *pIRB_flags = 0;      // clear IRB flags
4465           IRB_flags.SFA = 1;    // send SFS (not SEST index)
4466           SfsLen = *pIRB_flags;
4467     
4468           SfsLen <<= 24;        // shift flags to MSB
4469           if( type == ELS_RJT )
4470           {
4471             SfsLen += (32L + 8L); //  add len (header + payload)
4472     
4473             // ELS_RJT reason codes (utilize unused "reserved" field)
4474             CMDfchs->pl[0] = 1;
4475             CMDfchs->pl[1] = InFCHS->reserved;  
4476               
4477           }
4478           else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC)  )
4479             SfsLen += (32L + 4L); //  add len (header + payload)
4480           else if( type == ELS_PLOGI_ACC )
4481             SfsLen += (32L + 116L); //  add len (header + payload)
4482           else if( type == ELS_PRLI_ACC )
4483             SfsLen += (32L + 20L); //  add len (header + payload)
4484     
4485           CMDfchs->d_id |= 0x23000000L;  // R_CTL = 23 for -
4486                                        // Extended Link_Data: Control Reply
4487                        // TYPE[31-24] 01 Extended Link Service
4488                        // f_ctl[23:0] exchg responder, last seq, e_s, tsi
4489           CMDfchs->f_ctl = 0x01990000L;
4490           CMDfchs->seq_cnt = 0x0L;
4491           CMDfchs->ox_rx_id = 0L;        // clear
4492           CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
4493           CMDfchs->ox_rx_id <<= 16;      // shift them
4494     
4495           CMDfchs->ro = 0x0L;    // relative offset (n/a)
4496     
4497           BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4498     
4499           break;
4500     
4501     
4502                              // Fibre Channel SCSI 'originator' sequences...
4503                              // (originator means 'initiator' in FCP-SCSI)
4504     
4505         case SCSI_IWE: // TachLite Initiator Write Entry
4506         {
4507           PFC_LOGGEDIN_PORT pLoggedInPort = 
4508             Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
4509     
4510           Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4511           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
4512                            
4513           // first, build FCP_CMND
4514           // unique X_ID fix-ups in StartExchange 
4515     
4516           *pIRB_flags = 0;      // clear IRB flags
4517           IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
4518     
4519           // NOTE: unlike FC LinkService login frames, normal
4520           // SCSI commands are sent without outgoing verification
4521           IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
4522           SfsLen = *pIRB_flags;
4523     
4524           SfsLen <<= 24;        // shift flags to MSB
4525           SfsLen += 64L;        // add len to LSB (header & CMND payload)
4526     
4527           CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
4528     
4529                        // TYPE[31-24] 8 for FCP SCSI
4530                        // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4531                        //             valid RO
4532           CMDfchs->f_ctl = 0x08210008L;
4533           CMDfchs->seq_cnt = 0x0L;
4534           CMDfchs->ox_rx_id = 0L;        // clear for now (-or- in later)
4535           CMDfchs->ro = 0x0L;    // relative offset (n/a)
4536     
4537                        // now, fill out FCP-DATA header
4538                        // (use buffer inside SEST object)
4539           dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4540           dataHDR->reserved = 0L; // must clear
4541           dataHDR->sof_eof = 0x75002000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
4542           dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4543           dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4544                        // TYPE[31-24] 8 for FCP SCSI
4545                        // f_ctl[23:0] xfer S.I.| valid RO
4546           dataHDR->f_ctl = 0x08010008L;
4547           dataHDR->seq_cnt = 0x02000000L;  // sequence ID: df_ctl : seqence count
4548           dataHDR->ox_rx_id = 0L;        // clear; fix-up dataHDR fields later
4549           dataHDR->ro = 0x0L;    // relative offset (n/a)
4550     
4551                        // Now setup the SEST entry
4552           pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
4553           
4554                        // fill out the IWE:
4555     
4556                     // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
4557           pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
4558           
4559           
4560           // from login parameters with other port, what's the largest frame
4561           // we can send? 
4562           if( pLoggedInPort == NULL) 
4563           {
4564     	ulStatus = INVALID_ARGS;  // failed! give up
4565     	break;
4566           }
4567           if( pLoggedInPort->rx_data_size  >= 2048)
4568             fl = 0x00020000;  // 2048 code (only support 1024!)
4569           else if( pLoggedInPort->rx_data_size  >= 1024)
4570             fl = 0x00020000;  // 1024 code
4571           else if( pLoggedInPort->rx_data_size  >= 512)
4572             fl = 0x00010000;  // 512 code
4573           else
4574     	fl = 0;  // 128 bytes -- should never happen
4575           
4576           
4577           pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
4578           pIWE->Hdr_Addr = virt_to_bus( dataHDR );
4579           pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4580           pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4581           
4582           memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0, 
4583             sizeof( FCP_STATUS_RESPONSE) );  // clear out previous status
4584       
4585           pIWE->RSP_Addr = virt_to_bus(
4586                              &fcChip->SEST->RspHDR[ *fcExchangeIndex ]);
4587     
4588                        // Do we need local or extended gather list?
4589                        // depends on size - we can handle 3 len/addr pairs
4590                        // locally.
4591     
4592           fcp_dl = build_SEST_sgList( 
4593             &pIWE->GLen1, 
4594             Cmnd,       // S/G list
4595             &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
4596             &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4597     
4598           if( !fcp_dl ) // error building S/G list?
4599           {
4600             ulStatus = MEMPOOL_FAIL;
4601             break;      // give up
4602           }
4603     
4604                                  // Now that we know total data length in
4605                                  // the passed S/G buffer, set FCP CMND frame
4606           build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4607     
4608     
4609           
4610           if( sgPairs > 3 )  // need extended s/g list
4611             pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
4612           else               // local data pointers (in SEST)
4613             pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
4614     
4615                                   // ULONG 5
4616           pIWE->Link = 0x0000ffffL;   // Buff_Index | Link
4617     
4618           pIWE->RX_ID = 0x0L;     // DWord 6: RX_ID set by target XFER_RDY
4619     
4620                                           // DWord 7
4621           pIWE->Data_Len = 0L;    // TL enters rcv'd XFER_RDY BURST_LEN
4622           pIWE->Exp_RO = 0L;      // DWord 8
4623                                   // DWord 9
4624           pIWE->Exp_Byte_Cnt = fcp_dl;  // sum of gather buffers
4625         }
4626         break;
4627     
4628     
4629     
4630     
4631     
4632         case SCSI_IRE: // TachLite Initiator Read Entry
4633     
4634           if( Cmnd->timeout != 0)
4635           {
4636     //	printk("Cmnd->timeout %d\n", Cmnd->timeout);
4637     	// per Linux Scsi
4638             Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
4639           }
4640           else  // use our best guess, based on FC & device
4641           {
4642     
4643             if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)	
4644     	{
4645     	  // turn off our timeouts (for now...)
4646               Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF; 
4647     	}
4648     	else
4649     	{
4650               Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4651               Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
4652     	}
4653           }
4654     
4655       
4656           // first, build FCP_CMND
4657     
4658     
4659           *pIRB_flags = 0;      // clear IRB flags
4660           IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
4661                                 // NOTE: unlike FC LinkService login frames,
4662                                 // normal SCSI commands are sent "open loop"
4663           IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
4664           SfsLen = *pIRB_flags;
4665     
4666           SfsLen <<= 24;        // shift flags to MSB
4667           SfsLen += 64L;        // add len to LSB (header & CMND payload)
4668     
4669           CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
4670     
4671                  // TYPE[31-24] 8 for FCP SCSI
4672                  // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4673                  //             valid RO
4674           CMDfchs->f_ctl = 0x08210008L;
4675           CMDfchs->seq_cnt = 0x0L;
4676           // x_ID & data direction bit set later
4677           CMDfchs->ox_rx_id = 0xFFFF;        // clear
4678           CMDfchs->ro = 0x0L;    // relative offset (n/a)
4679     
4680     
4681     
4682                        // Now setup the SEST entry
4683           pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
4684     
4685           // fill out the IRE:
4686           // VALid entry:Dir outbound:enable CM:enal INT:
4687           pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
4688     
4689           pIRE->reserved = 0L;
4690           pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4691           pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4692     
4693                                 
4694           pIRE->RSP_Addr = virt_to_bus(
4695                                   &fcChip->SEST->RspHDR[ *fcExchangeIndex ]);
4696           
4697           
4698                        // Do we need local or extended gather list?
4699                        // depends on size - we can handle 3 len/addr pairs
4700                        // locally.
4701     
4702           fcp_dl = build_SEST_sgList( 
4703             &pIRE->SLen1, 
4704             Cmnd,       // SCSI command Data desc. with S/G list
4705             &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
4706             &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4707           
4708           
4709           if( !fcp_dl ) // error building S/G list?
4710           {
4711     	// It is permissible to have a ZERO LENGTH Read command.
4712     	// If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
4713     	// to 0 and continue.
4714     	if( Cmnd->request_bufflen == 0 )
4715     	{
4716     	  fcp_dl = 0; // no FC DATA frames expected
4717     
4718     	}
4719     	else
4720     	{
4721               ulStatus = MEMPOOL_FAIL;
4722               break;      // give up
4723     	}
4724           }
4725     
4726           // now that we know the S/G length, build CMND payload
4727           build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4728     
4729           
4730           if( sgPairs > 3 )  // need extended s/g list
4731             pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
4732           else
4733             pIRE->Buff_Off = 0x80000000; // local data, no offset
4734           
4735           pIRE->Buff_Index = 0x0L;    // DWord 5: Buff_Index | Reserved
4736     
4737           pIRE->Exp_RO  = 0x0L;       // DWord 6: Expected Rel. Offset
4738     
4739           pIRE->Byte_Count = 0;  // DWord 7: filled in by TL on err
4740           pIRE->reserved_ = 0;   // DWord 8: reserved
4741                                  // NOTE: 0 length READ is OK.
4742           pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
4743           
4744           break;
4745     
4746     
4747     
4748     
4749                              // Fibre Channel SCSI 'responder' sequences...
4750                              // (originator means 'target' in FCP-SCSI)
4751         case SCSI_TWE: // TachLite Target Write Entry
4752     
4753           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4754     
4755                            // first, build FCP_CMND
4756     
4757           *pIRB_flags = 0;      // clear IRB flags
4758           IRB_flags.SFA = 1;    // send SFS (XFER_RDY)
4759           SfsLen = *pIRB_flags;
4760     
4761           SfsLen <<= 24;        // shift flags to MSB
4762           SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4763     
4764           CMDfchs->d_id |= (0x05000000L);  // R_CTL = 5 for XFER_RDY
4765     
4766                        // TYPE[31-24] 8 for FCP SCSI
4767                        // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
4768                     //             valid RO
4769           CMDfchs->f_ctl = 0x08810008L;
4770           CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
4771                            // use originator (other port's) OX_ID
4772           CMDfchs->ox_rx_id = InFCHS->ox_rx_id;     // we want upper 16 bits
4773           CMDfchs->ro = 0x0L;    // relative offset (n/a)
4774     
4775                        // now, fill out FCP-RSP header
4776                        // (use buffer inside SEST object)
4777     
4778           rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4779           rspHDR->reserved = 0L; // must clear
4780           rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
4781           rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4782           rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4783                        // TYPE[31-24] 8 for FCP SCSI
4784                        // f_ctl[23:0] responder|last seq| xfer S.I.
4785           rspHDR->f_ctl = 0x08910000L;
4786           rspHDR->seq_cnt = 0x03000000;  // sequence ID
4787           rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
4788           rspHDR->ro = 0x0L;    // relative offset (n/a)
4789     
4790     
4791                        // Now setup the SEST entry
4792                        
4793           pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
4794     
4795           // fill out the TWE:
4796     
4797           // VALid entry:Dir outbound:enable CM:enal INT:
4798           pTWE->Seq_Accum = 0xC4000000L;  // upper word flags
4799           pTWE->reserved = 0L;
4800           pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
4801           pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4802           
4803     
4804                        // Do we need local or extended gather list?
4805                        // depends on size - we can handle 3 len/addr pairs
4806                        // locally.
4807     
4808           fcp_dl = build_SEST_sgList( 
4809             &pTWE->SLen1, 
4810             Cmnd,       // S/G list
4811             &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
4812             &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4813           
4814           
4815           if( !fcp_dl ) // error building S/G list?
4816           {
4817             ulStatus = MEMPOOL_FAIL;
4818             break;      // give up
4819           }
4820     
4821           // now that we know the S/G length, build CMND payload
4822           build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4823     
4824           
4825           if( sgPairs > 3 )  // need extended s/g list
4826             pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
4827           else
4828             pTWE->Buff_Off = 0x80000000; // local data, no offset
4829           
4830           pTWE->Buff_Index = 0;     // Buff_Index | Link
4831           pTWE->Exp_RO = 0;
4832           pTWE->Byte_Count = 0;  // filled in by TL on err
4833           pTWE->reserved_ = 0;
4834           pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
4835           
4836           break;
4837     
4838     
4839     
4840     
4841     
4842     
4843         case SCSI_TRE: // TachLite Target Read Entry
4844     
4845           // It doesn't make much sense for us to "time-out" a READ,
4846           // but we'll use it for design consistency and internal error recovery.
4847           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4848     
4849           // I/O request block settings...
4850           *pIRB_flags = 0;      // clear IRB flags
4851                                       // check PRLI (process login) info
4852                                       // to see if Initiator Requires XFER_RDY
4853                                       // if not, don't send one!
4854                                       // { PRLI check...}
4855           IRB_flags.SFA = 0;    // don't send XFER_RDY - start data
4856           SfsLen = *pIRB_flags;
4857     
4858           SfsLen <<= 24;        // shift flags to MSB
4859           SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4860     
4861     
4862           
4863           // now, fill out FCP-DATA header
4864                        // (use buffer inside SEST object)
4865           dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4866     
4867           dataHDR->reserved = 0L; // must clear
4868           dataHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
4869           dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4870           dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4871     
4872     
4873                        // TYPE[31-24] 8 for FCP SCSI
4874                        // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
4875                        //             valid RO
4876           dataHDR->f_ctl = 0x08810008L;
4877           dataHDR->seq_cnt = 0x01000000;  // sequence ID (no XRDY)
4878           dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
4879           dataHDR->ro = 0x0L;    // relative offset (n/a)
4880     
4881                        // now, fill out FCP-RSP header
4882                        // (use buffer inside SEST object)
4883           rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4884     
4885           rspHDR->reserved = 0L; // must clear
4886           rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
4887           rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4888           rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4889                        // TYPE[31-24] 8 for FCP SCSI
4890                        // f_ctl[23:0] responder|last seq| xfer S.I.
4891           rspHDR->f_ctl = 0x08910000L;
4892           rspHDR->seq_cnt = 0x02000000;  // sequence ID: df_ctl: sequence count
4893     
4894           rspHDR->ro = 0x0L;    // relative offset (n/a)
4895     
4896     
4897           // Now setup the SEST entry
4898           pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
4899     
4900     
4901           // VALid entry:Dir outbound:enable CM:enal INT:
4902           pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
4903           pTRE->Hdr_Addr = virt_to_bus( dataHDR );
4904           pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
4905           pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4906           pTRE->RSP_Addr = virt_to_bus( rspHDR );
4907     
4908     
4909                        // Do we need local or extended gather list?
4910                        // depends on size - we can handle 3 len/addr pairs
4911                        // locally.
4912     
4913           fcp_dl = build_SEST_sgList( 
4914             &pTRE->GLen1, 
4915             Cmnd,       // S/G list
4916             &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
4917             &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4918           
4919           
4920           if( !fcp_dl ) // error building S/G list?
4921           {
4922             ulStatus = MEMPOOL_FAIL;
4923             break;      // give up
4924           }
4925     
4926           // no payload or command to build -- READ doesn't need XRDY
4927     
4928           
4929           if( sgPairs > 3 )  // need extended s/g list
4930             pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
4931           else               // local data pointers (in SEST)
4932             pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
4933     
4934                                                 // ULONG 5
4935           pTRE->Buff_Index = 0L;   // Buff_Index | reserved
4936           pTRE->reserved = 0x0L;   // DWord 6
4937     
4938                                          // DWord 7: NOTE: zero length will
4939                                          // hang TachLite!
4940           pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
4941     
4942           pTRE->reserved_ = 0L;     // DWord 8
4943           pTRE->reserved__ = 0L;    // DWord 9
4944     
4945           break;
4946     
4947     
4948     
4949     
4950     
4951         
4952     
4953         case FCP_RESPONSE: 
4954                       // Target response frame: this sequence uses an OX/RX ID
4955                       // pair from a completed SEST exchange.  We built most
4956                       // of the response frame when we created the TWE/TRE.
4957     
4958           *pIRB_flags = 0;      // clear IRB flags
4959           IRB_flags.SFA = 1;    // send SFS (RSP)
4960           SfsLen = *pIRB_flags;
4961     
4962           SfsLen <<= 24;        // shift flags to MSB
4963           SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
4964           
4965     
4966           Exchanges->fcExchange[ *fcExchangeIndex].type = 
4967             FCP_RESPONSE; // change Exchange type to "response" phase
4968     
4969           // take advantage of prior knowledge of OX/RX_ID pair from
4970           // previous XFER outbound frame (still in fchs of exchange)
4971           fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id = 
4972             CMDfchs->ox_rx_id;
4973     
4974           // Check the status of the DATA phase of the exchange so we can report
4975           // status to the initiator
4976           buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
4977     
4978           memcpy(
4979             CMDfchs,  // re-use same XFER fchs for Response frame
4980             &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
4981             sizeof( TachFCHDR_RSP ));
4982           
4983             
4984           break;
4985     
4986         default:
4987           printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
4988           break;
4989     
4990         }
4991     
4992         
4993         
4994         if( !ulStatus)  // no errors above?
4995         {
4996           // FCHS is built; now build IRB
4997     
4998           // link the just built FCHS (the "command") to the IRB entry 
4999           // for this Exchange.
5000           pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB; 
5001         
5002                               // len & flags according to command type above
5003           pIRB->Req_A_SFS_Len = SfsLen;  // includes IRB flags & len
5004           pIRB->Req_A_SFS_Addr = virt_to_bus(CMDfchs); // TL needs physical addr
5005                                                       // of frame to send
5006           pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
5007     
5008         // Exchange is complete except for "fix-up" fields to be set
5009         // at Tachyon Queuing time:
5010         //    IRB->Req_A_Trans_ID (OX_ID/ RX_ID):  
5011         //        for SEST entry, lower bits correspond to actual FC Exchange ID
5012         //    fchs->OX_ID or RX_ID
5013         }
5014         else
5015         {
5016     #ifdef DBG     
5017           printk( "FC Error: SEST build Pool Allocation failed\n");
5018     #endif
5019           // return resources...
5020           cpqfcTSCompleteExchange( fcChip, *fcExchangeIndex);  // SEST build failed
5021         }
5022       }
5023       else  // no Exchanges available
5024       {
5025         ulStatus = SEST_FULL;
5026         printk( "FC Error: no fcExchanges available\n");
5027       }
5028       return ulStatus;
5029     }
5030     
5031     
5032     
5033     
5034     
5035     
5036     // set RSP payload fields
5037     static void  buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID) 
5038     {
5039       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5040       FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];  // shorthand
5041       PFCP_STATUS_RESPONSE pFcpStatus;
5042       
5043       memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
5044         sizeof( FCP_STATUS_RESPONSE) );
5045       if( pExchange->status ) // something wrong?
5046       {
5047         pFcpStatus = (PFCP_STATUS_RESPONSE)  // cast RSP buffer for this xchng
5048           &fcChip->SEST->RspHDR[ ExchangeID ].pl;
5049         if( pExchange->status & COUNT_ERROR )
5050         {
5051           
5052           // set FCP response len valid (so we can report count error)
5053           pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
5054           pFcpStatus->fcp_rsp_len = 0x04000000;  // 4 byte len (BIG Endian)
5055     
5056           pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
5057         }
5058       }
5059     }
5060     
5061     
5062     
5063     
5064     // This routine builds scatter/gather lists into SEST entries
5065     // INPUTS:
5066     //   SESTalPair - SEST address @DWordA "Local Buffer Length"
5067     //   sgList     - Scatter/Gather linked list of Len/Address data buffers
5068     // OUTPUT:
5069     //   sgPairs - number of valid address/length pairs
5070     // Remarks:
5071     //   The SEST data buffer pointers only depend on number of
5072     //   length/ address pairs, NOT on the type (IWE, TRE,...)
5073     //   Up to 3 pairs can be referenced in the SEST - more than 3
5074     //   require this Extended S/G list page.  The page holds 4, 8, 16...
5075     //   len/addr pairs, per Scatter/Gather List Page Length Reg.
5076     //   TachLite allows pages to be linked to any depth.
5077     
5078     //#define DBG_SEST_SGLIST 1 // for printing out S/G pairs with Ext. pages
5079     
5080     static ULONG build_SEST_sgList( 
5081         ULONG *SESTalPairStart,  // the 3 len/address buffers in SEST
5082         Scsi_Cmnd *Cmnd,
5083         ULONG *sgPairs, 
5084         PSGPAGES sgPages)  // link list of TL Ext. S/G pages from O/S Pool
5085         
5086     {
5087       ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
5088       ULONG* alPair = SESTalPairStart;
5089       ULONG alignedPageAddress;  // TL hardware alignment requirement
5090       int PairCount;
5091       unsigned long ulBuff;
5092       ULONG total_data_len=0; // (in bytes)
5093       ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
5094       ULONG thisMappingLen;
5095       struct scatterlist *sgl;  // S/G list (Linux format)
5096     
5097     
5098     
5099       if( !Cmnd->use_sg )  // no S/G list?
5100       {
5101         *sgPairs = 1;      // use "local" S/G pair in SEST entry
5102                            // (for now, ignore address bits above #31)
5103         *alPair++ = bytes_to_go & 0x7ffff; // bits 18-0, length
5104         ulBuff = virt_to_bus( Cmnd->request_buffer);
5105     #if BITS_PER_LONG > 32
5106         if( ulBuff >>32 )
5107         {
5108           printk("FATAL! Tachyon DMA address %p exceeds 32 bits\n", (void*)ulBuff );
5109           return 0;
5110         }
5111     #endif
5112         *alPair = (ULONG)ulBuff;      
5113         return bytes_to_go;
5114       }
5115     
5116     
5117       // [TBD - update for Linux to support > 32 bits addressing]
5118       // since the format for local & extended S/G lists is different,
5119       // check if S/G pairs exceeds 3.
5120       *sgPairs = Cmnd->use_sg;
5121       sgl = (struct scatterlist*)Cmnd->request_buffer;  
5122       
5123       if( *sgPairs <= 3 ) // need "local" SEST list
5124       {
5125         while( bytes_to_go)
5126         {
5127           thisMappingLen = sgl->length;  // we want them ALL on every pass
5128           bytes_to_go = bytes_to_go - thisMappingLen;
5129     
5130           // we have L/A pair; L = thisMappingLen, A = physicalAddress
5131           // load into SEST...
5132           total_data_len += thisMappingLen & 0x7ffff;  // mask in valid bits
5133                                                        // per SEST format
5134           *alPair = thisMappingLen & 0x7ffff; // bits 18-0, length
5135     //      physicalAddress.HighPart <= 19;  // shift to bit 19
5136     
5137                        // pick up bits 44-32 of upper 64-bit address
5138                        // and load into 31-19 LBAU (upper addr) of SEST entry
5139     //      *alPair++ |=(ULONG)((physicalAddress.HighPart & 0xFFF8)); 
5140           // on Tachlite TS's local S/G, we can handle 13 extra address bits
5141           // i.e., bits 31-19 are actually bits  44-32 of physicalAddress
5142     
5143           alPair++;
5144     
5145           ulBuff = virt_to_bus( sgl->address);
5146     #if BITS_PER_LONG > 32
5147           if( ulBuff >>32 )
5148           {
5149             printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff );
5150             return 0;
5151           }
5152     #endif
5153           *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
5154     
5155           ++sgl;  // next S/G pair
5156     #ifdef DBG_SEST_SGLIST
5157           printk(" thisLen %d ", thisMappingLen);
5158           printk(" remain %d\n", bytes_to_go);
5159     #endif
5160     
5161         }
5162       }
5163     
5164     
5165     
5166     
5167       else    // more than 3 pairs requires Extended S/G page (Pool Allocation)
5168       {
5169         // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
5170     
5171     
5172         
5173         for( i=2; i<6; i++)
5174           alPair[i] = 0;
5175     
5176         PairCount = TL_EXT_SG_PAGE_COUNT;    // forces initial page allocation
5177     
5178         while( bytes_to_go )
5179         {
5180     
5181     
5182           // Per SEST format, we can support 524287 byte lenghts per
5183           // S/G pair.  Typical user buffers are 4k, and very rarely
5184           // exceed 12k due to fragmentation of physical memory pages.
5185           // However, on certain O/S system (not "user") buffers (on platforms 
5186           // with huge memories like 256Meg), it's possible to exceed this
5187           // length in a single S/G address/len mapping.
5188           //
5189           // Check for Tachyon length boundary
5190           //
5191           if( sgl->length > 0x7ffff )
5192           {
5193             // never ask for more than we can handle
5194       	thisMappingLen = sgl->length & 0x7ffff;  
5195           }
5196           else
5197             thisMappingLen = sgl->length;        
5198           
5199     
5200     
5201           // should we load into "this" extended S/G page, or allocate
5202           // new page?
5203     
5204           if( PairCount >= TL_EXT_SG_PAGE_COUNT )
5205           {
5206             // have we exceeded the max possible extended pages?      
5207             if( AllocatedPages >= TL_MAX_SGPAGES)
5208             {
5209               printk("Error: aborted loop on %d Ext. S/G page allocations\n",
5210                 AllocatedPages);
5211     
5212               total_data_len = 0;  // failure!! Ext. S/G is All-or-none affair
5213               break; // failed
5214             }
5215             
5216             // Allocate the TL Extended S/G list page from O/S pool.  We have
5217             // to allocated twice what we want to ensure required TL alignment
5218             // (Tachlite TL/TS User Man. Rev 6.0, p 168)
5219             // We store the original allocated PVOID so we can free later
5220     
5221             sgPages->PoolPage[ AllocatedPages] = 
5222               kmalloc( TL_EXT_SG_PAGE_BYTELEN*2,GFP_ATOMIC); // double for alignment
5223     
5224             
5225             if( !sgPages->PoolPage[ AllocatedPages] )  // Allocation failed?
5226             {
5227     
5228               printk("Error: Allocation failed @ %d S/G page allocations\n",
5229                 AllocatedPages);
5230     
5231               total_data_len = 0;  // failure!! Ext. S/G is All-or-none affair
5232               break;               // give up
5233             }
5234                                    // clear out memory we just allocated                     
5235             memset( sgPages->PoolPage[AllocatedPages], 0,
5236               TL_EXT_SG_PAGE_BYTELEN*2);
5237     
5238           
5239             // align the memory - TL requires sizeof() Ext. S/G page alignment.
5240             // We doubled the actual required size so we could mask off LSBs 
5241             // to get desired offset
5242     
5243             ulBuff = virt_to_bus( sgPages->PoolPage[AllocatedPages]);
5244     
5245     #if BITS_PER_LONG > 32
5246             if( ulBuff >>32 )
5247             {
5248               printk("cqpfcTS: Tach ext. S/G DMA address %p > 32 bits\n", 
5249     		  (void*)ulBuff );
5250               return 0;
5251             }
5252     #endif
5253     	
5254             ulBuff += TL_EXT_SG_PAGE_BYTELEN; // ensures we pass align. boundary
5255             ulBuff &= (0xFFFFFFFF - (TL_EXT_SG_PAGE_BYTELEN -1) );// mask off LSBs
5256              
5257             alignedPageAddress = (ULONG)ulBuff;
5258     #ifdef DBG_SEST_SGLIST
5259             printk("new PoolPage: %p, alignedPageAddress %lXh\n", 
5260               sgPages->PoolPage[AllocatedPages], ulBuff);
5261     #endif
5262     
5263     
5264             // set pointer, in SEST if first Ext. S/G page, or in last pair
5265             // of linked Ext. S/G pages...
5266             // (Only 32-bit PVOIDs, so just load lower 32 bits)
5267             // NOTE: the Len field must be '0' if this is the first Ext. S/G
5268             // pointer in SEST, and not 0 otherwise.
5269             if( alPair == SESTalPairStart) // initial Ext. S/G list?
5270               *alPair = 0;
5271             else // not the SEST entry... Len must be non-0, so
5272                  // arbitrarily set it to number bytes remaining
5273               *alPair = ( bytes_to_go & 0x7ffff);
5274     
5275     #ifdef DBG_SEST_SGLIST
5276             printk("PairCount %d @%p even %Xh, ", 
5277               PairCount, alPair, *alPair);
5278     #endif
5279             alPair++;  // next DWORD
5280     
5281             *alPair = alignedPageAddress; // TL needs 32-bit physical
5282     #ifdef DBG_SEST_SGLIST
5283             printk("odd %Xh\n", *alPair);
5284     #endif
5285                        
5286             // now reset the pointer to the ACTUAL (Extended) S/G page
5287             // which will accept the Len/ PhysicalAddress pairs
5288             alPair = bus_to_virt(alignedPageAddress);
5289             
5290             AllocatedPages++;
5291             PairCount = 1;  // starting new Ext. S/G page
5292           }  // end of new TL Ext. S/G page allocation
5293     
5294           
5295           *alPair = thisMappingLen; // bits 18-0, length (range check above)
5296           
5297           
5298     //      physicalAddress.HighPart <= 19;  // shift to bit 19
5299           
5300                        // pick up bits 44-32 of upper 64-bit address
5301                        // and load into 31-19 LBAU (upper addr) of SEST entry
5302     //      *alPair |=(ULONG)((physicalAddress.HighPart & 0xFFF8)); 
5303     
5304           
5305     #ifdef DBG_SEST_SGLIST
5306           printk("PairCount %d @%p, even %Xh, ", 
5307             PairCount, alPair, *alPair);
5308     #endif
5309     
5310           alPair++;    // next DWORD
5311           // on Tachlite TS's local S/G, we can handle 13 extra address bits
5312           // i.e., bits 31-19 are actually bits  44-32 of physicalAddress
5313     
5314     
5315           ulBuff = virt_to_bus( sgl->address);
5316     #if BITS_PER_LONG > 32
5317           if( ulBuff >>32 )
5318           {
5319             printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff );
5320             return 0;
5321           }
5322     #endif
5323           *alPair = (ULONG)ulBuff; // lower 32 bits (31-0)
5324     
5325     
5326     #ifdef DBG_SEST_SGLIST
5327           printk("odd %Xh\n", *alPair);
5328     #endif
5329           alPair++;    // next DWORD
5330                                                
5331     
5332           PairCount++; // next Length/Address pair
5333           bytes_to_go -= thisMappingLen;
5334           total_data_len += thisMappingLen;  
5335           sgl++;  // next S/G pair
5336         }
5337       }
5338       return total_data_len;
5339     }
5340     
5341     
5342     
5343     // The Tachlite SEST table is referenced to OX_ID (or RX_ID).  To optimize
5344     // performance and debuggability, we index the Exchange structure to FC X_ID
5345     // This enables us to build exchanges for later en-queing to Tachyon,
5346     // provided we have an open X_ID slot. At Tachyon queing time, we only 
5347     // need an ERQ slot; then "fix-up" references in the 
5348     // IRB, FCHS, etc. as needed.
5349     // RETURNS:
5350     // 0 if successful
5351     // non-zero on error
5352     //sstartex
5353     ULONG cpqfcTSStartExchange( 
5354       CPQFCHBA *cpqfcHBAdata,                      
5355       LONG ExchangeID )
5356     {
5357       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
5358       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5359       FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
5360       USHORT producer, consumer;
5361       ULONG ulStatus=0;
5362       short int ErqIndex;
5363       BOOLEAN CompleteExchange = FALSE;  // e.g. ACC replies are complete
5364       BOOLEAN SestType=FALSE;
5365       ULONG InboundData=0;
5366     
5367       // We will manipulate Tachlite chip registers here to successfully
5368       // start exchanges. 
5369     
5370       // Check that link is not down -- we can't start an exchange on a
5371       // down link!
5372     
5373       if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
5374       {
5375     printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n",
5376              fcChip->Registers.FMstatus.value & 0xFF,
5377              ExchangeID,
5378              pExchange->type,
5379              pExchange->fchs.d_id);
5380     
5381         if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
5382         {
5383           // Our most popular LinkService commands are port discovery types
5384           // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
5385           // events, so it makes no sense to Que them.  However, ABTS should
5386           // be queued, since exchange sequences are likely destroyed by
5387           // Link Down events, and we want to notify other ports of broken
5388           // sequences by aborting the corresponding exchanges.
5389           if( pExchange->type != BLS_ABTS )
5390           {
5391     	ulStatus = LNKDWN_OSLS;
5392     	goto Done;
5393             // don't Que most LinkServ exchanges on LINK DOWN
5394           }
5395         }
5396     
5397         printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", 
5398           ExchangeID, pExchange->type);
5399         pExchange->status |= EXCHANGE_QUEUED;
5400         ulStatus = EXCHANGE_QUEUED;
5401         goto Done;
5402       }
5403     
5404       // Make sure ERQ has available space.
5405       
5406       producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
5407       consumer = (USHORT)fcChip->ERQ->consumerIndex;
5408       producer++;  // We are testing for full que by incrementing
5409       
5410       if( producer >= ERQ_LEN )  // rollover condition?
5411         producer = 0;
5412       if( consumer != producer ) // ERQ not full?
5413       {
5414         // ****************** Need Atomic access to chip registers!!********
5415         
5416         // remember ERQ PI for copying IRB
5417         ErqIndex = (USHORT)fcChip->ERQ->producerIndex; 
5418         fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
5419                    // we have an ERQ slot! If SCSI command, need SEST slot
5420                    // otherwise we are done.
5421     
5422         // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
5423         // set according to direction of data to/from Tachyon for SEST assists.
5424         // For consistency, enforce this rule for Link Service (non-SEST)
5425         // exchanges as well.
5426     
5427         // fix-up the X_ID field in IRB
5428         pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
5429     
5430         // fix-up the X_ID field in fchs -- depends on Originator or Responder,
5431         // outgoing or incoming data?
5432         switch( pExchange->type )
5433         {
5434                    // ORIGINATOR types...  we're setting our OX_ID and
5435                    // defaulting the responder's RX_ID to 0xFFFF
5436         
5437         case SCSI_IRE:
5438           // Requirement: set MSB of x_ID for Incoming TL data
5439           // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5440           InboundData = 0x8000;
5441     
5442         case SCSI_IWE:   
5443           SestType = TRUE;
5444           pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
5445           pExchange->fchs.ox_rx_id <<= 16;     // MSW shift
5446           pExchange->fchs.ox_rx_id |= 0xffff;  // add default RX_ID
5447           
5448           // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
5449           // (not necessary for IRE -- data buffer unused)
5450           if( pExchange->type == SCSI_IWE)
5451           {
5452             fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id = 
5453               pExchange->fchs.ox_rx_id;
5454     
5455           }
5456     
5457           break;
5458     
5459     
5460         case FCS_NSR:  // ext. link service Name Service Request
5461         case ELS_SCR:  // ext. link service State Change Registration
5462         case ELS_FDISC:// ext. link service login
5463         case ELS_FLOGI:// ext. link service login
5464         case ELS_LOGO: // FC-PH extended link service logout
5465         case BLS_NOP:  // Basic link service No OPeration
5466         case ELS_PLOGI:// ext. link service login (PLOGI)
5467         case ELS_PDISC:// ext. link service login (PDISC)
5468         case ELS_PRLI: // ext. link service process login
5469     
5470           pExchange->fchs.ox_rx_id = ExchangeID;
5471           pExchange->fchs.ox_rx_id <<= 16;  // MSW shift
5472           pExchange->fchs.ox_rx_id |= 0xffff;  // and RX_ID
5473     
5474           break;
5475           
5476     
5477     
5478     
5479                    // RESPONDER types... we must set our RX_ID while preserving
5480                    // sender's OX_ID
5481                    // outgoing (or no) data
5482         case ELS_RJT:       // extended link service reject 
5483         case ELS_LOGO_ACC: // FC-PH extended link service logout accept
5484         case ELS_ACC:      // ext. generic link service accept
5485         case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
5486         case ELS_PRLI_ACC: // ext. link service process login accept
5487     
5488           CompleteExchange = TRUE;   // Reply (ACC or RJT) is end of exchange
5489           pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
5490     
5491           break;
5492     
5493     
5494           // since we are a Responder, OX_ID should already be set by
5495           // cpqfcTSBuildExchange().  We need to -OR- in RX_ID
5496         case SCSI_TWE:
5497           SestType = TRUE;
5498           // Requirement: set MSB of x_ID for Incoming TL data
5499           // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5500     
5501           pExchange->fchs.ox_rx_id &= 0xFFFF0000;  // clear RX_ID
5502           // Requirement: set MSB of RX_ID for Incoming TL data
5503           // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5504           pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
5505           break;
5506               
5507         
5508         case SCSI_TRE:
5509           SestType = TRUE;
5510           
5511           // there is no XRDY for SEST target read; the data
5512           // header needs to be updated. Also update the RSP
5513           // exchange IDs for the status frame, in case it is sent automatically
5514           fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
5515           fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id = 
5516             fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5517           
5518           // for easier FCP response logic (works for TWE and TRE), 
5519           // copy exchange IDs.  (Not needed if TRE 'RSP' bit set)
5520           pExchange->fchs.ox_rx_id =
5521             fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5522     
5523           break;
5524     
5525     
5526         case FCP_RESPONSE:  // using existing OX_ID/ RX_ID pair,
5527                             // start SFS FCP-RESPONSE frame
5528           // OX/RX_ID should already be set! (See "fcBuild" above)
5529           CompleteExchange = TRUE;   // RSP is end of FCP-SCSI exchange
5530     
5531           
5532           break;
5533     
5534     
5535         case BLS_ABTS_RJT:  // uses new RX_ID, since SEST x_ID non-existent
5536         case BLS_ABTS_ACC:  // using existing OX_ID/ RX_ID pair from SEST entry
5537           CompleteExchange = TRUE;   // ACC or RJT marks end of FCP-SCSI exchange
5538         case BLS_ABTS:  // using existing OX_ID/ RX_ID pair from SEST entry
5539     
5540     
5541           break;
5542     
5543     
5544         default:
5545           printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
5546             pExchange->type, pExchange->type);
5547           return INVALID_ARGS;
5548         }
5549         
5550         
5551           // X_ID fields are entered -- copy IRB to Tachyon's ERQ
5552         
5553     
5554         memcpy(
5555             &fcChip->ERQ->QEntry[ ErqIndex ],  // dest.
5556             &pExchange->IRB,
5557             32);  // fixed (hardware) length!
5558     
5559         PCI_TRACEO( ExchangeID, 0xA0)
5560     
5561         // ACTION!  May generate INT and IMQ entry
5562         writel( fcChip->ERQ->producerIndex,
5563               fcChip->Registers.ERQproducerIndex.address);
5564     
5565       
5566         if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
5567         {
5568         
5569           // wait for completion! (TDB -- timeout and chip reset)
5570           
5571     
5572       PCI_TRACEO( ExchangeID, 0xA4)
5573       
5574           enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
5575           
5576           down_interruptible( cpqfcHBAdata->TYOBcomplete); 
5577       
5578           disable_irq( cpqfcHBAdata->HostAdapter->irq);
5579       PCI_TRACE( 0xA4)
5580     
5581           // On login exchanges, BAD_ALPA (non-existent port_id) results in 
5582           // FTO (Frame Time Out) on the Outbound Completion message.
5583           // If we got an FTO status, complete the exchange (free up slot)
5584           if( CompleteExchange ||   // flag from Reply frames
5585               pExchange->status )   // typically, can get FRAME_TO
5586           {
5587         	cpqfcTSCompleteExchange( fcChip, ExchangeID);  
5588           }
5589         }
5590     
5591         else                         // SEST Exchange
5592         {
5593           ulStatus = 0;   // ship & pray success (e.g. FCP-SCSI)
5594           
5595           if( CompleteExchange )   // by Type of exchange (e.g. end-of-xchng)
5596           {
5597         	cpqfcTSCompleteExchange( fcChip, ExchangeID);  
5598           }
5599            
5600           else
5601             pExchange->status &= ~EXCHANGE_QUEUED;  // clear ExchangeQueued flag 
5602     
5603         }
5604       }
5605     
5606       
5607       else                // ERQ 'producer' = 'consumer' and QUE is full
5608       {
5609         ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
5610       }
5611      
5612     Done: 
5613       PCI_TRACE( 0xA0)
5614       return ulStatus; 
5615     }
5616     
5617     
5618     
5619     
5620     
5621     // Scan fcController->fcExchanges array for a usuable index (a "free"
5622     // exchange).
5623     // Inputs:
5624     //   fcChip - pointer to TachLite chip structure
5625     // Return:
5626     //  index - exchange array element where exchange can be built
5627     //  -1    - exchange array is full
5628     // REMARKS:
5629     // Although this is a (yuk!) linear search, we presume
5630     // that the system will complete exchanges about as quickly as
5631     // they are submitted.  A full Exchange array (and hence, max linear
5632     // search time for free exchange slot) almost guarantees a Fibre problem 
5633     // of some sort.
5634     // In the interest of making exchanges easier to debug, we want a LRU
5635     // (Least Recently Used) scheme.
5636     
5637     
5638     static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
5639     {
5640       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5641       ULONG i;
5642       ULONG ulStatus=-1;  // assume failure
5643     
5644     
5645       if( type == SCSI_IRE ||
5646           type == SCSI_TRE ||
5647           type == SCSI_IWE ||
5648           type == SCSI_TWE)
5649       {
5650             // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
5651         if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
5652           fcChip->fcSestExchangeLRU = 0;
5653         i = fcChip->fcSestExchangeLRU; // typically it's already free!
5654     
5655         if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5656         {
5657           ulStatus = 0; // success!
5658         }
5659         
5660         else
5661         {         // YUK! we need to do a linear search for free element.
5662                   // Fragmentation of the fcExchange array is due to excessively
5663                   // long completions or timeouts.
5664           
5665           while( TRUE )
5666           {
5667             if( ++i >= TACH_SEST_LEN ) // rollover check
5668               i = 0;  // beginning of SEST X_IDs
5669     
5670     //        printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n", 
5671     //         i, Exchanges->fcExchange[i].type);
5672     
5673             if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5674             {
5675               ulStatus = 0; // success!
5676               break;
5677             }
5678             if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
5679             {
5680               printk( "SEST X_ID space full\n");
5681               break;       // failed - prevent inf. loop
5682             }
5683           }
5684         }
5685         fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
5686       }
5687     
5688       
5689       
5690       else  // Link Service type - X_IDs should be from TACH_SEST_LEN 
5691             // to TACH_MAX_XID
5692       {
5693         if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
5694             fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
5695           fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
5696     
5697         i = fcChip->fcLsExchangeLRU; // typically it's already free!
5698         if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5699         {
5700           ulStatus = 0; // success!
5701         }
5702         
5703         else
5704         {         // YUK! we need to do a linear search for free element
5705                   // Fragmentation of the fcExchange array is due to excessively
5706                   // long completions or timeouts.
5707           
5708           while( TRUE )
5709           {
5710             if( ++i >= TACH_MAX_XID ) // rollover check
5711               i = TACH_SEST_LEN;// beginning of Link Service X_IDs
5712     
5713     //        printk( "looping for xchng ID: i=%d, type=%Xh\n", 
5714     //         i, Exchanges->fcExchange[i].type);
5715     
5716             if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5717             {
5718               ulStatus = 0; // success!
5719               break;
5720             }
5721             if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
5722             {
5723               printk( "LinkService X_ID space full\n");
5724               break;       // failed - prevent inf. loop
5725             }
5726           }
5727         }
5728         fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
5729     
5730       }
5731     
5732       if( !ulStatus )  // success?
5733         Exchanges->fcExchange[i].type = type; // allocate it.
5734       
5735       else
5736         i = -1;  // error - all exchanges "open"
5737     
5738       return i;  
5739     }
5740     
5741     
5742     
5743     
5744     
5745     // We call this routine to free an Exchange for any reason:
5746     // completed successfully, completed with error, aborted, etc.
5747     
5748     // returns FALSE if Exchange failed and "retry" is acceptable
5749     // returns TRUE if Exchange was successful, or retry is impossible
5750     // (e.g. port/device gone).
5751     //scompleteexchange
5752     
5753     void cpqfcTSCompleteExchange( 
5754            PTACHYON fcChip, 
5755            ULONG x_ID)
5756     {
5757       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5758       
5759       if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
5760       {
5761         if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
5762         {
5763     //      TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
5764           printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
5765     			Exchanges->fcExchange[ x_ID ].type);
5766     
5767           goto CleanUpSestResources;  // this path should be very rare.
5768         }
5769     
5770         // we have Linux Scsi Cmnd ptr..., now check our Exchange status
5771         // to decide how to complete this SEST FCP exchange
5772     
5773         if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
5774                                                  // or abnormal exchange completion
5775         {
5776           // set FCP Link statistics
5777          
5778           if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
5779             fcChip->fcStats.timeouts++;
5780           if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
5781             fcChip->fcStats.FC4aborted++;
5782           if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
5783             fcChip->fcStats.CntErrors++;
5784           if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
5785             fcChip->fcStats.linkFailTX++;
5786           if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
5787             fcChip->fcStats.linkFailRX++;
5788           if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
5789             fcChip->fcStats.CntErrors++;
5790     
5791           // First, see if the Scsi upper level initiated an ABORT on this
5792           // exchange...
5793           if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
5794           {
5795             printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", 
5796                 x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5797             goto CleanUpSestResources;  // (we don't expect Linux _aborts)
5798           }
5799     
5800           // Did our driver timeout the Exchange, or did Tachyon indicate
5801           // a failure during transmission?  Ask for retry with "SOFT_ERROR"
5802           else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT) 
5803           {
5804     //        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
5805     //            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5806             Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5807           }
5808           
5809           // Did frame(s) for an open exchange arrive in the SFQ,
5810           // meaning the SEST was unable to process them?
5811           else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME) 
5812           {
5813     //        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
5814     //            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5815             Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5816           }
5817           
5818           // Did our driver timeout the Exchange, or did Tachyon indicate
5819           // a failure during transmission?  Ask for retry with "SOFT_ERROR"
5820           else if( 
5821                    (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
5822                    (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) ||
5823     	       (Exchanges->fcExchange[ x_ID ].status & FRAME_TO)    ||
5824     	       (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY)    ||
5825     	       (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY)    )
5826     
5827     
5828           {
5829     //        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
5830     //            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5831             Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5832     
5833     
5834           }
5835     
5836           // e.g., a LOGOut happened, or device never logged back in.
5837           else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED) 
5838           {
5839     //	printk(" *LOGOut or timeout on login!* ");
5840     	// trigger?
5841     //        TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
5842     
5843             Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
5844           }      
5845     		
5846     		      
5847           // Did Tachyon indicate a CNT error?  We need further analysis
5848           // to determine if the exchange is acceptable
5849           else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
5850           {
5851             UCHAR ScsiStatus;
5852             FCP_STATUS_RESPONSE *pFcpStatus = 
5853     	  (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
5854     
5855           	ScsiStatus = pFcpStatus->fcp_status >>24;
5856       
5857     	// If the command is a SCSI Read/Write type, we don't tolerate
5858     	// count errors of any kind; assume the count error is due to
5859     	// a dropped frame and ask for retry...
5860     	
5861     	if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) ||
5862     	    (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) ||		
5863                 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) ||
5864                 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) )
5865     	                   &&
5866                          ScsiStatus == 0 )
5867     	{
5868               // ask for retry
5869     /*          printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n", 
5870                 x_ID, Exchanges->fcExchange[ x_ID ].status,
5871                 Exchanges->fcExchange[ x_ID ].Cmnd);*/
5872               Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5873     	}
5874     	
5875     	else  // need more analysis
5876     	{
5877     	  cpqfcTSCheckandSnoopFCP(fcChip, x_ID);  // (will set ->result)
5878     	}
5879           }
5880           
5881           // default: NOTE! We don't ever want to get here.  Getting here
5882           // implies something new is happening that we've never had a test
5883           // case for.  Need code maintenance!  Return "ERROR"
5884           else
5885           {
5886             printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p\n", 
5887               Exchanges->fcExchange[ x_ID ].status, x_ID, 
5888     	  Exchanges->fcExchange[ x_ID ].Cmnd);
5889             Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
5890           }
5891         }
5892         else    // definitely no Tach problem, but perhaps an FCP problem
5893         {
5894           // set FCP Link statistic
5895           fcChip->fcStats.ok++;
5896           cpqfcTSCheckandSnoopFCP( fcChip, x_ID);  // (will set ->result)    
5897         }
5898     
5899         // OK, we've set the Scsi "->result" field, so proceed with calling
5900         // Linux Scsi "done" (if not NULL), and free any kernel memory we
5901         // may have allocated for the exchange.
5902     
5903       PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
5904         // complete the command back to upper Scsi drivers
5905         if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
5906         {
5907           // Calling "done" on an Linux _abort() aborted
5908           // Cmnd causes a kernel panic trying to re-free mem.
5909           // Actually, we shouldn't do anything with an _abort CMND
5910           if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
5911           {
5912             PCI_TRACE(0xAC)
5913             (*Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done)
5914     	   (Exchanges->fcExchange[ x_ID ].Cmnd);
5915           }
5916           else
5917           {
5918     
5919     //	printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
5920     //			x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5921           }
5922         }
5923         else{
5924           printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
5925     	Exchanges->fcExchange[ x_ID ].type, 
5926     	Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);	      
5927           printk(" cpqfcTS: Null scsi_done function pointer!\n");
5928         }
5929     
5930     
5931         // Now, clean up non-Scsi_Cmnd items...
5932     CleanUpSestResources:
5933         
5934         // Was an Extended Scatter/Gather page allocated?  We know
5935         // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
5936         if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
5937         {
5938           int i = 0;
5939     
5940           // extended S/G list was used -- Free the allocated ext. S/G pages
5941     
5942           while( fcChip->SEST->sgPages[x_ID].PoolPage[i] && 
5943                  (i < TL_MAX_SGPAGES) )
5944           {
5945             kfree( fcChip->SEST->sgPages[x_ID].PoolPage[i]);
5946             fcChip->SEST->sgPages[x_ID].PoolPage[i] = NULL;
5947             i++;
5948           }
5949         }
5950       
5951         Exchanges->fcExchange[ x_ID ].Cmnd = NULL; 
5952       }  // Done with FCP (SEST) exchanges
5953     
5954     
5955       // the remaining logic is common to ALL Exchanges: 
5956       // FCP(SEST) and LinkServ.
5957     
5958       Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!  
5959       Exchanges->fcExchange[ x_ID ].status = 0; 
5960     
5961       PCI_TRACEO( x_ID, 0xAC)
5962          
5963       
5964       return;
5965     }   // (END of CompleteExchange function)
5966      
5967     
5968     
5969     
5970     // Unfortunately, we must snoop all command completions in
5971     // order to manipulate certain return fields, and take note of
5972     // device types, etc., to facilitate the Fibre-Channel to SCSI
5973     // "mapping".  
5974     // (Watch for BIG Endian confusion on some payload fields)
5975     void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
5976     {
5977       FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5978       Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
5979       FCP_STATUS_RESPONSE *pFcpStatus = 
5980         (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
5981       UCHAR ScsiStatus;
5982     
5983       ScsiStatus = pFcpStatus->fcp_status >>24;
5984     
5985     #ifdef FCP_COMPLETION_DBG
5986       printk("ScsiStatus = 0x%X\n", ScsiStatus);
5987     #endif	
5988     
5989       // First, check FCP status
5990       if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
5991       {
5992         // check response code (RSP_CODE) -- most popular is bad len
5993         // 1st 4 bytes of rsp info -- only byte 3 interesting
5994         if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
5995         { 
5996     
5997           // do we EVER get here?
5998           printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
5999         }
6000       }
6001     
6002       // for now, go by the ScsiStatus, and manipulate certain
6003       // commands when necessary...
6004       if( ScsiStatus == 0) // SCSI status byte "good"?
6005       {
6006         Cmnd->result = 0; // everything's OK
6007     
6008         if( (Cmnd->cmnd[0] == INQUIRY)) 
6009         {
6010           UCHAR *InquiryData = Cmnd->request_buffer;
6011           PFC_LOGGEDIN_PORT pLoggedInPort;
6012     
6013           // We need to manipulate INQUIRY
6014           // strings for COMPAQ RAID controllers to force
6015           // Linux to scan additional LUNs.  Namely, set
6016           // the Inquiry string byte 2 (ANSI-approved version)
6017           // to 2.
6018     
6019           if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
6020           {
6021             InquiryData[2] = 0x2;  // claim SCSI-2 compliance,
6022                                    // so multiple LUNs may be scanned.
6023                                    // (no SCSI-2 problems known in CPQ)
6024           }
6025             
6026           // snoop the Inquiry to detect Disk, Tape, etc. type
6027           // (search linked list for the port_id we sent INQUIRY to)
6028           pLoggedInPort = fcFindLoggedInPort( fcChip,
6029             NULL,     // DON'T search Scsi Nexus (we will set it)
6030             Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
6031             NULL,     // DON'T search linked list for FC WWN
6032             NULL);    // DON'T care about end of list
6033      
6034           if( pLoggedInPort )
6035           {
6036             pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
6037           }
6038           else
6039           {
6040     	printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
6041               Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
6042           }
6043         }
6044       }
6045     
6046     
6047       // Scsi Status not good -- pass it back to caller 
6048     
6049       else
6050       {
6051         Cmnd->result = ScsiStatus; // SCSI status byte is 1st
6052         
6053         // check for valid "sense" data
6054     
6055         if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID ) 
6056         {            // limit Scsi Sense field length!
6057           int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
6058           
6059           SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ? 
6060             sizeof( Cmnd->sense_buffer) : SenseLen;
6061     	   
6062     
6063     #ifdef FCP_COMPLETION_DBG	    
6064           printk("copy sense_buffer %p, len %d, result %Xh\n",
6065             Cmnd->sense_buffer, SenseLen, Cmnd->result);
6066     #endif	  
6067     
6068           // NOTE: There is some dispute over the FCP response
6069           // format.  Most FC devices assume that FCP_RSP_INFO
6070           // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
6071           // is (virtually) always 0 and the field is "invalid".  
6072           // Some other devices assume that
6073           // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
6074           // when the FCP_RSP is invalid (this almost appears to be
6075           // one of those "religious" issues).
6076           // Consequently, we test the usual position of FCP_SNS_INFO
6077           // for 7Xh, since the SCSI sense format says the first
6078           // byte ("error code") should be 0x70 or 0x71.  In practice,
6079           // we find that every device does in fact have 0x70 or 0x71
6080           // in the first byte position, so this test works for all
6081           // FC devices.  
6082           // (This logic is especially effective for the CPQ/DEC HSG80
6083           // & HSG60 controllers).
6084     
6085           if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
6086             memcpy( Cmnd->sense_buffer, 
6087               &pFcpStatus->fcp_sns_info[0], SenseLen);
6088           else
6089           {
6090             unsigned char *sbPtr = 
6091     		(unsigned char *)&pFcpStatus->fcp_sns_info[0];
6092             sbPtr -= 8;  // back up 8 bytes hoping to find the
6093     	             // start of the sense buffer
6094             memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
6095           }
6096     
6097           // in the special case of Device Reset, tell upper layer
6098           // to immediately retry (with SOFT_ERROR status)
6099           // look for Sense Key Unit Attention (0x6) with ASC Device
6100           // Reset (0x29)
6101           //	    printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
6102           //		    SenseLen, Cmnd->sense_buffer[2], 
6103           //                   Cmnd->sense_buffer[12]);
6104           if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
6105     	        (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
6106           {
6107             Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
6108           }
6109      
6110           // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
6111           else if(  ((Cmnd->sense_buffer[2] & 0xF) == 0x4) &&  // "hardware error"
6112           	        (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code 
6113           {
6114     //        printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
6115     //		Cmnd->channel, Cmnd->target, Cmnd->lun);
6116           	Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
6117           }
6118           
6119         }  // (end of sense len valid)
6120     
6121         // there is no sense data to help out Linux's Scsi layers...
6122         // We'll just return the Scsi status and hope he will "do the 
6123         // right thing"
6124         else
6125         {
6126           // as far as we know, the Scsi status is sufficient
6127           Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
6128         }
6129       }
6130     }
6131     
6132     
6133     
6134     //PPPPPPPPPPPPPPPPPPPPPPPPP  PAYLOAD  PPPPPPPPP
6135     // build data PAYLOAD; SCSI FCP_CMND I.U.
6136     // remember BIG ENDIAN payload - DWord values must be byte-reversed
6137     // (hence the affinity for byte pointer building).
6138     
6139     static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
6140           UCHAR* payload, ULONG type, ULONG fcp_dl )
6141     {
6142       int i;
6143     
6144       
6145       switch( type)
6146       {
6147     		  
6148         case SCSI_IWE: 
6149         case SCSI_IRE:        
6150           // 8 bytes FCP_LUN
6151           // Peripheral Device or Volume Set addressing, and LUN mapping
6152           // When the FC port was looked up, we copied address mode
6153           // and any LUN mask to the scratch pad SCp.phase & .mode
6154     
6155           *payload++ = (UCHAR)Cmnd->SCp.phase;
6156     
6157           // Now, because of "lun masking" 
6158           // (aka selective storage presentation),
6159           // the contiguous Linux Scsi lun number may not match the
6160           // device's lun number, so we may have to "map".  
6161           
6162           *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
6163           
6164           // We don't know of anyone in the FC business using these 
6165           // extra "levels" of addressing.  In fact, confusion still exists
6166           // just using the FIRST level... ;-)
6167           
6168           *payload++ = 0;  // 2nd level addressing
6169           *payload++ = 0;
6170           *payload++ = 0;  // 3rd level addressing
6171           *payload++ = 0;
6172           *payload++ = 0;  // 4th level addressing
6173           *payload++ = 0;
6174     
6175           // 4 bytes Control Field FCP_CNTL
6176           *payload++ = 0;    // byte 0: (MSB) reserved
6177           *payload++ = 0;    // byte 1: task codes
6178     
6179                              // byte 2: task management flags
6180           // another "use" of the spare field to accomplish TDR
6181           // note combination needed
6182           if( (Cmnd->cmnd[0] == RELEASE) &&
6183               (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
6184           {
6185             Cmnd->cmnd[0] = 0;    // issue "Test Unit Ready" for TDR
6186             *payload++ = 0x20;    // target device reset bit
6187           }
6188           else
6189             *payload++ = 0;    // no TDR
6190     		      // byte 3: (LSB) execution management codes
6191     		      // bit 0 write, bit 1 read (don't set together)
6192           
6193           if( fcp_dl != 0 )
6194           {
6195             if( type == SCSI_IWE )         // WRITE
6196               *payload++ = 1;
6197             else                           // READ
6198               *payload++ = 2;
6199           }
6200           else
6201           {
6202     	// On some devices, if RD or WR bits are set,
6203     	// and fcp_dl is 0, they will generate an error on the command.
6204     	// (i.e., if direction is specified, they insist on a length).
6205     	*payload++ = 0;                // no data (necessary for CPQ)
6206           }
6207     
6208     
6209           // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
6210           // FCP_CDB allows 16 byte SCSI command descriptor blk;
6211           // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
6212           for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
6213     	*payload++ = Cmnd->cmnd[i];
6214     
6215           if( Cmnd->cmd_len == 16 )
6216           {
6217             memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
6218           }
6219           payload+= (16 - i);  
6220     
6221     		      // FCP_DL is largest number of expected data bytes
6222     		      // per CDB (i.e. read/write command)
6223           *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
6224           *payload++ = (UCHAR)(fcp_dl >>16);
6225           *payload++ = (UCHAR)(fcp_dl >>8);
6226           *payload++ = (UCHAR)fcp_dl;    // (LSB)
6227           break;
6228     
6229         case SCSI_TWE:          // need FCP_XFER_RDY
6230           *payload++ = 0;     // (4 bytes) DATA_RO (MSB byte 0)
6231           *payload++ = 0;
6232           *payload++ = 0;
6233           *payload++ = 0;     // LSB (byte 3)
6234     			     // (4 bytes) BURST_LEN
6235     			     // size of following FCP_DATA payload
6236           *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
6237           *payload++ = (UCHAR)(fcp_dl >>16);
6238           *payload++ = (UCHAR)(fcp_dl >>8);
6239           *payload++ = (UCHAR)fcp_dl;    // (LSB)
6240     		       // 4 bytes RESERVED
6241           *payload++ = 0;
6242           *payload++ = 0;
6243           *payload++ = 0;
6244           *payload++ = 0;
6245           break;
6246     
6247         default:
6248           break;
6249       }
6250     
6251       return 0;
6252     }
6253     
6254