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

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

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

  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/malloc.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 
 51 //#define LOGIN_DBG 1
 52 
 53 // REMARKS:
 54 // Since Tachyon chips may be permitted to wait from 500ms up to 2 sec
 55 // to empty an outgoing frame from its FIFO to the Fibre Channel stream,
 56 // we cannot do everything we need to in the interrupt handler.  Specifically,
 57 // every time a link re-init (e.g. LIP) takes place, all SCSI I/O has to be
 58 // suspended until the login sequences have been completed.  Login commands
 59 // are frames just like SCSI commands are frames; they are subject to the same
 60 // timeout issues and delays.  Also, various specs provide up to 2 seconds for
 61 // devices to log back in (i.e. respond with ACC to a login frame), so I/O to
 62 // that device has to be suspended.
 63 // A serious problem here occurs on highly loaded FC-AL systems.  If our FC port
 64 // has a low priority (e.g. high arbitrated loop physical address, alpa), and
 65 // some other device is hogging bandwidth (permissible under FC-AL), we might
 66 // time out thinking the link is hung, when it's simply busy.  Many such
 67 // considerations complicate the design.  Although Tachyon assumes control
 68 // (in silicon) for many link-specific issues, the Linux driver is left with the
 69 // rest, which turns out to be a difficult, time critical chore.
 70 
 71 // These "worker" functions will handle things like FC Logins; all
 72 // processes with I/O to our device must wait for the Login to complete
 73 // and (if successful) I/O to resume.  In the event of a malfunctioning or  
 74 // very busy loop, it may take hundreds of millisecs or even seconds to complete
 75 // a frame send.  We don't want to hang up the entire server (and all
 76 // processes which don't depend on Fibre) during this wait.
 77 
 78 // The Tachyon chip can have around 30,000 I/O operations ("exchanges")
 79 // open at one time.  However, each exchange must be initiated 
 80 // synchronously (i.e. each of the 30k I/O had to be started one at a
 81 // time by sending a starting frame via Tachyon's outbound que).  
 82 
 83 // To accomodate kernel "module" build, this driver limits the exchanges
 84 // to 256, because of the contiguous physical memory limitation of 128M.
 85 
 86 // Typical FC Exchanges are opened presuming the FC frames start without errors,
 87 // while Exchange completion is handled in the interrupt handler.  This
 88 // optimizes performance for the "everything's working" case.
 89 // However, when we have FC related errors or hot plugging of FC ports, we pause
 90 // I/O and handle FC-specific tasks in the worker thread.  These FC-specific
 91 // functions will handle things like FC Logins and Aborts.  As the Login sequence
 92 // completes to each and every target, I/O can resume to that target.  
 93 
 94 // Our kernel "worker thread" must share the HBA with threads calling 
 95 // "queuecommand".  We define a "BoardLock" semaphore which indicates
 96 // to "queuecommand" that the HBA is unavailable, and Cmnds are added to a
 97 // board lock Q.  When the worker thread finishes with the board, the board
 98 // lock Q commands are completed with status causing immediate retry.
 99 // Typically, the board is locked while Logins are in progress after an
