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