100 // FC Link Down condition.  When Cmnds are re-queued after board lock, the
101 // particular Scsi channel/target may or may not have logged back in.  When
102 // the device is waiting for login, the "prli" flag is clear, in which case
103 // commands are passed to a Link Down Q.  Whenever the login finally completes,
104 // the LinkDown Q is completed, again with status causing immediate retry.
105 // When FC devices are logged in, we build and start FC commands to the
106 // devices.
107 
108 // NOTE!! As of May 2000, kernel 2.2.14, the error recovery logic for devices 
109 // that never log back in (e.g. physically removed) is NOT completely
110 // understood.  I've still seen instances of system hangs on failed Write 
111 // commands (possibly from the ext2 layer?) on device removal.  Such special
112 // cases need to be evaluated from a system/application view - e.g., how
113 // exactly does the system want me to complete commands when the device is
114 // physically removed??
115 
116 // local functions
117 
118 static void SetLoginFields(
119   PFC_LOGGEDIN_PORT pLoggedInPort,
120   TachFCHDR_GCMND* fchs,
121   BOOLEAN PDisc,
122   BOOLEAN Originator);
123 
124 static void AnalyzeIncomingFrame( 
125        CPQFCHBA *cpqfcHBAdata,
126        ULONG QNdx );
127 
128 static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
129 
130 static int verify_PLOGI( PTACHYON fcChip,
131       TachFCHDR_GCMND* fchs, ULONG* reject_explain);
132 static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
133 
134 static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
135 static void BuildLinkServicePayload( 
136               PTACHYON fcChip, ULONG type, void* payload);
137 
138 static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
139         PFC_LOGGEDIN_PORT pLoggedInPort);
140 
141 static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
142 
143 static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
144 
145 static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
146                         PFC_LOGGEDIN_PORT pLoggedInPort);
147 
148 static void IssueReportLunsCommand( 
149               CPQFCHBA* cpqfcHBAdata, 
150               TachFCHDR_GCMND* fchs);
151 
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 occured, 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 }
1073 
1074   
1075 // On FC-AL, there is a chance that a previously known device can
1076 // be quietly removed (e.g. with non-managed hub), 
1077 // while a NEW device (with different WWN) took the same alpa or
1078 // even 24-bit port_id.  This chance is unlikely but we must always
1079 // check for it.
1080 static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
1081                 PFC_LOGGEDIN_PORT pLoggedInPort)
1082 {
1083   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1084   // set "other port" at beginning of fcPorts list
1085   PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
1086   while( pOtherPortWithPortId ) 
1087   {
1088     if( (pOtherPortWithPortId->port_id == 
1089          pLoggedInPort->port_id) 
1090                     &&
1091          (pOtherPortWithPortId != pLoggedInPort) )
1092     {
1093       // trouble!  (Implicitly) Log the other guy out
1094       printk(" *port_id %Xh is duplicated!* ", 
1095         pOtherPortWithPortId->port_id);
1096       cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId); 
1097    }
1098     pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
1099   }
1100 }
1101 
1102 
1103 
1104 
1105 
1106 
1107 // Dynamic Memory Allocation for newly discovered FC Ports.
1108 // For simplicity, maintain fcPorts structs for ALL
1109 // for discovered devices, including those we never do I/O with
1110 // (e.g. Fabric addresses)
1111 
1112 static PFC_LOGGEDIN_PORT CreateFcPort( 
1113           CPQFCHBA* cpqfcHBAdata, 
1114           PFC_LOGGEDIN_PORT pLastLoggedInPort, 
1115           TachFCHDR_GCMND* fchs,
1116           LOGIN_PAYLOAD* plogi)
1117 {
1118   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1119   PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
1120   int i;
1121 
1122 
1123   printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
1124   for( i=3; i>=0; i--)   // copy the LOGIN port's WWN
1125     printk("%02X", plogi->port_name[i]);
1126   for( i=7; i>3; i--)   // copy the LOGIN port's WWN
1127     printk("%02X", plogi->port_name[i]);
1128 
1129 
1130   // allocate mem for new port
1131   // (these are small and rare allocations...)
1132   pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
1133 
1134     
1135   // allocation succeeded?  Fill out NEW PORT
1136   if( pNextLoggedInPort )
1137   {    
1138                               // clear out any garbage (sometimes exists)
1139     memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
1140 
1141 
1142     // If we login to a Fabric, we don't want to treat it
1143     // as a SCSI device...
1144     if( (fchs->s_id & 0xFFF000) != 0xFFF000)
1145     {
1146       int i;
1147       
1148       // create a unique "virtual" SCSI Nexus (for now, just a
1149       // new target ID) -- we will update channel/target on REPORT_LUNS
1150       // special case for very first SCSI target...
1151       if( cpqfcHBAdata->HostAdapter->max_id == 0)
1152       {
1153         pNextLoggedInPort->ScsiNexus.target = 0;
1154         fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
1155       }
1156       else
1157       {
1158         pNextLoggedInPort->ScsiNexus.target =
1159           cpqfcHBAdata->HostAdapter->max_id;
1160       }
1161 
1162       // initialize the lun[] Nexus struct for lun masking      
1163       for( i=0; i< CPQFCTS_MAX_LUN; i++)
1164         pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
1165       
1166       pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
1167       
1168       printk(" SCSI Chan/Trgt %d/%d", 
1169           pNextLoggedInPort->ScsiNexus.channel,
1170           pNextLoggedInPort->ScsiNexus.target);
1171  
1172       // tell Scsi layers about the new target...
1173       cpqfcHBAdata->HostAdapter->max_id++; 
1174 //    printk("HostAdapter->max_id = %d\n",
1175 //      cpqfcHBAdata->HostAdapter->max_id);                 
1176     }                          
1177     else
1178     {
1179       // device is NOT SCSI (in case of Fabric)
1180       pNextLoggedInPort->ScsiNexus.target = -1;  // invalid
1181     }
1182 
1183           // create forward link to new port
1184     pLastLoggedInPort->pNextPort = pNextLoggedInPort;
1185     printk("\n");
1186 
1187   }     
1188   return pNextLoggedInPort;  // NULL on allocation failure
1189 }   // end NEW PORT (WWN) logic
1190 
1191 
1192 
1193 // For certain cases, we want to terminate exchanges without
1194 // sending ABTS to the device.  Examples include when an FC
1195 // device changed it's port_id after Loop re-init, or when
1196 // the device sent us a logout.  In the case of changed port_id,
1197 // we want to complete the command and return SOFT_ERROR to
1198 // force a re-try.  In the case of LOGOut, we might return
1199 // BAD_TARGET if the device is really gone.
1200 // Since we must ensure that Tachyon is not operating on the
1201 // exchange, we have to freeze the chip
1202 // sterminateex
1203 void cpqfcTSTerminateExchange( 
1204   CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
1205 {
1206   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1207   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1208   ULONG x_ID;
1209 
1210   if( ScsiNexus )
1211   {
1212 //    printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
1213 //                  ScsiNexus->channel, ScsiNexus->target);
1214 
1215   } 
1216   
1217   for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
1218   {
1219     if( Exchanges->fcExchange[x_ID].type )  // in use?
1220     {
1221       if( ScsiNexus == NULL ) // our HBA changed - term. all
1222       {
1223         Exchanges->fcExchange[x_ID].status = TerminateStatus;
1224         cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); 
1225       }
1226       else
1227       {
1228         // If a device, according to WWN, has been removed, it's
1229         // port_id may be used by another working device, so we
1230         // have to terminate by SCSI target, NOT port_id.
1231         if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
1232         {                        
1233           if( (Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
1234                         &&
1235             (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel)) 
1236           {
1237             Exchanges->fcExchange[x_ID].status = TerminateStatus;
1238             cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
1239           }
1240         }
1241 
1242         // (in case we ever need it...)
1243         // all SEST structures have a remote node ID at SEST DWORD 2
1244         //          if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
1245         //                ==  port_id)
1246       } 
1247     }
1248   }
1249 }
1250 
1251 
1252 static void ProcessELS_Request( 
1253               CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1254 {
1255   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1256 //  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1257 //  ULONG ox_id = (fchs->ox_rx_id >>16);
1258   PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
1259   BOOLEAN NeedReject = FALSE;
1260   ULONG ls_reject_code = 0; // default don'n know??
1261 
1262 
1263   // Check the incoming frame for a supported ELS type
1264   switch( fchs->pl[0] & 0xFFFF)
1265   {
1266   case 0x0050: //  PDISC?
1267 
1268     // Payload for PLOGI and PDISC is identical (request & reply)
1269     if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1270     {
1271       LOGIN_PAYLOAD logi;       // FC-PH Port Login
1272       
1273       // PDISC payload OK. If critical login fields
1274       // (e.g. WWN) matches last login for this port_id,
1275       // we may resume any prior exchanges
1276       // with the other port
1277 
1278       
1279       BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1280    
1281       pLoggedInPort = fcFindLoggedInPort( 
1282              fcChip, 
1283              NULL,     // don't search Scsi Nexus
1284              0,        // don't search linked list for port_id
1285              &logi.port_name[0],     // search linked list for WWN
1286              &pLastLoggedInPort);  // must return non-NULL; when a port_id
1287                                    // is not found, this pointer marks the
1288                                    // end of the singly linked list
1289     
1290       if( pLoggedInPort != NULL)   // WWN found (prior login OK)
1291       { 
1292            
1293         if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1294         {
1295           // Yes.  We were expecting PDISC?
1296           if( pLoggedInPort->pdisc )
1297           {
1298             // Yes; set fields accordingly.     (PDISC, not Originator)
1299             SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
1300        
1301             // send 'ACC' reply 
1302             cpqfcTSPutLinkQue( cpqfcHBAdata, 
1303                           ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1304                           fchs );
1305 
1306             // OK to resume I/O...
1307           }
1308           else
1309           {
1310             printk("Not expecting PDISC (pdisc=FALSE)\n");
1311             NeedReject = TRUE;
1312             // set reject reason code 
1313             ls_reject_code = 
1314               LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1315           }
1316         }
1317         else
1318         {
1319           if( pLoggedInPort->port_id != 0)
1320           {
1321             printk("PDISC PortID change: old %Xh, new %Xh\n",
1322               pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1323           }
1324           NeedReject = TRUE;
1325           // set reject reason code 
1326           ls_reject_code = 
1327             LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1328                   
1329         }
1330       }
1331       else
1332       {
1333         printk("PDISC Request from unknown WWN\n");
1334         NeedReject = TRUE;
1335           
1336         // set reject reason code 
1337         ls_reject_code = 
1338           LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
1339       }
1340 
1341     }
1342     else // Payload unacceptable
1343     {
1344       printk("payload unacceptable\n");
1345       NeedReject = TRUE;  // reject code already set
1346       
1347     }
1348 
1349     if( NeedReject)
1350     {
1351       ULONG port_id;
1352       // The PDISC failed.  Set login struct flags accordingly,
1353       // terminate any I/O to this port, and Q a PLOGI
1354       if( pLoggedInPort )
1355       {
1356         pLoggedInPort->pdisc = FALSE;
1357         pLoggedInPort->prli = FALSE;
1358         pLoggedInPort->plogi = FALSE;
1359         
1360         cpqfcTSTerminateExchange( cpqfcHBAdata, 
1361           &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1362         port_id = pLoggedInPort->port_id;
1363       }
1364       else
1365       {
1366         port_id = fchs->s_id &0xFFFFFF;
1367       }
1368       fchs->reserved = ls_reject_code; // borrow this (unused) field
1369       cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1370     }
1371    
1372     break;
1373 
1374 
1375 
1376   case 0x0003: //  PLOGI?
1377 
1378     // Payload for PLOGI and PDISC is identical (request & reply)
1379     if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1380     {
1381       LOGIN_PAYLOAD logi;       // FC-PH Port Login
1382       BOOLEAN NeedReject = FALSE;
1383       
1384       // PDISC payload OK. If critical login fields
1385       // (e.g. WWN) matches last login for this port_id,
1386       // we may resume any prior exchanges
1387       // with the other port
1388 
1389       
1390       BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1391    
1392       pLoggedInPort = fcFindLoggedInPort( 
1393              fcChip, 
1394              NULL,       // don't search Scsi Nexus
1395              0,        // don't search linked list for port_id
1396              &logi.port_name[0],     // search linked list for WWN
1397              &pLastLoggedInPort);  // must return non-NULL; when a port_id
1398                                    // is not found, this pointer marks the
1399                                    // end of the singly linked list
1400     
1401       if( pLoggedInPort == NULL)   // WWN not found -New Port
1402       { 
1403         pLoggedInPort = CreateFcPort( 
1404                           cpqfcHBAdata, 
1405                           pLastLoggedInPort, 
1406                           fchs,
1407                           &logi);
1408         if( pLoggedInPort == NULL )
1409         {
1410           printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1411           // Now Q a LOGOut Request, since we won't be talking to that device
1412         
1413           NeedReject = TRUE;  
1414           
1415           // set reject reason code 
1416           ls_reject_code = 
1417             LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
1418             
1419         }
1420       }
1421       if( !NeedReject )
1422       {
1423       
1424         // OK - we have valid fcPort ptr; set fields accordingly.   
1425         //                         (not PDISC, not Originator)
1426         SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); 
1427 
1428         // send 'ACC' reply 
1429         cpqfcTSPutLinkQue( cpqfcHBAdata, 
1430                       ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1431                       fchs );
1432       }
1433     }
1434     else // Payload unacceptable
1435     {
1436       printk("payload unacceptable\n");
1437       NeedReject = TRUE;  // reject code already set
1438     }
1439 
1440     if( NeedReject)
1441     {
1442       // The PDISC failed.  Set login struct flags accordingly,
1443       // terminate any I/O to this port, and Q a PLOGI
1444       pLoggedInPort->pdisc = FALSE;
1445       pLoggedInPort->prli = FALSE;
1446       pLoggedInPort->plogi = FALSE;
1447         
1448       fchs->reserved = ls_reject_code; // borrow this (unused) field
1449 
1450       // send 'RJT' reply 
1451       cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1452     }
1453    
1454     // terminate any exchanges with this device...
1455     if( pLoggedInPort )
1456     {
1457       cpqfcTSTerminateExchange( cpqfcHBAdata, 
1458         &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1459     }
1460     break;
1461 
1462 
1463 
1464   case 0x1020:  // PRLI?
1465   {
1466     BOOLEAN NeedReject = TRUE;
1467     pLoggedInPort = fcFindLoggedInPort( 
1468            fcChip, 
1469            NULL,       // don't search Scsi Nexus
1470            (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
1471            NULL,     // DON'T search linked list for WWN
1472            NULL);    // don't care
1473       
1474     if( pLoggedInPort == NULL ) 
1475     {
1476       // huh?
1477       printk(" Unexpected PRLI Request -not logged in!\n");
1478 
1479       // set reject reason code 
1480       ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1481       
1482       // Q a LOGOut here?
1483     }
1484     else
1485     {
1486       // verify the PRLI ACC payload
1487       if( !verify_PRLI( fchs, &ls_reject_code) )
1488       {
1489         // PRLI Reply is acceptable; were we expecting it?
1490         if( pLoggedInPort->plogi ) 
1491         { 
1492           // yes, we expected the PRLI ACC  (not PDISC; not Originator)
1493           SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1494 
1495           // Q an ACCept Reply
1496           cpqfcTSPutLinkQue( cpqfcHBAdata,
1497                         ELS_PRLI_ACC, 
1498                         fchs );   
1499           
1500           NeedReject = FALSE;
1501         }
1502         else
1503         {
1504           // huh?
1505           printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
1506 
1507           // set reject reason code 
1508           ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1509     
1510           // Q a LOGOut here?
1511           
1512         }
1513       }
1514       else
1515       {
1516         printk(" PRLI REQUEST payload failed verify\n");
1517         // (reject code set by "verify")
1518 
1519         // Q a LOGOut here?
1520       }
1521     }
1522 
1523     if( NeedReject )
1524     {
1525       // Q a ReJecT Reply with reason code
1526       fchs->reserved = ls_reject_code;
1527       cpqfcTSPutLinkQue( cpqfcHBAdata,
1528                     ELS_RJT, // Q Type
1529                     fchs );  
1530     }
1531   }
1532     break;
1533  
1534 
1535     
1536 
1537   case  0x0005:  // LOGOut?
1538   {
1539   // was this LOGOUT because we sent a ELS_PDISC to an FC device
1540   // with changed (or new) port_id, or does the port refuse 
1541   // to communicate to us?
1542   // We maintain a logout counter - if we get 3 consecutive LOGOuts,
1543   // give up!
1544     LOGOUT_PAYLOAD logo;
1545     BOOLEAN GiveUpOnDevice = FALSE;
1546     ULONG ls_reject_code = 0;
1547     
1548     BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
1549 
1550     pLoggedInPort = fcFindLoggedInPort( 
1551            fcChip, 
1552            NULL,     // don't search Scsi Nexus
1553            0,        // don't search linked list for port_id
1554            &logo.port_name[0],     // search linked list for WWN
1555            NULL);    // don't care about end of list
1556     
1557     if( pLoggedInPort ) // found the device?
1558     {
1559       // Q an ACC reply 
1560       cpqfcTSPutLinkQue( cpqfcHBAdata,
1561                     ELS_LOGO_ACC, // Q Type
1562                     fchs );       // device to respond to
1563 
1564       // set login struct fields (LOGO_counter increment)
1565       SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1566       
1567       // are we an Initiator?
1568       if( fcChip->Options.initiator)  
1569       {
1570         // we're an Initiator, so check if we should 
1571         // try (another?) login
1572 
1573         // Fabrics routinely log out from us after
1574         // getting device info - don't try to log them
1575         // back in.
1576         if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
1577         {
1578           ; // do nothing
1579         }
1580         else if( pLoggedInPort->LOGO_counter <= 3)
1581         {
1582           // try (another) login (PLOGI request)
1583           
1584           cpqfcTSPutLinkQue( cpqfcHBAdata,
1585                     ELS_PLOGI, // Q Type
1586                     fchs );  
1587         
1588           // Terminate I/O with "retry" potential
1589           cpqfcTSTerminateExchange( cpqfcHBAdata, 
1590                                     &pLoggedInPort->ScsiNexus,
1591                                     PORTID_CHANGED);
1592         }
1593         else
1594         {
1595           printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
1596                           fchs->s_id &&0xFFFFFF);
1597           GiveUpOnDevice = TRUE;
1598         }
1599       }
1600       else
1601       {
1602         GiveUpOnDevice = TRUE;
1603       }
1604 
1605 
1606       if( GiveUpOnDevice == TRUE )
1607       {
1608         cpqfcTSTerminateExchange( cpqfcHBAdata, 
1609                                   &pLoggedInPort->ScsiNexus,
1610                                   DEVICE_REMOVED);
1611       }
1612     }  
1613     else  // we don't know this WWN!
1614     {
1615       // Q a ReJecT Reply with reason code
1616       fchs->reserved = ls_reject_code;
1617       cpqfcTSPutLinkQue( cpqfcHBAdata,
1618                     ELS_RJT, // Q Type
1619                     fchs );  
1620     }
1621   }
1622     break;
1623 
1624 
1625 
1626 
1627   // FABRIC only case
1628   case 0x0461:  // ELS RSCN (Registered State Change Notification)?
1629   {
1630     int Ports;
1631     int i;
1632     __u32 Buff;
1633     // Typically, one or more devices have been added to or dropped
1634     // from the Fabric.
1635     // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
1636     // The first 32-bit word has a 2-byte Payload Length, which
1637     // includes the 4 bytes of the first word.  Consequently,
1638     // this PL len must never be less than 4, must be a multiple of 4,
1639     // and has a specified max value 256.
1640     // (Endianess!)
1641     Ports = ((fchs->pl[0] >>24) - 4) / 4;
1642     Ports = Ports > 63 ? 63 : Ports;
1643     
1644     printk(" RSCN ports: %d\n", Ports);
1645     if( Ports <= 0 )  // huh?
1646     {
1647       // ReJecT the command
1648       fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
1649     
1650       cpqfcTSPutLinkQue( cpqfcHBAdata,
1651                     ELS_RJT, // Q Type
1652                     fchs ); 
1653       
1654       break;
1655     }
1656     else  // Accept the command
1657     {
1658        cpqfcTSPutLinkQue( cpqfcHBAdata,
1659                     ELS_ACC, // Q Type
1660                     fchs ); 
1661     }
1662     
1663       // Check the "address format" to determine action.
1664       // We have 3 cases:
1665       // 0 = Port Address; 24-bit address of affected device
1666       // 1 = Area Address; MS 16 bits valid
1667       // 2 = Domain Address; MS 8 bits valid
1668     for( i=0; i<Ports; i++)
1669     { 
1670       BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
1671       switch( Buff & 0xFF000000)
1672       {
1673 
1674       case 0:  // Port Address?
1675         
1676       case 0x01000000: // Area Domain?
1677       case 0x02000000: // Domain Address
1678         // For example, "port_id" 0x201300 
1679         // OK, let's try a Name Service Request (Query)
1680       fchs->s_id = 0xFFFFFC;  // Name Server Address
1681       cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
1682 
1683       break;
1684         
1685         
1686       default:  // huh? new value on version change?
1687       break;
1688       }
1689     }
1690   }    
1691   break;    
1692 
1693 
1694 
1695     
1696   default:  // don't support this request (yet)
1697     // set reject reason code 
1698     fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 
1699                                     REQUEST_NOT_SUPPORTED);
1700     
1701     cpqfcTSPutLinkQue( cpqfcHBAdata,
1702                     ELS_RJT, // Q Type
1703                     fchs );     
1704     break;  
1705   }
1706 }
1707 
1708 
1709 static void ProcessELS_Reply( 
1710                 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1711 {
1712   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1713   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1714   ULONG ox_id = (fchs->ox_rx_id >>16);
1715   ULONG ls_reject_code;
1716   PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
1717   
1718   // If this is a valid reply, then we MUST have sent a request.
1719   // Verify that we can find a valid request OX_ID corresponding to
1720   // this reply
1721 
1722   
1723   if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
1724   {
1725     printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", 
1726                     ox_id, fchs->ox_rx_id & 0xffff);
1727     goto Quit;  // exit this routine
1728   }
1729 
1730 
1731   // Is the reply a RJT (reject)?
1732   if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
1733   {
1734 //  ******  REJECT REPLY  ********
1735     switch( Exchanges->fcExchange[ox_id].type )
1736     {
1737           
1738     case ELS_FDISC:  // we sent out Fabric Discovery
1739     case ELS_FLOGI:  // we sent out FLOGI
1740 
1741       printk("RJT received on Fabric Login from %Xh, reason %Xh\n", 
1742         fchs->s_id, fchs->pl[1]);    
1743 
1744     break;
1745 
1746     default:
1747     break;
1748     }
1749       
1750     goto Done;
1751   }
1752 
1753   // OK, we have an ACCept...
1754   // What's the ACC type? (according to what we sent)
1755   switch( Exchanges->fcExchange[ox_id].type )
1756   {
1757           
1758   case ELS_PLOGI:  // we sent out PLOGI
1759     if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1760     {
1761       LOGIN_PAYLOAD logi;       // FC-PH Port Login
1762       
1763       // login ACC payload acceptable; search for WWN in our list
1764       // of fcPorts
1765       
1766       BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1767    
1768       pLoggedInPort = fcFindLoggedInPort( 
1769              fcChip, 
1770              NULL,     // don't search Scsi Nexus
1771              0,        // don't search linked list for port_id
1772              &logi.port_name[0],     // search linked list for WWN
1773              &pLastLoggedInPort);  // must return non-NULL; when a port_id
1774                                    // is not found, this pointer marks the
1775                                    // end of the singly linked list
1776     
1777       if( pLoggedInPort == NULL)         // WWN not found - new port
1778       {
1779 
1780         pLoggedInPort = CreateFcPort( 
1781                           cpqfcHBAdata, 
1782                           pLastLoggedInPort, 
1783                           fchs,
1784                           &logi);
1785 
1786         if( pLoggedInPort == NULL )
1787         {
1788           printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1789           // Now Q a LOGOut Request, since we won't be talking to that device
1790         
1791           goto Done;  // exit with error! dropped login frame
1792         }
1793       }
1794       else      // WWN was already known.  Ensure that any open
1795                 // exchanges for this WWN are terminated.
1796         // NOTE: It's possible that a device can change its 
1797         // 24-bit port_id after a Link init or Fabric change 
1798         // (e.g. LIP or Fabric RSCN).  In that case, the old
1799         // 24-bit port_id may be duplicated, or no longer exist.
1800       {
1801 
1802         cpqfcTSTerminateExchange( cpqfcHBAdata, 
1803           &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1804       }
1805 
1806       // We have an fcPort struct - set fields accordingly
1807                                     // not PDISC, originator 
1808       SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1809                         
1810       // We just set a "port_id"; is it duplicated?
1811       TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1812 
1813       // For Fabric operation, we issued PLOGI to 0xFFFFFC
1814       // so we can send SCR (State Change Registration) 
1815       // Check for this special case...
1816       if( fchs->s_id == 0xFFFFFC ) 
1817       {
1818         // PLOGI ACC was a Fabric response... issue SCR
1819         fchs->s_id = 0xFFFFFD;  // address for SCR
1820         cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
1821       }
1822 
1823       else
1824       {
1825       // Now we need a PRLI to enable FCP-SCSI operation
1826       // set flags and Q up a ELS_PRLI
1827         cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
1828       }
1829     }
1830     else
1831     {
1832       // login payload unacceptable - reason in ls_reject_code
1833       // Q up a Logout Request
1834       printk("Login Payload unacceptable\n");
1835 
1836     }
1837     break;
1838 
1839 
1840   // PDISC logic very similar to PLOGI, except we never want
1841   // to allocate mem for "new" port, and we set flags differently
1842   // (might combine later with PLOGI logic for efficiency)  
1843   case ELS_PDISC:  // we sent out PDISC
1844     if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1845     {
1846       LOGIN_PAYLOAD logi;       // FC-PH Port Login
1847       BOOLEAN NeedLogin = FALSE;
1848       
1849       // login payload acceptable; search for WWN in our list
1850       // of (previously seen) fcPorts
1851       
1852       BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1853    
1854       pLoggedInPort = fcFindLoggedInPort( 
1855              fcChip, 
1856              NULL,     // don't search Scsi Nexus
1857              0,        // don't search linked list for port_id
1858              &logi.port_name[0],     // search linked list for WWN
1859              &pLastLoggedInPort);  // must return non-NULL; when a port_id
1860                                    // is not found, this pointer marks the
1861                                    // end of the singly linked list
1862     
1863       if( pLoggedInPort != NULL)   // WWN found?
1864       {
1865         // WWN has same port_id as last login?  (Of course, a properly
1866         // working FC device should NEVER ACCept a PDISC if it's
1867         // port_id changed, but check just in case...)
1868         if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1869         {
1870           // Yes.  We were expecting PDISC?
1871           if( pLoggedInPort->pdisc )
1872           {
1873             int i;
1874             
1875             
1876             // PDISC expected -- set fields.  (PDISC, Originator)
1877             SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
1878 
1879             // We are ready to resume FCP-SCSI to this device...
1880             // Do we need to start anything that was Queued?
1881 
1882             for( i=0; i< TACH_SEST_LEN; i++)
1883             {
1884               // see if any exchange for this PDISC'd port was queued
1885               if( ((fchs->s_id &0xFFFFFF) == 
1886                    (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
1887                       &&
1888                   (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
1889               {
1890                 fchs->reserved = i; // copy ExchangeID
1891 //                printk(" *Q x_ID %Xh after PDISC* ",i);
1892 
1893                 cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
1894               }
1895             }
1896 
1897             // Complete commands Q'd while we were waiting for Login
1898 
1899             UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
1900           }
1901           else
1902           {
1903             printk("Not expecting PDISC (pdisc=FALSE)\n");
1904             NeedLogin = TRUE;
1905           }
1906         }
1907         else
1908         {
1909           printk("PDISC PortID change: old %Xh, new %Xh\n",
1910             pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1911           NeedLogin = TRUE;
1912                   
1913         }
1914       }
1915       else
1916       {
1917         printk("PDISC ACC from unknown WWN\n");
1918         NeedLogin = TRUE;
1919       }
1920 
1921       if( NeedLogin)
1922       {
1923         
1924         // The PDISC failed.  Set login struct flags accordingly,
1925         // terminate any I/O to this port, and Q a PLOGI
1926         if( pLoggedInPort )  // FC device previously known?
1927         {
1928 
1929           cpqfcTSPutLinkQue( cpqfcHBAdata,
1930                     ELS_LOGO, // Q Type
1931                     fchs );   // has port_id to send to 
1932 
1933           // There are a variety of error scenarios which can result
1934           // in PDISC failure, so as a catchall, add the check for
1935           // duplicate port_id.
1936           TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1937 
1938 //    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
1939           pLoggedInPort->pdisc = FALSE;
1940           pLoggedInPort->prli = FALSE;
1941           pLoggedInPort->plogi = FALSE;
1942         
1943           cpqfcTSTerminateExchange( cpqfcHBAdata, 
1944             &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1945         }
1946         cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
1947       }
1948     }
1949     else
1950     {
1951       // login payload unacceptable - reason in ls_reject_code
1952       // Q up a Logout Request
1953       printk("ERROR: Login Payload unacceptable!\n");
1954 
1955     }
1956    
1957     break;
1958     
1959 
1960 
1961   case ELS_PRLI:  // we sent out PRLI
1962 
1963 
1964     pLoggedInPort = fcFindLoggedInPort( 
1965            fcChip, 
1966            NULL,       // don't search Scsi Nexus
1967            (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
1968            NULL,     // DON'T search linked list for WWN
1969            NULL);    // don't care
1970       
1971     if( pLoggedInPort == NULL ) 
1972     {
1973       // huh?
1974       printk(" Unexpected PRLI ACCept frame!\n");
1975 
1976       // Q a LOGOut here?
1977 
1978       goto Done;
1979     }
1980 
1981     // verify the PRLI ACC payload
1982     if( !verify_PRLI( fchs, &ls_reject_code) )
1983     {
1984       // PRLI Reply is acceptable; were we expecting it?
1985       if( pLoggedInPort->plogi ) 
1986       { 
1987         // yes, we expected the PRLI ACC  (not PDISC; Originator)
1988         SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1989 
1990         // OK, let's send a REPORT_LUNS command to determine
1991         // whether VSA or PDA FCP-LUN addressing is used.
1992         
1993         cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
1994         
1995         // It's possible that a device we were talking to changed 
1996         // port_id, and has logged back in.  This function ensures
1997         // that I/O will resume.
1998         UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
1999 
2000       }
2001       else
2002       {
2003         // huh?
2004         printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
2005 
2006         // Q a LOGOut here?
2007         goto Done;
2008       }
2009     }
2010     else
2011     {
2012       printk(" PRLI ACCept payload failed verify\n");
2013 
2014       // Q a LOGOut here?
2015     }
2016 
2017     break;
2018  
2019   case ELS_FLOGI:  // we sent out FLOGI (Fabric Login)
2020 
2021     // update the upper 16 bits of our port_id in Tachyon
2022     // the switch adds those upper 16 bits when responding
2023     // to us (i.e. we are the destination_id)
2024     fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
2025     writel( fcChip->Registers.my_al_pa,  
2026       fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
2027 
2028     // now send out a PLOGI to the well known port_id 0xFFFFFC
2029     fchs->s_id = 0xFFFFFC;
2030     cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
2031   
2032    break; 
2033 
2034 
2035   case ELS_FDISC:  // we sent out FDISC (Fabric Discovery (Login))
2036 
2037    printk( " ELS_FDISC success ");
2038    break;
2039    
2040 
2041   case ELS_SCR:  // we sent out State Change Registration
2042     // now we can issue Name Service Request to find any
2043     // Fabric-connected devices we might want to login to.
2044    
2045         
2046     fchs->s_id = 0xFFFFFC;  // Name Server Address
2047     cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
2048     
2049 
2050     break;
2051 
2052     
2053   default:
2054     printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", 
2055                     ox_id, fchs->ox_rx_id & 0xffff);
2056     break;
2057   }
2058 
2059   
2060 Done:
2061   // Regardless of whether the Reply is valid or not, the
2062   // the exchange is done - complete
2063   cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete
2064           
2065 Quit:    
2066   return;
2067 }
2068 
2069 
2070 
2071 
2072 
2073 
2074 // ****************  Fibre Channel Services  **************
2075 // This is where we process the Directory (Name) Service Reply
2076 // to know which devices are on the Fabric
2077 
2078 static void ProcessFCS_Reply( 
2079         CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
2080 {
2081   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2082   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2083   ULONG ox_id = (fchs->ox_rx_id >>16);
2084 //  ULONG ls_reject_code;
2085 //  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
2086   
2087   // If this is a valid reply, then we MUST have sent a request.
2088   // Verify that we can find a valid request OX_ID corresponding to
2089   // this reply
2090 
2091   if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
2092   {
2093     printk(" *Discarding Reply frame, xID %04X/%04X* ", 
2094                     ox_id, fchs->ox_rx_id & 0xffff);
2095     goto Quit;  // exit this routine
2096   }
2097 
2098 
2099   // OK, we were expecting it.  Now check to see if it's a
2100   // "Name Service" Reply, and if so force a re-validation of
2101   // Fabric device logins (i.e. Start the login timeout and
2102   // send PDISC or PLOGI)
2103   // (Endianess Byte Swap?)
2104   if( fchs->pl[1] == 0x02FC )  // Name Service
2105   {
2106     // got a new (or NULL) list of Fabric attach devices... 
2107     // Invalidate current logins
2108     
2109     PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
2110     while( pLoggedInPort ) // for all ports which are expecting
2111                            // PDISC after the next LIP, set the
2112                            // logoutTimer
2113     {
2114 
2115       if( (pLoggedInPort->port_id & 0xFFFF00)  // Fabric device?
2116                       &&
2117           (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
2118       {
2119         pLoggedInPort->LOGO_timer = 6;  // what's the Fabric timeout??
2120                                 // suspend any I/O in progress until
2121                                 // PDISC received...
2122         pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
2123       }
2124             
2125       pLoggedInPort = pLoggedInPort->pNextPort;
2126     }
2127     
2128     if( fchs->pl[2] == 0x0280)  // ACCept?
2129     {
2130       // Send PLOGI or PDISC to these Fabric devices
2131       SendLogins( cpqfcHBAdata, &fchs->pl[4] );  
2132     }
2133 
2134 
2135     // As of this writing, the only reason to reject is because NO
2136     // devices are left on the Fabric.  We already started
2137     // "logged out" timers; if the device(s) don't come
2138     // back, we'll do the implicit logout in the heart beat 
2139     // timer routine
2140     else  // ReJecT
2141     {
2142       // this just means no Fabric device is visible at this instant
2143     } 
2144   }
2145 
2146   // Regardless of whether the Reply is valid or not, the
2147   // the exchange is done - complete
2148   cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete
2149           
2150 Quit:    
2151   return;
2152 }
2153 
2154 
2155 
2156 
2157 
2158 
2159 
2160 static void AnalyzeIncomingFrame( 
2161         CPQFCHBA *cpqfcHBAdata,
2162         ULONG QNdx )
2163 {
2164   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2165   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2166   PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
2167   TachFCHDR_GCMND* fchs = 
2168     (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
2169 //  ULONG ls_reject_code;  // reason for rejecting login
2170   LONG ExchangeID;
2171 //  FC_LOGGEDIN_PORT *pLoggedInPort;
2172   BOOLEAN AbortAccept;  
2173 
2174   ENTER("AnalyzeIncomingFrame");
2175 
2176 
2177 
2178   switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
2179   {
2180 
2181   case SFQ_UNKNOWN:  // unknown frame (e.g. LIP position frame, NOP, etc.)
2182  
2183 
2184       // *********  FC-4 Device Data/ Fibre Channel Service *************
2185     if( ((fchs->d_id &0xF0000000) == 0)   // R_CTL (upper nibble) 0x0?
2186                 &&   
2187       (fchs->f_ctl & 0x20000000) )  // TYPE 20h is Fibre Channel Service
2188     {
2189 
2190       // ************** FCS Reply **********************
2191 
2192       if( (fchs->d_id & 0xff000000L) == 0x03000000L)  // (31:23 R_CTL)
2193       {
2194         ProcessFCS_Reply( cpqfcHBAdata, fchs );
2195 
2196       }  // end of  FCS logic
2197 
2198     }
2199     
2200 
2201       // ***********  Extended Link Service **************
2202 
2203     else if( fchs->d_id & 0x20000000   // R_CTL 0x2?
2204                   &&   
2205       (fchs->f_ctl & 0x01000000) )  // TYPE = 1
2206     {
2207 
2208                            // these frames are either a response to
2209                            // something we sent (0x23) or "unsolicited"
2210                            // frames (0x22).
2211 
2212 
2213       // **************Extended Link REPLY **********************
2214                            // R_CTL Solicited Control Reply
2215 
2216       if( (fchs->d_id & 0xff000000L) == 0x23000000L)  // (31:23 R_CTL)
2217       {
2218 
2219         ProcessELS_Reply( cpqfcHBAdata, fchs );
2220 
2221       }  // end of  "R_CTL Solicited Control Reply"
2222 
2223 
2224 
2225 
2226        // **************Extended Link REQUEST **********************
2227        // (unsolicited commands from another port or task...)
2228 
2229                            // R_CTL Ext Link REQUEST
2230       else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2231               (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
2232       {
2233 
2234 
2235 
2236         ProcessELS_Request( cpqfcHBAdata, fchs );
2237 
2238       }
2239 
2240 
2241 
2242         // ************** LILP **********************
2243       else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2244                (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
2245 
2246       {
2247         // SANMark specifies that when available, we must use
2248         // the LILP frame to determine which ALPAs to send Port Discovery
2249         // to...
2250 
2251         if( fchs->pl[0] == 0x0711L) //  ELS_PLOGI?
2252         {
2253 //        UCHAR *ptr = (UCHAR*)&fchs->pl[1];
2254 //        printk(" %d ALPAs found\n", *ptr);
2255           memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
2256           fcChip->Options.LILPin = 1; // our LILPmap is valid!
2257           // now post to make Port Discovery happen...
2258           cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);  
2259         }
2260       }
2261     }
2262 
2263      
2264     // *****************  BASIC LINK SERVICE *****************
2265     
2266     else if( fchs->d_id & 0x80000000  // R_CTL:
2267                     &&           // Basic Link Service Request
2268            !(fchs->f_ctl & 0xFF000000) )  // type=0 for BLS
2269     {
2270 
2271       // Check for ABTS (Abort Sequence)
2272       if( (fchs->d_id & 0x8F000000) == 0x81000000)
2273       {
2274         // look for OX_ID, S_ID pair that matches in our
2275         // fcExchanges table; if found, reply with ACCept and complete
2276         // the exchange
2277 
2278         // Per PLDA, an ABTS is sent by an initiator; therefore
2279         // assume that if we have an exhange open to the port who
2280         // sent ABTS, it will be the d_id of what we sent.  
2281         for( ExchangeID = 0, AbortAccept=FALSE;
2282              ExchangeID < TACH_SEST_LEN; ExchangeID++)
2283         {
2284             // Valid "target" exchange 24-bit port_id matches? 
2285             // NOTE: For the case of handling Intiator AND Target
2286             // functions on the same chip, we can have TWO Exchanges
2287             // with the same OX_ID -- OX_ID/FFFF for the CMND, and
2288             // OX_ID/RX_ID for the XRDY or DATA frame(s).  Ideally,
2289             // we would like to support ABTS from Initiators or Targets,
2290             // but it's not clear that can be supported on Tachyon for
2291             // all cases (requires more investigation).
2292             
2293           if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
2294                Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
2295                   &&
2296              ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2297              (fchs->s_id & 0xFFFFFF)) )
2298           {
2299               
2300               // target xchnge port_id matches -- how about OX_ID?
2301             if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
2302                     == (fchs->ox_rx_id & 0xFFFF0000) )
2303                     // yes! post ACCept response; will be completed by fcStart
2304             {
2305               Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
2306                 
2307                 // copy (add) rx_id field for simplified ACCept reply
2308               fchs->ox_rx_id = 
2309                 Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
2310                 
2311               cpqfcTSPutLinkQue( cpqfcHBAdata,
2312                             BLS_ABTS_ACC, // Q Type 
2313                             fchs );    // void QueContent
2314               AbortAccept = TRUE;
2315       printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", 
2316              fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
2317               break;      // ABTS can affect only ONE exchange -exit loop
2318             }
2319           }
2320         }  // end of FOR loop
2321         if( !AbortAccept ) // can't ACCept ABTS - send Reject
2322         {
2323       printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", 
2324             fchs->ox_rx_id);
2325           if( Exchanges->fcExchange[ ExchangeID].type 
2326                 &&
2327               !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
2328                & 0x80000000))
2329           {
2330             cpqfcTSCompleteExchange( fcChip, ExchangeID);
2331           }
2332           else
2333           {
2334             printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", 
2335               ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
2336           }
2337         }
2338       }
2339 
2340       // Check for BLS {ABTS? (Abort Sequence)} ACCept
2341       else if( (fchs->d_id & 0x8F000000) == 0x84000000)
2342       {
2343         // target has responded with ACC for our ABTS;
2344         // complete the indicated exchange with ABORTED status 
2345         // Make no checks for correct RX_ID, since
2346         // all we need to conform ABTS ACC is the OX_ID.
2347         // Verify that the d_id matches!
2348  
2349         ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2350 //      printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n", 
2351 //          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
2352 //          Exchanges->fcExchange[ExchangeID].status);
2353 
2354 
2355         
2356         if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2357         {
2358             // Does "target" exchange 24-bit port_id match? 
2359             // (See "NOTE" above for handling Intiator AND Target in
2360             // the same device driver)
2361             // First, if this is a target response, then we originated
2362             // (initiated) it with BLS_ABTS:
2363           
2364           if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2365 
2366                   &&
2367             // Second, does the source of this ACC match the destination
2368             // of who we originally sent it to?
2369              ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2370              (fchs->s_id & 0xFFFFFF)) )
2371           {
2372             cpqfcTSCompleteExchange( fcChip, ExchangeID );
2373           }
2374         }              
2375       }
2376       // Check for BLS {ABTS? (Abort Sequence)} ReJecT
2377       else if( (fchs->d_id & 0x8F000000) == 0x85000000)
2378       {
2379         // target has responded with RJT for our ABTS;
2380         // complete the indicated exchange with ABORTED status 
2381         // Make no checks for correct RX_ID, since
2382         // all we need to conform ABTS ACC is the OX_ID.
2383         // Verify that the d_id matches!
2384  
2385         ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2386 //      printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n", 
2387 //          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
2388 
2389         if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2390         {  
2391             // Does "target" exchange 24-bit port_id match? 
2392             // (See "NOTE" above for handling Intiator AND Target in
2393             // the same device driver)
2394             // First, if this is a target response, then we originated
2395             // (initiated) it with BLS_ABTS:
2396                   
2397           if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2398 
2399                   &&
2400             // Second, does the source of this ACC match the destination
2401             // of who we originally sent it to?
2402              ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2403              (fchs->s_id & 0xFFFFFF)) )
2404           {
2405             // YES! NOTE: There is a bug in CPQ's RA-4000 box 
2406             // where the "reason code" isn't returned in the payload
2407             // For now, simply presume the reject is because the target
2408             // already completed the exchange...
2409             
2410 //            printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
2411             cpqfcTSCompleteExchange( fcChip, ExchangeID );
2412           }
2413         } 
2414       }  // end of ABTS check
2415     }  // end of Basic Link Service Request
2416     break;
2417   
2418     default:
2419       printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
2420         fcLQ->Qitem[QNdx].Type,
2421         fcLQ->Qitem[QNdx].Type);
2422     break;
2423   }
2424 }
2425 
2426 
2427 // Function for Port Discovery necessary after every FC 
2428 // initialization (e.g. LIP).
2429 // Also may be called if from Fabric Name Service logic.
2430 
2431 static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
2432 {
2433   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2434   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2435   ULONG ulStatus=0;
2436   TachFCHDR_GCMND fchs;  // copy fields for transmission
2437   int i;
2438   ULONG loginType;
2439   LONG ExchangeID;
2440   PFC_LOGGEDIN_PORT pLoggedInPort;
2441   __u32 PortIds[ number_of_al_pa];
2442   int NumberOfPorts=0;
2443 
2444   // We're going to presume (for now) that our limit of Fabric devices
2445   // is the same as the number of alpa on a private loop (126 devices).
2446   // (Of course this could be changed to support however many we have
2447   // memory for).
2448   memset( &PortIds[0], 0, sizeof(PortIds));
2449    
2450   // First, check if this login is for our own Link Initialization
2451   // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
2452   // from a switch.  If we are logging into Fabric devices, we'll
2453   // have a non-NULL FabricPortId pointer
2454   
2455   if( FabricPortIds != NULL) // may need logins
2456   {
2457     int LastPort=FALSE;
2458     i = 0;
2459     while( !LastPort)
2460     {
2461       // port IDs From NSR payload; byte swap needed?
2462       BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
2463  
2464 //      printk("FPortId[%d] %Xh ", i, PortIds[i]);
2465       if( PortIds[i] & 0x80000000)
2466         LastPort = TRUE;
2467       
2468       PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
2469       // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
2470       // erroneously use ALPA 0.
2471       if( PortIds[i]  ) // need non-zero port_id...
2472         i++;
2473       
2474       if( i >= number_of_al_pa ) // (in)sanity check
2475         break;
2476       FabricPortIds++;  // next...
2477     }
2478 
2479     NumberOfPorts = i;
2480 //    printk("NumberOf Fabric ports %d", NumberOfPorts);
2481   }
2482   
2483   else  // need to send logins on our "local" link
2484   {
2485   
2486     // are we a loop port?  If so, check for reception of LILP frame,
2487     // and if received use it (SANMark requirement)
2488     if( fcChip->Options.LILPin )
2489     {
2490       int j=0;
2491       // sanity check on number of ALPAs from LILP frame...
2492       // For format of LILP frame, see FC-AL specs or 
2493       // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
2494       // First byte is number of ALPAs
2495       i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
2496       NumberOfPorts = i;
2497 //      printk(" LILP alpa count %d ", i);
2498       while( i > 0)
2499       {
2500         PortIds[j] = fcChip->LILPmap[1+ j];
2501         j++; i--;
2502       }
2503     }
2504     else  // have to send login to everybody
2505     {
2506       int j=0;
2507       i = number_of_al_pa;
2508       NumberOfPorts = i;
2509       while( i > 0)
2510       {
2511         PortIds[j] = valid_al_pa[j]; // all legal ALPAs
2512         j++; i--;
2513       }
2514     }
2515   }
2516 
2517 
2518   // Now we have a copy of the port_ids (and how many)...
2519   for( i = 0; i < NumberOfPorts; i++)
2520   {
2521     // 24-bit FC Port ID
2522     fchs.s_id = PortIds[i];  // note: only 8-bits used for ALPA
2523 
2524 
2525     // don't log into ourselves (Linux Scsi disk scan will stop on
2526     // no TARGET support error on us, and quit trying for rest of devices)
2527     if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
2528       continue;
2529 
2530     // fabric login needed?
2531     if( (fchs.s_id == 0) || 
2532         (fcChip->Options.fabric == 1) )
2533     {
2534       fcChip->Options.flogi = 1;  // fabric needs longer for login
2535       // Do we need FLOGI or FDISC?
2536       pLoggedInPort = fcFindLoggedInPort( 
2537              fcChip, 
2538              NULL,           // don't search SCSI Nexus
2539              0xFFFFFC,       // search linked list for Fabric port_id
2540              NULL,           // don't search WWN
2541              NULL);          // (don't care about end of list)
2542 
2543       if( pLoggedInPort )    // If found, we have prior experience with
2544                              // this port -- check whether PDISC is needed
2545       {
2546         if( pLoggedInPort->flogi )
2547         {
2548           // does the switch support FDISC?? (FLOGI for now...)
2549           loginType = ELS_FLOGI;  // prior FLOGI still valid
2550         }
2551         else
2552           loginType = ELS_FLOGI;  // expired FLOGI
2553       }
2554       else                      // first FLOGI?
2555         loginType = ELS_FLOGI;  
2556 
2557 
2558       fchs.s_id = 0xFFFFFE;   // well known F_Port address
2559 
2560       // Fabrics are not required to support FDISC, and
2561       // it's not clear if that helps us anyway, since
2562       // we'll want a Name Service Request to re-verify
2563       // visible devices...
2564       // Consequently, we always want our upper 16 bit
2565       // port_id to be zero (we'll be rejected if we
2566       // use our prior port_id if we've been plugged into
2567       // a different switch port).
2568       // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
2569       // If our ALPA is 55h for instance, we want the FC frame
2570       // s_id to be 0x000055, while Tach's my_al_pa register
2571       // must be 0x000155, to force an OPN at ALPA 0 
2572       // (the Fabric port)
2573       fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
2574       writel( fcChip->Registers.my_al_pa | 0x0100,  
2575         fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
2576     }
2577 
2578     else // not FLOGI...
2579     {
2580       // should we send PLOGI or PDISC?  Check if any prior port_id
2581       // (e.g. alpa) completed a PLOGI/PRLI exchange by checking 
2582       // the pdisc flag.
2583 
2584       pLoggedInPort = fcFindLoggedInPort( 
2585              fcChip, 
2586              NULL,           // don't search SCSI Nexus
2587              fchs.s_id,      // search linked list for al_pa
2588              NULL,           // don't search WWN
2589              NULL);          // (don't care about end of list)
2590 
2591              
2592 
2593       if( pLoggedInPort )      // If found, we have prior experience with
2594                              // this port -- check whether PDISC is needed
2595       {
2596         if( pLoggedInPort->pdisc )
2597         {
2598           loginType = ELS_PDISC;  // prior PLOGI and PRLI maybe still valid
2599            
2600         }
2601         else
2602           loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
2603       }
2604       else                      // never talked to this port_id before
2605         loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
2606     }
2607 
2608 
2609     
2610     ulStatus = cpqfcTSBuildExchange(
2611           cpqfcHBAdata,
2612           loginType,            // e.g. PLOGI
2613           &fchs,        // no incoming frame (we are originator)
2614           NULL,         // no data (no scatter/gather list)
2615           &ExchangeID );// fcController->fcExchanges index, -1 if failed
2616 
2617     if( !ulStatus ) // Exchange setup OK?
2618     {
2619       ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
2620       if( !ulStatus )
2621       {
2622           // submitted to Tach's Outbound Que (ERQ PI incremented)
2623           // waited for completion for ELS type (Login frames issued
2624           // synchronously)
2625 
2626         if( loginType == ELS_PDISC )
2627         {
2628           // now, we really shouldn't Revalidate SEST exchanges until
2629           // we get an ACC reply from our target and verify that
2630           // the target address/WWN is unchanged.  However, when a fast
2631           // target gets the PDISC, they can send SEST Exchange data
2632           // before we even get around to processing the PDISC ACC.
2633           // Consequently, we lose the I/O.
2634           // To avoid this, go ahead and Revalidate when the PDISC goes
2635           // out, anticipating that the ACC will be truly acceptable
2636           // (this happens 99.9999....% of the time).
2637           // If we revalidate a SEST write, and write data goes to a
2638           // target that is NOT the one we originated the WRITE to,
2639           // that target is required (FCP-SCSI specs, etc) to discard 
2640           // our WRITE data.
2641 
2642           // Re-validate SEST entries (Tachyon hardware assists)
2643           RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort); 
2644     //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
2645         }
2646       }
2647       else  // give up immediately on error
2648       {
2649 #ifdef LOGIN_DBG
2650         printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
2651 #endif
2652         break;
2653       }
2654 
2655               
2656       if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
2657       {
2658         ulStatus = LNKDWN_OSLS;
2659 #ifdef LOGIN_DBG
2660         printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
2661 #endif
2662         break;
2663       }
2664         // Check the exchange for bad status (i.e. FrameTimeOut),
2665         // and complete on bad status (most likely due to BAD_ALPA)
2666         // on LDn, DPC function may already complete (ABORT) a started
2667         // exchange, so check type first (type = 0 on complete).
2668       if( Exchanges->fcExchange[ExchangeID].status )
2669       {
2670 #ifdef LOGIN_DBG 
2671         printk("completing x_ID %X on status %Xh\n", 
2672           ExchangeID, Exchanges->fcExchange[ExchangeID].status);
2673 #endif
2674         cpqfcTSCompleteExchange( fcChip, ExchangeID);
2675       }
2676     }
2677     else   // Xchange setup failed...
2678     {
2679 #ifdef LOGIN_DBG
2680       printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
2681 #endif
2682       break;
2683     }
2684   }
2685   if( !ulStatus )
2686   {
2687     // set the event signifying that all ALPAs were sent out.
2688 #ifdef LOGIN_DBG
2689     printk("SendLogins: PortDiscDone\n");
2690 #endif
2691     cpqfcHBAdata->PortDiscDone = 1;
2692 
2693 
2694     // TL/TS UG, pg. 184
2695     // 0x0065 = 100ms for RT_TOV
2696     // 0x01f5 = 500ms for ED_TOV
2697     fcChip->Registers.ed_tov.value = 0x006501f5L; 
2698     writel( fcChip->Registers.ed_tov.value,
2699       (fcChip->Registers.ed_tov.address));
2700 
2701     // set the LP_TOV back to ED_TOV (i.e. 500 ms)
2702     writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
2703   }
2704   else
2705   {
2706     printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", 
2707       ExchangeID, fchs.s_id, ulStatus);
2708   }
2709   LEAVE("SendLogins");
2710 
2711 }
2712 
2713 
2714 // for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
2715 // D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
2716 static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
2717 {
2718   struct Scsi_Host *HostAdapter = Cmnd->host;
2719   CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
2720   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2721   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2722   PFC_LOGGEDIN_PORT pLoggedInPort; 
2723   int LunListLen=0;
2724   int i;
2725   ULONG x_ID = 0xFFFFFFFF;
2726   UCHAR *ucBuff = Cmnd->request_buffer;
2727 
2728 //  printk("cpqfcTS: ReportLunsDone \n");
2729   // first, we need to find the Exchange for this command,
2730   // so we can find the fcPort struct to make the indicated
2731   // changes.
2732   for( i=0; i< TACH_SEST_LEN; i++)
2733   {
2734     if( Exchanges->fcExchange[i].type   // exchange defined?
2735                    &&
2736        (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
2737               
2738     {
2739       x_ID = i;  // found exchange!
2740       break;
2741     }
2742   }
2743   if( x_ID == 0xFFFFFFFF)
2744   {
2745 //    printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
2746     goto Done;  // Report Luns FC Exchange gone; 
2747                 // exchange probably Terminated by Implicit logout
2748   }
2749 
2750 
2751   // search linked list for the port_id we sent INQUIRY to
2752   pLoggedInPort = fcFindLoggedInPort( fcChip,
2753     NULL,     // DON'T search Scsi Nexus (we will set it)
2754     Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
2755     NULL,     // DON'T search linked list for FC WWN
2756     NULL);    // DON'T care about end of list
2757  
2758   if( !pLoggedInPort )
2759   {
2760 //    printk("cpqfcTS: ReportLuns failed - device gone\n");
2761     goto Done; // error! can't find logged in Port
2762   }    
2763   LunListLen = ucBuff[3];
2764   LunListLen += ucBuff[2]>>8;
2765 
2766   if( !LunListLen )  // failed
2767   {
2768     // generically speaking, a soft error means we should retry...
2769     if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
2770     {
2771       if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
2772                 (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
2773       {
2774         TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
2775       // did we fail because of "check condition, device reset?"
2776       // e.g. the device was reset (i.e., at every power up)
2777       // retry the Report Luns
2778       
2779       // who are we sending it to?
2780       // we know this because we have a copy of the command
2781       // frame from the original Report Lun command -
2782       // switch the d_id/s_id fields, because the Exchange Build
2783       // context is "reply to source".
2784       
2785         fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
2786         cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
2787       }
2788     }
2789     else  // probably, the device doesn't support Report Luns
2790       pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;  
2791   }
2792   else  // we have LUN info - check VSA mode
2793   {
2794     // for now, assume all LUNs will have same addr mode
2795     // for VSA, payload byte 8 will be 0x40; otherwise, 0
2796     pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];  
2797       
2798     // Since we got a Report Luns answer, set lun masking flag
2799     pLoggedInPort->ScsiNexus.LunMasking = 1;
2800 
2801     if( LunListLen > 8*CPQFCTS_MAX_LUN)   // We expect CPQFCTS_MAX_LUN max
2802       LunListLen = 8*CPQFCTS_MAX_LUN;
2803 
2804 /*   
2805     printk("Device WWN %08X%08X Reports Luns @: ", 
2806           (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
2807           (ULONG)(pLoggedInPort->u.liWWN>>32));
2808             
2809     for( i=8; i<LunListLen+8; i+=8)
2810     {  
2811       printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
2812     }
2813     printk("\n");
2814 */
2815     
2816     // Since the device was kind enough to tell us where the
2817     // LUNs are, lets ensure they are contiguous for Linux's
2818     // SCSI driver scan, which expects them to start at 0.
2819     // Since Linux only supports 8 LUNs, only copy the first
2820     // eight from the report luns command
2821 
2822     // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
2823     // LUNs 4001, 4004, etc., because other LUNs are masked from
2824     // this HBA (owned by someone else).  We'll make those appear as
2825     // LUN 0, 1... to Linux
2826     {
2827       int j;
2828       int AppendLunList = 0;
2829       // Walk through the LUN list.  The 'j' array number is
2830       // Linux's lun #, while the value of .lun[j] is the target's
2831       // lun #.
2832       // Once we build a LUN list, it's possible for a known device 
2833       // to go offline while volumes (LUNs) are added.  Later,
2834       // the device will do another PLOGI ... Report Luns command,
2835       // and we must not alter the existing Linux Lun map.
2836       // (This will be very rare).
2837       for( j=0; j < CPQFCTS_MAX_LUN; j++)
2838       {
2839         if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
2840         {
2841           AppendLunList = 1;
2842           break;
2843         }
2844       }
2845       if( AppendLunList )
2846       {
2847         int k;
2848         int FreeLunIndex;
2849 //        printk("cpqfcTS: AppendLunList\n");
2850 
2851         // If we get a new Report Luns, we cannot change
2852         // any existing LUN mapping! (Only additive entry)
2853         // For all LUNs in ReportLun list
2854         // if RL lun != ScsiNexus lun
2855         //   if RL lun present in ScsiNexus lun[], continue
2856         //   else find ScsiNexus lun[]==FF and add, continue
2857         
2858         for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2859         {
2860           if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
2861           {
2862             // something changed from the last Report Luns
2863             printk(" cpqfcTS: Report Lun change!\n");
2864             for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN; 
2865                  k < CPQFCTS_MAX_LUN; k++)
2866             {
2867               if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
2868               {
2869                 FreeLunIndex = k;
2870                 break;
2871               }
2872               if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
2873                 break; // we already masked this lun
2874             }
2875             if( k >= CPQFCTS_MAX_LUN )
2876             {
2877               printk(" no room for new LUN %d\n", ucBuff[i+1]);
2878             }
2879             else if( k == FreeLunIndex )  // need to add LUN
2880             {
2881               pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
2882 //            printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
2883               
2884             }
2885             else
2886             {
2887               // lun already known
2888             }
2889             break;
2890           }
2891         }
2892         // print out the new list...
2893         for( j=0; j< CPQFCTS_MAX_LUN; j++)
2894         {
2895           if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
2896             break; // done
2897 //        printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2898         }
2899       }
2900       else
2901       {
2902 //        printk("Linux SCSI LUNs[] -> Device LUNs: ");
2903         // first time - this is easy
2904         for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2905         {
2906           pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
2907 //        printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2908         }
2909 //      printk("\n");
2910       }
2911     }
2912   }
2913 
2914 Done:  
2915 }
2916 
2917 // After successfully getting a "Process Login" (PRLI) from an
2918 // FC port, we want to Discover the LUNs so that we know the
2919 // addressing type (e.g., FCP-SCSI Volume Set Address, Peripheral
2920 // Unit Device), and whether SSP (Selective Storage Presentation or
2921 // Lun Masking) has made the LUN numbers non-zero based or 
2922 // non-contiguous.  To remain backward compatible with the SCSI-2
2923 // driver model, which expects a contiguous LUNs starting at 0,
2924 // will use the ReportLuns info to map from "device" to "Linux" 
2925 // LUNs.
2926 static void IssueReportLunsCommand( 
2927               CPQFCHBA* cpqfcHBAdata, 
2928               TachFCHDR_GCMND* fchs)
2929 {
2930   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2931   PFC_LOGGEDIN_PORT pLoggedInPort; 
2932   Scsi_Cmnd *Cmnd;
2933   LONG x_ID;
2934   ULONG ulStatus;
2935   UCHAR *ucBuff;
2936 
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     for( i=0; i<8; i++)  // valid WWN passed?  NULL WWN invalid
3342     {
3343       if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
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           }
3397           else
3398             Cmnd->SCp.have_data_in = Cmnd->lun; // Linux & target luns match
3399         }
3400         break; // found it!
3401       }
3402     }
3403     
3404     if( port_id_valid ) // look for alpa first
3405     {
3406       if( pLoggedInPort->port_id == port_id )
3407         break;  // found it!
3408     }
3409     if( wwn_valid ) // look for wwn second
3410     {
3411 
3412       if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
3413       {  
3414                  // all 8 bytes of WWN match
3415         break;   // found it!
3416       }
3417     }
3418                 
3419     pLoggedInPort = pLoggedInPort->pNextPort; // try next port
3420   }
3421 
3422   return pLoggedInPort;
3423 }
3424 
3425 
3426 
3427 
3428 // 
3429 // We need to examine the SEST table and re-validate
3430 // any open Exchanges for this LoggedInPort
3431 // To make Tachyon pay attention, Freeze FCP assists,
3432 // set VAL bits, Unfreeze FCP assists
3433 static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
3434                         PFC_LOGGEDIN_PORT pLoggedInPort)
3435 {
3436   CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3437   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
3438   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3439   ULONG x_ID;
3440   BOOLEAN TachFroze = FALSE;
3441   
3442   
3443   // re-validate any SEST exchanges that are permitted
3444   // to survive the link down (e.g., good PDISC performed)
3445   for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
3446   {
3447 
3448     // If the SEST entry port_id matches the pLoggedInPort,
3449     // we need to re-validate
3450     if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
3451          || 
3452         (Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
3453     {
3454                      
3455       if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF)  // (24-bit port ID)
3456             == pLoggedInPort->port_id) 
3457       {
3458 //      printk(" re-val xID %Xh ", x_ID);
3459         if( !TachFroze )  // freeze if not already frozen
3460           TachFroze |= FreezeTach( cpqfcHBAdata);
3461         fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
3462       }
3463     } 
3464   }
3465 
3466   if( TachFroze) 
3467   { 
3468     fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
3469   }
3470 } 
3471 
3472 
3473 // Complete an Linux Cmnds that we Queued because
3474 // our FC link was down (cause immediate retry)
3475 
3476 static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
3477                         PFC_LOGGEDIN_PORT pLoggedInPort)
3478 {
3479 //  Scsi_Device *sdev = HostAdapter->host_queue;
3480   CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3481   Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
3482   Scsi_Cmnd *Cmnd;
3483   int indx;
3484 
3485  
3486   
3487   // if the device was previously "blocked", make sure
3488   // we unblock it so Linux SCSI will resume
3489 
3490   pLoggedInPort->device_blocked = FALSE; // clear our flag
3491 
3492   // check the Link Down command ptr buffer;
3493   // we can complete now causing immediate retry
3494   for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
3495   {
3496     if( *SCptr != NULL ) // scsi command to complete?
3497     {
3498 #ifdef DUMMYCMND_DBG
3499       printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
3500 #endif
3501       Cmnd = *SCptr;
3502 
3503 
3504       // Are there any Q'd commands for this target?
3505       if( (Cmnd->target == pLoggedInPort->ScsiNexus.target)
3506                &&
3507           (Cmnd->channel == pLoggedInPort->ScsiNexus.channel) )
3508       {
3509         Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
3510         if( Cmnd->scsi_done != NULL)
3511           (*Cmnd->scsi_done)(Cmnd);
3512         else
3513           printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
3514                   pLoggedInPort->port_id);
3515         *SCptr = NULL;  // free this slot for next use
3516       }
3517     }
3518   }
3519 }
3520 
3521   
3522 //#define WWN_DBG 1
3523 
3524 static void SetLoginFields(
3525   PFC_LOGGEDIN_PORT pLoggedInPort,
3526   TachFCHDR_GCMND* fchs,
3527   BOOLEAN PDisc,
3528   BOOLEAN Originator)
3529 {
3530   LOGIN_PAYLOAD logi;       // FC-PH Port Login
3531   PRLI_REQUEST prli;  // copy for BIG ENDIAN switch
3532   int i;
3533 #ifdef WWN_DBG
3534   ULONG ulBuff;
3535 #endif
3536 
3537   BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
3538 
3539   pLoggedInPort->Originator = Originator;
3540   pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
3541   
3542   switch( fchs->pl[0] & 0xffff )
3543   {
3544   case 0x00000002:  //  PLOGI or PDISC ACCept?
3545     if( PDisc )     // PDISC accept
3546       goto PDISC_case;
3547 
3548   case 0x00000003:  //  ELS_PLOGI or ELS_PLOGI_ACC
3549 
3550   // Login BB_credit typically 0 for Tachyons
3551     pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
3552 
3553     // e.g. 128, 256, 1024, 2048 per FC-PH spec
3554     // We have to use this when setting up SEST Writes,
3555     // since that determines frame size we send.
3556     pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
3557     pLoggedInPort->plogi = TRUE;
3558     pLoggedInPort->pdisc = FALSE;
3559     pLoggedInPort->prli = FALSE;    // ELS_PLOGI resets
3560     pLoggedInPort->flogi = FALSE;   // ELS_PLOGI resets
3561     pLoggedInPort->logo = FALSE;    // ELS_PLOGI resets
3562     pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
3563     pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
3564 
3565     // was this PLOGI to a Fabric?
3566     if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
3567       pLoggedInPort->flogi = TRUE;
3568 
3569 
3570     for( i=0; i<8; i++)   // copy the LOGIN port's WWN
3571       pLoggedInPort->u.ucWWN[i] = logi.port_name[i];  
3572 
3573 #ifdef WWN_DBG
3574     ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3575     if( pLoggedInPort->Originator)
3576       printk("o");
3577     else
3578       printk("r");
3579     printk("PLOGI port_id %Xh, WWN %08X",
3580       pLoggedInPort->port_id, ulBuff);
3581 
3582     ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3583     printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
3584 #endif
3585     break;
3586 
3587 
3588 
3589   
3590   case 0x00000005:  //  ELS_LOGO (logout)
3591 
3592 
3593     pLoggedInPort->plogi = FALSE;
3594     pLoggedInPort->pdisc = FALSE;
3595     pLoggedInPort->prli = FALSE;   // ELS_PLOGI resets
3596     pLoggedInPort->flogi = FALSE;  // ELS_PLOGI resets
3597     pLoggedInPort->logo = TRUE;    // ELS_PLOGI resets
3598     pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
3599     pLoggedInPort->LOGO_timer = 0;
3600 #ifdef WWN_DBG
3601     ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3602     if( pLoggedInPort->Originator)
3603       printk("o");
3604     else
3605       printk("r");
3606     printk("LOGO port_id %Xh, WWN %08X",
3607       pLoggedInPort->port_id, ulBuff);
3608 
3609     ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3610     printk("%08Xh\n", ulBuff);
3611 #endif
3612     break;
3613 
3614 
3615 
3616 PDISC_case:
3617   case 0x00000050: //  ELS_PDISC or ELS_PDISC_ACC
3618     pLoggedInPort->LOGO_timer = 0;  // stop the time-out
3619       
3620     pLoggedInPort->prli = TRUE;     // ready to accept FCP-SCSI I/O
3621     
3622 
3623       
3624 #ifdef WWN_DBG
3625     ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3626     if( pLoggedInPort->Originator)
3627       printk("o");
3628     else
3629       printk("r");
3630     printk("PDISC port_id %Xh, WWN %08X",
3631       pLoggedInPort->port_id, ulBuff);
3632 
3633     ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3634     printk("%08Xh\n", ulBuff);
3635 #endif
3636 
3637 
3638     
3639     break;
3640 
3641 
3642     
3643   case  0x1020L: //  PRLI?
3644   case  0x1002L: //  PRLI ACCept?
3645     BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
3646 
3647     pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
3648     pLoggedInPort->prli = TRUE;  // PLOGI resets, PDISC doesn't
3649 
3650     pLoggedInPort->pdisc = TRUE;  // expect to send (or receive) PDISC
3651                                   // next time
3652     pLoggedInPort->LOGO_timer = 0;  // will be set next LinkDown
3653 #ifdef WWN_DBG
3654     ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3655     if( pLoggedInPort->Originator)
3656       printk("o");
3657     else
3658       printk("r");
3659     printk("PRLI port_id %Xh, WWN %08X",
3660       pLoggedInPort->port_id, ulBuff);
3661 
3662     ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3663       printk("%08Xh\n", ulBuff);
3664 #endif
3665 
3666     break;
3667 
3668   }
3669 
3670   return;
3671 }
3672 
3673 
3674 
3675 
3676 
3677 
3678 static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
3679 {
3680   LOGIN_PAYLOAD *plogi;  // FC-PH Port Login
3681   LOGIN_PAYLOAD PlogiPayload;   // copy for BIG ENDIAN switch
3682   PRLI_REQUEST  *prli;          // FCP-SCSI Process Login
3683   PRLI_REQUEST  PrliPayload;    // copy for BIG ENDIAN switch
3684   LOGOUT_PAYLOAD  *logo;
3685   LOGOUT_PAYLOAD  LogoutPayload;
3686 //  PRLO_REQUEST  *prlo;
3687 //  PRLO_REQUEST  PrloPayload;
3688   REJECT_MESSAGE rjt, *prjt;
3689 
3690   memset( &PlogiPayload, 0, sizeof( PlogiPayload));
3691   plogi = &PlogiPayload;    // load into stack buffer,
3692                                 // then BIG-ENDIAN switch a copy to caller
3693 
3694 
3695   switch( type )  // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
3696   {
3697     case ELS_FDISC:
3698     case ELS_FLOGI:
3699     case ELS_PLOGI_ACC:   // FC-PH PORT Login Accept
3700     case ELS_PLOGI:   // FC-PH PORT Login
3701     case ELS_PDISC:   // FC-PH2 Port Discovery - same payload as ELS_PLOGI
3702       plogi->login_cmd = LS_PLOGI;
3703       if( type == ELS_PDISC)
3704         plogi->login_cmd = LS_PDISC;
3705       else if( type == ELS_PLOGI_ACC )
3706         plogi->login_cmd = LS_ACC;
3707 
3708       plogi->cmn_services.bb_credit = 0x00;
3709       plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
3710       plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
3711       plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
3712       plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
3713               RANDOM_RELATIVE_OFFSET;
3714 
3715              // fill in with World Wide Name based Port Name - 8 UCHARs
3716              // get from Tach registers WWN hi & lo
3717       LoadWWN( fcChip, plogi->port_name, 0);
3718              // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
3719              // get from Tach registers WWN hi & lo
3720       LoadWWN( fcChip, plogi->node_name, 1);
3721 
3722         // For Seagate Drives.
3723         //
3724       plogi->cmn_services.common_features |= 0x800;
3725       plogi->cmn_services.rel_offset = 0xFE;
3726       plogi->cmn_services.concurrent_seq = 1;
3727       plogi->class1.service_options = 0x00;
3728       plogi->class2.service_options = 0x00;
3729       plogi->class3.service_options = CLASS_VALID;
3730       plogi->class3.initiator_control = 0x00;
3731       plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
3732       plogi->class3.recipient_control =
3733              ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
3734       plogi->class3.concurrent_sequences = 1;
3735       plogi->class3.open_sequences = 1;
3736       plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
3737       plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
3738       plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '';
3739       plogi->vendor_version[4] = ''; plogi->vendor_version[5] = '';
3740 
3741 
3742       // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
3743       if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
3744       {
3745         if( type == ELS_FLOGI )
3746           plogi->login_cmd = LS_FLOGI;  
3747         else
3748           plogi->login_cmd = LS_FDISC;  
3749 
3750         plogi->cmn_services.lowest_ver = 0x20;
3751         plogi->cmn_services.common_features = 0x0800;
3752         plogi->cmn_services.rel_offset = 0;
3753         plogi->cmn_services.concurrent_seq = 0;
3754 
3755         plogi->class3.service_options = 0x8800;
3756         plogi->class3.rx_data_size = 0;
3757         plogi->class3.recipient_control = 0;
3758         plogi->class3.concurrent_sequences = 0;
3759         plogi->class3.open_sequences = 0;
3760       }
3761       
3762               // copy back to caller's buff, w/ BIG ENDIAN swap
3763       BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  sizeof(PlogiPayload));
3764       break;
3765 
3766     
3767     case ELS_ACC:       // generic Extended Link Service ACCept     
3768       plogi->login_cmd = LS_ACC;
3769               // copy back to caller's buff, w/ BIG ENDIAN swap
3770       BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  4);
3771       break;
3772 
3773 
3774       
3775     case ELS_SCR:    // Fabric State Change Registration
3776     {
3777       SCR_PL scr;     // state change registration
3778 
3779       memset( &scr, 0, sizeof(scr));
3780 
3781       scr.command = LS_SCR;  // 0x62000000
3782                              // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
3783       scr.function = 3;      // 1 = Events detected by Fabric
3784                              // 2 = N_Port detected registration
3785                              // 3 = Full registration
3786       
3787       // copy back to caller's buff, w/ BIG ENDIAN swap
3788       BigEndianSwap( (UCHAR*)&scr, payload,  sizeof(SCR_PL));
3789     }
3790     
3791     break;
3792 
3793     
3794     case FCS_NSR:    // Fabric Name Service Request
3795     {
3796       NSR_PL nsr;    // Name Server Req. payload
3797 
3798       memset( &nsr, 0, sizeof(NSR_PL));
3799 
3800                              // see Brocade Fabric Programming Guide,
3801                              // Rev 1.3, pg 4-44
3802       nsr.CT_Rev = 0x01000000;
3803       nsr.FCS_Type = 0xFC020000;
3804       nsr.Command_code = 0x01710000;
3805       nsr.FCP = 8;
3806      
3807       // copy back to caller's buff, w/ BIG ENDIAN swap
3808       BigEndianSwap( (UCHAR*)&nsr, payload,  sizeof(NSR_PL));
3809     }
3810     
3811     break;
3812 
3813 
3814 
3815     
3816     case ELS_LOGO:   // FC-PH PORT LogOut
3817       logo = &LogoutPayload;    // load into stack buffer,
3818                                 // then BIG-ENDIAN switch a copy to caller
3819       logo->cmd = LS_LOGO;
3820                                 // load the 3 UCHARs of the node name
3821                                 // (if private loop, upper two UCHARs 0)
3822       logo->reserved = 0;
3823 
3824       logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
3825       logo->n_port_identifier[1] =
3826                      (UCHAR)(fcChip->Registers.my_al_pa>>8);
3827       logo->n_port_identifier[2] =
3828                      (UCHAR)(fcChip->Registers.my_al_pa>>16);
3829              // fill in with World Wide Name based Port Name - 8 UCHARs
3830              // get from Tach registers WWN hi & lo
3831       LoadWWN( fcChip, logo->port_name, 0);
3832 
3833       BigEndianSwap( (UCHAR*)&LogoutPayload,
3834                      payload,  sizeof(LogoutPayload) );  // 16 UCHAR struct
3835       break;
3836 
3837 
3838     case ELS_LOGO_ACC:     // Logout Accept (FH-PH pg 149, table 74)
3839       logo = &LogoutPayload;    // load into stack buffer,
3840                                 // then BIG-ENDIAN switch a copy to caller
3841       logo->cmd = LS_ACC;
3842       BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 );  // 4 UCHAR cmnd
3843       break;
3844       
3845 
3846     case ELS_RJT:          // ELS_RJT link service reject (FH-PH pg 155)
3847 
3848       prjt = (REJECT_MESSAGE*)payload;  // pick up passed data
3849       rjt.command_code = ELS_RJT;
3850                        // reverse fields, because of Swap that follows...
3851       rjt.vendor = prjt->reserved; // vendor specific
3852       rjt.explain = prjt->reason; //
3853       rjt.reason = prjt->explain; //
3854       rjt.reserved = prjt->vendor; //
3855                        // BIG-ENDIAN switch a copy to caller
3856       BigEndianSwap( (UCHAR*)&rjt, payload, 8 );  // 8 UCHAR cmnd
3857       break;
3858 
3859 
3860 
3861 
3862 
3863     case ELS_PRLI_ACC:  // Process Login ACCept
3864     case ELS_PRLI:  // Process Login
3865     case ELS_PRLO:  // Process Logout
3866       memset( &PrliPayload, 0, sizeof( PrliPayload));
3867       prli = &PrliPayload;      // load into stack buffer,
3868 
3869       if( type == ELS_PRLI )
3870         prli->cmd = 0x20;  // Login
3871       else if( type == ELS_PRLO )
3872         prli->cmd = 0x21;  // Logout
3873       else if( type == ELS_PRLI_ACC )
3874       {
3875         prli->cmd = 0x02;  // Login ACCept
3876         prli->valid = REQUEST_EXECUTED;
3877       }
3878 
3879 
3880       prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
3881       prli->fcp_info = READ_XFER_RDY;
3882       prli->page_length = 0x10;
3883       prli->payload_length = 20;
3884                                 // Can be initiator AND target
3885 
3886       if( fcChip->Options.initiator )
3887         prli->fcp_info |= INITIATOR_FUNCTION;
3888       if( fcChip->Options.target )
3889         prli->fcp_info |= TARGET_FUNCTION;
3890 
3891       BigEndianSwap( (UCHAR*)&PrliPayload, payload,  prli->payload_length);
3892       break;
3893 
3894 
3895 
3896     default:  // no can do - programming error
3897       printk(" BuildLinkServicePayload unknown!\n");
3898       break;
3899   }
3900 }
3901 
3902 // loads 8 UCHARs for PORT name or NODE name base on
3903 // controller's WWN.
3904 void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
3905 {
3906   UCHAR* bPtr, i;
3907 
3908   switch( type )
3909   {
3910     case 0:  // Port_Name
3911       bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3912       for( i =0; i<4; i++)
3913         dest[i] = *bPtr++;
3914       bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3915       for( i =4; i<8; i++)
3916         dest[i] = *bPtr++;
3917       break;
3918     case 1:  // Node/Fabric _Name
3919       bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3920       for( i =0; i<4; i++)
3921         dest[i] = *bPtr++;
3922       bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3923       for( i =4; i<8; i++)
3924         dest[i] = *bPtr++;
3925       break;
3926   }
3927   
3928 }
3929 
3930 
3931 
3932 // We check the Port Login payload for required values.  Note that
3933 // ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
3934 
3935 
3936 int verify_PLOGI( PTACHYON fcChip,
3937                   TachFCHDR_GCMND* fchs, 
3938                   ULONG* reject_explain)
3939 {
3940   LOGIN_PAYLOAD login;
3941 
3942                   // source, dest, len (should be mult. of 4)
3943   BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login,  sizeof(login));
3944 
3945                             // check FC version
3946                             // if other port's highest supported version
3947                             // is less than our lowest, and 
3948                             // if other port's lowest
3949   if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
3950       login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
3951   {
3952     *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
3953     return LOGICAL_ERROR;
3954   }
3955 
3956                             // Receive Data Field Size must be >=128
3957                             // per FC-PH
3958   if (login.cmn_services.bb_rx_size < 128)
3959   {
3960     *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
3961     return LOGICAL_ERROR;
3962   }
3963 
3964                             // Only check Class 3 params
3965   if( login.class3.service_options & CLASS_VALID)
3966   {
3967     if (login.class3.rx_data_size < 128)
3968     {
3969       *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
3970       return LOGICAL_ERROR;
3971     }
3972     if( login.class3.initiator_control & XID_REQUIRED)
3973     {
3974       *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
3975       return LOGICAL_ERROR;
3976     }
3977   }
3978   return 0;   // success
3979 }
3980 
3981 
3982 
3983 
3984 int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
3985 {
3986   PRLI_REQUEST prli;  // buffer for BIG ENDIAN
3987 
3988                   // source, dest, len (should be mult. of 4)
3989   BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli,  sizeof(prli));
3990 
3991   if( prli.fcp_info == 0 )  // i.e., not target or initiator?
3992   {
3993     *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
3994     return LOGICAL_ERROR;
3995   }
3996 
3997   return 0;  // success
3998 }
3999 
4000 
4001 // SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
4002 // INPUTS:
4003 //   source   - ptr to LITTLE ENDIAN ULONGS
4004 //   cnt      - number of UCHARs to switch (should be mult. of ULONG)
4005 // OUTPUTS:
4006 //   dest     - ptr to BIG ENDIAN copy
4007 // RETURN:
4008 //   none
4009 //
4010 void BigEndianSwap( UCHAR *source, UCHAR *dest,  USHORT cnt)
4011 {
4012   int i,j;
4013 
4014   source+=3;   // start at MSB of 1st ULONG
4015   for( j=0; j < cnt; j+=4, source+=4, dest+=4)  // every ULONG
4016   {
4017     for( i=0; i<4; i++)  // every UCHAR in ULONG
4018           *(dest+i) = *(source-i);
4019   }
4020 }
4021 
4022 
4023 
4024 
4025 // Build FC Exchanges............
4026 
4027 static void  buildFCPstatus( 
4028   PTACHYON fcChip, 
4029   ULONG ExchangeID);
4030 
4031 static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
4032 
4033 static ULONG build_SEST_sgList( 
4034   ULONG *SESTalPairStart,
4035   Scsi_Cmnd *Cmnd,
4036   ULONG *sgPairs,
4037   PSGPAGES sgPages  // link list of TL Ext. S/G pages from O/S Pool
4038 );
4039 
4040 static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
4041   UCHAR* payload, ULONG type, ULONG fcp_dl );
4042 
4043 
4044 /*
4045                              IRB
4046       ERQ           __________________
4047   |          |   / | Req_A_SFS_Len    |        ____________________
4048   |----------|  /  | Req_A_SFS_Addr   |------->|  Reserved         |
4049   |   IRB    | /   | Req_A_D_ID       |        | SOF EOF TimeStamp |
4050   |-----------/    | Req_A_SEST_Index |-+      | R_CTL |   D_ID    |
4051   |   IRB    |     | Req_B...         | |      | CS_CTL|   S_ID    | 
4052   |-----------\    |                  | |      | TYPE  |   F_CTL   |
4053   |   IRB    | \   |                  | |      | SEQ_ID  | SEQ_CNT |
4054   |-----------  \  |                  | +-->+--| OX_ID   | RX_ID   |
4055   |          |   \ |__________________|     |  |       RO          |
4056                                             |  | pl (payload/cmnd) |
4057                                             |  |        .....      |
4058                                             |  |___________________|
4059                                             |
4060                                             |
4061 +-------------------------------------------+
4062 |
4063 |
4064 |                        e.g. IWE    
4065 |    SEST           __________________             for FCP_DATA
4066 | |          |   / |       | Hdr_Len  |        ____________________
4067 | |----------|  /  |  Hdr_Addr_Addr   |------->|  Reserved         |
4068 | |   [0]    | /   |Remote_ID| RSP_Len|        | SOF EOF TimeStamp |
4069 | |-----------/    |   RSP_Addr       |---+    | R_CTL |   D_ID    |
4070 +->   [1]    |     |       | Buff_Off |   |    | CS_CTL|   S_ID    | 
4071   |-----------\    |BuffIndex| Link   |   |    | TYPE  |   F_CTL   |
4072   |   [2]    | \   | Rsvd  |   RX_ID  |   |    | SEQ_ID  | SEQ_CNT |
4073   |-----------  \  |    Data_Len      |   |    | OX_ID   | RX_ID   |
4074   |    ...   |   \ |     Exp_RO       |   |    |       RO          |
4075   |----------|     |   Exp_Byte_Cnt   |   |    |___________________|
4076   | SEST_LEN |  +--|    Len           |   |                                             
4077   |__________|  |  |   Address        |   |                                              
4078                 |  |    ...           |   |         for FCP_RSP  
4079                 |  |__________________|   |    ____________________
4080                 |                         +----|  Reserved         |   
4081                 |                              | SOF EOF TimeStamp |
4082                 |                              | R_CTL |   D_ID    |
4083                 |                              | CS_CTL|   S_ID    | 
4084                 +--- local or extended         |     ....          |
4085                      scatter/gather lists
4086                      defining upper-layer
4087                      data (e.g. from user's App)
4088 
4089 
4090 */
4091 // All TachLite commands must start with a SFS (Single Frame Sequence)
4092 // command.  In the simplest case (a NOP Basic Link command),
4093 // only one frame header and ERQ entry is required.  The most complex
4094 // case is the SCSI assisted command, which requires an ERQ entry,
4095 // SEST entry, and several frame headers and data buffers all
4096 // logically linked together.
4097 // Inputs:
4098 //   cpqfcHBAdata  - controller struct
4099 //   type          - PLOGI, SCSI_IWE, etc.
4100 //   InFCHS        - Incoming Tachlite FCHS which prompted this exchange
4101 //                   (only s_id set if we are originating)
4102 //   Data          - PVOID to data struct consistent with "type"
4103 //   fcExchangeIndex - pointer to OX/RD ID value of built exchange
4104 // Return:
4105 //   fcExchangeIndex - OX/RD ID value if successful
4106 //   0    - success
4107 //  INVALID_ARGS    - NULL/ invalid passed args
4108 //  BAD_ALPA        - Bad source al_pa address
4109 //  LNKDWN_OSLS     - Link Down (according to this controller)
4110 //  OUTQUE_FULL     - Outbound Que full
4111 //  DRIVERQ_FULL    - controller's Exchange array full
4112 //  SEST_FULL       - SEST table full
4113 //
4114 // Remarks:
4115 // Psuedo code:
4116 // Check for NULL pointers / bad args
4117 // Build outgoing FCHS - the header/payload struct
4118 // Build IRB (for ERQ entry)
4119 // if SCSI command, build SEST entry (e.g. IWE, TRE,...)
4120 // return success
4121 
4122 //sbuildex
4123 ULONG cpqfcTSBuildExchange(
4124   CPQFCHBA *cpqfcHBAdata,
4125   ULONG type, // e.g. PLOGI
4126   TachFCHDR_GCMND* InFCHS,  // incoming FCHS
4127   void *Data,               // the CDB, scatter/gather, etc.  
4128   LONG *fcExchangeIndex )   // points to allocated exchange, 
4129 {
4130   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
4131   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
4132   ULONG ulStatus = 0;  // assume OK
4133   USHORT ox_ID, rx_ID=0xFFFF;
4134   ULONG SfsLen=0L;
4135   TachLiteIRB* pIRB;
4136   IRBflags IRB_flags;
4137   UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
4138   TachFCHDR_GCMND* CMDfchs;
4139   TachFCHDR* dataHDR;     // 32 byte HEADER ONLY FCP-DATA buffer
4140   TachFCHDR_RSP* rspHDR;     // 32 byte header + RSP payload
4141   Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data;   // Linux Scsi CDB, S/G, ...
4142   TachLiteIWE* pIWE;
4143   TachLiteIRE* pIRE;
4144   TachLiteTWE* pTWE;
4145   TachLiteTRE* pTRE;
4146   ULONG fcp_dl;           // total byte length of DATA transfered
4147   ULONG fl;               // frame length (FC frame size, 128, 256, 512, 1024)
4148   ULONG sgPairs;          // number of valid scatter/gather pairs
4149   int FCP_SCSI_command;
4150   BA_ACC_PAYLOAD *ba_acc;
4151   BA_RJT_PAYLOAD *ba_rjt;
4152 
4153                           // check passed ARGS
4154   if( !fcChip->ERQ )      // NULL ptr means uninitialized Tachlite chip
4155     return INVALID_ARGS;
4156 
4157 
4158   if( type == SCSI_IRE ||
4159       type == SCSI_TRE ||
4160       type == SCSI_IWE ||
4161       type == SCSI_TWE)
4162     FCP_SCSI_command = 1;
4163 
4164   else
4165     FCP_SCSI_command = 0;
4166 
4167 
4168                      // for commands that pass payload data (e.g. SCSI write)
4169                      // examine command struct - verify that the
4170                      // length of s/g buffers is adequate for total payload
4171                      // length (end of list is NULL address)
4172 
4173   if( FCP_SCSI_command )
4174   {
4175     if( Data )     // must have data descriptor (S/G list -- at least
4176                    // one address with at least 1 byte of data)
4177     {
4178       // something to do (later)?
4179     }
4180 
4181     else
4182       return INVALID_ARGS;  // invalid DATA ptr
4183   }
4184 
4185     
4186 
4187          // we can build an Exchange for later Queuing (on the TL chip)
4188          // if an empty slot is available in the DevExt for this controller
4189          // look for available Exchange slot...
4190 
4191   if( type != FCP_RESPONSE &&
4192       type != BLS_ABTS &&
4193       type != BLS_ABTS_ACC )  // already have Exchange slot!
4194     *fcExchangeIndex = FindFreeExchange( fcChip, type );
4195 
4196   if( *fcExchangeIndex != -1 )   // Exchange is available?
4197   {
4198                      // assign tmp ptr (shorthand)
4199     CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs; 
4200 
4201 
4202     if( Cmnd != NULL ) // (necessary for ABTS cases)
4203     {
4204       Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
4205       Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort = 
4206         fcFindLoggedInPort( fcChip,
4207           Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
4208           0,        // DON'T search linked list for FC port id
4209           NULL,     // DON'T search linked list for FC WWN
4210           NULL);    // DON'T care about end of list
4211 
4212     }
4213 
4214 
4215                      // Build the command frame header (& data) according
4216                      // to command type
4217 
4218                      // fields common for all SFS frame types
4219     CMDfchs->reserved = 0L; // must clear
4220     CMDfchs->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; LCr=0, no TS
4221     
4222              // get the destination port_id from incoming FCHS
4223              // (initialized before calling if we're Originator)
4224              // Frame goes to port it was from - the source_id
4225     
4226     CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
4227     CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4228 
4229 
4230     // now enter command-specific fields
4231     switch( type )
4232     {
4233 
4234     case BLS_NOP:   // FC defined basic link service command NO-OP
4235                 // ensure unique X_IDs! (use tracking function)
4236 
4237       *pIRB_flags = 0;      // clear IRB flags
4238       IRB_flags.SFA = 1;    // send SFS (not SEST index)
4239       SfsLen = *pIRB_flags;
4240 
4241       SfsLen <<= 24;        // shift flags to MSB
4242       SfsLen += 32L;        // add len to LSB (header only - no payload)
4243 
4244                    // TYPE[31-24] 00 Basic Link Service
4245                    // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4246       CMDfchs->d_id |= 0x80000000L;  // R_CTL = 80 for NOP (Basic Link Ser.)
4247       CMDfchs->f_ctl = 0x00310000L;  // xchng originator, 1st seq,....
4248       CMDfchs->seq_cnt = 0x0L;
4249       CMDfchs->ox_rx_id = 0xFFFF;        // RX_ID for now; OX_ID on start
4250       CMDfchs->ro = 0x0L;    // relative offset (n/a)
4251       CMDfchs->pl[0] = 0xaabbccddL;   // words 8-15 frame data payload (n/a)
4252       Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
4253                                       // (NOP should complete ~instantly)
4254       break;
4255 
4256 
4257     
4258     
4259     case BLS_ABTS_ACC:  // Abort Sequence ACCept
4260       *pIRB_flags = 0;      // clear IRB flags
4261       IRB_flags.SFA = 1;    // send SFS (not SEST index)
4262       SfsLen = *pIRB_flags;
4263 
4264       SfsLen <<= 24;        // shift flags to MSB
4265       SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
4266 
4267       CMDfchs->d_id |= 0x84000000L;  // R_CTL = 84 for BASIC ACCept
4268                    // TYPE[31-24] 00 Basic Link Service
4269                    // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4270       CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
4271                    // CMDfchs->seq_id & count might be set from DataHdr?
4272       CMDfchs->ro = 0x0L;    // relative offset (n/a)
4273       Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4274                         // (Timeout in case of weird error)
4275       
4276       // now set the ACCept payload...
4277       ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
4278       memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
4279       // Since PLDA requires (only) entire Exchange aborts, we don't need
4280       // to worry about what the last sequence was.
4281 
4282       // We expect that a "target" task is accepting the abort, so we
4283       // can use the OX/RX ID pair 
4284       ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
4285  
4286       // source, dest, #bytes
4287       BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
4288 
4289       ba_acc->low_seq_cnt = 0;
4290       ba_acc->high_seq_cnt = 0xFFFF;
4291 
4292 
4293       break;
4294     
4295 
4296     case BLS_ABTS_RJT:  // Abort Sequence ACCept
4297       *pIRB_flags = 0;      // clear IRB flags
4298       IRB_flags.SFA = 1;    // send SFS (not SEST index)
4299       SfsLen = *pIRB_flags;
4300 
4301       SfsLen <<= 24;        // shift flags to MSB
4302       SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
4303 
4304       CMDfchs->d_id |= 0x85000000L;  // R_CTL = 85 for BASIC ReJecT
4305                    // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4306                    // TYPE[31-24] 00 Basic Link Service
4307       CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
4308                    // CMDfchs->seq_id & count might be set from DataHdr?
4309       CMDfchs->ro = 0x0L;    // relative offset (n/a)
4310       Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4311                         // (Timeout in case of weird error)
4312       
4313       CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
4314       
4315       // now set the ReJecT payload...
4316       ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
4317       memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
4318 
4319       // We expect that a "target" task couldn't find the Exhange in the
4320       // array of active exchanges, so we use a new LinkService X_ID.
4321       // See Reject payload description in FC-PH (Rev 4.3), pg. 140
4322       ba_rjt->reason_code = 0x09; // "unable to perform command request"
4323       ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
4324 
4325 
4326       break;
4327     
4328     
4329     
4330     case BLS_ABTS:   // FC defined basic link service command ABTS 
4331                      // Abort Sequence
4332                      
4333 
4334       *pIRB_flags = 0;      // clear IRB flags
4335       IRB_flags.SFA = 1;    // send SFS (not SEST index)
4336       SfsLen = *pIRB_flags;
4337 
4338       SfsLen <<= 24;        // shift flags to MSB
4339       SfsLen += 32L;        // add len to LSB (header only - no payload)
4340 
4341                    // TYPE[31-24] 00 Basic Link Service
4342                    // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4343       CMDfchs->d_id |= 0x81000000L;  // R_CTL = 81 for ABTS
4344       CMDfchs->f_ctl = 0x00110000L;  // xchnge originator, last seq, xfer SI
4345                    // CMDfchs->seq_id & count might be set from DataHdr?
4346       CMDfchs->ro = 0x0L;    // relative offset (n/a)
4347       Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4348                         // (ABTS must timeout when responder is gone)
4349       break;
4350 
4351     
4352     
4353     case FCS_NSR:    // Fabric Name Service Request
4354        Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4355 
4356 
4357       Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4358                          // OX_ID, linked to Driver Transaction ID
4359                          // (fix-up at Queing time)
4360       CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4361                                     // OX_ID set at ERQueing time
4362       *pIRB_flags = 0;      // clear IRB flags
4363       IRB_flags.SFA = 1;    // send SFS (not SEST index)
4364       SfsLen = *pIRB_flags;
4365 
4366       SfsLen <<= 24;        // shift flags to MSB
4367       SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
4368 
4369       CMDfchs->d_id |= 0x02000000L;  // R_CTL = 02 for -
4370                                    // Name Service Request: Unsolicited 
4371                    // TYPE[31-24] 01 Extended Link Service
4372                    // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4373       CMDfchs->f_ctl = 0x20210000L;
4374                    // OX_ID will be fixed-up at Tachyon enqueing time
4375       CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4376       CMDfchs->ro = 0x0L;    // relative offset (n/a)
4377 
4378       BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4379 
4380    
4381     
4382     
4383     
4384     
4385       break;
4386     
4387     
4388     
4389     
4390     case ELS_PLOGI:  // FC-PH extended link service command Port Login
4391       // (May, 2000)
4392       // NOTE! This special case facilitates SANMark testing.  The SANMark
4393       // test script for initialization-timeout.fcal.SANMark-1.fc
4394       // "eats" the OPN() primitive without issuing an R_RDY, causing
4395       // Tachyon to report LST (loop state timeout), which causes a
4396       // LIP.  To avoid this, simply send out the frame (i.e. assuming a
4397       // buffer credit of 1) without waiting for R_RDY.  Many FC devices
4398       // (other than Tachyon) have been doing this for years.  We don't
4399       // ever want to do this for non-Link Service frames unless the
4400       // other device really did report non-zero login BB credit (i.e.
4401       // in the PLOGI ACCept frame).
4402 //      CMDfchs->sof_eof |= 0x00000400L;  // LCr=1
4403     
4404     case ELS_FDISC:  // Fabric Discovery (Login)
4405     case ELS_FLOGI:  // Fabric Login
4406     case ELS_SCR:    // Fabric State Change Registration
4407     case ELS_LOGO:   // FC-PH extended link service command Port Logout
4408     case ELS_PDISC:  // FC-PH extended link service cmnd Port Discovery
4409     case ELS_PRLI:   // FC-PH extended link service cmnd Process Login
4410 
4411       Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4412 
4413 
4414       Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4415                          // OX_ID, linked to Driver Transaction ID
4416                          // (fix-up at Queing time)
4417       CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4418                                     // OX_ID set at ERQueing time
4419       *pIRB_flags = 0;      // clear IRB flags
4420       IRB_flags.SFA = 1;    // send SFS (not SEST index)
4421       SfsLen = *pIRB_flags;
4422 
4423       SfsLen <<= 24;        // shift flags to MSB
4424       if( type == ELS_LOGO )
4425         SfsLen += (32L + 16L); //  add len (header & PLOGI payload)
4426       else if( type == ELS_PRLI )
4427         SfsLen += (32L + 20L); //  add len (header & PRLI payload)
4428       else if( type == ELS_SCR )
4429         SfsLen += (32L + sizeof(SCR_PL)); //  add len (header & SCR payload)
4430       else
4431         SfsLen += (32L + 116L); //  add len (header & PLOGI payload)
4432 
4433       CMDfchs->d_id |= 0x22000000L;  // R_CTL = 22 for -
4434                                    // Extended Link_Data: Unsolicited Control
4435                    // TYPE[31-24] 01 Extended Link Service
4436                    // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4437       CMDfchs->f_ctl = 0x01210000L;
4438                    // OX_ID will be fixed-up at Tachyon enqueing time
4439       CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4440       CMDfchs->ro = 0x0L;    // relative offset (n/a)
4441 
4442       BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4443 
4444       break;
4445 
4446 
4447 
4448     case ELS_LOGO_ACC: // FC-PH extended link service logout accept
4449     case ELS_RJT:          // extended link service reject (add reason)
4450     case ELS_ACC:      // ext. link service generic accept
4451     case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
4452     case ELS_PRLI_ACC: // ext. link service process login accept
4453 
4454 
4455       Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
4456                 // ensure unique X_IDs! (use tracking function)
4457                 // OX_ID from initiator cmd
4458       ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16); 
4459       rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
4460 
4461       *pIRB_flags = 0;      // clear IRB flags
4462       IRB_flags.SFA = 1;    // send SFS (not SEST index)
4463       SfsLen = *pIRB_flags;
4464 
4465       SfsLen <<= 24;        // shift flags to MSB
4466       if( type == ELS_RJT )
4467       {
4468         SfsLen += (32L + 8L); //  add len (header + payload)
4469 
4470         // ELS_RJT reason codes (utilize unused "reserved" field)
4471         CMDfchs->pl[0] = 1;
4472         CMDfchs->pl[1] = InFCHS->reserved;  
4473           
4474       }
4475       else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC)  )
4476         SfsLen += (32L + 4L); //  add len (header + payload)
4477       else if( type == ELS_PLOGI_ACC )
4478         SfsLen += (32L + 116L); //  add len (header + payload)
4479       else if( type == ELS_PRLI_ACC )
4480         SfsLen += (32L + 20L); //  add len (header + payload)
4481 
4482       CMDfchs->d_id |= 0x23000000L;  // R_CTL = 23 for -
4483                                    // Extended Link_Data: Control Reply
4484                    // TYPE[31-24] 01 Extended Link Service
4485                    // f_ctl[23:0] exchg responder, last seq, e_s, tsi
4486       CMDfchs->f_ctl = 0x01990000L;
4487       CMDfchs->seq_cnt = 0x0L;
4488       CMDfchs->ox_rx_id = 0L;        // clear
4489       CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
4490       CMDfchs->ox_rx_id <<= 16;      // shift them
4491 
4492       CMDfchs->ro = 0x0L;    // relative offset (n/a)
4493 
4494       BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4495 
4496       break;
4497 
4498 
4499                          // Fibre Channel SCSI 'originator' sequences...
4500                          // (originator means 'initiator' in FCP-SCSI)
4501     case SCSI_IWE: // TachLite Initiator Write Entry
4502     {
4503       PFC_LOGGEDIN_PORT pLoggedInPort = 
4504         Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
4505 
4506       Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4507       Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
4508                        
4509       // first, build FCP_CMND
4510       // unique X_ID fix-ups in StartExchange 
4511 
4512       *pIRB_flags = 0;      // clear IRB flags
4513       IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
4514 
4515       // NOTE: unlike FC LinkService login frames, normal
4516       // SCSI commands are sent without outgoing verification
4517       IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
4518       SfsLen = *pIRB_flags;
4519 
4520       SfsLen <<= 24;        // shift flags to MSB
4521       SfsLen += 64L;        // add len to LSB (header & CMND payload)
4522 
4523       CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
4524 
4525                    // TYPE[31-24] 8 for FCP SCSI
4526                    // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4527                    //             valid RO
4528       CMDfchs->f_ctl = 0x08210008L;
4529       CMDfchs->seq_cnt = 0x0L;
4530       CMDfchs->ox_rx_id = 0L;        // clear for now (-or- in later)
4531       CMDfchs->ro = 0x0L;    // relative offset (n/a)
4532 
4533                    // now, fill out FCP-DATA header
4534                    // (use buffer inside SEST object)
4535       dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4536       dataHDR->reserved = 0L; // must clear
4537       dataHDR->sof_eof = 0x75002000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
4538       dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4539       dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4540                    // TYPE[31-24] 8 for FCP SCSI
4541                    // f_ctl[23:0] xfer S.I.| valid RO
4542       dataHDR->f_ctl = 0x08010008L;
4543       dataHDR->seq_cnt = 0x02000000L;  // sequence ID: df_ctl : seqence count
4544       dataHDR->ox_rx_id = 0L;        // clear; fix-up dataHDR fields later
4545       dataHDR->ro = 0x0L;    // relative offset (n/a)
4546 
4547                    // Now setup the SEST entry
4548       pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
4549       
4550                    // fill out the IWE:
4551 
4552                 // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
4553       pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
4554       
4555       
4556       // from login parameters with other port, what's the largest frame
4557       // we can send? 
4558       if( pLoggedInPort == NULL) 
4559       {
4560         ulStatus = INVALID_ARGS;  // failed! give up
4561         break;
4562       }
4563       if( pLoggedInPort->rx_data_size  >= 2048)
4564         fl = 0x00020000;  // 2048 code (only support 1024!)
4565       else if( pLoggedInPort->rx_data_size  >= 1024)
4566         fl = 0x00020000;  // 1024 code
4567       else if( pLoggedInPort->rx_data_size  >= 512)
4568         fl = 0x00010000;  // 512 code
4569       else
4570         fl = 0;  // 128 bytes -- should never happen
4571       
4572       
4573       pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
4574       pIWE->Hdr_Addr = virt_to_bus( dataHDR );
4575       pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4576       pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4577       
4578       memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0, 
4579         sizeof( FCP_STATUS_RESPONSE) );  // clear out previous status
4580   
4581       pIWE->RSP_Addr = virt_to_bus(
4582                          &fcChip->SEST->RspHDR[ *fcExchangeIndex ]);
4583 
4584                    // Do we need local or extended gather list?
4585                    // depends on size - we can handle 3 len/addr pairs
4586                    // locally.
4587 
4588       fcp_dl = build_SEST_sgList( 
4589         &pIWE->GLen1, 
4590         Cmnd,       // S/G list
4591         &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
4592         &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4593 
4594       if( !fcp_dl ) // error building S/G list?
4595       {
4596         ulStatus = MEMPOOL_FAIL;
4597         break;      // give up
4598       }
4599 
4600                              // Now that we know total data length in
4601                              // the passed S/G buffer, set FCP CMND frame
4602       build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4603 
4604 
4605       
4606       if( sgPairs > 3 )  // need extended s/g list
4607         pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
4608       else               // local data pointers (in SEST)
4609         pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
4610 
4611                               // ULONG 5
4612       pIWE->Link = 0x0000ffffL;   // Buff_Index | Link
4613 
4614       pIWE->RX_ID = 0x0L;     // DWord 6: RX_ID set by target XFER_RDY
4615 
4616                                       // DWord 7
4617       pIWE->Data_Len = 0L;    // TL enters rcv'd XFER_RDY BURST_LEN
4618       pIWE->Exp_RO = 0L;      // DWord 8
4619                               // DWord 9
4620       pIWE->Exp_Byte_Cnt = fcp_dl;  // sum of gather buffers
4621     }
4622     break;
4623 
4624 
4625 
4626 
4627 
4628     case SCSI_IRE: // TachLite Initiator Read Entry
4629 
4630       if( Cmnd->timeout != 0)
4631       {
4632 //      printk("Cmnd->timeout %d\n", Cmnd->timeout);
4633         // per Linux Scsi
4634         Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
4635       }
4636       else  // use our best guess, based on FC & device
4637       {
4638 
4639         if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)     
4640         {
4641           // turn off our timeouts (for now...)
4642           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF; 
4643         }
4644         else
4645         {
4646           Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4647           Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
4648         }
4649       }
4650 
4651   
4652       // first, build FCP_CMND
4653 
4654 
4655       *pIRB_flags = 0;      // clear IRB flags
4656       IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
4657                             // NOTE: unlike FC LinkService login frames,
4658                             // normal SCSI commands are sent "open loop"
4659       IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
4660       SfsLen = *pIRB_flags;
4661 
4662       SfsLen <<= 24;        // shift flags to MSB
4663       SfsLen += 64L;        // add len to LSB (header & CMND payload)
4664 
4665       CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
4666 
4667              // TYPE[31-24] 8 for FCP SCSI
4668              // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4669              //             valid RO
4670       CMDfchs->f_ctl = 0x08210008L;
4671       CMDfchs->seq_cnt = 0x0L;
4672       // x_ID & data direction bit set later
4673       CMDfchs->ox_rx_id = 0xFFFF;        // clear
4674       CMDfchs->ro = 0x0L;    // relative offset (n/a)
4675 
4676 
4677 
4678                    // Now setup the SEST entry
4679       pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
4680 
4681       // fill out the IRE:
4682       // VALid entry:Dir outbound:enable CM:enal INT:
4683       pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
4684 
4685       pIRE->reserved = 0L;
4686       pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4687       pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4688 
4689                             
4690       pIRE->RSP_Addr = virt_to_bus(
4691                               &fcChip->SEST->RspHDR[ *fcExchangeIndex ]);
4692       
4693       
4694                    // Do we need local or extended gather list?
4695                    // depends on size - we can handle 3 len/addr pairs
4696                    // locally.
4697 
4698       fcp_dl = build_SEST_sgList( 
4699         &pIRE->SLen1, 
4700         Cmnd,       // SCSI command Data desc. with S/G list
4701         &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
4702         &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4703       
4704       
4705       if( !fcp_dl ) // error building S/G list?
4706       {
4707         // It is permissible to have a ZERO LENGTH Read command.
4708         // If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
4709         // to 0 and continue.
4710         if( Cmnd->request_bufflen == 0 )
4711         {
4712           fcp_dl = 0; // no FC DATA frames expected
4713 
4714         }
4715         else
4716         {
4717           ulStatus = MEMPOOL_FAIL;
4718           break;      // give up
4719         }
4720       }
4721 
4722       // now that we know the S/G length, build CMND payload
4723       build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4724 
4725       
4726       if( sgPairs > 3 )  // need extended s/g list
4727         pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
4728       else
4729         pIRE->Buff_Off = 0x80000000; // local data, no offset
4730       
4731       pIRE->Buff_Index = 0x0L;    // DWord 5: Buff_Index | Reserved
4732 
4733       pIRE->Exp_RO  = 0x0L;       // DWord 6: Expected Rel. Offset
4734 
4735       pIRE->Byte_Count = 0;  // DWord 7: filled in by TL on err
4736       pIRE->reserved_ = 0;   // DWord 8: reserved
4737                              // NOTE: 0 length READ is OK.
4738       pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
4739       
4740       break;
4741 
4742 
4743 
4744 
4745                          // Fibre Channel SCSI 'responder' sequences...
4746                          // (originator means 'target' in FCP-SCSI)
4747     case SCSI_TWE: // TachLite Target Write Entry
4748 
4749       Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4750 
4751                        // first, build FCP_CMND
4752 
4753       *pIRB_flags = 0;      // clear IRB flags
4754       IRB_flags.SFA = 1;    // send SFS (XFER_RDY)
4755       SfsLen = *pIRB_flags;
4756 
4757       SfsLen <<= 24;        // shift flags to MSB
4758       SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4759 
4760       CMDfchs->d_id |= (0x05000000L);  // R_CTL = 5 for XFER_RDY
4761 
4762                    // TYPE[31-24] 8 for FCP SCSI
4763                    // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
4764                 //             valid RO
4765       CMDfchs->f_ctl = 0x08810008L;
4766       CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
4767                        // use originator (other port's) OX_ID
4768       CMDfchs->ox_rx_id = InFCHS->ox_rx_id;     // we want upper 16 bits
4769       CMDfchs->ro = 0x0L;    // relative offset (n/a)
4770 
4771                    // now, fill out FCP-RSP header
4772                    // (use buffer inside SEST object)
4773 
4774       rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4775       rspHDR->reserved = 0L; // must clear
4776       rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
4777       rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4778       rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4779                    // TYPE[31-24] 8 for FCP SCSI
4780                    // f_ctl[23:0] responder|last seq| xfer S.I.
4781       rspHDR->f_ctl = 0x08910000L;
4782       rspHDR->seq_cnt = 0x03000000;  // sequence ID
4783       rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
4784       rspHDR->ro = 0x0L;    // relative offset (n/a)
4785 
4786 
4787                    // Now setup the SEST entry
4788                    
4789       pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
4790 
4791       // fill out the TWE:
4792 
4793       // VALid entry:Dir outbound:enable CM:enal INT:
4794       pTWE->Seq_Accum = 0xC4000000L;  // upper word flags
4795       pTWE->reserved = 0L;
4796       pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
4797       pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4798       
4799 
4800                    // Do we need local or extended gather list?
4801                    // depends on size - we can handle 3 len/addr pairs
4802                    // locally.
4803 
4804       fcp_dl = build_SEST_sgList( 
4805         &pTWE->SLen1, 
4806         Cmnd,       // S/G list
4807         &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
4808         &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4809       
4810       
4811       if( !fcp_dl ) // error building S/G list?
4812       {
4813         ulStatus = MEMPOOL_FAIL;
4814         break;      // give up
4815       }
4816 
4817       // now that we know the S/G length, build CMND payload
4818       build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4819 
4820       
4821       if( sgPairs > 3 )  // need extended s/g list
4822         pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
4823       else
4824         pTWE->Buff_Off = 0x80000000; // local data, no offset
4825       
4826       pTWE->Buff_Index = 0;     // Buff_Index | Link
4827       pTWE->Exp_RO = 0;
4828       pTWE->Byte_Count = 0;  // filled in by TL on err
4829       pTWE->reserved_ = 0;
4830       pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
4831       
4832       break;
4833 
4834 
4835 
4836 
4837 
4838 
4839     case SCSI_TRE: // TachLite Target Read Entry
4840 
4841       // It doesn't make much sense for us to "time-out" a READ,
4842       // but we'll use it for design consistency and internal error recovery.
4843       Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4844 
4845       // I/O request block settings...
4846       *pIRB_flags = 0;      // clear IRB flags
4847                                   // check PRLI (process login) info
4848                                   // to see if Initiator Requires XFER_RDY
4849                                   // if not, don't send one!
4850                                   // { PRLI check...}
4851       IRB_flags.SFA = 0;    // don't send XFER_RDY - start data
4852       SfsLen = *pIRB_flags;
4853 
4854       SfsLen <<= 24;        // shift flags to MSB
4855       SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4856 
4857 
4858       
4859       // now, fill out FCP-DATA header
4860                    // (use buffer inside SEST object)
4861       dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4862 
4863       dataHDR->reserved = 0L; // must clear
4864       dataHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
4865       dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4866       dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4867 
4868 
4869                    // TYPE[31-24] 8 for FCP SCSI
4870                    // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
4871                    //             valid RO
4872       dataHDR->f_ctl = 0x08810008L;
4873       dataHDR->seq_cnt = 0x01000000;  // sequence ID (no XRDY)
4874       dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
4875       dataHDR->ro = 0x0L;    // relative offset (n/a)
4876 
4877                    // now, fill out FCP-RSP header
4878                    // (use buffer inside SEST object)
4879       rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4880 
4881       rspHDR->reserved = 0L; // must clear
4882       rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
4883       rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4884       rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4885                    // TYPE[31-24] 8 for FCP SCSI
4886                    // f_ctl[23:0] responder|last seq| xfer S.I.
4887       rspHDR->f_ctl = 0x08910000L;
4888       rspHDR->seq_cnt = 0x02000000;  // sequence ID: df_ctl: sequence count
4889 
4890       rspHDR->ro = 0x0L;    // relative offset (n/a)
4891 
4892 
4893       // Now setup the SEST entry
4894       pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
4895 
4896 
4897       // VALid entry:Dir outbound:enable CM:enal INT:
4898       pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
4899       pTRE->Hdr_Addr = virt_to_bus( dataHDR );
4900       pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
4901       pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4902       pTRE->RSP_Addr = virt_to_bus( rspHDR );
4903 
4904 
4905                    // Do we need local or extended gather list?
4906                    // depends on size - we can handle 3 len/addr pairs
4907                    // locally.
4908 
4909       fcp_dl = build_SEST_sgList( 
4910         &pTRE->GLen1, 
4911         Cmnd,       // S/G list
4912         &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
4913         &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4914       
4915       
4916       if( !fcp_dl ) // error building S/G list?
4917       {
4918         ulStatus = MEMPOOL_FAIL;
4919         break;      // give up
4920       }
4921 
4922       // no payload or command to build -- READ doesn't need XRDY
4923 
4924       
4925       if( sgPairs > 3 )  // need extended s/g list
4926         pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
4927       else               // local data pointers (in SEST)
4928         pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
4929 
4930                                             // ULONG 5
4931       pTRE->Buff_Index = 0L;   // Buff_Index | reserved
4932       pTRE->reserved = 0x0L;   // DWord 6
4933 
4934                                      // DWord 7: NOTE: zero length will
4935                                      // hang TachLite!
4936       pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
4937 
4938       pTRE->reserved_ = 0L;     // DWord 8
4939       pTRE->reserved__ = 0L;    // DWord 9
4940 
4941       break;
4942 
4943 
4944 
4945 
4946 
4947     
4948 
4949     case FCP_RESPONSE: 
4950                   // Target response frame: this sequence uses an OX/RX ID
4951                   // pair from a completed SEST exchange.  We built most
4952                   // of the response frame when we created the TWE/TRE.
4953 
4954       *pIRB_flags = 0;      // clear IRB flags
4955       IRB_flags.SFA = 1;    // send SFS (RSP)
4956       SfsLen = *pIRB_flags;
4957 
4958       SfsLen <<= 24;        // shift flags to MSB
4959       SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
4960       
4961 
4962       Exchanges->fcExchange[ *fcExchangeIndex].type = 
4963         FCP_RESPONSE; // change Exchange type to "response" phase
4964 
4965       // take advantage of prior knowledge of OX/RX_ID pair from
4966       // previous XFER outbound frame (still in fchs of exchange)
4967       fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id = 
4968         CMDfchs->ox_rx_id;
4969 
4970       // Check the status of the DATA phase of the exchange so we can report
4971       // status to the initiator
4972       buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
4973 
4974       memcpy(
4975         CMDfchs,  // re-use same XFER fchs for Response frame
4976         &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
4977         sizeof( TachFCHDR_RSP ));
4978       
4979         
4980       break;
4981 
4982     default:
4983       printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
4984       break;
4985 
4986     }
4987 
4988     
4989     
4990     if( !ulStatus)  // no errors above?
4991     {
4992       // FCHS is built; now build IRB
4993 
4994       // link the just built FCHS (the "command") to the IRB entry 
4995       // for this Exchange.
4996       pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB; 
4997     
4998                           // len & flags according to command type above
4999       pIRB->Req_A_SFS_Len = SfsLen;  // includes IRB flags & len
5000       pIRB->Req_A_SFS_Addr = virt_to_bus(CMDfchs); // TL needs physical addr
5001                                                   // of frame to send
5002       pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
5003 
5004     // Exchange is complete except for "fix-up" fields to be set
5005     // at Tachyon Queuing time:
5006     //    IRB->Req_A_Trans_ID (OX_ID/ RX_ID):  
5007     //        for SEST entry, lower bits correspond to actual FC Exchange ID
5008     //    fchs->OX_ID or RX_ID
5009     }
5010     else
5011     {
5012 #ifdef DBG     
5013       printk( "FC Error: SEST build Pool Allocation failed\n");
5014 #endif
5015       // return resources...
5016       cpqfcTSCompleteExchange( fcChip, *fcExchangeIndex);  // SEST build failed
5017     }
5018   }
5019   else  // no Exchanges available
5020   {
5021     ulStatus = SEST_FULL;
5022     printk( "FC Error: no fcExchanges available\n");
5023   }
5024   return ulStatus;
5025 }
5026 
5027 
5028 
5029 
5030 
5031 
5032 // set RSP payload fields
5033 static void  buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID) 
5034 {
5035   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5036   FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];  // shorthand
5037   PFCP_STATUS_RESPONSE pFcpStatus;
5038   
5039   memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
5040     sizeof( FCP_STATUS_RESPONSE) );
5041   if( pExchange->status ) // something wrong?
5042   {
5043     pFcpStatus = (PFCP_STATUS_RESPONSE)  // cast RSP buffer for this xchng
5044       &fcChip->SEST->RspHDR[ ExchangeID ].pl;
5045     if( pExchange->status & COUNT_ERROR )
5046     {
5047       
5048       // set FCP response len valid (so we can report count error)
5049       pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
5050       pFcpStatus->fcp_rsp_len = 0x04000000;  // 4 byte len (BIG Endian)
5051 
5052       pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
5053     }
5054   }
5055 }
5056 
5057 
5058 
5059 
5060 // This routine builds scatter/gather lists into SEST entries
5061 // INPUTS:
5062 //   SESTalPair - SEST address @DWordA "Local Buffer Length"
5063 //   sgList     - Scatter/Gather linked list of Len/Address data buffers
5064 // OUTPUT:
5065 //   sgPairs - number of valid address/length pairs
5066 // Remarks:
5067 //   The SEST data buffer pointers only depend on number of
5068 //   length/ address pairs, NOT on the type (IWE, TRE,...)
5069 //   Up to 3 pairs can be referenced in the SEST - more than 3
5070 //   require this Extended S/G list page.  The page holds 4, 8, 16...
5071 //   len/addr pairs, per Scatter/Gather List Page Length Reg.
5072 //   TachLite allows pages to be linked to any depth.
5073 
5074 //#define DBG_SEST_SGLIST 1 // for printing out S/G pairs with Ext. pages
5075 
5076 static ULONG build_SEST_sgList( 
5077     ULONG *SESTalPairStart,  // the 3 len/address buffers in SEST
5078     Scsi_Cmnd *Cmnd,
5079     ULONG *sgPairs, 
5080     PSGPAGES sgPages)  // link list of TL Ext. S/G pages from O/S Pool
5081     
5082 {
5083   ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
5084   ULONG* alPair = SESTalPairStart;
5085   ULONG alignedPageAddress;  // TL hardware alignment requirement
5086   int PairCount;
5087   unsigned long ulBuff;
5088   ULONG total_data_len=0; // (in bytes)
5089   ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
5090   ULONG thisMappingLen;
5091   struct scatterlist *sgl;  // S/G list (Linux format)
5092 
5093 
5094 
5095   if( !Cmnd->use_sg )  // no S/G list?
5096   {
5097     *sgPairs = 1;      // use "local" S/G pair in SEST entry
5098                        // (for now, ignore address bits above #31)
5099     *alPair++ = bytes_to_go & 0x7ffff; // bits 18-0, length
5100     ulBuff = virt_to_bus( Cmnd->request_buffer);
5101 #if BITS_PER_LONG > 32
5102     if( ulBuff >>32 )
5103     {
5104       printk("FATAL! Tachyon DMA address %p exceeds 32 bits\n", (void*)ulBuff );
5105       return 0;
5106     }
5107 #endif
5108     *alPair = (ULONG)ulBuff;      
5109     return bytes_to_go;
5110   }
5111 
5112 
5113   // [TBD - update for Linux to support > 32 bits addressing]
5114   // since the format for local & extended S/G lists is different,
5115   // check if S/G pairs exceeds 3.
5116   *sgPairs = Cmnd->use_sg;
5117   sgl = (struct scatterlist*)Cmnd->request_buffer;  
5118   
5119   if( *sgPairs <= 3 ) // need "local" SEST list
5120   {
5121     while( bytes_to_go)
5122     {
5123       thisMappingLen = sgl->length;  // we want them ALL on every pass
5124       bytes_to_go = bytes_to_go - thisMappingLen;
5125 
5126       // we have L/A pair; L = thisMappingLen, A = physicalAddress
5127       // load into SEST...
5128       total_data_len += thisMappingLen & 0x7ffff;  // mask in valid bits
5129                                                    // per SEST format
5130       *alPair = thisMappingLen & 0x7ffff; // bits 18-0, length
5131 //      physicalAddress.HighPart <= 19;  // shift to bit 19
5132 
5133                    // pick up bits 44-32 of upper 64-bit address
5134                    // and load into 31-19 LBAU (upper addr) of SEST entry
5135 //      *alPair++ |=(ULONG)((physicalAddress.HighPart & 0xFFF8)); 
5136       // on Tachlite TS's local S/G, we can handle 13 extra address bits
5137       // i.e., bits 31-19 are actually bits  44-32 of physicalAddress
5138 
5139       alPair++;
5140 
5141       ulBuff = virt_to_bus( sgl->address);
5142 #if BITS_PER_LONG > 32
5143       if( ulBuff >>32 )
5144       {
5145         printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff );
5146         return 0;
5147       }
5148 #endif
5149       *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
5150 
5151       ++sgl;  // next S/G pair
5152 #ifdef DBG_SEST_SGLIST
5153       printk(" thisLen %d ", thisMappingLen);
5154       printk(" remain %d\n", bytes_to_go);
5155 #endif
5156 
5157     }
5158   }
5159 
5160 
5161 
5162 
5163   else    // more than 3 pairs requires Extended S/G page (Pool Allocation)
5164   {
5165     // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
5166 
5167 
5168     
5169     for( i=2; i<6; i++)
5170       alPair[i] = 0;
5171 
5172     PairCount = TL_EXT_SG_PAGE_COUNT;    // forces initial page allocation
5173 
5174     while( bytes_to_go )
5175     {
5176 
5177 
5178       // Per SEST format, we can support 524287 byte lenghts per
5179       // S/G pair.  Typical user buffers are 4k, and very rarely
5180       // exceed 12k due to fragmentation of physical memory pages.
5181       // However, on certain O/S system (not "user") buffers (on platforms 
5182       // with huge memories like 256Meg), it's possible to exceed this
5183       // length in a single S/G address/len mapping.
5184       //
5185       // Check for Tachyon length boundary
5186       //
5187       if( sgl->length > 0x7ffff )
5188       {
5189         // never ask for more than we can handle
5190         thisMappingLen = sgl->length & 0x7ffff;  
5191       }
5192       else
5193         thisMappingLen = sgl->length;        
5194       
5195 
5196 
5197       // should we load into "this" extended S/G page, or allocate
5198       // new page?
5199 
5200       if( PairCount >= TL_EXT_SG_PAGE_COUNT )
5201       {
5202         // have we exceeded the max possible extended pages?      
5203         if( AllocatedPages >= TL_MAX_SGPAGES)
5204         {
5205           printk("Error: aborted loop on %d Ext. S/G page allocations\n",
5206             AllocatedPages);
5207 
5208           total_data_len = 0;  // failure!! Ext. S/G is All-or-none affair
5209           break; // failed
5210         }
5211         
5212         // Allocate the TL Extended S/G list page from O/S pool.  We have
5213         // to allocated twice what we want to ensure required TL alignment
5214         // (Tachlite TL/TS User Man. Rev 6.0, p 168)
5215         // We store the original allocated PVOID so we can free later
5216 
5217         sgPages->PoolPage[ AllocatedPages] = 
5218           kmalloc( TL_EXT_SG_PAGE_BYTELEN*2,GFP_ATOMIC); // double for alignment
5219 
5220         
5221         if( !sgPages->PoolPage[ AllocatedPages] )  // Allocation failed?
5222         {
5223 
5224           printk("Error: Allocation failed @ %d S/G page allocations\n",
5225             AllocatedPages);
5226 
5227           total_data_len = 0;  // failure!! Ext. S/G is All-or-none affair
5228           break;               // give up
5229         }
5230                                // clear out memory we just allocated                     
5231         memset( sgPages->PoolPage[AllocatedPages], 0,
5232           TL_EXT_SG_PAGE_BYTELEN*2);
5233 
5234       
5235         // align the memory - TL requires sizeof() Ext. S/G page alignment.
5236         // We doubled the actual required size so we could mask off LSBs 
5237         // to get desired offset
5238 
5239         ulBuff = virt_to_bus( sgPages->PoolPage[AllocatedPages]);
5240 
5241 #if BITS_PER_LONG > 32
5242         if( ulBuff >>32 )
5243         {
5244           printk("cqpfcTS: Tach ext. S/G DMA address %p > 32 bits\n", 
5245                   (void*)ulBuff );
5246           return 0;
5247         }
5248 #endif
5249         
5250         ulBuff += TL_EXT_SG_PAGE_BYTELEN; // ensures we pass align. boundary
5251         ulBuff &= (0xFFFFFFFF - (TL_EXT_SG_PAGE_BYTELEN -1) );// mask off LSBs
5252          
5253         alignedPageAddress = (ULONG)ulBuff;
5254 #ifdef DBG_SEST_SGLIST
5255         printk("new PoolPage: %p, alignedPageAddress %lXh\n", 
5256           sgPages->PoolPage[AllocatedPages], ulBuff);
5257 #endif
5258 
5259 
5260         // set pointer, in SEST if first Ext. S/G page, or in last pair
5261         // of linked Ext. S/G pages...
5262         // (Only 32-bit PVOIDs, so just load lower 32 bits)
5263         // NOTE: the Len field must be '' if this is the first Ext. S/G
5264         // pointer in SEST, and not 0 otherwise.
5265         if( alPair == SESTalPairStart) // initial Ext. S/G list?
5266           *alPair = 0;
5267         else // not the SEST entry... Len must be non-0, so
5268              // arbitrarily set it to number bytes remaining
5269           *alPair = ( bytes_to_go & 0x7ffff);
5270 
5271 #ifdef DBG_SEST_SGLIST
5272         printk("PairCount %d @%p even %Xh, ", 
5273           PairCount, alPair, *alPair);
5274 #endif
5275         alPair++;  // next DWORD
5276 
5277         *alPair = alignedPageAddress; // TL needs 32-bit physical
5278 #ifdef DBG_SEST_SGLIST
5279         printk("odd %Xh\n", *alPair);
5280 #endif
5281                    
5282         // now reset the pointer to the ACTUAL (Extended) S/G page
5283         // which will accept the Len/ PhysicalAddress pairs
5284         alPair = bus_to_virt(alignedPageAddress);
5285         
5286         AllocatedPages++;
5287         PairCount = 1;  // starting new Ext. S/G page
5288       }  // end of new TL Ext. S/G page allocation
5289 
5290       
5291       *alPair = thisMappingLen; // bits 18-0, length (range check above)
5292       
5293       
5294 //      physicalAddress.HighPart <= 19;  // shift to bit 19
5295       
5296                    // pick up bits 44-32 of upper 64-bit address
5297                    // and load into 31-19 LBAU (upper addr) of SEST entry
5298 //      *alPair |=(ULONG)((physicalAddress.HighPart & 0xFFF8)); 
5299 
5300       
5301 #ifdef DBG_SEST_SGLIST
5302       printk("PairCount %d @%p, even %Xh, ", 
5303         PairCount, alPair, *alPair);
5304 #endif
5305 
5306       alPair++;    // next DWORD
5307       // on Tachlite TS's local S/G, we can handle 13 extra address bits
5308       // i.e., bits 31-19 are actually bits  44-32 of physicalAddress
5309 
5310 
5311       ulBuff = virt_to_bus( sgl->address);
5312 #if BITS_PER_LONG > 32
5313       if( ulBuff >>32 )
5314       {
5315         printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff );
5316         return 0;
5317       }
5318 #endif
5319       *alPair = (ULONG)ulBuff; // lower 32 bits (31-0)
5320 
5321 
5322 #ifdef DBG_SEST_SGLIST
5323       printk("odd %Xh\n", *alPair);
5324 #endif
5325       alPair++;    // next DWORD
5326                                            
5327 
5328       PairCount++; // next Length/Address pair
5329       bytes_to_go -= thisMappingLen;
5330       total_data_len += thisMappingLen;  
5331       sgl++;  // next S/G pair
5332     }
5333   }
5334   return total_data_len;
5335 }
5336 
5337 
5338 
5339 // The Tachlite SEST table is referenced to OX_ID (or RX_ID).  To optimize
5340 // performance and debuggability, we index the Exchange structure to FC X_ID
5341 // This enables us to build exchanges for later en-queing to Tachyon,
5342 // provided we have an open X_ID slot. At Tachyon queing time, we only 
5343 // need an ERQ slot; then "fix-up" references in the 
5344 // IRB, FCHS, etc. as needed.
5345 // RETURNS:
5346 // 0 if successful
5347 // non-zero on error
5348 //sstartex
5349 ULONG cpqfcTSStartExchange( 
5350   CPQFCHBA *cpqfcHBAdata,                      
5351   LONG ExchangeID )
5352 {
5353   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
5354   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5355   FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
5356   USHORT producer, consumer;
5357   ULONG ulStatus=0;
5358   short int ErqIndex;
5359   BOOLEAN CompleteExchange = FALSE;  // e.g. ACC replies are complete
5360   BOOLEAN SestType=FALSE;
5361   ULONG InboundData=0;
5362 
5363   // We will manipulate Tachlite chip registers here to successfully
5364   // start exchanges. 
5365 
5366   // Check that link is not down -- we can't start an exchange on a
5367   // down link!
5368 
5369   if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
5370   {
5371 printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n",
5372          fcChip->Registers.FMstatus.value & 0xFF,
5373          ExchangeID,
5374          pExchange->type,
5375          pExchange->fchs.d_id);
5376 
5377     if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
5378     {
5379       // Our most popular LinkService commands are port discovery types
5380       // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
5381       // events, so it makes no sense to Que them.  However, ABTS should
5382       // be queued, since exchange sequences are likely destroyed by
5383       // Link Down events, and we want to notify other ports of broken
5384       // sequences by aborting the corresponding exchanges.
5385       if( pExchange->type != BLS_ABTS )
5386       {
5387         ulStatus = LNKDWN_OSLS;
5388         goto Done;
5389         // don't Que most LinkServ exchanges on LINK DOWN
5390       }
5391     }
5392 
5393     printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", 
5394       ExchangeID, pExchange->type);
5395     pExchange->status |= EXCHANGE_QUEUED;
5396     ulStatus = EXCHANGE_QUEUED;
5397     goto Done;
5398   }
5399 
5400   // Make sure ERQ has available space.
5401   
5402   producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
5403   consumer = (USHORT)fcChip->ERQ->consumerIndex;
5404   producer++;  // We are testing for full que by incrementing
5405   
5406   if( producer >= ERQ_LEN )  // rollover condition?
5407     producer = 0;
5408   if( consumer != producer ) // ERQ not full?
5409   {
5410     // ****************** Need Atomic access to chip registers!!********
5411     
5412     // remember ERQ PI for copying IRB
5413     ErqIndex = (USHORT)fcChip->ERQ->producerIndex; 
5414     fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
5415                // we have an ERQ slot! If SCSI command, need SEST slot
5416                // otherwise we are done.
5417 
5418     // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
5419     // set according to direction of data to/from Tachyon for SEST assists.
5420     // For consistency, enforce this rule for Link Service (non-SEST)
5421     // exchanges as well.
5422 
5423     // fix-up the X_ID field in IRB
5424     pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
5425 
5426     // fix-up the X_ID field in fchs -- depends on Originator or Responder,
5427     // outgoing or incoming data?
5428     switch( pExchange->type )
5429     {
5430                // ORIGINATOR types...  we're setting our OX_ID and
5431                // defaulting the responder's RX_ID to 0xFFFF
5432     
5433     case SCSI_IRE:
5434       // Requirement: set MSB of x_ID for Incoming TL data
5435       // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5436       InboundData = 0x8000;
5437 
5438     case SCSI_IWE:   
5439       SestType = TRUE;
5440       pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
5441       pExchange->fchs.ox_rx_id <<= 16;     // MSW shift
5442       pExchange->fchs.ox_rx_id |= 0xffff;  // add default RX_ID
5443       
5444       // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
5445       // (not necessary for IRE -- data buffer unused)
5446       if( pExchange->type == SCSI_IWE)
5447       {
5448         fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id = 
5449           pExchange->fchs.ox_rx_id;
5450 
5451       }
5452 
5453       break;
5454 
5455 
5456     case FCS_NSR:  // ext. link service Name Service Request
5457     case ELS_SCR:  // ext. link service State Change Registration
5458     case ELS_FDISC:// ext. link service login
5459     case ELS_FLOGI:// ext. link service login
5460     case ELS_LOGO: // FC-PH extended link service logout
5461     case BLS_NOP:  // Basic link service No OPeration
5462     case ELS_PLOGI:// ext. link service login (PLOGI)
5463     case ELS_PDISC:// ext. link service login (PDISC)
5464     case ELS_PRLI: // ext. link service process login
5465 
5466       pExchange->fchs.ox_rx_id = ExchangeID;
5467       pExchange->fchs.ox_rx_id <<= 16;  // MSW shift
5468       pExchange->fchs.ox_rx_id |= 0xffff;  // and RX_ID
5469 
5470       break;
5471       
5472 
5473 
5474 
5475                // RESPONDER types... we must set our RX_ID while preserving
5476                // sender's OX_ID
5477                // outgoing (or no) data
5478     case ELS_RJT:       // extended link service reject 
5479     case ELS_LOGO_ACC: // FC-PH extended link service logout accept
5480     case ELS_ACC:      // ext. generic link service accept
5481     case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
5482     case ELS_PRLI_ACC: // ext. link service process login accept
5483 
5484       CompleteExchange = TRUE;   // Reply (ACC or RJT) is end of exchange
5485       pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
5486 
5487       break;
5488 
5489 
5490       // since we are a Responder, OX_ID should already be set by
5491       // cpqfcTSBuildExchange().  We need to -OR- in RX_ID
5492     case SCSI_TWE:
5493       SestType = TRUE;
5494       // Requirement: set MSB of x_ID for Incoming TL data
5495       // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5496 
5497       pExchange->fchs.ox_rx_id &= 0xFFFF0000;  // clear RX_ID
5498       // Requirement: set MSB of RX_ID for Incoming TL data
5499       // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5500       pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
5501       break;
5502           
5503     
5504     case SCSI_TRE:
5505       SestType = TRUE;
5506       
5507       // there is no XRDY for SEST target read; the data
5508       // header needs to be updated. Also update the RSP
5509       // exchange IDs for the status frame, in case it is sent automatically
5510       fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
5511       fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id = 
5512         fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5513       
5514       // for easier FCP response logic (works for TWE and TRE), 
5515       // copy exchange IDs.  (Not needed if TRE 'RSP' bit set)
5516       pExchange->fchs.ox_rx_id =
5517         fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5518 
5519       break;
5520 
5521 
5522     case FCP_RESPONSE:  // using existing OX_ID/ RX_ID pair,
5523                         // start SFS FCP-RESPONSE frame
5524       // OX/RX_ID should already be set! (See "fcBuild" above)
5525       CompleteExchange = TRUE;   // RSP is end of FCP-SCSI exchange
5526 
5527       
5528       break;
5529 
5530 
5531     case BLS_ABTS_RJT:  // uses new RX_ID, since SEST x_ID non-existent
5532     case BLS_ABTS_ACC:  // using existing OX_ID/ RX_ID pair from SEST entry
5533       CompleteExchange = TRUE;   // ACC or RJT marks end of FCP-SCSI exchange
5534     case BLS_ABTS:  // using existing OX_ID/ RX_ID pair from SEST entry
5535 
5536 
5537       break;
5538 
5539 
5540     default:
5541       printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
5542         pExchange->type, pExchange->type);
5543       return INVALID_ARGS;
5544     }
5545     
5546     
5547       // X_ID fields are entered -- copy IRB to Tachyon's ERQ
5548     
5549 
5550     memcpy(
5551         &fcChip->ERQ->QEntry[ ErqIndex ],  // dest.
5552         &pExchange->IRB,
5553         32);  // fixed (hardware) length!
5554 
5555     PCI_TRACEO( ExchangeID, 0xA0)
5556 
5557     // ACTION!  May generate INT and IMQ entry
5558     writel( fcChip->ERQ->producerIndex,
5559           fcChip->Registers.ERQproducerIndex.address);
5560 
5561   
5562     if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
5563     {
5564     
5565       // wait for completion! (TDB -- timeout and chip reset)
5566       
5567 
5568   PCI_TRACEO( ExchangeID, 0xA4)
5569   
5570       enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
5571       
5572       down_interruptible( cpqfcHBAdata->TYOBcomplete); 
5573   
5574       disable_irq( cpqfcHBAdata->HostAdapter->irq);
5575   PCI_TRACE( 0xA4)
5576 
5577       // On login exchanges, BAD_ALPA (non-existent port_id) results in 
5578       // FTO (Frame Time Out) on the Outbound Completion message.
5579       // If we got an FTO status, complete the exchange (free up slot)
5580       if( CompleteExchange ||   // flag from Reply frames
5581           pExchange->status )   // typically, can get FRAME_TO
5582       {
5583         cpqfcTSCompleteExchange( fcChip, ExchangeID);  
5584       }
5585     }
5586 
5587     else                         // SEST Exchange
5588     {
5589       ulStatus = 0;   // ship & pray success (e.g. FCP-SCSI)
5590       
5591       if( CompleteExchange )   // by Type of exchange (e.g. end-of-xchng)
5592       {
5593         cpqfcTSCompleteExchange( fcChip, ExchangeID);  
5594       }
5595        
5596       else
5597         pExchange->status &= ~EXCHANGE_QUEUED;  // clear ExchangeQueued flag 
5598 
5599     }
5600   }
5601 
5602   
5603   else                // ERQ 'producer' = 'consumer' and QUE is full
5604   {
5605     ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
5606   }
5607  
5608 Done: 
5609   PCI_TRACE( 0xA0)
5610   return ulStatus; 
5611 }
5612 
5613 
5614 
5615 
5616 
5617 // Scan fcController->fcExchanges array for a usuable index (a "free"
5618 // exchange).
5619 // Inputs:
5620 //   fcChip - pointer to TachLite chip structure
5621 // Return:
5622 //  index - exchange array element where exchange can be built
5623 //  -1    - exchange array is full
5624 // REMARKS:
5625 // Although this is a (yuk!) linear search, we presume
5626 // that the system will complete exchanges about as quickly as
5627 // they are submitted.  A full Exchange array (and hence, max linear
5628 // search time for free exchange slot) almost guarantees a Fibre problem 
5629 // of some sort.
5630 // In the interest of making exchanges easier to debug, we want a LRU
5631 // (Least Recently Used) scheme.
5632 
5633 
5634 static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
5635 {
5636   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5637   ULONG i;
5638   ULONG ulStatus=-1;  // assume failure
5639 
5640 
5641   if( type == SCSI_IRE ||
5642       type == SCSI_TRE ||
5643       type == SCSI_IWE ||
5644       type == SCSI_TWE)
5645   {
5646         // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
5647     if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
5648       fcChip->fcSestExchangeLRU = 0;
5649     i = fcChip->fcSestExchangeLRU; // typically it's already free!
5650 
5651     if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5652     {
5653       ulStatus = 0; // success!
5654     }
5655     
5656     else
5657     {         // YUK! we need to do a linear search for free element.
5658               // Fragmentation of the fcExchange array is due to excessively
5659               // long completions or timeouts.
5660       
5661       while( TRUE )
5662       {
5663         if( ++i >= TACH_SEST_LEN ) // rollover check
5664           i = 0;  // beginning of SEST X_IDs
5665 
5666 //        printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n", 
5667 //         i, Exchanges->fcExchange[i].type);
5668 
5669         if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5670         {
5671           ulStatus = 0; // success!
5672           break;
5673         }
5674         if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
5675         {
5676           printk( "SEST X_ID space full\n");
5677           break;       // failed - prevent inf. loop
5678         }
5679       }
5680     }
5681     fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
5682   }
5683 
5684   
5685   
5686   else  // Link Service type - X_IDs should be from TACH_SEST_LEN 
5687         // to TACH_MAX_XID
5688   {
5689     if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
5690         fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
5691       fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
5692 
5693     i = fcChip->fcLsExchangeLRU; // typically it's already free!
5694     if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5695     {
5696       ulStatus = 0; // success!
5697     }
5698     
5699     else
5700     {         // YUK! we need to do a linear search for free element
5701               // Fragmentation of the fcExchange array is due to excessively
5702               // long completions or timeouts.
5703       
5704       while( TRUE )
5705       {
5706         if( ++i >= TACH_MAX_XID ) // rollover check
5707           i = TACH_SEST_LEN;// beginning of Link Service X_IDs
5708 
5709 //        printk( "looping for xchng ID: i=%d, type=%Xh\n", 
5710 //         i, Exchanges->fcExchange[i].type);
5711 
5712         if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5713         {
5714           ulStatus = 0; // success!
5715           break;
5716         }
5717         if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
5718         {
5719           printk( "LinkService X_ID space full\n");
5720           break;       // failed - prevent inf. loop
5721         }
5722       }
5723     }
5724     fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
5725 
5726   }
5727 
5728   if( !ulStatus )  // success?
5729     Exchanges->fcExchange[i].type = type; // allocate it.
5730   
5731   else
5732     i = -1;  // error - all exchanges "open"
5733 
5734   return i;  
5735 }
5736 
5737 
5738 
5739 
5740 
5741 // We call this routine to free an Exchange for any reason:
5742 // completed successfully, completed with error, aborted, etc.
5743 
5744 // returns FALSE if Exchange failed and "retry" is acceptable
5745 // returns TRUE if Exchange was successful, or retry is impossible
5746 // (e.g. port/device gone).
5747 //scompleteexchange
5748 
5749 void cpqfcTSCompleteExchange( 
5750        PTACHYON fcChip, 
5751        ULONG x_ID)
5752 {
5753   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5754   
5755   if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
5756   {
5757     if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
5758     {
5759 //      TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
5760       printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
5761                         Exchanges->fcExchange[ x_ID ].type);
5762 
5763       goto CleanUpSestResources;  // this path should be very rare.
5764     }
5765 
5766     // we have Linux Scsi Cmnd ptr..., now check our Exchange status
5767     // to decide how to complete this SEST FCP exchange
5768 
5769     if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
5770                                              // or abnormal exchange completion
5771     {
5772       // set FCP Link statistics
5773      
5774       if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
5775         fcChip->fcStats.timeouts++;
5776       if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
5777         fcChip->fcStats.FC4aborted++;
5778       if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
5779         fcChip->fcStats.CntErrors++;
5780       if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
5781         fcChip->fcStats.linkFailTX++;
5782       if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
5783         fcChip->fcStats.linkFailRX++;
5784       if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
5785         fcChip->fcStats.CntErrors++;
5786 
5787       // First, see if the Scsi upper level initiated an ABORT on this
5788       // exchange...
5789       if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
5790       {
5791         printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", 
5792             x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5793         goto CleanUpSestResources;  // (we don't expect Linux _aborts)
5794       }
5795 
5796       // Did our driver timeout the Exchange, or did Tachyon indicate
5797       // a failure during transmission?  Ask for retry with "SOFT_ERROR"
5798       else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT) 
5799       {
5800 //        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
5801 //            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5802         Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5803       }
5804       
5805       // Did frame(s) for an open exchange arrive in the SFQ,
5806       // meaning the SEST was unable to process them?
5807       else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME) 
5808       {
5809 //        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
5810 //            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5811         Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5812       }
5813       
5814       // Did our driver timeout the Exchange, or did Tachyon indicate
5815       // a failure during transmission?  Ask for retry with "SOFT_ERROR"
5816       else if( 
5817                (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
5818                (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) ||
5819                (Exchanges->fcExchange[ x_ID ].status & FRAME_TO)    ||
5820                (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY)    ||
5821                (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY)    )
5822 
5823 
5824       {
5825 //        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
5826 //            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5827         Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5828 
5829 
5830       }
5831 
5832       // e.g., a LOGOut happened, or device never logged back in.
5833       else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED) 
5834       {
5835 //      printk(" *LOGOut or timeout on login!* ");
5836         // trigger?
5837 //        TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
5838 
5839         Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
5840       }      
5841                 
5842                       
5843       // Did Tachyon indicate a CNT error?  We need further analysis
5844       // to determine if the exchange is acceptable
5845       else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
5846       {
5847         UCHAR ScsiStatus;
5848         FCP_STATUS_RESPONSE *pFcpStatus = 
5849           (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
5850 
5851         ScsiStatus = pFcpStatus->fcp_status >>24;
5852   
5853         // If the command is a SCSI Read/Write type, we don't tolerate
5854         // count errors of any kind; assume the count error is due to
5855         // a dropped frame and ask for retry...
5856         
5857         if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) ||
5858             (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) ||            
5859             (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) ||
5860             (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) )
5861                            &&
5862                      ScsiStatus == 0 )
5863         {
5864           // ask for retry
5865 /*          printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n", 
5866             x_ID, Exchanges->fcExchange[ x_ID ].status,
5867             Exchanges->fcExchange[ x_ID ].Cmnd);*/
5868           Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5869         }
5870         
5871         else  // need more analysis
5872         {
5873           cpqfcTSCheckandSnoopFCP(fcChip, x_ID);  // (will set ->result)
5874         }
5875       }
5876       
5877       // default: NOTE! We don't ever want to get here.  Getting here
5878       // implies something new is happening that we've never had a test
5879       // case for.  Need code maintenance!  Return "ERROR"
5880       else
5881       {
5882         printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p\n", 
5883           Exchanges->fcExchange[ x_ID ].status, x_ID, 
5884           Exchanges->fcExchange[ x_ID ].Cmnd);
5885         Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
5886       }
5887     }
5888     else    // definitely no Tach problem, but perhaps an FCP problem
5889     {
5890       // set FCP Link statistic
5891       fcChip->fcStats.ok++;
5892       cpqfcTSCheckandSnoopFCP( fcChip, x_ID);  // (will set ->result)    
5893     }
5894 
5895     // OK, we've set the Scsi "->result" field, so proceed with calling
5896     // Linux Scsi "done" (if not NULL), and free any kernel memory we
5897     // may have allocated for the exchange.
5898 
5899   PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
5900     // complete the command back to upper Scsi drivers
5901     if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
5902     {
5903       // Calling "done" on an Linux _abort() aborted
5904       // Cmnd causes a kernel panic trying to re-free mem.
5905       // Actually, we shouldn't do anything with an _abort CMND
5906       if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
5907       {
5908         PCI_TRACE(0xAC)
5909         (*Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done)
5910            (Exchanges->fcExchange[ x_ID ].Cmnd);
5911       }
5912       else
5913       {
5914 
5915 //      printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
5916 //                      x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5917       }
5918     }
5919     else{
5920       printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
5921         Exchanges->fcExchange[ x_ID ].type, 
5922         Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);         
5923       printk(" cpqfcTS: Null scsi_done function pointer!\n");
5924     }
5925 
5926 
5927     // Now, clean up non-Scsi_Cmnd items...
5928 CleanUpSestResources:
5929     
5930     // Was an Extended Scatter/Gather page allocated?  We know
5931     // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
5932     if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
5933     {
5934       int i = 0;
5935 
5936       // extended S/G list was used -- Free the allocated ext. S/G pages
5937 
5938       while( fcChip->SEST->sgPages[x_ID].PoolPage[i] && 
5939              (i < TL_MAX_SGPAGES) )
5940       {
5941         kfree( fcChip->SEST->sgPages[x_ID].PoolPage[i]);
5942         fcChip->SEST->sgPages[x_ID].PoolPage[i] = NULL;
5943         i++;
5944       }
5945     }
5946   
5947     Exchanges->fcExchange[ x_ID ].Cmnd = NULL; 
5948   }  // Done with FCP (SEST) exchanges
5949 
5950 
5951   // the remaining logic is common to ALL Exchanges: 
5952   // FCP(SEST) and LinkServ.
5953 
5954   Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!  
5955   Exchanges->fcExchange[ x_ID ].status = 0; 
5956 
5957   PCI_TRACEO( x_ID, 0xAC)
5958      
5959   
5960   return;
5961 }   // (END of CompleteExchange function)
5962  
5963 
5964 
5965 
5966 // Unfortunately, we must snoop all command completions in
5967 // order to manipulate certain return fields, and take note of
5968 // device types, etc., to facilitate the Fibre-Channel to SCSI
5969 // "mapping".  
5970 // (Watch for BIG Endian confusion on some payload fields)
5971 void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
5972 {
5973   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5974   Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
5975   FCP_STATUS_RESPONSE *pFcpStatus = 
5976     (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
5977   UCHAR ScsiStatus;
5978 
5979   ScsiStatus = pFcpStatus->fcp_status >>24;
5980 
5981 #ifdef FCP_COMPLETION_DBG
5982   printk("ScsiStatus = 0x%X\n", ScsiStatus);
5983 #endif  
5984 
5985   // First, check FCP status
5986   if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
5987   {
5988     // check response code (RSP_CODE) -- most popular is bad len
5989     // 1st 4 bytes of rsp info -- only byte 3 interesting
5990     if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
5991     { 
5992 
5993       // do we EVER get here?
5994       printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
5995     }
5996   }
5997 
5998   // for now, go by the ScsiStatus, and manipulate certain
5999   // commands when necessary...
6000   if( ScsiStatus == 0) // SCSI status byte "good"?
6001   {
6002     Cmnd->result = 0; // everything's OK
6003 
6004     if( (Cmnd->cmnd[0] == INQUIRY)) 
6005     {
6006       UCHAR *InquiryData = Cmnd->request_buffer;
6007       PFC_LOGGEDIN_PORT pLoggedInPort;
6008 
6009       // We need to manipulate INQUIRY
6010       // strings for COMPAQ RAID controllers to force
6011       // Linux to scan additional LUNs.  Namely, set
6012       // the Inquiry string byte 2 (ANSI-approved version)
6013       // to 2.
6014 
6015       if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
6016       {
6017         InquiryData[2] = 0x2;  // claim SCSI-2 compliance,
6018                                // so multiple LUNs may be scanned.
6019                                // (no SCSI-2 problems known in CPQ)
6020       }
6021         
6022       // snoop the Inquiry to detect Disk, Tape, etc. type
6023       // (search linked list for the port_id we sent INQUIRY to)
6024       pLoggedInPort = fcFindLoggedInPort( fcChip,
6025         NULL,     // DON'T search Scsi Nexus (we will set it)
6026         Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
6027         NULL,     // DON'T search linked list for FC WWN
6028         NULL);    // DON'T care about end of list
6029  
6030       if( pLoggedInPort )
6031       {
6032         pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
6033       }
6034       else
6035       {
6036         printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
6037           Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
6038       }
6039     }
6040   }
6041 
6042 
6043   // Scsi Status not good -- pass it back to caller 
6044 
6045   else
6046   {
6047     Cmnd->result = ScsiStatus; // SCSI status byte is 1st
6048     
6049     // check for valid "sense" data
6050 
6051     if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID ) 
6052     {            // limit Scsi Sense field length!
6053       int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
6054       
6055       SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ? 
6056         sizeof( Cmnd->sense_buffer) : SenseLen;
6057            
6058 
6059 #ifdef FCP_COMPLETION_DBG           
6060       printk("copy sense_buffer %p, len %d, result %Xh\n",
6061         Cmnd->sense_buffer, SenseLen, Cmnd->result);
6062 #endif    
6063 
6064       // NOTE: There is some dispute over the FCP response
6065       // format.  Most FC devices assume that FCP_RSP_INFO
6066       // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
6067       // is (virtually) always 0 and the field is "invalid".  
6068       // Some other devices assume that
6069       // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
6070       // when the FCP_RSP is invalid (this almost appears to be
6071       // one of those "religious" issues).
6072       // Consequently, we test the usual position of FCP_SNS_INFO
6073       // for 7Xh, since the SCSI sense format says the first
6074       // byte ("error code") should be 0x70 or 0x71.  In practice,
6075       // we find that every device does in fact have 0x70 or 0x71
6076       // in the first byte position, so this test works for all
6077       // FC devices.  
6078       // (This logic is especially effective for the CPQ/DEC HSG80
6079       // & HSG60 controllers).
6080 
6081       if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
6082         memcpy( Cmnd->sense_buffer, 
6083           &pFcpStatus->fcp_sns_info[0], SenseLen);
6084       else
6085       {
6086         unsigned char *sbPtr = 
6087                 (unsigned char *)&pFcpStatus->fcp_sns_info[0];
6088         sbPtr -= 8;  // back up 8 bytes hoping to find the
6089                      // start of the sense buffer
6090         memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
6091       }
6092 
6093       // in the special case of Device Reset, tell upper layer
6094       // to immediately retry (with SOFT_ERROR status)
6095       // look for Sense Key Unit Attention (0x6) with ASC Device
6096       // Reset (0x29)
6097       //            printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
6098       //                    SenseLen, Cmnd->sense_buffer[2], 
6099       //                   Cmnd->sense_buffer[12]);
6100       if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
6101                 (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
6102       {
6103         Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
6104       }
6105  
6106       // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
6107       else if(  ((Cmnd->sense_buffer[2] & 0xF) == 0x4) &&  // "hardware error"
6108                 (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code 
6109       {
6110 //        printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
6111 //              Cmnd->channel, Cmnd->target, Cmnd->lun);
6112         Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
6113       }
6114       
6115     }  // (end of sense len valid)
6116 
6117     // there is no sense data to help out Linux's Scsi layers...
6118     // We'll just return the Scsi status and hope he will "do the 
6119     // right thing"
6120     else
6121     {
6122       // as far as we know, the Scsi status is sufficient
6123       Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
6124     }
6125   }
6126 }
6127 
6128 
6129 
6130 //PPPPPPPPPPPPPPPPPPPPPPPPP  PAYLOAD  PPPPPPPPP
6131 // build data PAYLOAD; SCSI FCP_CMND I.U.
6132 // remember BIG ENDIAN payload - DWord values must be byte-reversed
6133 // (hence the affinity for byte pointer building).
6134 
6135 static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
6136       UCHAR* payload, ULONG type, ULONG fcp_dl )
6137 {
6138   int i;
6139 
6140   
6141   switch( type)
6142   {
6143                   
6144     case SCSI_IWE: 
6145     case SCSI_IRE:        
6146       // 8 bytes FCP_LUN
6147       // Peripheral Device or Volume Set addressing, and LUN mapping
6148       // When the FC port was looked up, we copied address mode
6149       // and any LUN mask to the scratch pad SCp.phase & .mode
6150 
6151       *payload++ = (UCHAR)Cmnd->SCp.phase;
6152 
6153       // Now, because of "lun masking" 
6154       // (aka selective storage presentation),
6155       // the contiguous Linux Scsi lun number may not match the
6156       // device's lun number, so we may have to "map".  
6157       
6158       *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
6159       
6160       // We don't know of anyone in the FC business using these 
6161       // extra "levels" of addressing.  In fact, confusion still exists
6162       // just using the FIRST level... ;-)
6163       
6164       *payload++ = 0;  // 2nd level addressing
6165       *payload++ = 0;
6166       *payload++ = 0;  // 3rd level addressing
6167       *payload++ = 0;
6168       *payload++ = 0;  // 4th level addressing
6169       *payload++ = 0;
6170 
6171       // 4 bytes Control Field FCP_CNTL
6172       *payload++ = 0;    // byte 0: (MSB) reserved
6173       *payload++ = 0;    // byte 1: task codes
6174       *payload++ = 0;    // byte 2: task management flags
6175                       // byte 3: (LSB) execution management codes
6176                       // bit 0 write, bit 1 read (don't set together)
6177       
6178       if( fcp_dl != 0 )
6179       {
6180         if( type == SCSI_IWE )         // WRITE
6181           *payload++ = 1;
6182         else                           // READ
6183           *payload++ = 2;
6184       }
6185       else
6186       {
6187         // On some devices, if RD or WR bits are set,
6188         // and fcp_dl is 0, they will generate an error on the command.
6189         // (i.e., if direction is specified, they insist on a length).
6190         *payload++ = 0;                // no data (necessary for CPQ)
6191       }
6192 
6193 
6194       // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
6195       // FCP_CDB allows 16 byte SCSI command descriptor blk;
6196       // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
6197       for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
6198         *payload++ = Cmnd->cmnd[i];
6199 
6200       if( Cmnd->cmd_len == 16 )
6201       {
6202         memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
6203       }
6204       payload+= (16 - i);  
6205 
6206                       // FCP_DL is largest number of expected data bytes
6207                       // per CDB (i.e. read/write command)
6208       *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
6209       *payload++ = (UCHAR)(fcp_dl >>16);
6210       *payload++ = (UCHAR)(fcp_dl >>8);
6211       *payload++ = (UCHAR)fcp_dl;    // (LSB)
6212       break;
6213 
6214     case SCSI_TWE:          // need FCP_XFER_RDY
6215       *payload++ = 0;     // (4 bytes) DATA_RO (MSB byte 0)
6216       *payload++ = 0;
6217       *payload++ = 0;
6218       *payload++ = 0;     // LSB (byte 3)
6219                              // (4 bytes) BURST_LEN
6220                              // size of following FCP_DATA payload
6221       *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
6222       *payload++ = (UCHAR)(fcp_dl >>16);
6223       *payload++ = (UCHAR)(fcp_dl >>8);
6224       *payload++ = (UCHAR)fcp_dl;    // (LSB)
6225                        // 4 bytes RESERVED
6226       *payload++ = 0;
6227       *payload++ = 0;
6228       *payload++ = 0;
6229       *payload++ = 0;
6230       break;
6231 
6232     default:
6233       break;
6234   }
6235 
6236   return 0;
6237 }
6238 
6239 

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

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