- Kai Germaschewski: ISDN update (including Makefiles)
[davej-history.git] / drivers / scsi / cpqfcTSworker.c
blobd3416ab6d7df3212d64486d123a0252215bfd282
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
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.
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
22 #include <linux/sched.h>
23 #include <linux/timer.h>
24 #include <linux/string.h>
25 #include <linux/malloc.h>
26 #include <linux/ioport.h>
27 #include <linux/kernel.h>
28 #include <linux/stat.h>
29 #include <linux/blk.h>
30 #include <linux/interrupt.h>
31 #include <linux/delay.h>
32 #include <linux/smp_lock.h>
34 #define __KERNEL_SYSCALLS__
36 #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
38 #include <linux/unistd.h>
40 #include <asm/system.h>
41 #include <asm/irq.h>
42 #include <asm/dma.h>
46 #include "sd.h"
47 #include "hosts.h" // struct Scsi_Host definition for T handler
48 #include "cpqfcTSchip.h"
49 #include "cpqfcTSstructs.h"
51 //#define LOGIN_DBG 1
53 // REMARKS:
54 // Since Tachyon chips may be permitted to wait from 500ms up to 2 sec
55 // to empty an outgoing frame from its FIFO to the Fibre Channel stream,
56 // we cannot do everything we need to in the interrupt handler. Specifically,
57 // every time a link re-init (e.g. LIP) takes place, all SCSI I/O has to be
58 // suspended until the login sequences have been completed. Login commands
59 // are frames just like SCSI commands are frames; they are subject to the same
60 // timeout issues and delays. Also, various specs provide up to 2 seconds for
61 // devices to log back in (i.e. respond with ACC to a login frame), so I/O to
62 // that device has to be suspended.
63 // A serious problem here occurs on highly loaded FC-AL systems. If our FC port
64 // has a low priority (e.g. high arbitrated loop physical address, alpa), and
65 // some other device is hogging bandwidth (permissible under FC-AL), we might
66 // time out thinking the link is hung, when it's simply busy. Many such
67 // considerations complicate the design. Although Tachyon assumes control
68 // (in silicon) for many link-specific issues, the Linux driver is left with the
69 // rest, which turns out to be a difficult, time critical chore.
71 // These "worker" functions will handle things like FC Logins; all
72 // processes with I/O to our device must wait for the Login to complete
73 // and (if successful) I/O to resume. In the event of a malfunctioning or
74 // very busy loop, it may take hundreds of millisecs or even seconds to complete
75 // a frame send. We don't want to hang up the entire server (and all
76 // processes which don't depend on Fibre) during this wait.
78 // The Tachyon chip can have around 30,000 I/O operations ("exchanges")
79 // open at one time. However, each exchange must be initiated
80 // synchronously (i.e. each of the 30k I/O had to be started one at a
81 // time by sending a starting frame via Tachyon's outbound que).
83 // To accomodate kernel "module" build, this driver limits the exchanges
84 // to 256, because of the contiguous physical memory limitation of 128M.
86 // Typical FC Exchanges are opened presuming the FC frames start without errors,
87 // while Exchange completion is handled in the interrupt handler. This
88 // optimizes performance for the "everything's working" case.
89 // However, when we have FC related errors or hot plugging of FC ports, we pause
90 // I/O and handle FC-specific tasks in the worker thread. These FC-specific
91 // functions will handle things like FC Logins and Aborts. As the Login sequence
92 // completes to each and every target, I/O can resume to that target.
94 // Our kernel "worker thread" must share the HBA with threads calling
95 // "queuecommand". We define a "BoardLock" semaphore which indicates
96 // to "queuecommand" that the HBA is unavailable, and Cmnds are added to a
97 // board lock Q. When the worker thread finishes with the board, the board
98 // lock Q commands are completed with status causing immediate retry.
99 // Typically, the board is locked while Logins are in progress after an
100 // FC Link Down condition. When Cmnds are re-queued after board lock, the
101 // particular Scsi channel/target may or may not have logged back in. When
102 // the device is waiting for login, the "prli" flag is clear, in which case
103 // commands are passed to a Link Down Q. Whenever the login finally completes,
104 // the LinkDown Q is completed, again with status causing immediate retry.
105 // When FC devices are logged in, we build and start FC commands to the
106 // devices.
108 // NOTE!! As of May 2000, kernel 2.2.14, the error recovery logic for devices
109 // that never log back in (e.g. physically removed) is NOT completely
110 // understood. I've still seen instances of system hangs on failed Write
111 // commands (possibly from the ext2 layer?) on device removal. Such special
112 // cases need to be evaluated from a system/application view - e.g., how
113 // exactly does the system want me to complete commands when the device is
114 // physically removed??
116 // local functions
118 static void SetLoginFields(
119 PFC_LOGGEDIN_PORT pLoggedInPort,
120 TachFCHDR_GCMND* fchs,
121 BOOLEAN PDisc,
122 BOOLEAN Originator);
124 static void AnalyzeIncomingFrame(
125 CPQFCHBA *cpqfcHBAdata,
126 ULONG QNdx );
128 static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
130 static int verify_PLOGI( PTACHYON fcChip,
131 TachFCHDR_GCMND* fchs, ULONG* reject_explain);
132 static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
134 static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
135 static void BuildLinkServicePayload(
136 PTACHYON fcChip, ULONG type, void* payload);
138 static void UnblockScsiDevice( struct Scsi_Host *HostAdapter,
139 PFC_LOGGEDIN_PORT pLoggedInPort);
141 static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
143 static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
145 static void RevalidateSEST( struct Scsi_Host *HostAdapter,
146 PFC_LOGGEDIN_PORT pLoggedInPort);
148 static void IssueReportLunsCommand(
149 CPQFCHBA* cpqfcHBAdata,
150 TachFCHDR_GCMND* fchs);
153 // (see scsi_error.c comments on kernel task creation)
155 void cpqfcTSWorkerThread( void *host)
157 struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
158 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
159 #ifdef PCI_KERNEL_TRACE
160 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
161 #endif
162 struct fs_struct *fs;
163 DECLARE_MUTEX_LOCKED(fcQueReady);
164 DECLARE_MUTEX_LOCKED(fcTYOBcomplete);
165 DECLARE_MUTEX_LOCKED(TachFrozen);
166 DECLARE_MUTEX_LOCKED(BoardLock);
168 ENTER("WorkerThread");
170 lock_kernel();
172 * If we were started as result of loading a module, close all of the
173 * user space pages. We don't need them, and if we didn't close them
174 * they would be locked into memory.
176 exit_mm(current);
178 current->session = 1;
179 current->pgrp = 1;
181 /* Become as one with the init task */
183 exit_fs(current); /* current->fs->count--; */
184 fs = init_task.fs;
185 // Some kernels compiled for SMP, while actually running
186 // on a uniproc machine, will return NULL for this call
187 if( !fs)
189 printk(" cpqfcTS FATAL: fs is NULL! Is this an SMP kernel on uniproc machine?\n ");
192 else
194 current->fs = fs;
195 atomic_inc(&fs->count);
198 siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
202 * Set the name of this process.
204 sprintf(current->comm, "cpqfcTS_wt_%d", HostAdapter->host_no);
206 cpqfcHBAdata->fcQueReady = &fcQueReady; // primary wait point
207 cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
208 cpqfcHBAdata->TachFrozen = &TachFrozen;
211 cpqfcHBAdata->worker_thread = current;
213 unlock_kernel();
215 if( cpqfcHBAdata->notify_wt != NULL )
216 up( cpqfcHBAdata->notify_wt); // OK to continue
218 while(1)
220 unsigned long flags;
222 down_interruptible( &fcQueReady); // wait for something to do
224 if (signal_pending(current) )
225 break;
227 PCI_TRACE( 0x90)
228 // first, take the IO lock so the SCSI upper layers can't call
229 // into our _quecommand function (this also disables INTs)
230 spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
231 PCI_TRACE( 0x90)
233 CPQ_SPINLOCK_HBA( cpqfcHBAdata)
234 // next, set this pointer to indicate to the _quecommand function
235 // that the board is in use, so it should que the command and
236 // immediately return (we don't actually require the semaphore function
237 // in this driver rev)
239 cpqfcHBAdata->BoardLock = &BoardLock;
241 PCI_TRACE( 0x90)
243 // release the IO lock (and re-enable interrupts)
244 spin_unlock_irqrestore( &io_request_lock, flags);
246 // disable OUR HBA interrupt (keep them off as much as possible
247 // during error recovery)
248 disable_irq( cpqfcHBAdata->HostAdapter->irq);
250 // OK, let's process the Fibre Channel Link Q and do the work
251 cpqfcTS_WorkTask( HostAdapter);
253 // hopefully, no more "work" to do;
254 // re-enable our INTs for "normal" completion processing
255 enable_irq( cpqfcHBAdata->HostAdapter->irq);
258 cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
259 CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
262 // Now, complete any Cmnd we Q'd up while BoardLock was held
264 CompleteBoardLockCmnd( cpqfcHBAdata);
268 // hopefully, the signal was for our module exit...
269 if( cpqfcHBAdata->notify_wt != NULL )
270 up( cpqfcHBAdata->notify_wt); // yep, we're outta here
274 // Freeze Tachyon routine.
275 // If Tachyon is already frozen, return FALSE
276 // If Tachyon is not frozen, call freeze function, return TRUE
278 static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
280 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
281 BOOLEAN FrozeTach = FALSE;
282 // It's possible that the chip is already frozen; if so,
283 // "Freezing" again will NOT! generate another Freeze
284 // Completion Message.
286 if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
287 { // (need to freeze...)
288 fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
290 // 2. Get Tach freeze confirmation
291 // (synchronize SEST manipulation with Freeze Completion Message)
292 // we need INTs on so semaphore can be set.
293 enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
294 down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
295 // can we TIMEOUT semaphore wait?? TBD
296 disable_irq( cpqfcHBAdata->HostAdapter->irq);
298 FrozeTach = TRUE;
299 } // (else, already frozen)
301 return FrozeTach;
307 // This is the kernel worker thread task, which processes FC
308 // tasks which were queued by the Interrupt handler or by
309 // other WorkTask functions.
311 #define DBG 1
312 //#undef DBG
313 void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
315 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
316 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
317 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
318 ULONG QconsumerNdx;
319 LONG ExchangeID;
320 ULONG ulStatus=0;
321 TachFCHDR_GCMND fchs;
322 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
324 ENTER("WorkTask");
326 // copy current index to work on
327 QconsumerNdx = fcLQ->consumer;
329 PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
332 // NOTE: when this switch completes, we will "consume" the Que item
333 // printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
334 switch( fcLQ->Qitem[QconsumerNdx].Type )
336 // incoming frame - link service (ACC, UNSOL REQ, etc.)
337 // or FCP-SCSI command
338 case SFQ_UNKNOWN:
339 AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
341 break;
345 case EXCHANGE_QUEUED: // an Exchange (i.e. FCP-SCSI) was previously
346 // Queued because the link was down. The
347 // heartbeat timer detected it and Queued it here.
348 // We attempt to start it again, and if
349 // successful we clear the EXCHANGE_Q flag.
350 // If the link doesn't come up, the Exchange
351 // will eventually time-out.
353 ExchangeID = (LONG) // x_ID copied from DPC timeout function
354 fcLQ->Qitem[QconsumerNdx].ulBuff[0];
356 // It's possible that a Q'd exchange could have already
357 // been started by other logic (e.g. ABTS process)
358 // Don't start if already started (Q'd flag clear)
360 if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
362 // printk(" *Start Q'd x_ID %Xh: type %Xh ",
363 // ExchangeID, Exchanges->fcExchange[ExchangeID].type);
365 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
366 if( !ulStatus )
368 // printk("success* ");
370 else
372 #ifdef DBG
374 if( ulStatus == EXCHANGE_QUEUED)
375 printk("Queued* ");
376 else
377 printk("failed* ");
379 #endif
382 break;
385 case LINKDOWN:
386 // (lots of things already done in INT handler) future here?
387 break;
390 case LINKACTIVE: // Tachyon set the Lup bit in FM status
391 // NOTE: some misbehaving FC ports (like Tach2.1)
392 // can re-LIP immediately after a LIP completes.
394 // if "initiator", need to verify LOGs with ports
395 // printk("\n*LNKUP* ");
397 if( fcChip->Options.initiator )
398 SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
399 // if SendLogins successfully completes, PortDiscDone
400 // will be set.
403 // If SendLogins was successful, then we expect to get incoming
404 // ACCepts or REJECTs, which are handled below.
406 break;
408 // LinkService and Fabric request/reply processing
409 case ELS_FDISC: // need to send Fabric Discovery (Login)
410 case ELS_FLOGI: // need to send Fabric Login
411 case ELS_SCR: // need to send State Change Registration
412 case FCS_NSR: // need to send Name Service Request
413 case ELS_PLOGI: // need to send PLOGI
414 case ELS_ACC: // send generic ACCept
415 case ELS_PLOGI_ACC: // need to send ELS ACCept frame to recv'd PLOGI
416 case ELS_PRLI_ACC: // need to send ELS ACCept frame to recv'd PRLI
417 case ELS_LOGO: // need to send ELS LOGO (logout)
418 case ELS_LOGO_ACC: // need to send ELS ACCept frame to recv'd PLOGI
419 case ELS_RJT: // ReJecT reply
420 case ELS_PRLI: // need to send ELS PRLI
423 // printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
424 // if PortDiscDone is not set, it means the SendLogins routine
425 // failed to complete -- assume that LDn occured, so login frames
426 // are invalid
427 if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
429 printk("Discard Q'd ELS login frame\n");
430 break;
433 ulStatus = cpqfcTSBuildExchange(
434 cpqfcHBAdata,
435 fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
436 (TachFCHDR_GCMND*)
437 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
438 NULL, // no data (no scatter/gather list)
439 &ExchangeID );// fcController->fcExchanges index, -1 if failed
441 if( !ulStatus ) // Exchange setup?
443 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
444 if( !ulStatus )
446 // submitted to Tach's Outbound Que (ERQ PI incremented)
447 // waited for completion for ELS type (Login frames issued
448 // synchronously)
450 else
451 // check reason for Exchange not being started - we might
452 // want to Queue and start later, or fail with error
458 else // Xchange setup failed...
459 printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
461 break;
463 case SCSI_REPORT_LUNS:
464 // pass the incoming frame (actually, it's a PRLI frame)
465 // so we can send REPORT_LUNS, in order to determine VSA/PDU
466 // FCP-SCSI Lun address mode
467 IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
468 fcLQ->Qitem[QconsumerNdx].ulBuff);
470 break;
475 case BLS_ABTS: // need to ABORT one or more exchanges
477 LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
478 BOOLEAN FrozeTach = FALSE;
480 if( x_ID > TACH_SEST_LEN ) // (in)sanity check
482 // printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
483 break;
487 if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
489 // printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
491 break; // nothing to abort!
494 //#define ABTS_DBG
495 #ifdef ABTS_DBG
496 printk("INV SEST[%X] ", x_ID);
497 if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
499 printk("FC2TO");
501 if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
503 printk("IA");
505 if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
507 printk("PORTID");
509 if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
511 printk("DEVRM");
513 if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
515 printk("LKF");
517 if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
519 printk("FRMTO");
521 if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
523 printk("ABSQ");
525 if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
527 printk("SFQFR");
530 if( Exchanges->fcExchange[ x_ID].type == 0x2000)
531 printk(" WR");
532 else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
533 printk(" RD");
534 else if( Exchanges->fcExchange[ x_ID].type == 0x10)
535 printk(" ABTS");
536 else
537 printk(" %Xh", Exchanges->fcExchange[ x_ID].type);
539 if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
541 printk(" Cmd %p, ",
542 Exchanges->fcExchange[ x_ID].Cmnd);
544 printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n",
545 cpqfcHBAdata->HBAnum,
546 Exchanges->fcExchange[ x_ID].Cmnd->channel,
547 Exchanges->fcExchange[ x_ID].Cmnd->target,
548 Exchanges->fcExchange[ x_ID].Cmnd->lun,
549 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
551 else // assume that Cmnd ptr is invalid on _abort()
553 printk(" Cmd ptr invalid\n");
556 #endif
559 // Steps to ABORT a SEST exchange:
560 // 1. Freeze TL SCSI assists & ERQ (everything)
561 // 2. Receive FROZEN inbound CM (must succeed!)
562 // 3. Invalidate x_ID SEST entry
563 // 4. Resume TL SCSI assists & ERQ (everything)
564 // 5. Build/start on exchange - change "type" to BLS_ABTS,
565 // timeout to X sec (RA_TOV from PLDA is actually 0)
566 // 6. Set Exchange Q'd status if ABTS cannot be started,
567 // or simply complete Exchange in "Terminate" condition
569 PCI_TRACEO( x_ID, 0xB4)
571 // 1 & 2 . Freeze Tach & get confirmation of freeze
572 FrozeTach = FreezeTach( cpqfcHBAdata);
574 // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
575 // FC2_TIMEOUT means we are originating the abort, while
576 // TARGET_ABORT means we are ACCepting an abort.
577 // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are
578 // all from Tachyon:
579 // Exchange was corrupted by LDn or other FC physical failure
580 // INITIATOR_ABORT means the upper layer driver/application
581 // requested the abort.
585 // clear bit 31 (VALid), to invalidate & take control from TL
586 fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
589 // examine and Tach's "Linked List" for IWEs that
590 // received (nearly) simultaneous transfer ready (XRDY)
591 // repair linked list if necessary (TBD!)
592 // (If we ignore the "Linked List", we will time out
593 // WRITE commands where we received the FCP-SCSI XFRDY
594 // frame (because Tachyon didn't processes it). Linked List
595 // management should be done as an optimization.
597 // readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
602 // 4. Resume all Tachlite functions (for other open Exchanges)
603 // as quickly as possible to allow other exchanges to other ports
604 // to resume. Freezing Tachyon may cause cascading errors, because
605 // any received SEST frame cannot be processed by the SEST.
606 // Don't "unfreeze" unless Link is operational
607 if( FrozeTach ) // did we just freeze it (above)?
608 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
611 PCI_TRACEO( x_ID, 0xB4)
613 // Note there is no confirmation that the chip is "unfrozen". Also,
614 // if the Link is down when unfreeze is called, it has no effect.
615 // Chip will unfreeze when the Link is back up.
617 // 5. Now send out Abort commands if possible
618 // Some Aborts can't be "sent" (Port_id changed or gone);
619 // if the device is gone, there is no port_id to send the ABTS to.
621 if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
623 !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
625 Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
626 fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
627 ulStatus = cpqfcTSBuildExchange(
628 cpqfcHBAdata,
629 BLS_ABTS,
630 &fchs, // (uses only s_id)
631 NULL, // (no scatter/gather list for ABTS)
632 &x_ID );// ABTS on this Exchange ID
634 if( !ulStatus ) // Exchange setup build OK?
637 // ABTS may be needed because an Exchange was corrupted
638 // by a Link disruption. If the Link is UP, we can
639 // presume that this ABTS can start immediately; otherwise,
640 // set Que'd status so the Login functions
641 // can restart it when the FC physical Link is restored
642 if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
644 // printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
645 Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
648 else // what FC device (port_id) does the Cmd belong to?
650 PFC_LOGGEDIN_PORT pLoggedInPort =
651 Exchanges->fcExchange[ x_ID].pLoggedInPort;
653 // if Port is logged in, we might start the abort.
655 if( (pLoggedInPort != NULL)
657 (pLoggedInPort->prli == TRUE) )
659 // it's possible that an Exchange has already been Queued
660 // to start after Login completes. Check and don't
661 // start it (again) here if Q'd status set
662 // printk(" ABTS xchg %Xh ", x_ID);
663 if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
665 // printk("already Q'd ");
667 else
669 // printk("starting ");
671 fcChip->fcStats.FC2aborted++;
672 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
673 if( !ulStatus )
675 // OK
676 // submitted to Tach's Outbound Que (ERQ PI incremented)
678 else
680 /* printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
681 ulStatus, x_ID);
686 else
688 /* printk(" ABTS NOT starting xchg %Xh, %p ",
689 x_ID, pLoggedInPort);
690 if( pLoggedInPort )
691 printk("prli %d ", pLoggedInPort->prli);
696 else // what the #@!
697 { // how do we fail to build an Exchange for ABTS??
698 printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
699 ulStatus, x_ID);
702 else // abort without ABTS -- just complete exchange/Cmnd to Linux
704 // printk(" *Terminating x_ID %Xh on %Xh* ",
705 // x_ID, Exchanges->fcExchange[x_ID].status);
706 cpqfcTSCompleteExchange( fcChip, x_ID);
710 } // end of ABTS case
711 break;
715 case BLS_ABTS_ACC: // need to ACCept one ABTS
716 // (NOTE! this code not updated for Linux yet..)
719 printk(" *ABTS_ACC* ");
720 // 1. Freeze TL
722 fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
724 memcpy( // copy the incoming ABTS frame
725 &fchs,
726 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
727 sizeof( fchs));
729 // 3. OK, Tachyon is frozen so we can invalidate SEST entry
730 // (if necessary)
731 // Status FC2_TIMEOUT means we are originating the abort, while
732 // TARGET_ABORT means we are ACCepting an abort
734 ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
735 // printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
738 // sanity check on received ExchangeID
739 if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
741 // clear bit 31 (VALid), to invalidate & take control from TL
742 // printk("Invalidating SEST exchange %Xh\n", ExchangeID);
743 fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
747 // 4. Resume all Tachlite functions (for other open Exchanges)
748 // as quickly as possible to allow other exchanges to other ports
749 // to resume. Freezing Tachyon for too long may royally screw
750 // up everything!
751 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
753 // Note there is no confirmation that the chip is "unfrozen". Also,
754 // if the Link is down when unfreeze is called, it has no effect.
755 // Chip will unfreeze when the Link is back up.
757 // 5. Now send out Abort ACC reply for this exchange
758 Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
760 fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
761 ulStatus = cpqfcTSBuildExchange(
762 cpqfcHBAdata,
763 BLS_ABTS_ACC,
764 &fchs,
765 NULL, // no data (no scatter/gather list)
766 &ExchangeID );// fcController->fcExchanges index, -1 if failed
768 if( !ulStatus ) // Exchange setup?
770 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
771 if( !ulStatus )
773 // submitted to Tach's Outbound Que (ERQ PI incremented)
774 // waited for completion for ELS type (Login frames issued
775 // synchronously)
777 else
778 // check reason for Exchange not being started - we might
779 // want to Queue and start later, or fail with error
784 break;
787 case BLS_ABTS_RJT: // need to ReJecT one ABTS; reject implies the
788 // exchange doesn't exist in the TARGET context.
789 // ExchangeID has to come from LinkService space.
791 printk(" *ABTS_RJT* ");
792 ulStatus = cpqfcTSBuildExchange(
793 cpqfcHBAdata,
794 BLS_ABTS_RJT,
795 (TachFCHDR_GCMND*)
796 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
797 NULL, // no data (no scatter/gather list)
798 &ExchangeID );// fcController->fcExchanges index, -1 if failed
800 if( !ulStatus ) // Exchange setup OK?
802 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
803 // If it fails, we aren't required to retry.
805 if( ulStatus )
807 printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
809 else
811 printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
815 break;
819 default:
820 break;
821 } // end switch
822 //doNothing:
823 // done with this item - now set the NEXT index
825 if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
827 fcLQ->consumer = 0;
829 else
831 fcLQ->consumer++;
834 PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
836 LEAVE("WorkTask");
837 return;
843 // When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login)
844 // commands come in, post to the LinkQ so that action can be taken outside the
845 // interrupt handler.
846 // This circular Q works like Tachyon's que - the producer points to the next
847 // (unused) entry. Called by Interrupt handler, WorkerThread, Timer
848 // sputlinkq
849 void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
850 int Type,
851 void *QueContent)
853 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
854 // FC_EXCHANGES *Exchanges = fcChip->Exchanges;
855 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
856 ULONG ndx;
858 ENTER("cpqfcTSPutLinkQ");
860 ndx = fcLQ->producer;
862 ndx += 1; // test for Que full
866 if( ndx >= FC_LINKQ_DEPTH ) // rollover test
867 ndx = 0;
869 if( ndx == fcLQ->consumer ) // QUE full test
871 // QUE was full! lost LK command (fatal to logic)
872 fcChip->fcStats.lnkQueFull++;
874 printk("*LinkQ Full!*");
875 TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
878 int i;
879 printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
880 fcLQ->consumer);
882 for( i=0; i< FC_LINKQ_DEPTH; )
884 printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
885 if( (++i %8) == 0) printk("\n");
890 printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
892 else // QUE next element
894 // Prevent certain multiple (back-to-back) requests.
895 // This is important in that we don't want to issue multiple
896 // ABTS for the same Exchange, or do multiple FM inits, etc.
897 // We can never be sure of the timing of events reported to
898 // us by Tach's IMQ, which can depend on system/bus speeds,
899 // FC physical link circumstances, etc.
901 if( (fcLQ->producer != fcLQ->consumer)
903 (Type == FMINIT) )
905 LONG lastNdx; // compute previous producer index
906 if( fcLQ->producer)
907 lastNdx = fcLQ->producer- 1;
908 else
909 lastNdx = FC_LINKQ_DEPTH-1;
912 if( fcLQ->Qitem[lastNdx].Type == FMINIT)
914 // printk(" *skip FMINIT Q post* ");
915 // goto DoneWithPutQ;
920 // OK, add the Q'd item...
922 fcLQ->Qitem[fcLQ->producer].Type = Type;
924 memcpy(
925 fcLQ->Qitem[fcLQ->producer].ulBuff,
926 QueContent,
927 sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
929 fcLQ->producer = ndx; // increment Que producer
931 // set semaphore to wake up Kernel (worker) thread
933 up( cpqfcHBAdata->fcQueReady );
936 //DoneWithPutQ:
938 LEAVE("cpqfcTSPutLinkQ");
944 // reset device ext FC link Q
945 void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
948 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
949 fcLQ->producer = 0;
950 fcLQ->consumer = 0;
958 // When Tachyon gets an unassisted FCP-SCSI frame, post here so
959 // an arbitrary context thread (e.g. IOCTL loopback test function)
960 // can process it.
962 // (NOTE: Not revised for Linux)
963 // This Q works like Tachyon's que - the producer points to the next
964 // (unused) entry.
965 void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
966 int Type,
967 void *QueContent)
969 // CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
970 // PTACHYON fcChip = &cpqfcHBAdata->fcChip;
972 // ULONG ndx;
974 // ULONG *pExchangeID;
975 // LONG ExchangeID;
978 KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
979 ndx = pDevExt->fcScsiQue.producer + 1; // test for Que full
981 if( ndx >= FC_SCSIQ_DEPTH ) // rollover test
982 ndx = 0;
984 if( ndx == pDevExt->fcScsiQue.consumer ) // QUE full test
986 // QUE was full! lost LK command (fatal to logic)
987 fcChip->fcStats.ScsiQueFull++;
988 #ifdef DBG
989 printk( "fcPutScsiQue - FULL!\n");
990 #endif
993 else // QUE next element
995 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].Type = Type;
997 if( Type == FCP_RSP )
999 // this TL inbound message type means that a TL SEST exchange has
1000 // copied an FCP response frame into a buffer pointed to by the SEST
1001 // entry. That buffer is allocated in the SEST structure at ->RspHDR.
1002 // Copy the RspHDR for use by the Que handler.
1003 pExchangeID = (ULONG *)QueContent;
1005 memcpy(
1006 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
1007 &fcChip->SEST->RspHDR[ *pExchangeID ],
1008 sizeof(pDevExt->fcScsiQue.Qitem[0].ulBuff)); // (any element for size)
1011 else
1013 memcpy(
1014 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
1015 QueContent,
1016 sizeof(pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff));
1019 pDevExt->fcScsiQue.producer = ndx; // increment Que
1022 KeSetEvent( &pDevExt->TYIBscsi, // signal any waiting thread
1023 0, // no priority boost
1024 FALSE ); // no waiting later for this event
1026 KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
1036 static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
1038 static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
1040 static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
1042 void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
1043 PFC_LOGGEDIN_PORT pFcPort)
1045 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1047 if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
1049 fcChip->fcStats.logouts++;
1050 printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n",
1051 (ULONG)pFcPort->u.liWWN,
1052 (ULONG)(pFcPort->u.liWWN >>32),
1053 pFcPort->port_id);
1055 // Terminate I/O with this (Linux) Scsi target
1056 cpqfcTSTerminateExchange( cpqfcHBAdata,
1057 &pFcPort->ScsiNexus,
1058 DEVICE_REMOVED);
1061 // Do an "implicit logout" - we can't really Logout the device
1062 // (i.e. with LOGOut Request) because of port_id confusion
1063 // (i.e. the Other port has no port_id).
1064 // A new login for that WWN will have to re-write port_id (0 invalid)
1065 pFcPort->port_id = 0; // invalid!
1066 pFcPort->pdisc = FALSE;
1067 pFcPort->prli = FALSE;
1068 pFcPort->plogi = FALSE;
1069 pFcPort->flogi = FALSE;
1070 pFcPort->LOGO_timer = 0;
1071 pFcPort->device_blocked = TRUE; // block Scsi Requests
1075 // On FC-AL, there is a chance that a previously known device can
1076 // be quietly removed (e.g. with non-managed hub),
1077 // while a NEW device (with different WWN) took the same alpa or
1078 // even 24-bit port_id. This chance is unlikely but we must always
1079 // check for it.
1080 static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
1081 PFC_LOGGEDIN_PORT pLoggedInPort)
1083 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1084 // set "other port" at beginning of fcPorts list
1085 PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
1086 while( pOtherPortWithPortId )
1088 if( (pOtherPortWithPortId->port_id ==
1089 pLoggedInPort->port_id)
1091 (pOtherPortWithPortId != pLoggedInPort) )
1093 // trouble! (Implicitly) Log the other guy out
1094 printk(" *port_id %Xh is duplicated!* ",
1095 pOtherPortWithPortId->port_id);
1096 cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId);
1098 pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
1107 // Dynamic Memory Allocation for newly discovered FC Ports.
1108 // For simplicity, maintain fcPorts structs for ALL
1109 // for discovered devices, including those we never do I/O with
1110 // (e.g. Fabric addresses)
1112 static PFC_LOGGEDIN_PORT CreateFcPort(
1113 CPQFCHBA* cpqfcHBAdata,
1114 PFC_LOGGEDIN_PORT pLastLoggedInPort,
1115 TachFCHDR_GCMND* fchs,
1116 LOGIN_PAYLOAD* plogi)
1118 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1119 PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
1120 int i;
1123 printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
1124 for( i=3; i>=0; i--) // copy the LOGIN port's WWN
1125 printk("%02X", plogi->port_name[i]);
1126 for( i=7; i>3; i--) // copy the LOGIN port's WWN
1127 printk("%02X", plogi->port_name[i]);
1130 // allocate mem for new port
1131 // (these are small and rare allocations...)
1132 pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
1135 // allocation succeeded? Fill out NEW PORT
1136 if( pNextLoggedInPort )
1138 // clear out any garbage (sometimes exists)
1139 memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
1142 // If we login to a Fabric, we don't want to treat it
1143 // as a SCSI device...
1144 if( (fchs->s_id & 0xFFF000) != 0xFFF000)
1146 int i;
1148 // create a unique "virtual" SCSI Nexus (for now, just a
1149 // new target ID) -- we will update channel/target on REPORT_LUNS
1150 // special case for very first SCSI target...
1151 if( cpqfcHBAdata->HostAdapter->max_id == 0)
1153 pNextLoggedInPort->ScsiNexus.target = 0;
1154 fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
1156 else
1158 pNextLoggedInPort->ScsiNexus.target =
1159 cpqfcHBAdata->HostAdapter->max_id;
1162 // initialize the lun[] Nexus struct for lun masking
1163 for( i=0; i< CPQFCTS_MAX_LUN; i++)
1164 pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
1166 pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
1168 printk(" SCSI Chan/Trgt %d/%d",
1169 pNextLoggedInPort->ScsiNexus.channel,
1170 pNextLoggedInPort->ScsiNexus.target);
1172 // tell Scsi layers about the new target...
1173 cpqfcHBAdata->HostAdapter->max_id++;
1174 // printk("HostAdapter->max_id = %d\n",
1175 // cpqfcHBAdata->HostAdapter->max_id);
1177 else
1179 // device is NOT SCSI (in case of Fabric)
1180 pNextLoggedInPort->ScsiNexus.target = -1; // invalid
1183 // create forward link to new port
1184 pLastLoggedInPort->pNextPort = pNextLoggedInPort;
1185 printk("\n");
1188 return pNextLoggedInPort; // NULL on allocation failure
1189 } // end NEW PORT (WWN) logic
1193 // For certain cases, we want to terminate exchanges without
1194 // sending ABTS to the device. Examples include when an FC
1195 // device changed it's port_id after Loop re-init, or when
1196 // the device sent us a logout. In the case of changed port_id,
1197 // we want to complete the command and return SOFT_ERROR to
1198 // force a re-try. In the case of LOGOut, we might return
1199 // BAD_TARGET if the device is really gone.
1200 // Since we must ensure that Tachyon is not operating on the
1201 // exchange, we have to freeze the chip
1202 // sterminateex
1203 void cpqfcTSTerminateExchange(
1204 CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
1206 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1207 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1208 ULONG x_ID;
1210 if( ScsiNexus )
1212 // printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
1213 // ScsiNexus->channel, ScsiNexus->target);
1217 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
1219 if( Exchanges->fcExchange[x_ID].type ) // in use?
1221 if( ScsiNexus == NULL ) // our HBA changed - term. all
1223 Exchanges->fcExchange[x_ID].status = TerminateStatus;
1224 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID );
1226 else
1228 // If a device, according to WWN, has been removed, it's
1229 // port_id may be used by another working device, so we
1230 // have to terminate by SCSI target, NOT port_id.
1231 if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
1233 if( (Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
1235 (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel))
1237 Exchanges->fcExchange[x_ID].status = TerminateStatus;
1238 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
1242 // (in case we ever need it...)
1243 // all SEST structures have a remote node ID at SEST DWORD 2
1244 // if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
1245 // == port_id)
1252 static void ProcessELS_Request(
1253 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1255 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1256 // FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1257 // ULONG ox_id = (fchs->ox_rx_id >>16);
1258 PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
1259 BOOLEAN NeedReject = FALSE;
1260 ULONG ls_reject_code = 0; // default don'n know??
1263 // Check the incoming frame for a supported ELS type
1264 switch( fchs->pl[0] & 0xFFFF)
1266 case 0x0050: // PDISC?
1268 // Payload for PLOGI and PDISC is identical (request & reply)
1269 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1271 LOGIN_PAYLOAD logi; // FC-PH Port Login
1273 // PDISC payload OK. If critical login fields
1274 // (e.g. WWN) matches last login for this port_id,
1275 // we may resume any prior exchanges
1276 // with the other port
1279 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1281 pLoggedInPort = fcFindLoggedInPort(
1282 fcChip,
1283 NULL, // don't search Scsi Nexus
1284 0, // don't search linked list for port_id
1285 &logi.port_name[0], // search linked list for WWN
1286 &pLastLoggedInPort); // must return non-NULL; when a port_id
1287 // is not found, this pointer marks the
1288 // end of the singly linked list
1290 if( pLoggedInPort != NULL) // WWN found (prior login OK)
1293 if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1295 // Yes. We were expecting PDISC?
1296 if( pLoggedInPort->pdisc )
1298 // Yes; set fields accordingly. (PDISC, not Originator)
1299 SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
1301 // send 'ACC' reply
1302 cpqfcTSPutLinkQue( cpqfcHBAdata,
1303 ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1304 fchs );
1306 // OK to resume I/O...
1308 else
1310 printk("Not expecting PDISC (pdisc=FALSE)\n");
1311 NeedReject = TRUE;
1312 // set reject reason code
1313 ls_reject_code =
1314 LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1317 else
1319 if( pLoggedInPort->port_id != 0)
1321 printk("PDISC PortID change: old %Xh, new %Xh\n",
1322 pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1324 NeedReject = TRUE;
1325 // set reject reason code
1326 ls_reject_code =
1327 LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1331 else
1333 printk("PDISC Request from unknown WWN\n");
1334 NeedReject = TRUE;
1336 // set reject reason code
1337 ls_reject_code =
1338 LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
1342 else // Payload unacceptable
1344 printk("payload unacceptable\n");
1345 NeedReject = TRUE; // reject code already set
1349 if( NeedReject)
1351 ULONG port_id;
1352 // The PDISC failed. Set login struct flags accordingly,
1353 // terminate any I/O to this port, and Q a PLOGI
1354 if( pLoggedInPort )
1356 pLoggedInPort->pdisc = FALSE;
1357 pLoggedInPort->prli = FALSE;
1358 pLoggedInPort->plogi = FALSE;
1360 cpqfcTSTerminateExchange( cpqfcHBAdata,
1361 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1362 port_id = pLoggedInPort->port_id;
1364 else
1366 port_id = fchs->s_id &0xFFFFFF;
1368 fchs->reserved = ls_reject_code; // borrow this (unused) field
1369 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1372 break;
1376 case 0x0003: // PLOGI?
1378 // Payload for PLOGI and PDISC is identical (request & reply)
1379 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1381 LOGIN_PAYLOAD logi; // FC-PH Port Login
1382 BOOLEAN NeedReject = FALSE;
1384 // PDISC payload OK. If critical login fields
1385 // (e.g. WWN) matches last login for this port_id,
1386 // we may resume any prior exchanges
1387 // with the other port
1390 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1392 pLoggedInPort = fcFindLoggedInPort(
1393 fcChip,
1394 NULL, // don't search Scsi Nexus
1395 0, // don't search linked list for port_id
1396 &logi.port_name[0], // search linked list for WWN
1397 &pLastLoggedInPort); // must return non-NULL; when a port_id
1398 // is not found, this pointer marks the
1399 // end of the singly linked list
1401 if( pLoggedInPort == NULL) // WWN not found -New Port
1403 pLoggedInPort = CreateFcPort(
1404 cpqfcHBAdata,
1405 pLastLoggedInPort,
1406 fchs,
1407 &logi);
1408 if( pLoggedInPort == NULL )
1410 printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1411 // Now Q a LOGOut Request, since we won't be talking to that device
1413 NeedReject = TRUE;
1415 // set reject reason code
1416 ls_reject_code =
1417 LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
1421 if( !NeedReject )
1424 // OK - we have valid fcPort ptr; set fields accordingly.
1425 // (not PDISC, not Originator)
1426 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1428 // send 'ACC' reply
1429 cpqfcTSPutLinkQue( cpqfcHBAdata,
1430 ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1431 fchs );
1434 else // Payload unacceptable
1436 printk("payload unacceptable\n");
1437 NeedReject = TRUE; // reject code already set
1440 if( NeedReject)
1442 // The PDISC failed. Set login struct flags accordingly,
1443 // terminate any I/O to this port, and Q a PLOGI
1444 pLoggedInPort->pdisc = FALSE;
1445 pLoggedInPort->prli = FALSE;
1446 pLoggedInPort->plogi = FALSE;
1448 fchs->reserved = ls_reject_code; // borrow this (unused) field
1450 // send 'RJT' reply
1451 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1454 // terminate any exchanges with this device...
1455 if( pLoggedInPort )
1457 cpqfcTSTerminateExchange( cpqfcHBAdata,
1458 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1460 break;
1464 case 0x1020: // PRLI?
1466 BOOLEAN NeedReject = TRUE;
1467 pLoggedInPort = fcFindLoggedInPort(
1468 fcChip,
1469 NULL, // don't search Scsi Nexus
1470 (fchs->s_id & 0xFFFFFF), // search linked list for port_id
1471 NULL, // DON'T search linked list for WWN
1472 NULL); // don't care
1474 if( pLoggedInPort == NULL )
1476 // huh?
1477 printk(" Unexpected PRLI Request -not logged in!\n");
1479 // set reject reason code
1480 ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1482 // Q a LOGOut here?
1484 else
1486 // verify the PRLI ACC payload
1487 if( !verify_PRLI( fchs, &ls_reject_code) )
1489 // PRLI Reply is acceptable; were we expecting it?
1490 if( pLoggedInPort->plogi )
1492 // yes, we expected the PRLI ACC (not PDISC; not Originator)
1493 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1495 // Q an ACCept Reply
1496 cpqfcTSPutLinkQue( cpqfcHBAdata,
1497 ELS_PRLI_ACC,
1498 fchs );
1500 NeedReject = FALSE;
1502 else
1504 // huh?
1505 printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
1507 // set reject reason code
1508 ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1510 // Q a LOGOut here?
1514 else
1516 printk(" PRLI REQUEST payload failed verify\n");
1517 // (reject code set by "verify")
1519 // Q a LOGOut here?
1523 if( NeedReject )
1525 // Q a ReJecT Reply with reason code
1526 fchs->reserved = ls_reject_code;
1527 cpqfcTSPutLinkQue( cpqfcHBAdata,
1528 ELS_RJT, // Q Type
1529 fchs );
1532 break;
1537 case 0x0005: // LOGOut?
1539 // was this LOGOUT because we sent a ELS_PDISC to an FC device
1540 // with changed (or new) port_id, or does the port refuse
1541 // to communicate to us?
1542 // We maintain a logout counter - if we get 3 consecutive LOGOuts,
1543 // give up!
1544 LOGOUT_PAYLOAD logo;
1545 BOOLEAN GiveUpOnDevice = FALSE;
1546 ULONG ls_reject_code = 0;
1548 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
1550 pLoggedInPort = fcFindLoggedInPort(
1551 fcChip,
1552 NULL, // don't search Scsi Nexus
1553 0, // don't search linked list for port_id
1554 &logo.port_name[0], // search linked list for WWN
1555 NULL); // don't care about end of list
1557 if( pLoggedInPort ) // found the device?
1559 // Q an ACC reply
1560 cpqfcTSPutLinkQue( cpqfcHBAdata,
1561 ELS_LOGO_ACC, // Q Type
1562 fchs ); // device to respond to
1564 // set login struct fields (LOGO_counter increment)
1565 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1567 // are we an Initiator?
1568 if( fcChip->Options.initiator)
1570 // we're an Initiator, so check if we should
1571 // try (another?) login
1573 // Fabrics routinely log out from us after
1574 // getting device info - don't try to log them
1575 // back in.
1576 if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
1578 ; // do nothing
1580 else if( pLoggedInPort->LOGO_counter <= 3)
1582 // try (another) login (PLOGI request)
1584 cpqfcTSPutLinkQue( cpqfcHBAdata,
1585 ELS_PLOGI, // Q Type
1586 fchs );
1588 // Terminate I/O with "retry" potential
1589 cpqfcTSTerminateExchange( cpqfcHBAdata,
1590 &pLoggedInPort->ScsiNexus,
1591 PORTID_CHANGED);
1593 else
1595 printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
1596 fchs->s_id &&0xFFFFFF);
1597 GiveUpOnDevice = TRUE;
1600 else
1602 GiveUpOnDevice = TRUE;
1606 if( GiveUpOnDevice == TRUE )
1608 cpqfcTSTerminateExchange( cpqfcHBAdata,
1609 &pLoggedInPort->ScsiNexus,
1610 DEVICE_REMOVED);
1613 else // we don't know this WWN!
1615 // Q a ReJecT Reply with reason code
1616 fchs->reserved = ls_reject_code;
1617 cpqfcTSPutLinkQue( cpqfcHBAdata,
1618 ELS_RJT, // Q Type
1619 fchs );
1622 break;
1627 // FABRIC only case
1628 case 0x0461: // ELS RSCN (Registered State Change Notification)?
1630 int Ports;
1631 int i;
1632 __u32 Buff;
1633 // Typically, one or more devices have been added to or dropped
1634 // from the Fabric.
1635 // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
1636 // The first 32-bit word has a 2-byte Payload Length, which
1637 // includes the 4 bytes of the first word. Consequently,
1638 // this PL len must never be less than 4, must be a multiple of 4,
1639 // and has a specified max value 256.
1640 // (Endianess!)
1641 Ports = ((fchs->pl[0] >>24) - 4) / 4;
1642 Ports = Ports > 63 ? 63 : Ports;
1644 printk(" RSCN ports: %d\n", Ports);
1645 if( Ports <= 0 ) // huh?
1647 // ReJecT the command
1648 fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
1650 cpqfcTSPutLinkQue( cpqfcHBAdata,
1651 ELS_RJT, // Q Type
1652 fchs );
1654 break;
1656 else // Accept the command
1658 cpqfcTSPutLinkQue( cpqfcHBAdata,
1659 ELS_ACC, // Q Type
1660 fchs );
1663 // Check the "address format" to determine action.
1664 // We have 3 cases:
1665 // 0 = Port Address; 24-bit address of affected device
1666 // 1 = Area Address; MS 16 bits valid
1667 // 2 = Domain Address; MS 8 bits valid
1668 for( i=0; i<Ports; i++)
1670 BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
1671 switch( Buff & 0xFF000000)
1674 case 0: // Port Address?
1676 case 0x01000000: // Area Domain?
1677 case 0x02000000: // Domain Address
1678 // For example, "port_id" 0x201300
1679 // OK, let's try a Name Service Request (Query)
1680 fchs->s_id = 0xFFFFFC; // Name Server Address
1681 cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
1683 break;
1686 default: // huh? new value on version change?
1687 break;
1691 break;
1696 default: // don't support this request (yet)
1697 // set reject reason code
1698 fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM,
1699 REQUEST_NOT_SUPPORTED);
1701 cpqfcTSPutLinkQue( cpqfcHBAdata,
1702 ELS_RJT, // Q Type
1703 fchs );
1704 break;
1709 static void ProcessELS_Reply(
1710 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1712 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1713 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1714 ULONG ox_id = (fchs->ox_rx_id >>16);
1715 ULONG ls_reject_code;
1716 PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
1718 // If this is a valid reply, then we MUST have sent a request.
1719 // Verify that we can find a valid request OX_ID corresponding to
1720 // this reply
1723 if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
1725 printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ",
1726 ox_id, fchs->ox_rx_id & 0xffff);
1727 goto Quit; // exit this routine
1731 // Is the reply a RJT (reject)?
1732 if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
1734 // ****** REJECT REPLY ********
1735 switch( Exchanges->fcExchange[ox_id].type )
1738 case ELS_FDISC: // we sent out Fabric Discovery
1739 case ELS_FLOGI: // we sent out FLOGI
1741 printk("RJT received on Fabric Login from %Xh, reason %Xh\n",
1742 fchs->s_id, fchs->pl[1]);
1744 break;
1746 default:
1747 break;
1750 goto Done;
1753 // OK, we have an ACCept...
1754 // What's the ACC type? (according to what we sent)
1755 switch( Exchanges->fcExchange[ox_id].type )
1758 case ELS_PLOGI: // we sent out PLOGI
1759 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1761 LOGIN_PAYLOAD logi; // FC-PH Port Login
1763 // login ACC payload acceptable; search for WWN in our list
1764 // of fcPorts
1766 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1768 pLoggedInPort = fcFindLoggedInPort(
1769 fcChip,
1770 NULL, // don't search Scsi Nexus
1771 0, // don't search linked list for port_id
1772 &logi.port_name[0], // search linked list for WWN
1773 &pLastLoggedInPort); // must return non-NULL; when a port_id
1774 // is not found, this pointer marks the
1775 // end of the singly linked list
1777 if( pLoggedInPort == NULL) // WWN not found - new port
1780 pLoggedInPort = CreateFcPort(
1781 cpqfcHBAdata,
1782 pLastLoggedInPort,
1783 fchs,
1784 &logi);
1786 if( pLoggedInPort == NULL )
1788 printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1789 // Now Q a LOGOut Request, since we won't be talking to that device
1791 goto Done; // exit with error! dropped login frame
1794 else // WWN was already known. Ensure that any open
1795 // exchanges for this WWN are terminated.
1796 // NOTE: It's possible that a device can change its
1797 // 24-bit port_id after a Link init or Fabric change
1798 // (e.g. LIP or Fabric RSCN). In that case, the old
1799 // 24-bit port_id may be duplicated, or no longer exist.
1802 cpqfcTSTerminateExchange( cpqfcHBAdata,
1803 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1806 // We have an fcPort struct - set fields accordingly
1807 // not PDISC, originator
1808 SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1810 // We just set a "port_id"; is it duplicated?
1811 TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1813 // For Fabric operation, we issued PLOGI to 0xFFFFFC
1814 // so we can send SCR (State Change Registration)
1815 // Check for this special case...
1816 if( fchs->s_id == 0xFFFFFC )
1818 // PLOGI ACC was a Fabric response... issue SCR
1819 fchs->s_id = 0xFFFFFD; // address for SCR
1820 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
1823 else
1825 // Now we need a PRLI to enable FCP-SCSI operation
1826 // set flags and Q up a ELS_PRLI
1827 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
1830 else
1832 // login payload unacceptable - reason in ls_reject_code
1833 // Q up a Logout Request
1834 printk("Login Payload unacceptable\n");
1837 break;
1840 // PDISC logic very similar to PLOGI, except we never want
1841 // to allocate mem for "new" port, and we set flags differently
1842 // (might combine later with PLOGI logic for efficiency)
1843 case ELS_PDISC: // we sent out PDISC
1844 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1846 LOGIN_PAYLOAD logi; // FC-PH Port Login
1847 BOOLEAN NeedLogin = FALSE;
1849 // login payload acceptable; search for WWN in our list
1850 // of (previously seen) fcPorts
1852 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1854 pLoggedInPort = fcFindLoggedInPort(
1855 fcChip,
1856 NULL, // don't search Scsi Nexus
1857 0, // don't search linked list for port_id
1858 &logi.port_name[0], // search linked list for WWN
1859 &pLastLoggedInPort); // must return non-NULL; when a port_id
1860 // is not found, this pointer marks the
1861 // end of the singly linked list
1863 if( pLoggedInPort != NULL) // WWN found?
1865 // WWN has same port_id as last login? (Of course, a properly
1866 // working FC device should NEVER ACCept a PDISC if it's
1867 // port_id changed, but check just in case...)
1868 if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1870 // Yes. We were expecting PDISC?
1871 if( pLoggedInPort->pdisc )
1873 int i;
1876 // PDISC expected -- set fields. (PDISC, Originator)
1877 SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
1879 // We are ready to resume FCP-SCSI to this device...
1880 // Do we need to start anything that was Queued?
1882 for( i=0; i< TACH_SEST_LEN; i++)
1884 // see if any exchange for this PDISC'd port was queued
1885 if( ((fchs->s_id &0xFFFFFF) ==
1886 (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
1888 (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
1890 fchs->reserved = i; // copy ExchangeID
1891 // printk(" *Q x_ID %Xh after PDISC* ",i);
1893 cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
1897 // Complete commands Q'd while we were waiting for Login
1899 UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
1901 else
1903 printk("Not expecting PDISC (pdisc=FALSE)\n");
1904 NeedLogin = TRUE;
1907 else
1909 printk("PDISC PortID change: old %Xh, new %Xh\n",
1910 pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1911 NeedLogin = TRUE;
1915 else
1917 printk("PDISC ACC from unknown WWN\n");
1918 NeedLogin = TRUE;
1921 if( NeedLogin)
1924 // The PDISC failed. Set login struct flags accordingly,
1925 // terminate any I/O to this port, and Q a PLOGI
1926 if( pLoggedInPort ) // FC device previously known?
1929 cpqfcTSPutLinkQue( cpqfcHBAdata,
1930 ELS_LOGO, // Q Type
1931 fchs ); // has port_id to send to
1933 // There are a variety of error scenarios which can result
1934 // in PDISC failure, so as a catchall, add the check for
1935 // duplicate port_id.
1936 TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1938 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
1939 pLoggedInPort->pdisc = FALSE;
1940 pLoggedInPort->prli = FALSE;
1941 pLoggedInPort->plogi = FALSE;
1943 cpqfcTSTerminateExchange( cpqfcHBAdata,
1944 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1946 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
1949 else
1951 // login payload unacceptable - reason in ls_reject_code
1952 // Q up a Logout Request
1953 printk("ERROR: Login Payload unacceptable!\n");
1957 break;
1961 case ELS_PRLI: // we sent out PRLI
1964 pLoggedInPort = fcFindLoggedInPort(
1965 fcChip,
1966 NULL, // don't search Scsi Nexus
1967 (fchs->s_id & 0xFFFFFF), // search linked list for port_id
1968 NULL, // DON'T search linked list for WWN
1969 NULL); // don't care
1971 if( pLoggedInPort == NULL )
1973 // huh?
1974 printk(" Unexpected PRLI ACCept frame!\n");
1976 // Q a LOGOut here?
1978 goto Done;
1981 // verify the PRLI ACC payload
1982 if( !verify_PRLI( fchs, &ls_reject_code) )
1984 // PRLI Reply is acceptable; were we expecting it?
1985 if( pLoggedInPort->plogi )
1987 // yes, we expected the PRLI ACC (not PDISC; Originator)
1988 SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1990 // OK, let's send a REPORT_LUNS command to determine
1991 // whether VSA or PDA FCP-LUN addressing is used.
1993 cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
1995 // It's possible that a device we were talking to changed
1996 // port_id, and has logged back in. This function ensures
1997 // that I/O will resume.
1998 UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
2001 else
2003 // huh?
2004 printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
2006 // Q a LOGOut here?
2007 goto Done;
2010 else
2012 printk(" PRLI ACCept payload failed verify\n");
2014 // Q a LOGOut here?
2017 break;
2019 case ELS_FLOGI: // we sent out FLOGI (Fabric Login)
2021 // update the upper 16 bits of our port_id in Tachyon
2022 // the switch adds those upper 16 bits when responding
2023 // to us (i.e. we are the destination_id)
2024 fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
2025 writel( fcChip->Registers.my_al_pa,
2026 fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
2028 // now send out a PLOGI to the well known port_id 0xFFFFFC
2029 fchs->s_id = 0xFFFFFC;
2030 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
2032 break;
2035 case ELS_FDISC: // we sent out FDISC (Fabric Discovery (Login))
2037 printk( " ELS_FDISC success ");
2038 break;
2041 case ELS_SCR: // we sent out State Change Registration
2042 // now we can issue Name Service Request to find any
2043 // Fabric-connected devices we might want to login to.
2046 fchs->s_id = 0xFFFFFC; // Name Server Address
2047 cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
2050 break;
2053 default:
2054 printk(" *Discarding unknown ACC frame, xID %04X/%04X* ",
2055 ox_id, fchs->ox_rx_id & 0xffff);
2056 break;
2060 Done:
2061 // Regardless of whether the Reply is valid or not, the
2062 // the exchange is done - complete
2063 cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete
2065 Quit:
2066 return;
2074 // **************** Fibre Channel Services **************
2075 // This is where we process the Directory (Name) Service Reply
2076 // to know which devices are on the Fabric
2078 static void ProcessFCS_Reply(
2079 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
2081 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2082 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2083 ULONG ox_id = (fchs->ox_rx_id >>16);
2084 // ULONG ls_reject_code;
2085 // PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
2087 // If this is a valid reply, then we MUST have sent a request.
2088 // Verify that we can find a valid request OX_ID corresponding to
2089 // this reply
2091 if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
2093 printk(" *Discarding Reply frame, xID %04X/%04X* ",
2094 ox_id, fchs->ox_rx_id & 0xffff);
2095 goto Quit; // exit this routine
2099 // OK, we were expecting it. Now check to see if it's a
2100 // "Name Service" Reply, and if so force a re-validation of
2101 // Fabric device logins (i.e. Start the login timeout and
2102 // send PDISC or PLOGI)
2103 // (Endianess Byte Swap?)
2104 if( fchs->pl[1] == 0x02FC ) // Name Service
2106 // got a new (or NULL) list of Fabric attach devices...
2107 // Invalidate current logins
2109 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
2110 while( pLoggedInPort ) // for all ports which are expecting
2111 // PDISC after the next LIP, set the
2112 // logoutTimer
2115 if( (pLoggedInPort->port_id & 0xFFFF00) // Fabric device?
2117 (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
2119 pLoggedInPort->LOGO_timer = 6; // what's the Fabric timeout??
2120 // suspend any I/O in progress until
2121 // PDISC received...
2122 pLoggedInPort->prli = FALSE; // block FCP-SCSI commands
2125 pLoggedInPort = pLoggedInPort->pNextPort;
2128 if( fchs->pl[2] == 0x0280) // ACCept?
2130 // Send PLOGI or PDISC to these Fabric devices
2131 SendLogins( cpqfcHBAdata, &fchs->pl[4] );
2135 // As of this writing, the only reason to reject is because NO
2136 // devices are left on the Fabric. We already started
2137 // "logged out" timers; if the device(s) don't come
2138 // back, we'll do the implicit logout in the heart beat
2139 // timer routine
2140 else // ReJecT
2142 // this just means no Fabric device is visible at this instant
2146 // Regardless of whether the Reply is valid or not, the
2147 // the exchange is done - complete
2148 cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete
2150 Quit:
2151 return;
2160 static void AnalyzeIncomingFrame(
2161 CPQFCHBA *cpqfcHBAdata,
2162 ULONG QNdx )
2164 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2165 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2166 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
2167 TachFCHDR_GCMND* fchs =
2168 (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
2169 // ULONG ls_reject_code; // reason for rejecting login
2170 LONG ExchangeID;
2171 // FC_LOGGEDIN_PORT *pLoggedInPort;
2172 BOOLEAN AbortAccept;
2174 ENTER("AnalyzeIncomingFrame");
2178 switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
2181 case SFQ_UNKNOWN: // unknown frame (e.g. LIP position frame, NOP, etc.)
2184 // ********* FC-4 Device Data/ Fibre Channel Service *************
2185 if( ((fchs->d_id &0xF0000000) == 0) // R_CTL (upper nibble) 0x0?
2187 (fchs->f_ctl & 0x20000000) ) // TYPE 20h is Fibre Channel Service
2190 // ************** FCS Reply **********************
2192 if( (fchs->d_id & 0xff000000L) == 0x03000000L) // (31:23 R_CTL)
2194 ProcessFCS_Reply( cpqfcHBAdata, fchs );
2196 } // end of FCS logic
2201 // *********** Extended Link Service **************
2203 else if( fchs->d_id & 0x20000000 // R_CTL 0x2?
2205 (fchs->f_ctl & 0x01000000) ) // TYPE = 1
2208 // these frames are either a response to
2209 // something we sent (0x23) or "unsolicited"
2210 // frames (0x22).
2213 // **************Extended Link REPLY **********************
2214 // R_CTL Solicited Control Reply
2216 if( (fchs->d_id & 0xff000000L) == 0x23000000L) // (31:23 R_CTL)
2219 ProcessELS_Reply( cpqfcHBAdata, fchs );
2221 } // end of "R_CTL Solicited Control Reply"
2226 // **************Extended Link REQUEST **********************
2227 // (unsolicited commands from another port or task...)
2229 // R_CTL Ext Link REQUEST
2230 else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2231 (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
2236 ProcessELS_Request( cpqfcHBAdata, fchs );
2242 // ************** LILP **********************
2243 else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2244 (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
2247 // SANMark specifies that when available, we must use
2248 // the LILP frame to determine which ALPAs to send Port Discovery
2249 // to...
2251 if( fchs->pl[0] == 0x0711L) // ELS_PLOGI?
2253 // UCHAR *ptr = (UCHAR*)&fchs->pl[1];
2254 // printk(" %d ALPAs found\n", *ptr);
2255 memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
2256 fcChip->Options.LILPin = 1; // our LILPmap is valid!
2257 // now post to make Port Discovery happen...
2258 cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);
2264 // ***************** BASIC LINK SERVICE *****************
2266 else if( fchs->d_id & 0x80000000 // R_CTL:
2267 && // Basic Link Service Request
2268 !(fchs->f_ctl & 0xFF000000) ) // type=0 for BLS
2271 // Check for ABTS (Abort Sequence)
2272 if( (fchs->d_id & 0x8F000000) == 0x81000000)
2274 // look for OX_ID, S_ID pair that matches in our
2275 // fcExchanges table; if found, reply with ACCept and complete
2276 // the exchange
2278 // Per PLDA, an ABTS is sent by an initiator; therefore
2279 // assume that if we have an exhange open to the port who
2280 // sent ABTS, it will be the d_id of what we sent.
2281 for( ExchangeID = 0, AbortAccept=FALSE;
2282 ExchangeID < TACH_SEST_LEN; ExchangeID++)
2284 // Valid "target" exchange 24-bit port_id matches?
2285 // NOTE: For the case of handling Intiator AND Target
2286 // functions on the same chip, we can have TWO Exchanges
2287 // with the same OX_ID -- OX_ID/FFFF for the CMND, and
2288 // OX_ID/RX_ID for the XRDY or DATA frame(s). Ideally,
2289 // we would like to support ABTS from Initiators or Targets,
2290 // but it's not clear that can be supported on Tachyon for
2291 // all cases (requires more investigation).
2293 if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
2294 Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
2296 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2297 (fchs->s_id & 0xFFFFFF)) )
2300 // target xchnge port_id matches -- how about OX_ID?
2301 if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
2302 == (fchs->ox_rx_id & 0xFFFF0000) )
2303 // yes! post ACCept response; will be completed by fcStart
2305 Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
2307 // copy (add) rx_id field for simplified ACCept reply
2308 fchs->ox_rx_id =
2309 Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
2311 cpqfcTSPutLinkQue( cpqfcHBAdata,
2312 BLS_ABTS_ACC, // Q Type
2313 fchs ); // void QueContent
2314 AbortAccept = TRUE;
2315 printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n",
2316 fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
2317 break; // ABTS can affect only ONE exchange -exit loop
2320 } // end of FOR loop
2321 if( !AbortAccept ) // can't ACCept ABTS - send Reject
2323 printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n",
2324 fchs->ox_rx_id);
2325 if( Exchanges->fcExchange[ ExchangeID].type
2327 !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
2328 & 0x80000000))
2330 cpqfcTSCompleteExchange( fcChip, ExchangeID);
2332 else
2334 printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n",
2335 ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
2340 // Check for BLS {ABTS? (Abort Sequence)} ACCept
2341 else if( (fchs->d_id & 0x8F000000) == 0x84000000)
2343 // target has responded with ACC for our ABTS;
2344 // complete the indicated exchange with ABORTED status
2345 // Make no checks for correct RX_ID, since
2346 // all we need to conform ABTS ACC is the OX_ID.
2347 // Verify that the d_id matches!
2349 ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2350 // printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n",
2351 // fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
2352 // Exchanges->fcExchange[ExchangeID].status);
2356 if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2358 // Does "target" exchange 24-bit port_id match?
2359 // (See "NOTE" above for handling Intiator AND Target in
2360 // the same device driver)
2361 // First, if this is a target response, then we originated
2362 // (initiated) it with BLS_ABTS:
2364 if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2367 // Second, does the source of this ACC match the destination
2368 // of who we originally sent it to?
2369 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2370 (fchs->s_id & 0xFFFFFF)) )
2372 cpqfcTSCompleteExchange( fcChip, ExchangeID );
2376 // Check for BLS {ABTS? (Abort Sequence)} ReJecT
2377 else if( (fchs->d_id & 0x8F000000) == 0x85000000)
2379 // target has responded with RJT for our ABTS;
2380 // complete the indicated exchange with ABORTED status
2381 // Make no checks for correct RX_ID, since
2382 // all we need to conform ABTS ACC is the OX_ID.
2383 // Verify that the d_id matches!
2385 ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2386 // printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n",
2387 // fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
2389 if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2391 // Does "target" exchange 24-bit port_id match?
2392 // (See "NOTE" above for handling Intiator AND Target in
2393 // the same device driver)
2394 // First, if this is a target response, then we originated
2395 // (initiated) it with BLS_ABTS:
2397 if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2400 // Second, does the source of this ACC match the destination
2401 // of who we originally sent it to?
2402 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2403 (fchs->s_id & 0xFFFFFF)) )
2405 // YES! NOTE: There is a bug in CPQ's RA-4000 box
2406 // where the "reason code" isn't returned in the payload
2407 // For now, simply presume the reject is because the target
2408 // already completed the exchange...
2410 // printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
2411 cpqfcTSCompleteExchange( fcChip, ExchangeID );
2414 } // end of ABTS check
2415 } // end of Basic Link Service Request
2416 break;
2418 default:
2419 printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
2420 fcLQ->Qitem[QNdx].Type,
2421 fcLQ->Qitem[QNdx].Type);
2422 break;
2427 // Function for Port Discovery necessary after every FC
2428 // initialization (e.g. LIP).
2429 // Also may be called if from Fabric Name Service logic.
2431 static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
2433 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2434 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2435 ULONG ulStatus=0;
2436 TachFCHDR_GCMND fchs; // copy fields for transmission
2437 int i;
2438 ULONG loginType;
2439 LONG ExchangeID;
2440 PFC_LOGGEDIN_PORT pLoggedInPort;
2441 __u32 PortIds[ number_of_al_pa];
2442 int NumberOfPorts=0;
2444 // We're going to presume (for now) that our limit of Fabric devices
2445 // is the same as the number of alpa on a private loop (126 devices).
2446 // (Of course this could be changed to support however many we have
2447 // memory for).
2448 memset( &PortIds[0], 0, sizeof(PortIds));
2450 // First, check if this login is for our own Link Initialization
2451 // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
2452 // from a switch. If we are logging into Fabric devices, we'll
2453 // have a non-NULL FabricPortId pointer
2455 if( FabricPortIds != NULL) // may need logins
2457 int LastPort=FALSE;
2458 i = 0;
2459 while( !LastPort)
2461 // port IDs From NSR payload; byte swap needed?
2462 BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
2464 // printk("FPortId[%d] %Xh ", i, PortIds[i]);
2465 if( PortIds[i] & 0x80000000)
2466 LastPort = TRUE;
2468 PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
2469 // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
2470 // erroneously use ALPA 0.
2471 if( PortIds[i] ) // need non-zero port_id...
2472 i++;
2474 if( i >= number_of_al_pa ) // (in)sanity check
2475 break;
2476 FabricPortIds++; // next...
2479 NumberOfPorts = i;
2480 // printk("NumberOf Fabric ports %d", NumberOfPorts);
2483 else // need to send logins on our "local" link
2486 // are we a loop port? If so, check for reception of LILP frame,
2487 // and if received use it (SANMark requirement)
2488 if( fcChip->Options.LILPin )
2490 int j=0;
2491 // sanity check on number of ALPAs from LILP frame...
2492 // For format of LILP frame, see FC-AL specs or
2493 // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
2494 // First byte is number of ALPAs
2495 i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
2496 NumberOfPorts = i;
2497 // printk(" LILP alpa count %d ", i);
2498 while( i > 0)
2500 PortIds[j] = fcChip->LILPmap[1+ j];
2501 j++; i--;
2504 else // have to send login to everybody
2506 int j=0;
2507 i = number_of_al_pa;
2508 NumberOfPorts = i;
2509 while( i > 0)
2511 PortIds[j] = valid_al_pa[j]; // all legal ALPAs
2512 j++; i--;
2518 // Now we have a copy of the port_ids (and how many)...
2519 for( i = 0; i < NumberOfPorts; i++)
2521 // 24-bit FC Port ID
2522 fchs.s_id = PortIds[i]; // note: only 8-bits used for ALPA
2525 // don't log into ourselves (Linux Scsi disk scan will stop on
2526 // no TARGET support error on us, and quit trying for rest of devices)
2527 if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
2528 continue;
2530 // fabric login needed?
2531 if( (fchs.s_id == 0) ||
2532 (fcChip->Options.fabric == 1) )
2534 fcChip->Options.flogi = 1; // fabric needs longer for login
2535 // Do we need FLOGI or FDISC?
2536 pLoggedInPort = fcFindLoggedInPort(
2537 fcChip,
2538 NULL, // don't search SCSI Nexus
2539 0xFFFFFC, // search linked list for Fabric port_id
2540 NULL, // don't search WWN
2541 NULL); // (don't care about end of list)
2543 if( pLoggedInPort ) // If found, we have prior experience with
2544 // this port -- check whether PDISC is needed
2546 if( pLoggedInPort->flogi )
2548 // does the switch support FDISC?? (FLOGI for now...)
2549 loginType = ELS_FLOGI; // prior FLOGI still valid
2551 else
2552 loginType = ELS_FLOGI; // expired FLOGI
2554 else // first FLOGI?
2555 loginType = ELS_FLOGI;
2558 fchs.s_id = 0xFFFFFE; // well known F_Port address
2560 // Fabrics are not required to support FDISC, and
2561 // it's not clear if that helps us anyway, since
2562 // we'll want a Name Service Request to re-verify
2563 // visible devices...
2564 // Consequently, we always want our upper 16 bit
2565 // port_id to be zero (we'll be rejected if we
2566 // use our prior port_id if we've been plugged into
2567 // a different switch port).
2568 // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
2569 // If our ALPA is 55h for instance, we want the FC frame
2570 // s_id to be 0x000055, while Tach's my_al_pa register
2571 // must be 0x000155, to force an OPN at ALPA 0
2572 // (the Fabric port)
2573 fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
2574 writel( fcChip->Registers.my_al_pa | 0x0100,
2575 fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
2578 else // not FLOGI...
2580 // should we send PLOGI or PDISC? Check if any prior port_id
2581 // (e.g. alpa) completed a PLOGI/PRLI exchange by checking
2582 // the pdisc flag.
2584 pLoggedInPort = fcFindLoggedInPort(
2585 fcChip,
2586 NULL, // don't search SCSI Nexus
2587 fchs.s_id, // search linked list for al_pa
2588 NULL, // don't search WWN
2589 NULL); // (don't care about end of list)
2593 if( pLoggedInPort ) // If found, we have prior experience with
2594 // this port -- check whether PDISC is needed
2596 if( pLoggedInPort->pdisc )
2598 loginType = ELS_PDISC; // prior PLOGI and PRLI maybe still valid
2601 else
2602 loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
2604 else // never talked to this port_id before
2605 loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
2610 ulStatus = cpqfcTSBuildExchange(
2611 cpqfcHBAdata,
2612 loginType, // e.g. PLOGI
2613 &fchs, // no incoming frame (we are originator)
2614 NULL, // no data (no scatter/gather list)
2615 &ExchangeID );// fcController->fcExchanges index, -1 if failed
2617 if( !ulStatus ) // Exchange setup OK?
2619 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
2620 if( !ulStatus )
2622 // submitted to Tach's Outbound Que (ERQ PI incremented)
2623 // waited for completion for ELS type (Login frames issued
2624 // synchronously)
2626 if( loginType == ELS_PDISC )
2628 // now, we really shouldn't Revalidate SEST exchanges until
2629 // we get an ACC reply from our target and verify that
2630 // the target address/WWN is unchanged. However, when a fast
2631 // target gets the PDISC, they can send SEST Exchange data
2632 // before we even get around to processing the PDISC ACC.
2633 // Consequently, we lose the I/O.
2634 // To avoid this, go ahead and Revalidate when the PDISC goes
2635 // out, anticipating that the ACC will be truly acceptable
2636 // (this happens 99.9999....% of the time).
2637 // If we revalidate a SEST write, and write data goes to a
2638 // target that is NOT the one we originated the WRITE to,
2639 // that target is required (FCP-SCSI specs, etc) to discard
2640 // our WRITE data.
2642 // Re-validate SEST entries (Tachyon hardware assists)
2643 RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort);
2644 //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
2647 else // give up immediately on error
2649 #ifdef LOGIN_DBG
2650 printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
2651 #endif
2652 break;
2656 if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
2658 ulStatus = LNKDWN_OSLS;
2659 #ifdef LOGIN_DBG
2660 printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
2661 #endif
2662 break;
2664 // Check the exchange for bad status (i.e. FrameTimeOut),
2665 // and complete on bad status (most likely due to BAD_ALPA)
2666 // on LDn, DPC function may already complete (ABORT) a started
2667 // exchange, so check type first (type = 0 on complete).
2668 if( Exchanges->fcExchange[ExchangeID].status )
2670 #ifdef LOGIN_DBG
2671 printk("completing x_ID %X on status %Xh\n",
2672 ExchangeID, Exchanges->fcExchange[ExchangeID].status);
2673 #endif
2674 cpqfcTSCompleteExchange( fcChip, ExchangeID);
2677 else // Xchange setup failed...
2679 #ifdef LOGIN_DBG
2680 printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
2681 #endif
2682 break;
2685 if( !ulStatus )
2687 // set the event signifying that all ALPAs were sent out.
2688 #ifdef LOGIN_DBG
2689 printk("SendLogins: PortDiscDone\n");
2690 #endif
2691 cpqfcHBAdata->PortDiscDone = 1;
2694 // TL/TS UG, pg. 184
2695 // 0x0065 = 100ms for RT_TOV
2696 // 0x01f5 = 500ms for ED_TOV
2697 fcChip->Registers.ed_tov.value = 0x006501f5L;
2698 writel( fcChip->Registers.ed_tov.value,
2699 (fcChip->Registers.ed_tov.address));
2701 // set the LP_TOV back to ED_TOV (i.e. 500 ms)
2702 writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
2704 else
2706 printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n",
2707 ExchangeID, fchs.s_id, ulStatus);
2709 LEAVE("SendLogins");
2714 // for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
2715 // D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
2716 static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
2718 struct Scsi_Host *HostAdapter = Cmnd->host;
2719 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
2720 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2721 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2722 PFC_LOGGEDIN_PORT pLoggedInPort;
2723 int LunListLen=0;
2724 int i;
2725 ULONG x_ID = 0xFFFFFFFF;
2726 UCHAR *ucBuff = Cmnd->request_buffer;
2728 // printk("cpqfcTS: ReportLunsDone \n");
2729 // first, we need to find the Exchange for this command,
2730 // so we can find the fcPort struct to make the indicated
2731 // changes.
2732 for( i=0; i< TACH_SEST_LEN; i++)
2734 if( Exchanges->fcExchange[i].type // exchange defined?
2736 (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
2739 x_ID = i; // found exchange!
2740 break;
2743 if( x_ID == 0xFFFFFFFF)
2745 // printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
2746 goto Done; // Report Luns FC Exchange gone;
2747 // exchange probably Terminated by Implicit logout
2751 // search linked list for the port_id we sent INQUIRY to
2752 pLoggedInPort = fcFindLoggedInPort( fcChip,
2753 NULL, // DON'T search Scsi Nexus (we will set it)
2754 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,
2755 NULL, // DON'T search linked list for FC WWN
2756 NULL); // DON'T care about end of list
2758 if( !pLoggedInPort )
2760 // printk("cpqfcTS: ReportLuns failed - device gone\n");
2761 goto Done; // error! can't find logged in Port
2763 LunListLen = ucBuff[3];
2764 LunListLen += ucBuff[2]>>8;
2766 if( !LunListLen ) // failed
2768 // generically speaking, a soft error means we should retry...
2769 if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
2771 if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
2772 (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
2774 TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
2775 // did we fail because of "check condition, device reset?"
2776 // e.g. the device was reset (i.e., at every power up)
2777 // retry the Report Luns
2779 // who are we sending it to?
2780 // we know this because we have a copy of the command
2781 // frame from the original Report Lun command -
2782 // switch the d_id/s_id fields, because the Exchange Build
2783 // context is "reply to source".
2785 fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
2786 cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
2789 else // probably, the device doesn't support Report Luns
2790 pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;
2792 else // we have LUN info - check VSA mode
2794 // for now, assume all LUNs will have same addr mode
2795 // for VSA, payload byte 8 will be 0x40; otherwise, 0
2796 pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];
2798 // Since we got a Report Luns answer, set lun masking flag
2799 pLoggedInPort->ScsiNexus.LunMasking = 1;
2801 if( LunListLen > 8*CPQFCTS_MAX_LUN) // We expect CPQFCTS_MAX_LUN max
2802 LunListLen = 8*CPQFCTS_MAX_LUN;
2805 printk("Device WWN %08X%08X Reports Luns @: ",
2806 (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
2807 (ULONG)(pLoggedInPort->u.liWWN>>32));
2809 for( i=8; i<LunListLen+8; i+=8)
2811 printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
2813 printk("\n");
2816 // Since the device was kind enough to tell us where the
2817 // LUNs are, lets ensure they are contiguous for Linux's
2818 // SCSI driver scan, which expects them to start at 0.
2819 // Since Linux only supports 8 LUNs, only copy the first
2820 // eight from the report luns command
2822 // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
2823 // LUNs 4001, 4004, etc., because other LUNs are masked from
2824 // this HBA (owned by someone else). We'll make those appear as
2825 // LUN 0, 1... to Linux
2827 int j;
2828 int AppendLunList = 0;
2829 // Walk through the LUN list. The 'j' array number is
2830 // Linux's lun #, while the value of .lun[j] is the target's
2831 // lun #.
2832 // Once we build a LUN list, it's possible for a known device
2833 // to go offline while volumes (LUNs) are added. Later,
2834 // the device will do another PLOGI ... Report Luns command,
2835 // and we must not alter the existing Linux Lun map.
2836 // (This will be very rare).
2837 for( j=0; j < CPQFCTS_MAX_LUN; j++)
2839 if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
2841 AppendLunList = 1;
2842 break;
2845 if( AppendLunList )
2847 int k;
2848 int FreeLunIndex;
2849 // printk("cpqfcTS: AppendLunList\n");
2851 // If we get a new Report Luns, we cannot change
2852 // any existing LUN mapping! (Only additive entry)
2853 // For all LUNs in ReportLun list
2854 // if RL lun != ScsiNexus lun
2855 // if RL lun present in ScsiNexus lun[], continue
2856 // else find ScsiNexus lun[]==FF and add, continue
2858 for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2860 if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
2862 // something changed from the last Report Luns
2863 printk(" cpqfcTS: Report Lun change!\n");
2864 for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN;
2865 k < CPQFCTS_MAX_LUN; k++)
2867 if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
2869 FreeLunIndex = k;
2870 break;
2872 if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
2873 break; // we already masked this lun
2875 if( k >= CPQFCTS_MAX_LUN )
2877 printk(" no room for new LUN %d\n", ucBuff[i+1]);
2879 else if( k == FreeLunIndex ) // need to add LUN
2881 pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
2882 // printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
2885 else
2887 // lun already known
2889 break;
2892 // print out the new list...
2893 for( j=0; j< CPQFCTS_MAX_LUN; j++)
2895 if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
2896 break; // done
2897 // printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2900 else
2902 // printk("Linux SCSI LUNs[] -> Device LUNs: ");
2903 // first time - this is easy
2904 for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2906 pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
2907 // printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2909 // printk("\n");
2914 Done:
2917 // After successfully getting a "Process Login" (PRLI) from an
2918 // FC port, we want to Discover the LUNs so that we know the
2919 // addressing type (e.g., FCP-SCSI Volume Set Address, Peripheral
2920 // Unit Device), and whether SSP (Selective Storage Presentation or
2921 // Lun Masking) has made the LUN numbers non-zero based or
2922 // non-contiguous. To remain backward compatible with the SCSI-2
2923 // driver model, which expects a contiguous LUNs starting at 0,
2924 // will use the ReportLuns info to map from "device" to "Linux"
2925 // LUNs.
2926 static void IssueReportLunsCommand(
2927 CPQFCHBA* cpqfcHBAdata,
2928 TachFCHDR_GCMND* fchs)
2930 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2931 PFC_LOGGEDIN_PORT pLoggedInPort;
2932 Scsi_Cmnd *Cmnd;
2933 LONG x_ID;
2934 ULONG ulStatus;
2935 UCHAR *ucBuff;
2938 if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
2940 printk("Discard Q'd ReportLun command\n");
2941 goto Done;
2944 // find the device (from port_id) we're talking to
2945 pLoggedInPort = fcFindLoggedInPort( fcChip,
2946 NULL, // DON'T search Scsi Nexus
2947 fchs->s_id & 0xFFFFFF,
2948 NULL, // DON'T search linked list for FC WWN
2949 NULL); // DON'T care about end of list
2950 if( pLoggedInPort ) // we'd BETTER find it!
2954 if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
2955 goto Done; // forget it - FC device not a "target"
2957 // now use the port's Scsi Command buffer for the
2958 // Report Luns Command
2960 Cmnd = &pLoggedInPort->ScsiCmnd;
2961 ucBuff = pLoggedInPort->ReportLunsPayload;
2963 memset( Cmnd, 0, sizeof(Scsi_Cmnd));
2964 memset( ucBuff, 0, REPORT_LUNS_PL);
2966 Cmnd->scsi_done = ScsiReportLunsDone;
2967 Cmnd->host = cpqfcHBAdata->HostAdapter;
2969 Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload;
2970 Cmnd->request_bufflen = REPORT_LUNS_PL;
2972 Cmnd->cmnd[0] = 0xA0;
2973 Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
2974 Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL;
2975 Cmnd->cmd_len = 12;
2977 Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
2978 Cmnd->target = pLoggedInPort->ScsiNexus.target;
2981 ulStatus = cpqfcTSBuildExchange(
2982 cpqfcHBAdata,
2983 SCSI_IRE,
2984 fchs,
2985 Cmnd, // buffer for Report Lun data
2986 &x_ID );// fcController->fcExchanges index, -1 if failed
2988 if( !ulStatus ) // Exchange setup?
2990 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
2991 if( !ulStatus )
2993 // submitted to Tach's Outbound Que (ERQ PI incremented)
2994 // waited for completion for ELS type (Login frames issued
2995 // synchronously)
2997 else
2998 // check reason for Exchange not being started - we might
2999 // want to Queue and start later, or fail with error
3005 else // Xchange setup failed...
3006 printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
3008 else // like, we just got a PRLI ACC, and now the port is gone?
3010 printk(" can't send ReportLuns - no login for port_id %Xh\n",
3011 fchs->s_id & 0xFFFFFF);
3016 Done:
3026 static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata)
3028 int i;
3029 for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--)
3031 if( cpqfcHBAdata->BoardLockCmnd[i] != NULL )
3033 Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i];
3034 cpqfcHBAdata->BoardLockCmnd[i] = NULL;
3035 Cmnd->result = (DID_SOFT_ERROR << 16); // ask for retry
3036 // printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
3037 // i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
3038 if( Cmnd->scsi_done != NULL)
3039 (*Cmnd->scsi_done)(Cmnd);
3049 // runs every 1 second for FC exchange timeouts and implicit FC device logouts
3051 void cpqfcTSheartbeat( unsigned long ptr )
3053 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr;
3054 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
3055 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3056 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
3057 ULONG i;
3058 unsigned long flags;
3059 DECLARE_MUTEX_LOCKED(BoardLock);
3061 PCI_TRACE( 0xA8)
3063 if( cpqfcHBAdata->BoardLock) // Worker Task Running?
3064 goto Skip;
3066 spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
3068 PCI_TRACE( 0xA8)
3071 cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
3073 // release the IO lock (and re-enable interrupts)
3074 spin_unlock_irqrestore( &io_request_lock, flags);
3076 // Ensure no contention from _quecommand or Worker process
3077 CPQ_SPINLOCK_HBA( cpqfcHBAdata)
3079 PCI_TRACE( 0xA8)
3082 disable_irq( cpqfcHBAdata->HostAdapter->irq); // our IRQ
3084 // Complete the "bad target" commands (normally only used during
3085 // initialization, since we aren't supposed to call "scsi_done"
3086 // inside the queuecommand() function).
3088 for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
3090 if( cpqfcHBAdata->BadTargetCmnd[i] )
3092 Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
3093 cpqfcHBAdata->BadTargetCmnd[i] = NULL;
3094 Cmnd->result = (DID_BAD_TARGET << 16);
3095 if( Cmnd->scsi_done != NULL)
3096 (*Cmnd->scsi_done)(Cmnd);
3098 else
3099 break;
3103 // logged in ports -- re-login check (ports required to verify login with
3104 // PDISC after LIP within 2 secs)
3106 // prevent contention
3107 while( pLoggedInPort ) // for all ports which are expecting
3108 // PDISC after the next LIP, check to see if
3109 // time is up!
3111 // Important: we only detect "timeout" condition on TRANSITION
3112 // from non-zero to zero
3113 if( pLoggedInPort->LOGO_timer ) // time-out "armed"?
3115 if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0?
3117 // LOGOUT time! Per PLDA, PDISC hasn't complete in 2 secs, so
3118 // issue LOGO request and destroy all I/O with other FC port(s).
3121 printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
3122 printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n",
3123 pLoggedInPort->ScsiNexus.channel,
3124 pLoggedInPort->ScsiNexus.target,
3125 pLoggedInPort->port_id,
3126 (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
3127 (ULONG)(pLoggedInPort->u.liWWN>>32));
3130 cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
3133 // else simply decremented - maybe next time...
3135 pLoggedInPort = pLoggedInPort->pNextPort;
3142 // ************ FC EXCHANGE TIMEOUT CHECK **************
3144 for( i=0; i< TACH_MAX_XID; i++)
3146 if( Exchanges->fcExchange[i].type ) // exchange defined?
3149 if( !Exchanges->fcExchange[i].timeOut ) // time expired
3151 // Set Exchange timeout status
3152 Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
3154 if( i >= TACH_SEST_LEN ) // Link Service Exchange
3156 cpqfcTSCompleteExchange( fcChip, i); // Don't "abort" LinkService
3159 else // SEST Exchange TO -- may post ABTS to Worker Thread Que
3161 // (Make sure we don't keep timing it out; let other functions
3162 // complete it or set the timeOut as needed)
3163 Exchanges->fcExchange[i].timeOut = 30000; // seconds default
3165 if( Exchanges->fcExchange[i].type
3167 (BLS_ABTS | BLS_ABTS_ACC ) )
3169 // For BLS_ABTS*, an upper level might still have
3170 // an outstanding command waiting for low-level completion.
3171 // Also, in the case of a WRITE, we MUST get confirmation
3172 // of either ABTS ACC or RJT before re-using the Exchange.
3173 // It's possible that the RAID cache algorithm can hang
3174 // if we fail to complete a WRITE to a LBA, when a READ
3175 // comes later to that same LBA. Therefore, we must
3176 // ensure that the target verifies receipt of ABTS for
3177 // the exchange
3179 printk("~TO Q'd ABTS (x_ID %Xh)~ ", i);
3180 // TriggerHBA( fcChip->Registers.ReMapMemBase);
3182 // On timeout of a ABTS exchange, check to
3183 // see if the FC device has a current valid login.
3184 // If so, restart it.
3185 pLoggedInPort = fcFindLoggedInPort( fcChip,
3186 Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
3187 0, // DON'T search linked list for FC port id
3188 NULL, // DON'T search linked list for FC WWN
3189 NULL); // DON'T care about end of list
3191 // device exists?
3192 if( pLoggedInPort ) // device exists?
3194 if( pLoggedInPort->prli ) // logged in for FCP-SCSI?
3196 // attempt to restart the ABTS
3197 printk(" ~restarting ABTS~ ");
3198 cpqfcTSStartExchange( cpqfcHBAdata, i );
3203 else // not an ABTS
3206 // We expect the WorkerThread to change the xchng type to
3207 // abort and set appropriate timeout.
3208 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out
3212 else // time not expired...
3214 // decrement timeout: 1 or more seconds left
3215 --Exchanges->fcExchange[i].timeOut;
3221 enable_irq( cpqfcHBAdata->HostAdapter->irq);
3224 CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
3226 cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued
3228 // Now, complete any Cmnd we Q'd up while BoardLock was held
3230 CompleteBoardLockCmnd( cpqfcHBAdata);
3233 // restart the timer to run again (1 sec later)
3234 Skip:
3235 mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ);
3237 PCI_TRACEO( i, 0xA8)
3238 return;
3242 // put valid FC-AL physical address in spec order
3243 static const UCHAR valid_al_pa[]={
3244 0xef, 0xe8, 0xe4, 0xe2,
3245 0xe1, 0xE0, 0xDC, 0xDA,
3246 0xD9, 0xD6, 0xD5, 0xD4,
3247 0xD3, 0xD2, 0xD1, 0xCe,
3248 0xCd, 0xCc, 0xCb, 0xCa,
3249 0xC9, 0xC7, 0xC6, 0xC5,
3250 0xC3, 0xBc, 0xBa, 0xB9,
3251 0xB6, 0xB5, 0xB4, 0xB3,
3252 0xB2, 0xB1, 0xae, 0xad,
3253 0xAc, 0xAb, 0xAa, 0xA9,
3255 0xA7, 0xA6, 0xA5, 0xA3,
3256 0x9f, 0x9e, 0x9d, 0x9b,
3257 0x98, 0x97, 0x90, 0x8f,
3258 0x88, 0x84, 0x82, 0x81,
3259 0x80, 0x7c, 0x7a, 0x79,
3260 0x76, 0x75, 0x74, 0x73,
3261 0x72, 0x71, 0x6e, 0x6d,
3262 0x6c, 0x6b, 0x6a, 0x69,
3263 0x67, 0x66, 0x65, 0x63,
3264 0x5c, 0x5a, 0x59, 0x56,
3266 0x55, 0x54, 0x53, 0x52,
3267 0x51, 0x4e, 0x4d, 0x4c,
3268 0x4b, 0x4a, 0x49, 0x47,
3269 0x46, 0x45, 0x43, 0x3c,
3270 0x3a, 0x39, 0x36, 0x35,
3271 0x34, 0x33, 0x32, 0x31,
3272 0x2e, 0x2d, 0x2c, 0x2b,
3273 0x2a, 0x29, 0x27, 0x26,
3274 0x25, 0x23, 0x1f, 0x1E,
3275 0x1d, 0x1b, 0x18, 0x17,
3277 0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case
3279 const int number_of_al_pa = (sizeof(valid_al_pa) );
3283 // this function looks up an al_pa from the table of valid al_pa's
3284 // we decrement from the last decimal loop ID, because soft al_pa
3285 // (our typical case) are assigned with highest priority (and high al_pa)
3286 // first. See "In-Depth FC-AL", R. Kembel pg. 38
3287 // INPUTS:
3288 // al_pa - 24 bit port identifier (8 bit al_pa on private loop)
3289 // RETURN:
3290 // Loop ID - serves are index to array of logged in ports
3291 // -1 - invalid al_pa (not all 8 bit values are legal)
3293 #if (0)
3294 static int GetLoopID( ULONG al_pa )
3296 int i;
3298 for( i = number_of_al_pa -1; i >= 0; i--) // dec.
3300 if( valid_al_pa[i] == (UCHAR)al_pa ) // take lowest 8 bits
3301 return i; // success - found valid al_pa; return decimal LoopID
3303 return -1; // failed - not found
3305 #endif
3308 // Search the singly (forward) linked list "fcPorts" looking for
3309 // either the SCSI target (if != -1), port_id (if not NULL),
3310 // or WWN (if not null), in that specific order.
3311 // If we find a SCSI nexus (from Cmnd arg), set the SCp.phase
3312 // field according to VSA or PDU
3313 // RETURNS:
3314 // Ptr to logged in port struct if found
3315 // (NULL if not found)
3316 // pLastLoggedInPort - ptr to last struct (for adding new ones)
3318 PFC_LOGGEDIN_PORT fcFindLoggedInPort(
3319 PTACHYON fcChip,
3320 Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
3321 ULONG port_id, // search linked list for al_pa, or
3322 UCHAR wwn[8], // search linked list for WWN, or...
3323 PFC_LOGGEDIN_PORT *pLastLoggedInPort )
3326 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
3327 BOOLEAN target_id_valid=FALSE;
3328 BOOLEAN port_id_valid=FALSE;
3329 BOOLEAN wwn_valid=FALSE;
3330 int i;
3333 if( Cmnd != NULL )
3334 target_id_valid = TRUE;
3336 else if( port_id ) // note! 24-bit NULL address is illegal
3337 port_id_valid = TRUE;
3339 else
3341 for( i=0; i<8; i++) // valid WWN passed? NULL WWN invalid
3343 if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
3345 if( wwn[i] != 0 )
3346 wwn_valid = TRUE; // any non-zero byte makes (presumably) valid
3350 // check other options ...
3353 // In case multiple search options are given, we use a priority
3354 // scheme:
3355 // While valid pLoggedIn Ptr
3356 // If port_id is valid
3357 // if port_id matches, return Ptr
3358 // If wwn is valid
3359 // if wwn matches, return Ptr
3360 // Next Ptr in list
3362 // Return NULL (not found)
3365 while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid)
3367 if( pLastLoggedInPort ) // caller's pointer valid?
3368 *pLastLoggedInPort = pLoggedInPort; // end of linked list
3370 if( target_id_valid )
3372 // check Linux Scsi Cmnd for channel/target Nexus match
3373 // (all luns are accessed through matching "pLoggedInPort")
3374 if( (pLoggedInPort->ScsiNexus.target == Cmnd->target)
3376 (pLoggedInPort->ScsiNexus.channel == Cmnd->channel))
3378 // For "passthru" modes, the IOCTL caller is responsible
3379 // for setting the FCP-LUN addressing
3380 if( !Cmnd->SCp.sent_command ) // NOT passthru?
3383 // set the FCP-LUN addressing type
3384 Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;
3386 // set the Device Type we got from the snooped INQUIRY string
3387 Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
3389 // handle LUN masking; if not "default" (illegal) lun value,
3390 // the use it. These lun values are set by a successful
3391 // Report Luns command
3392 if( pLoggedInPort->ScsiNexus.LunMasking == 1)
3394 // we KNOW all the valid LUNs... 0xFF is invalid!
3395 Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
3397 else
3398 Cmnd->SCp.have_data_in = Cmnd->lun; // Linux & target luns match
3400 break; // found it!
3404 if( port_id_valid ) // look for alpa first
3406 if( pLoggedInPort->port_id == port_id )
3407 break; // found it!
3409 if( wwn_valid ) // look for wwn second
3412 if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
3414 // all 8 bytes of WWN match
3415 break; // found it!
3419 pLoggedInPort = pLoggedInPort->pNextPort; // try next port
3422 return pLoggedInPort;
3429 // We need to examine the SEST table and re-validate
3430 // any open Exchanges for this LoggedInPort
3431 // To make Tachyon pay attention, Freeze FCP assists,
3432 // set VAL bits, Unfreeze FCP assists
3433 static void RevalidateSEST( struct Scsi_Host *HostAdapter,
3434 PFC_LOGGEDIN_PORT pLoggedInPort)
3436 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3437 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
3438 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3439 ULONG x_ID;
3440 BOOLEAN TachFroze = FALSE;
3443 // re-validate any SEST exchanges that are permitted
3444 // to survive the link down (e.g., good PDISC performed)
3445 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
3448 // If the SEST entry port_id matches the pLoggedInPort,
3449 // we need to re-validate
3450 if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
3452 (Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
3455 if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF) // (24-bit port ID)
3456 == pLoggedInPort->port_id)
3458 // printk(" re-val xID %Xh ", x_ID);
3459 if( !TachFroze ) // freeze if not already frozen
3460 TachFroze |= FreezeTach( cpqfcHBAdata);
3461 fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
3466 if( TachFroze)
3468 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
3473 // Complete an Linux Cmnds that we Queued because
3474 // our FC link was down (cause immediate retry)
3476 static void UnblockScsiDevice( struct Scsi_Host *HostAdapter,
3477 PFC_LOGGEDIN_PORT pLoggedInPort)
3479 // Scsi_Device *sdev = HostAdapter->host_queue;
3480 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3481 Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
3482 Scsi_Cmnd *Cmnd;
3483 int indx;
3487 // if the device was previously "blocked", make sure
3488 // we unblock it so Linux SCSI will resume
3490 pLoggedInPort->device_blocked = FALSE; // clear our flag
3492 // check the Link Down command ptr buffer;
3493 // we can complete now causing immediate retry
3494 for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
3496 if( *SCptr != NULL ) // scsi command to complete?
3498 #ifdef DUMMYCMND_DBG
3499 printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
3500 #endif
3501 Cmnd = *SCptr;
3504 // Are there any Q'd commands for this target?
3505 if( (Cmnd->target == pLoggedInPort->ScsiNexus.target)
3507 (Cmnd->channel == pLoggedInPort->ScsiNexus.channel) )
3509 Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
3510 if( Cmnd->scsi_done != NULL)
3511 (*Cmnd->scsi_done)(Cmnd);
3512 else
3513 printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
3514 pLoggedInPort->port_id);
3515 *SCptr = NULL; // free this slot for next use
3522 //#define WWN_DBG 1
3524 static void SetLoginFields(
3525 PFC_LOGGEDIN_PORT pLoggedInPort,
3526 TachFCHDR_GCMND* fchs,
3527 BOOLEAN PDisc,
3528 BOOLEAN Originator)
3530 LOGIN_PAYLOAD logi; // FC-PH Port Login
3531 PRLI_REQUEST prli; // copy for BIG ENDIAN switch
3532 int i;
3533 #ifdef WWN_DBG
3534 ULONG ulBuff;
3535 #endif
3537 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
3539 pLoggedInPort->Originator = Originator;
3540 pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
3542 switch( fchs->pl[0] & 0xffff )
3544 case 0x00000002: // PLOGI or PDISC ACCept?
3545 if( PDisc ) // PDISC accept
3546 goto PDISC_case;
3548 case 0x00000003: // ELS_PLOGI or ELS_PLOGI_ACC
3550 // Login BB_credit typically 0 for Tachyons
3551 pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
3553 // e.g. 128, 256, 1024, 2048 per FC-PH spec
3554 // We have to use this when setting up SEST Writes,
3555 // since that determines frame size we send.
3556 pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
3557 pLoggedInPort->plogi = TRUE;
3558 pLoggedInPort->pdisc = FALSE;
3559 pLoggedInPort->prli = FALSE; // ELS_PLOGI resets
3560 pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets
3561 pLoggedInPort->logo = FALSE; // ELS_PLOGI resets
3562 pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
3563 pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
3565 // was this PLOGI to a Fabric?
3566 if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
3567 pLoggedInPort->flogi = TRUE;
3570 for( i=0; i<8; i++) // copy the LOGIN port's WWN
3571 pLoggedInPort->u.ucWWN[i] = logi.port_name[i];
3573 #ifdef WWN_DBG
3574 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3575 if( pLoggedInPort->Originator)
3576 printk("o");
3577 else
3578 printk("r");
3579 printk("PLOGI port_id %Xh, WWN %08X",
3580 pLoggedInPort->port_id, ulBuff);
3582 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3583 printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
3584 #endif
3585 break;
3590 case 0x00000005: // ELS_LOGO (logout)
3593 pLoggedInPort->plogi = FALSE;
3594 pLoggedInPort->pdisc = FALSE;
3595 pLoggedInPort->prli = FALSE; // ELS_PLOGI resets
3596 pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets
3597 pLoggedInPort->logo = TRUE; // ELS_PLOGI resets
3598 pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
3599 pLoggedInPort->LOGO_timer = 0;
3600 #ifdef WWN_DBG
3601 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3602 if( pLoggedInPort->Originator)
3603 printk("o");
3604 else
3605 printk("r");
3606 printk("LOGO port_id %Xh, WWN %08X",
3607 pLoggedInPort->port_id, ulBuff);
3609 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3610 printk("%08Xh\n", ulBuff);
3611 #endif
3612 break;
3616 PDISC_case:
3617 case 0x00000050: // ELS_PDISC or ELS_PDISC_ACC
3618 pLoggedInPort->LOGO_timer = 0; // stop the time-out
3620 pLoggedInPort->prli = TRUE; // ready to accept FCP-SCSI I/O
3624 #ifdef WWN_DBG
3625 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3626 if( pLoggedInPort->Originator)
3627 printk("o");
3628 else
3629 printk("r");
3630 printk("PDISC port_id %Xh, WWN %08X",
3631 pLoggedInPort->port_id, ulBuff);
3633 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3634 printk("%08Xh\n", ulBuff);
3635 #endif
3639 break;
3643 case 0x1020L: // PRLI?
3644 case 0x1002L: // PRLI ACCept?
3645 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
3647 pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
3648 pLoggedInPort->prli = TRUE; // PLOGI resets, PDISC doesn't
3650 pLoggedInPort->pdisc = TRUE; // expect to send (or receive) PDISC
3651 // next time
3652 pLoggedInPort->LOGO_timer = 0; // will be set next LinkDown
3653 #ifdef WWN_DBG
3654 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3655 if( pLoggedInPort->Originator)
3656 printk("o");
3657 else
3658 printk("r");
3659 printk("PRLI port_id %Xh, WWN %08X",
3660 pLoggedInPort->port_id, ulBuff);
3662 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3663 printk("%08Xh\n", ulBuff);
3664 #endif
3666 break;
3670 return;
3678 static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
3680 LOGIN_PAYLOAD *plogi; // FC-PH Port Login
3681 LOGIN_PAYLOAD PlogiPayload; // copy for BIG ENDIAN switch
3682 PRLI_REQUEST *prli; // FCP-SCSI Process Login
3683 PRLI_REQUEST PrliPayload; // copy for BIG ENDIAN switch
3684 LOGOUT_PAYLOAD *logo;
3685 LOGOUT_PAYLOAD LogoutPayload;
3686 // PRLO_REQUEST *prlo;
3687 // PRLO_REQUEST PrloPayload;
3688 REJECT_MESSAGE rjt, *prjt;
3690 memset( &PlogiPayload, 0, sizeof( PlogiPayload));
3691 plogi = &PlogiPayload; // load into stack buffer,
3692 // then BIG-ENDIAN switch a copy to caller
3695 switch( type ) // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
3697 case ELS_FDISC:
3698 case ELS_FLOGI:
3699 case ELS_PLOGI_ACC: // FC-PH PORT Login Accept
3700 case ELS_PLOGI: // FC-PH PORT Login
3701 case ELS_PDISC: // FC-PH2 Port Discovery - same payload as ELS_PLOGI
3702 plogi->login_cmd = LS_PLOGI;
3703 if( type == ELS_PDISC)
3704 plogi->login_cmd = LS_PDISC;
3705 else if( type == ELS_PLOGI_ACC )
3706 plogi->login_cmd = LS_ACC;
3708 plogi->cmn_services.bb_credit = 0x00;
3709 plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
3710 plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
3711 plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
3712 plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
3713 RANDOM_RELATIVE_OFFSET;
3715 // fill in with World Wide Name based Port Name - 8 UCHARs
3716 // get from Tach registers WWN hi & lo
3717 LoadWWN( fcChip, plogi->port_name, 0);
3718 // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
3719 // get from Tach registers WWN hi & lo
3720 LoadWWN( fcChip, plogi->node_name, 1);
3722 // For Seagate Drives.
3724 plogi->cmn_services.common_features |= 0x800;
3725 plogi->cmn_services.rel_offset = 0xFE;
3726 plogi->cmn_services.concurrent_seq = 1;
3727 plogi->class1.service_options = 0x00;
3728 plogi->class2.service_options = 0x00;
3729 plogi->class3.service_options = CLASS_VALID;
3730 plogi->class3.initiator_control = 0x00;
3731 plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
3732 plogi->class3.recipient_control =
3733 ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
3734 plogi->class3.concurrent_sequences = 1;
3735 plogi->class3.open_sequences = 1;
3736 plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
3737 plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
3738 plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0';
3739 plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0';
3742 // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
3743 if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
3745 if( type == ELS_FLOGI )
3746 plogi->login_cmd = LS_FLOGI;
3747 else
3748 plogi->login_cmd = LS_FDISC;
3750 plogi->cmn_services.lowest_ver = 0x20;
3751 plogi->cmn_services.common_features = 0x0800;
3752 plogi->cmn_services.rel_offset = 0;
3753 plogi->cmn_services.concurrent_seq = 0;
3755 plogi->class3.service_options = 0x8800;
3756 plogi->class3.rx_data_size = 0;
3757 plogi->class3.recipient_control = 0;
3758 plogi->class3.concurrent_sequences = 0;
3759 plogi->class3.open_sequences = 0;
3762 // copy back to caller's buff, w/ BIG ENDIAN swap
3763 BigEndianSwap( (UCHAR*)&PlogiPayload, payload, sizeof(PlogiPayload));
3764 break;
3767 case ELS_ACC: // generic Extended Link Service ACCept
3768 plogi->login_cmd = LS_ACC;
3769 // copy back to caller's buff, w/ BIG ENDIAN swap
3770 BigEndianSwap( (UCHAR*)&PlogiPayload, payload, 4);
3771 break;
3775 case ELS_SCR: // Fabric State Change Registration
3777 SCR_PL scr; // state change registration
3779 memset( &scr, 0, sizeof(scr));
3781 scr.command = LS_SCR; // 0x62000000
3782 // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
3783 scr.function = 3; // 1 = Events detected by Fabric
3784 // 2 = N_Port detected registration
3785 // 3 = Full registration
3787 // copy back to caller's buff, w/ BIG ENDIAN swap
3788 BigEndianSwap( (UCHAR*)&scr, payload, sizeof(SCR_PL));
3791 break;
3794 case FCS_NSR: // Fabric Name Service Request
3796 NSR_PL nsr; // Name Server Req. payload
3798 memset( &nsr, 0, sizeof(NSR_PL));
3800 // see Brocade Fabric Programming Guide,
3801 // Rev 1.3, pg 4-44
3802 nsr.CT_Rev = 0x01000000;
3803 nsr.FCS_Type = 0xFC020000;
3804 nsr.Command_code = 0x01710000;
3805 nsr.FCP = 8;
3807 // copy back to caller's buff, w/ BIG ENDIAN swap
3808 BigEndianSwap( (UCHAR*)&nsr, payload, sizeof(NSR_PL));
3811 break;
3816 case ELS_LOGO: // FC-PH PORT LogOut
3817 logo = &LogoutPayload; // load into stack buffer,
3818 // then BIG-ENDIAN switch a copy to caller
3819 logo->cmd = LS_LOGO;
3820 // load the 3 UCHARs of the node name
3821 // (if private loop, upper two UCHARs 0)
3822 logo->reserved = 0;
3824 logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
3825 logo->n_port_identifier[1] =
3826 (UCHAR)(fcChip->Registers.my_al_pa>>8);
3827 logo->n_port_identifier[2] =
3828 (UCHAR)(fcChip->Registers.my_al_pa>>16);
3829 // fill in with World Wide Name based Port Name - 8 UCHARs
3830 // get from Tach registers WWN hi & lo
3831 LoadWWN( fcChip, logo->port_name, 0);
3833 BigEndianSwap( (UCHAR*)&LogoutPayload,
3834 payload, sizeof(LogoutPayload) ); // 16 UCHAR struct
3835 break;
3838 case ELS_LOGO_ACC: // Logout Accept (FH-PH pg 149, table 74)
3839 logo = &LogoutPayload; // load into stack buffer,
3840 // then BIG-ENDIAN switch a copy to caller
3841 logo->cmd = LS_ACC;
3842 BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 ); // 4 UCHAR cmnd
3843 break;
3846 case ELS_RJT: // ELS_RJT link service reject (FH-PH pg 155)
3848 prjt = (REJECT_MESSAGE*)payload; // pick up passed data
3849 rjt.command_code = ELS_RJT;
3850 // reverse fields, because of Swap that follows...
3851 rjt.vendor = prjt->reserved; // vendor specific
3852 rjt.explain = prjt->reason; //
3853 rjt.reason = prjt->explain; //
3854 rjt.reserved = prjt->vendor; //
3855 // BIG-ENDIAN switch a copy to caller
3856 BigEndianSwap( (UCHAR*)&rjt, payload, 8 ); // 8 UCHAR cmnd
3857 break;
3863 case ELS_PRLI_ACC: // Process Login ACCept
3864 case ELS_PRLI: // Process Login
3865 case ELS_PRLO: // Process Logout
3866 memset( &PrliPayload, 0, sizeof( PrliPayload));
3867 prli = &PrliPayload; // load into stack buffer,
3869 if( type == ELS_PRLI )
3870 prli->cmd = 0x20; // Login
3871 else if( type == ELS_PRLO )
3872 prli->cmd = 0x21; // Logout
3873 else if( type == ELS_PRLI_ACC )
3875 prli->cmd = 0x02; // Login ACCept
3876 prli->valid = REQUEST_EXECUTED;
3880 prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
3881 prli->fcp_info = READ_XFER_RDY;
3882 prli->page_length = 0x10;
3883 prli->payload_length = 20;
3884 // Can be initiator AND target
3886 if( fcChip->Options.initiator )
3887 prli->fcp_info |= INITIATOR_FUNCTION;
3888 if( fcChip->Options.target )
3889 prli->fcp_info |= TARGET_FUNCTION;
3891 BigEndianSwap( (UCHAR*)&PrliPayload, payload, prli->payload_length);
3892 break;
3896 default: // no can do - programming error
3897 printk(" BuildLinkServicePayload unknown!\n");
3898 break;
3902 // loads 8 UCHARs for PORT name or NODE name base on
3903 // controller's WWN.
3904 void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
3906 UCHAR* bPtr, i;
3908 switch( type )
3910 case 0: // Port_Name
3911 bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3912 for( i =0; i<4; i++)
3913 dest[i] = *bPtr++;
3914 bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3915 for( i =4; i<8; i++)
3916 dest[i] = *bPtr++;
3917 break;
3918 case 1: // Node/Fabric _Name
3919 bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3920 for( i =0; i<4; i++)
3921 dest[i] = *bPtr++;
3922 bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3923 for( i =4; i<8; i++)
3924 dest[i] = *bPtr++;
3925 break;
3932 // We check the Port Login payload for required values. Note that
3933 // ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
3936 int verify_PLOGI( PTACHYON fcChip,
3937 TachFCHDR_GCMND* fchs,
3938 ULONG* reject_explain)
3940 LOGIN_PAYLOAD login;
3942 // source, dest, len (should be mult. of 4)
3943 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login, sizeof(login));
3945 // check FC version
3946 // if other port's highest supported version
3947 // is less than our lowest, and
3948 // if other port's lowest
3949 if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
3950 login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
3952 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
3953 return LOGICAL_ERROR;
3956 // Receive Data Field Size must be >=128
3957 // per FC-PH
3958 if (login.cmn_services.bb_rx_size < 128)
3960 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
3961 return LOGICAL_ERROR;
3964 // Only check Class 3 params
3965 if( login.class3.service_options & CLASS_VALID)
3967 if (login.class3.rx_data_size < 128)
3969 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
3970 return LOGICAL_ERROR;
3972 if( login.class3.initiator_control & XID_REQUIRED)
3974 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
3975 return LOGICAL_ERROR;
3978 return 0; // success
3984 int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
3986 PRLI_REQUEST prli; // buffer for BIG ENDIAN
3988 // source, dest, len (should be mult. of 4)
3989 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
3991 if( prli.fcp_info == 0 ) // i.e., not target or initiator?
3993 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
3994 return LOGICAL_ERROR;
3997 return 0; // success
4001 // SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
4002 // INPUTS:
4003 // source - ptr to LITTLE ENDIAN ULONGS
4004 // cnt - number of UCHARs to switch (should be mult. of ULONG)
4005 // OUTPUTS:
4006 // dest - ptr to BIG ENDIAN copy
4007 // RETURN:
4008 // none
4010 void BigEndianSwap( UCHAR *source, UCHAR *dest, USHORT cnt)
4012 int i,j;
4014 source+=3; // start at MSB of 1st ULONG
4015 for( j=0; j < cnt; j+=4, source+=4, dest+=4) // every ULONG
4017 for( i=0; i<4; i++) // every UCHAR in ULONG
4018 *(dest+i) = *(source-i);
4025 // Build FC Exchanges............
4027 static void buildFCPstatus(
4028 PTACHYON fcChip,
4029 ULONG ExchangeID);
4031 static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
4033 static ULONG build_SEST_sgList(
4034 ULONG *SESTalPairStart,
4035 Scsi_Cmnd *Cmnd,
4036 ULONG *sgPairs,
4037 PSGPAGES sgPages // link list of TL Ext. S/G pages from O/S Pool
4040 static int build_FCP_payload( Scsi_Cmnd *Cmnd,
4041 UCHAR* payload, ULONG type, ULONG fcp_dl );
4046 ERQ __________________
4047 | | / | Req_A_SFS_Len | ____________________
4048 |----------| / | Req_A_SFS_Addr |------->| Reserved |
4049 | IRB | / | Req_A_D_ID | | SOF EOF TimeStamp |
4050 |-----------/ | Req_A_SEST_Index |-+ | R_CTL | D_ID |
4051 | IRB | | Req_B... | | | CS_CTL| S_ID |
4052 |-----------\ | | | | TYPE | F_CTL |
4053 | IRB | \ | | | | SEQ_ID | SEQ_CNT |
4054 |----------- \ | | +-->+--| OX_ID | RX_ID |
4055 | | \ |__________________| | | RO |
4056 | | pl (payload/cmnd) |
4057 | | ..... |
4058 | |___________________|
4061 +-------------------------------------------+
4064 | e.g. IWE
4065 | SEST __________________ for FCP_DATA
4066 | | | / | | Hdr_Len | ____________________
4067 | |----------| / | Hdr_Addr_Addr |------->| Reserved |
4068 | | [0] | / |Remote_ID| RSP_Len| | SOF EOF TimeStamp |
4069 | |-----------/ | RSP_Addr |---+ | R_CTL | D_ID |
4070 +-> [1] | | | Buff_Off | | | CS_CTL| S_ID |
4071 |-----------\ |BuffIndex| Link | | | TYPE | F_CTL |
4072 | [2] | \ | Rsvd | RX_ID | | | SEQ_ID | SEQ_CNT |
4073 |----------- \ | Data_Len | | | OX_ID | RX_ID |
4074 | ... | \ | Exp_RO | | | RO |
4075 |----------| | Exp_Byte_Cnt | | |___________________|
4076 | SEST_LEN | +--| Len | |
4077 |__________| | | Address | |
4078 | | ... | | for FCP_RSP
4079 | |__________________| | ____________________
4080 | +----| Reserved |
4081 | | SOF EOF TimeStamp |
4082 | | R_CTL | D_ID |
4083 | | CS_CTL| S_ID |
4084 +--- local or extended | .... |
4085 scatter/gather lists
4086 defining upper-layer
4087 data (e.g. from user's App)
4091 // All TachLite commands must start with a SFS (Single Frame Sequence)
4092 // command. In the simplest case (a NOP Basic Link command),
4093 // only one frame header and ERQ entry is required. The most complex
4094 // case is the SCSI assisted command, which requires an ERQ entry,
4095 // SEST entry, and several frame headers and data buffers all
4096 // logically linked together.
4097 // Inputs:
4098 // cpqfcHBAdata - controller struct
4099 // type - PLOGI, SCSI_IWE, etc.
4100 // InFCHS - Incoming Tachlite FCHS which prompted this exchange
4101 // (only s_id set if we are originating)
4102 // Data - PVOID to data struct consistent with "type"
4103 // fcExchangeIndex - pointer to OX/RD ID value of built exchange
4104 // Return:
4105 // fcExchangeIndex - OX/RD ID value if successful
4106 // 0 - success
4107 // INVALID_ARGS - NULL/ invalid passed args
4108 // BAD_ALPA - Bad source al_pa address
4109 // LNKDWN_OSLS - Link Down (according to this controller)
4110 // OUTQUE_FULL - Outbound Que full
4111 // DRIVERQ_FULL - controller's Exchange array full
4112 // SEST_FULL - SEST table full
4114 // Remarks:
4115 // Psuedo code:
4116 // Check for NULL pointers / bad args
4117 // Build outgoing FCHS - the header/payload struct
4118 // Build IRB (for ERQ entry)
4119 // if SCSI command, build SEST entry (e.g. IWE, TRE,...)
4120 // return success
4122 //sbuildex
4123 ULONG cpqfcTSBuildExchange(
4124 CPQFCHBA *cpqfcHBAdata,
4125 ULONG type, // e.g. PLOGI
4126 TachFCHDR_GCMND* InFCHS, // incoming FCHS
4127 void *Data, // the CDB, scatter/gather, etc.
4128 LONG *fcExchangeIndex ) // points to allocated exchange,
4130 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
4131 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
4132 ULONG ulStatus = 0; // assume OK
4133 USHORT ox_ID, rx_ID=0xFFFF;
4134 ULONG SfsLen=0L;
4135 TachLiteIRB* pIRB;
4136 IRBflags IRB_flags;
4137 UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
4138 TachFCHDR_GCMND* CMDfchs;
4139 TachFCHDR* dataHDR; // 32 byte HEADER ONLY FCP-DATA buffer
4140 TachFCHDR_RSP* rspHDR; // 32 byte header + RSP payload
4141 Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data; // Linux Scsi CDB, S/G, ...
4142 TachLiteIWE* pIWE;
4143 TachLiteIRE* pIRE;
4144 TachLiteTWE* pTWE;
4145 TachLiteTRE* pTRE;
4146 ULONG fcp_dl; // total byte length of DATA transfered
4147 ULONG fl; // frame length (FC frame size, 128, 256, 512, 1024)
4148 ULONG sgPairs; // number of valid scatter/gather pairs
4149 int FCP_SCSI_command;
4150 BA_ACC_PAYLOAD *ba_acc;
4151 BA_RJT_PAYLOAD *ba_rjt;
4153 // check passed ARGS
4154 if( !fcChip->ERQ ) // NULL ptr means uninitialized Tachlite chip
4155 return INVALID_ARGS;
4158 if( type == SCSI_IRE ||
4159 type == SCSI_TRE ||
4160 type == SCSI_IWE ||
4161 type == SCSI_TWE)
4162 FCP_SCSI_command = 1;
4164 else
4165 FCP_SCSI_command = 0;
4168 // for commands that pass payload data (e.g. SCSI write)
4169 // examine command struct - verify that the
4170 // length of s/g buffers is adequate for total payload
4171 // length (end of list is NULL address)
4173 if( FCP_SCSI_command )
4175 if( Data ) // must have data descriptor (S/G list -- at least
4176 // one address with at least 1 byte of data)
4178 // something to do (later)?
4181 else
4182 return INVALID_ARGS; // invalid DATA ptr
4187 // we can build an Exchange for later Queuing (on the TL chip)
4188 // if an empty slot is available in the DevExt for this controller
4189 // look for available Exchange slot...
4191 if( type != FCP_RESPONSE &&
4192 type != BLS_ABTS &&
4193 type != BLS_ABTS_ACC ) // already have Exchange slot!
4194 *fcExchangeIndex = FindFreeExchange( fcChip, type );
4196 if( *fcExchangeIndex != -1 ) // Exchange is available?
4198 // assign tmp ptr (shorthand)
4199 CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs;
4202 if( Cmnd != NULL ) // (necessary for ABTS cases)
4204 Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
4205 Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort =
4206 fcFindLoggedInPort( fcChip,
4207 Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
4208 0, // DON'T search linked list for FC port id
4209 NULL, // DON'T search linked list for FC WWN
4210 NULL); // DON'T care about end of list
4215 // Build the command frame header (& data) according
4216 // to command type
4218 // fields common for all SFS frame types
4219 CMDfchs->reserved = 0L; // must clear
4220 CMDfchs->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; LCr=0, no TS
4222 // get the destination port_id from incoming FCHS
4223 // (initialized before calling if we're Originator)
4224 // Frame goes to port it was from - the source_id
4226 CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
4227 CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4230 // now enter command-specific fields
4231 switch( type )
4234 case BLS_NOP: // FC defined basic link service command NO-OP
4235 // ensure unique X_IDs! (use tracking function)
4237 *pIRB_flags = 0; // clear IRB flags
4238 IRB_flags.SFA = 1; // send SFS (not SEST index)
4239 SfsLen = *pIRB_flags;
4241 SfsLen <<= 24; // shift flags to MSB
4242 SfsLen += 32L; // add len to LSB (header only - no payload)
4244 // TYPE[31-24] 00 Basic Link Service
4245 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4246 CMDfchs->d_id |= 0x80000000L; // R_CTL = 80 for NOP (Basic Link Ser.)
4247 CMDfchs->f_ctl = 0x00310000L; // xchng originator, 1st seq,....
4248 CMDfchs->seq_cnt = 0x0L;
4249 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID for now; OX_ID on start
4250 CMDfchs->ro = 0x0L; // relative offset (n/a)
4251 CMDfchs->pl[0] = 0xaabbccddL; // words 8-15 frame data payload (n/a)
4252 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
4253 // (NOP should complete ~instantly)
4254 break;
4259 case BLS_ABTS_ACC: // Abort Sequence ACCept
4260 *pIRB_flags = 0; // clear IRB flags
4261 IRB_flags.SFA = 1; // send SFS (not SEST index)
4262 SfsLen = *pIRB_flags;
4264 SfsLen <<= 24; // shift flags to MSB
4265 SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
4267 CMDfchs->d_id |= 0x84000000L; // R_CTL = 84 for BASIC ACCept
4268 // TYPE[31-24] 00 Basic Link Service
4269 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4270 CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
4271 // CMDfchs->seq_id & count might be set from DataHdr?
4272 CMDfchs->ro = 0x0L; // relative offset (n/a)
4273 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4274 // (Timeout in case of weird error)
4276 // now set the ACCept payload...
4277 ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
4278 memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
4279 // Since PLDA requires (only) entire Exchange aborts, we don't need
4280 // to worry about what the last sequence was.
4282 // We expect that a "target" task is accepting the abort, so we
4283 // can use the OX/RX ID pair
4284 ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
4286 // source, dest, #bytes
4287 BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
4289 ba_acc->low_seq_cnt = 0;
4290 ba_acc->high_seq_cnt = 0xFFFF;
4293 break;
4296 case BLS_ABTS_RJT: // Abort Sequence ACCept
4297 *pIRB_flags = 0; // clear IRB flags
4298 IRB_flags.SFA = 1; // send SFS (not SEST index)
4299 SfsLen = *pIRB_flags;
4301 SfsLen <<= 24; // shift flags to MSB
4302 SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
4304 CMDfchs->d_id |= 0x85000000L; // R_CTL = 85 for BASIC ReJecT
4305 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4306 // TYPE[31-24] 00 Basic Link Service
4307 CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
4308 // CMDfchs->seq_id & count might be set from DataHdr?
4309 CMDfchs->ro = 0x0L; // relative offset (n/a)
4310 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4311 // (Timeout in case of weird error)
4313 CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
4315 // now set the ReJecT payload...
4316 ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
4317 memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
4319 // We expect that a "target" task couldn't find the Exhange in the
4320 // array of active exchanges, so we use a new LinkService X_ID.
4321 // See Reject payload description in FC-PH (Rev 4.3), pg. 140
4322 ba_rjt->reason_code = 0x09; // "unable to perform command request"
4323 ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
4326 break;
4330 case BLS_ABTS: // FC defined basic link service command ABTS
4331 // Abort Sequence
4334 *pIRB_flags = 0; // clear IRB flags
4335 IRB_flags.SFA = 1; // send SFS (not SEST index)
4336 SfsLen = *pIRB_flags;
4338 SfsLen <<= 24; // shift flags to MSB
4339 SfsLen += 32L; // add len to LSB (header only - no payload)
4341 // TYPE[31-24] 00 Basic Link Service
4342 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4343 CMDfchs->d_id |= 0x81000000L; // R_CTL = 81 for ABTS
4344 CMDfchs->f_ctl = 0x00110000L; // xchnge originator, last seq, xfer SI
4345 // CMDfchs->seq_id & count might be set from DataHdr?
4346 CMDfchs->ro = 0x0L; // relative offset (n/a)
4347 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4348 // (ABTS must timeout when responder is gone)
4349 break;
4353 case FCS_NSR: // Fabric Name Service Request
4354 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4357 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4358 // OX_ID, linked to Driver Transaction ID
4359 // (fix-up at Queing time)
4360 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4361 // OX_ID set at ERQueing time
4362 *pIRB_flags = 0; // clear IRB flags
4363 IRB_flags.SFA = 1; // send SFS (not SEST index)
4364 SfsLen = *pIRB_flags;
4366 SfsLen <<= 24; // shift flags to MSB
4367 SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
4369 CMDfchs->d_id |= 0x02000000L; // R_CTL = 02 for -
4370 // Name Service Request: Unsolicited
4371 // TYPE[31-24] 01 Extended Link Service
4372 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4373 CMDfchs->f_ctl = 0x20210000L;
4374 // OX_ID will be fixed-up at Tachyon enqueing time
4375 CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4376 CMDfchs->ro = 0x0L; // relative offset (n/a)
4378 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4385 break;
4390 case ELS_PLOGI: // FC-PH extended link service command Port Login
4391 // (May, 2000)
4392 // NOTE! This special case facilitates SANMark testing. The SANMark
4393 // test script for initialization-timeout.fcal.SANMark-1.fc
4394 // "eats" the OPN() primitive without issuing an R_RDY, causing
4395 // Tachyon to report LST (loop state timeout), which causes a
4396 // LIP. To avoid this, simply send out the frame (i.e. assuming a
4397 // buffer credit of 1) without waiting for R_RDY. Many FC devices
4398 // (other than Tachyon) have been doing this for years. We don't
4399 // ever want to do this for non-Link Service frames unless the
4400 // other device really did report non-zero login BB credit (i.e.
4401 // in the PLOGI ACCept frame).
4402 // CMDfchs->sof_eof |= 0x00000400L; // LCr=1
4404 case ELS_FDISC: // Fabric Discovery (Login)
4405 case ELS_FLOGI: // Fabric Login
4406 case ELS_SCR: // Fabric State Change Registration
4407 case ELS_LOGO: // FC-PH extended link service command Port Logout
4408 case ELS_PDISC: // FC-PH extended link service cmnd Port Discovery
4409 case ELS_PRLI: // FC-PH extended link service cmnd Process Login
4411 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4414 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4415 // OX_ID, linked to Driver Transaction ID
4416 // (fix-up at Queing time)
4417 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4418 // OX_ID set at ERQueing time
4419 *pIRB_flags = 0; // clear IRB flags
4420 IRB_flags.SFA = 1; // send SFS (not SEST index)
4421 SfsLen = *pIRB_flags;
4423 SfsLen <<= 24; // shift flags to MSB
4424 if( type == ELS_LOGO )
4425 SfsLen += (32L + 16L); // add len (header & PLOGI payload)
4426 else if( type == ELS_PRLI )
4427 SfsLen += (32L + 20L); // add len (header & PRLI payload)
4428 else if( type == ELS_SCR )
4429 SfsLen += (32L + sizeof(SCR_PL)); // add len (header & SCR payload)
4430 else
4431 SfsLen += (32L + 116L); // add len (header & PLOGI payload)
4433 CMDfchs->d_id |= 0x22000000L; // R_CTL = 22 for -
4434 // Extended Link_Data: Unsolicited Control
4435 // TYPE[31-24] 01 Extended Link Service
4436 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4437 CMDfchs->f_ctl = 0x01210000L;
4438 // OX_ID will be fixed-up at Tachyon enqueing time
4439 CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4440 CMDfchs->ro = 0x0L; // relative offset (n/a)
4442 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4444 break;
4448 case ELS_LOGO_ACC: // FC-PH extended link service logout accept
4449 case ELS_RJT: // extended link service reject (add reason)
4450 case ELS_ACC: // ext. link service generic accept
4451 case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
4452 case ELS_PRLI_ACC: // ext. link service process login accept
4455 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
4456 // ensure unique X_IDs! (use tracking function)
4457 // OX_ID from initiator cmd
4458 ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16);
4459 rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
4461 *pIRB_flags = 0; // clear IRB flags
4462 IRB_flags.SFA = 1; // send SFS (not SEST index)
4463 SfsLen = *pIRB_flags;
4465 SfsLen <<= 24; // shift flags to MSB
4466 if( type == ELS_RJT )
4468 SfsLen += (32L + 8L); // add len (header + payload)
4470 // ELS_RJT reason codes (utilize unused "reserved" field)
4471 CMDfchs->pl[0] = 1;
4472 CMDfchs->pl[1] = InFCHS->reserved;
4475 else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC) )
4476 SfsLen += (32L + 4L); // add len (header + payload)
4477 else if( type == ELS_PLOGI_ACC )
4478 SfsLen += (32L + 116L); // add len (header + payload)
4479 else if( type == ELS_PRLI_ACC )
4480 SfsLen += (32L + 20L); // add len (header + payload)
4482 CMDfchs->d_id |= 0x23000000L; // R_CTL = 23 for -
4483 // Extended Link_Data: Control Reply
4484 // TYPE[31-24] 01 Extended Link Service
4485 // f_ctl[23:0] exchg responder, last seq, e_s, tsi
4486 CMDfchs->f_ctl = 0x01990000L;
4487 CMDfchs->seq_cnt = 0x0L;
4488 CMDfchs->ox_rx_id = 0L; // clear
4489 CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
4490 CMDfchs->ox_rx_id <<= 16; // shift them
4492 CMDfchs->ro = 0x0L; // relative offset (n/a)
4494 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4496 break;
4499 // Fibre Channel SCSI 'originator' sequences...
4500 // (originator means 'initiator' in FCP-SCSI)
4501 case SCSI_IWE: // TachLite Initiator Write Entry
4503 PFC_LOGGEDIN_PORT pLoggedInPort =
4504 Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
4506 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4507 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
4509 // first, build FCP_CMND
4510 // unique X_ID fix-ups in StartExchange
4512 *pIRB_flags = 0; // clear IRB flags
4513 IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
4515 // NOTE: unlike FC LinkService login frames, normal
4516 // SCSI commands are sent without outgoing verification
4517 IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
4518 SfsLen = *pIRB_flags;
4520 SfsLen <<= 24; // shift flags to MSB
4521 SfsLen += 64L; // add len to LSB (header & CMND payload)
4523 CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
4525 // TYPE[31-24] 8 for FCP SCSI
4526 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4527 // valid RO
4528 CMDfchs->f_ctl = 0x08210008L;
4529 CMDfchs->seq_cnt = 0x0L;
4530 CMDfchs->ox_rx_id = 0L; // clear for now (-or- in later)
4531 CMDfchs->ro = 0x0L; // relative offset (n/a)
4533 // now, fill out FCP-DATA header
4534 // (use buffer inside SEST object)
4535 dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4536 dataHDR->reserved = 0L; // must clear
4537 dataHDR->sof_eof = 0x75002000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4538 dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4539 dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4540 // TYPE[31-24] 8 for FCP SCSI
4541 // f_ctl[23:0] xfer S.I.| valid RO
4542 dataHDR->f_ctl = 0x08010008L;
4543 dataHDR->seq_cnt = 0x02000000L; // sequence ID: df_ctl : seqence count
4544 dataHDR->ox_rx_id = 0L; // clear; fix-up dataHDR fields later
4545 dataHDR->ro = 0x0L; // relative offset (n/a)
4547 // Now setup the SEST entry
4548 pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
4550 // fill out the IWE:
4552 // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
4553 pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
4556 // from login parameters with other port, what's the largest frame
4557 // we can send?
4558 if( pLoggedInPort == NULL)
4560 ulStatus = INVALID_ARGS; // failed! give up
4561 break;
4563 if( pLoggedInPort->rx_data_size >= 2048)
4564 fl = 0x00020000; // 2048 code (only support 1024!)
4565 else if( pLoggedInPort->rx_data_size >= 1024)
4566 fl = 0x00020000; // 1024 code
4567 else if( pLoggedInPort->rx_data_size >= 512)
4568 fl = 0x00010000; // 512 code
4569 else
4570 fl = 0; // 128 bytes -- should never happen
4573 pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
4574 pIWE->Hdr_Addr = virt_to_bus( dataHDR );
4575 pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4576 pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4578 memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0,
4579 sizeof( FCP_STATUS_RESPONSE) ); // clear out previous status
4581 pIWE->RSP_Addr = virt_to_bus(
4582 &fcChip->SEST->RspHDR[ *fcExchangeIndex ]);
4584 // Do we need local or extended gather list?
4585 // depends on size - we can handle 3 len/addr pairs
4586 // locally.
4588 fcp_dl = build_SEST_sgList(
4589 &pIWE->GLen1,
4590 Cmnd, // S/G list
4591 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4592 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4594 if( !fcp_dl ) // error building S/G list?
4596 ulStatus = MEMPOOL_FAIL;
4597 break; // give up
4600 // Now that we know total data length in
4601 // the passed S/G buffer, set FCP CMND frame
4602 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4606 if( sgPairs > 3 ) // need extended s/g list
4607 pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
4608 else // local data pointers (in SEST)
4609 pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
4611 // ULONG 5
4612 pIWE->Link = 0x0000ffffL; // Buff_Index | Link
4614 pIWE->RX_ID = 0x0L; // DWord 6: RX_ID set by target XFER_RDY
4616 // DWord 7
4617 pIWE->Data_Len = 0L; // TL enters rcv'd XFER_RDY BURST_LEN
4618 pIWE->Exp_RO = 0L; // DWord 8
4619 // DWord 9
4620 pIWE->Exp_Byte_Cnt = fcp_dl; // sum of gather buffers
4622 break;
4628 case SCSI_IRE: // TachLite Initiator Read Entry
4630 if( Cmnd->timeout != 0)
4632 // printk("Cmnd->timeout %d\n", Cmnd->timeout);
4633 // per Linux Scsi
4634 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
4636 else // use our best guess, based on FC & device
4639 if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)
4641 // turn off our timeouts (for now...)
4642 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF;
4644 else
4646 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4647 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
4652 // first, build FCP_CMND
4655 *pIRB_flags = 0; // clear IRB flags
4656 IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
4657 // NOTE: unlike FC LinkService login frames,
4658 // normal SCSI commands are sent "open loop"
4659 IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
4660 SfsLen = *pIRB_flags;
4662 SfsLen <<= 24; // shift flags to MSB
4663 SfsLen += 64L; // add len to LSB (header & CMND payload)
4665 CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
4667 // TYPE[31-24] 8 for FCP SCSI
4668 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4669 // valid RO
4670 CMDfchs->f_ctl = 0x08210008L;
4671 CMDfchs->seq_cnt = 0x0L;
4672 // x_ID & data direction bit set later
4673 CMDfchs->ox_rx_id = 0xFFFF; // clear
4674 CMDfchs->ro = 0x0L; // relative offset (n/a)
4678 // Now setup the SEST entry
4679 pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
4681 // fill out the IRE:
4682 // VALid entry:Dir outbound:enable CM:enal INT:
4683 pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
4685 pIRE->reserved = 0L;
4686 pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4687 pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4690 pIRE->RSP_Addr = virt_to_bus(
4691 &fcChip->SEST->RspHDR[ *fcExchangeIndex ]);
4694 // Do we need local or extended gather list?
4695 // depends on size - we can handle 3 len/addr pairs
4696 // locally.
4698 fcp_dl = build_SEST_sgList(
4699 &pIRE->SLen1,
4700 Cmnd, // SCSI command Data desc. with S/G list
4701 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4702 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4705 if( !fcp_dl ) // error building S/G list?
4707 // It is permissible to have a ZERO LENGTH Read command.
4708 // If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
4709 // to 0 and continue.
4710 if( Cmnd->request_bufflen == 0 )
4712 fcp_dl = 0; // no FC DATA frames expected
4715 else
4717 ulStatus = MEMPOOL_FAIL;
4718 break; // give up
4722 // now that we know the S/G length, build CMND payload
4723 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4726 if( sgPairs > 3 ) // need extended s/g list
4727 pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
4728 else
4729 pIRE->Buff_Off = 0x80000000; // local data, no offset
4731 pIRE->Buff_Index = 0x0L; // DWord 5: Buff_Index | Reserved
4733 pIRE->Exp_RO = 0x0L; // DWord 6: Expected Rel. Offset
4735 pIRE->Byte_Count = 0; // DWord 7: filled in by TL on err
4736 pIRE->reserved_ = 0; // DWord 8: reserved
4737 // NOTE: 0 length READ is OK.
4738 pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
4740 break;
4745 // Fibre Channel SCSI 'responder' sequences...
4746 // (originator means 'target' in FCP-SCSI)
4747 case SCSI_TWE: // TachLite Target Write Entry
4749 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4751 // first, build FCP_CMND
4753 *pIRB_flags = 0; // clear IRB flags
4754 IRB_flags.SFA = 1; // send SFS (XFER_RDY)
4755 SfsLen = *pIRB_flags;
4757 SfsLen <<= 24; // shift flags to MSB
4758 SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4760 CMDfchs->d_id |= (0x05000000L); // R_CTL = 5 for XFER_RDY
4762 // TYPE[31-24] 8 for FCP SCSI
4763 // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
4764 // valid RO
4765 CMDfchs->f_ctl = 0x08810008L;
4766 CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
4767 // use originator (other port's) OX_ID
4768 CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // we want upper 16 bits
4769 CMDfchs->ro = 0x0L; // relative offset (n/a)
4771 // now, fill out FCP-RSP header
4772 // (use buffer inside SEST object)
4774 rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4775 rspHDR->reserved = 0L; // must clear
4776 rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4777 rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4778 rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4779 // TYPE[31-24] 8 for FCP SCSI
4780 // f_ctl[23:0] responder|last seq| xfer S.I.
4781 rspHDR->f_ctl = 0x08910000L;
4782 rspHDR->seq_cnt = 0x03000000; // sequence ID
4783 rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
4784 rspHDR->ro = 0x0L; // relative offset (n/a)
4787 // Now setup the SEST entry
4789 pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
4791 // fill out the TWE:
4793 // VALid entry:Dir outbound:enable CM:enal INT:
4794 pTWE->Seq_Accum = 0xC4000000L; // upper word flags
4795 pTWE->reserved = 0L;
4796 pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
4797 pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4800 // Do we need local or extended gather list?
4801 // depends on size - we can handle 3 len/addr pairs
4802 // locally.
4804 fcp_dl = build_SEST_sgList(
4805 &pTWE->SLen1,
4806 Cmnd, // S/G list
4807 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4808 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4811 if( !fcp_dl ) // error building S/G list?
4813 ulStatus = MEMPOOL_FAIL;
4814 break; // give up
4817 // now that we know the S/G length, build CMND payload
4818 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4821 if( sgPairs > 3 ) // need extended s/g list
4822 pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
4823 else
4824 pTWE->Buff_Off = 0x80000000; // local data, no offset
4826 pTWE->Buff_Index = 0; // Buff_Index | Link
4827 pTWE->Exp_RO = 0;
4828 pTWE->Byte_Count = 0; // filled in by TL on err
4829 pTWE->reserved_ = 0;
4830 pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
4832 break;
4839 case SCSI_TRE: // TachLite Target Read Entry
4841 // It doesn't make much sense for us to "time-out" a READ,
4842 // but we'll use it for design consistency and internal error recovery.
4843 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4845 // I/O request block settings...
4846 *pIRB_flags = 0; // clear IRB flags
4847 // check PRLI (process login) info
4848 // to see if Initiator Requires XFER_RDY
4849 // if not, don't send one!
4850 // { PRLI check...}
4851 IRB_flags.SFA = 0; // don't send XFER_RDY - start data
4852 SfsLen = *pIRB_flags;
4854 SfsLen <<= 24; // shift flags to MSB
4855 SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4859 // now, fill out FCP-DATA header
4860 // (use buffer inside SEST object)
4861 dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4863 dataHDR->reserved = 0L; // must clear
4864 dataHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
4865 dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4866 dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4869 // TYPE[31-24] 8 for FCP SCSI
4870 // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
4871 // valid RO
4872 dataHDR->f_ctl = 0x08810008L;
4873 dataHDR->seq_cnt = 0x01000000; // sequence ID (no XRDY)
4874 dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
4875 dataHDR->ro = 0x0L; // relative offset (n/a)
4877 // now, fill out FCP-RSP header
4878 // (use buffer inside SEST object)
4879 rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4881 rspHDR->reserved = 0L; // must clear
4882 rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4883 rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4884 rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4885 // TYPE[31-24] 8 for FCP SCSI
4886 // f_ctl[23:0] responder|last seq| xfer S.I.
4887 rspHDR->f_ctl = 0x08910000L;
4888 rspHDR->seq_cnt = 0x02000000; // sequence ID: df_ctl: sequence count
4890 rspHDR->ro = 0x0L; // relative offset (n/a)
4893 // Now setup the SEST entry
4894 pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
4897 // VALid entry:Dir outbound:enable CM:enal INT:
4898 pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
4899 pTRE->Hdr_Addr = virt_to_bus( dataHDR );
4900 pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
4901 pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4902 pTRE->RSP_Addr = virt_to_bus( rspHDR );
4905 // Do we need local or extended gather list?
4906 // depends on size - we can handle 3 len/addr pairs
4907 // locally.
4909 fcp_dl = build_SEST_sgList(
4910 &pTRE->GLen1,
4911 Cmnd, // S/G list
4912 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4913 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4916 if( !fcp_dl ) // error building S/G list?
4918 ulStatus = MEMPOOL_FAIL;
4919 break; // give up
4922 // no payload or command to build -- READ doesn't need XRDY
4925 if( sgPairs > 3 ) // need extended s/g list
4926 pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
4927 else // local data pointers (in SEST)
4928 pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
4930 // ULONG 5
4931 pTRE->Buff_Index = 0L; // Buff_Index | reserved
4932 pTRE->reserved = 0x0L; // DWord 6
4934 // DWord 7: NOTE: zero length will
4935 // hang TachLite!
4936 pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
4938 pTRE->reserved_ = 0L; // DWord 8
4939 pTRE->reserved__ = 0L; // DWord 9
4941 break;
4949 case FCP_RESPONSE:
4950 // Target response frame: this sequence uses an OX/RX ID
4951 // pair from a completed SEST exchange. We built most
4952 // of the response frame when we created the TWE/TRE.
4954 *pIRB_flags = 0; // clear IRB flags
4955 IRB_flags.SFA = 1; // send SFS (RSP)
4956 SfsLen = *pIRB_flags;
4958 SfsLen <<= 24; // shift flags to MSB
4959 SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
4962 Exchanges->fcExchange[ *fcExchangeIndex].type =
4963 FCP_RESPONSE; // change Exchange type to "response" phase
4965 // take advantage of prior knowledge of OX/RX_ID pair from
4966 // previous XFER outbound frame (still in fchs of exchange)
4967 fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id =
4968 CMDfchs->ox_rx_id;
4970 // Check the status of the DATA phase of the exchange so we can report
4971 // status to the initiator
4972 buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
4974 memcpy(
4975 CMDfchs, // re-use same XFER fchs for Response frame
4976 &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
4977 sizeof( TachFCHDR_RSP ));
4980 break;
4982 default:
4983 printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
4984 break;
4990 if( !ulStatus) // no errors above?
4992 // FCHS is built; now build IRB
4994 // link the just built FCHS (the "command") to the IRB entry
4995 // for this Exchange.
4996 pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB;
4998 // len & flags according to command type above
4999 pIRB->Req_A_SFS_Len = SfsLen; // includes IRB flags & len
5000 pIRB->Req_A_SFS_Addr = virt_to_bus(CMDfchs); // TL needs physical addr
5001 // of frame to send
5002 pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
5004 // Exchange is complete except for "fix-up" fields to be set
5005 // at Tachyon Queuing time:
5006 // IRB->Req_A_Trans_ID (OX_ID/ RX_ID):
5007 // for SEST entry, lower bits correspond to actual FC Exchange ID
5008 // fchs->OX_ID or RX_ID
5010 else
5012 #ifdef DBG
5013 printk( "FC Error: SEST build Pool Allocation failed\n");
5014 #endif
5015 // return resources...
5016 cpqfcTSCompleteExchange( fcChip, *fcExchangeIndex); // SEST build failed
5019 else // no Exchanges available
5021 ulStatus = SEST_FULL;
5022 printk( "FC Error: no fcExchanges available\n");
5024 return ulStatus;
5032 // set RSP payload fields
5033 static void buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID)
5035 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5036 FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID]; // shorthand
5037 PFCP_STATUS_RESPONSE pFcpStatus;
5039 memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
5040 sizeof( FCP_STATUS_RESPONSE) );
5041 if( pExchange->status ) // something wrong?
5043 pFcpStatus = (PFCP_STATUS_RESPONSE) // cast RSP buffer for this xchng
5044 &fcChip->SEST->RspHDR[ ExchangeID ].pl;
5045 if( pExchange->status & COUNT_ERROR )
5048 // set FCP response len valid (so we can report count error)
5049 pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
5050 pFcpStatus->fcp_rsp_len = 0x04000000; // 4 byte len (BIG Endian)
5052 pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
5060 // This routine builds scatter/gather lists into SEST entries
5061 // INPUTS:
5062 // SESTalPair - SEST address @DWordA "Local Buffer Length"
5063 // sgList - Scatter/Gather linked list of Len/Address data buffers
5064 // OUTPUT:
5065 // sgPairs - number of valid address/length pairs
5066 // Remarks:
5067 // The SEST data buffer pointers only depend on number of
5068 // length/ address pairs, NOT on the type (IWE, TRE,...)
5069 // Up to 3 pairs can be referenced in the SEST - more than 3
5070 // require this Extended S/G list page. The page holds 4, 8, 16...
5071 // len/addr pairs, per Scatter/Gather List Page Length Reg.
5072 // TachLite allows pages to be linked to any depth.
5074 //#define DBG_SEST_SGLIST 1 // for printing out S/G pairs with Ext. pages
5076 static ULONG build_SEST_sgList(
5077 ULONG *SESTalPairStart, // the 3 len/address buffers in SEST
5078 Scsi_Cmnd *Cmnd,
5079 ULONG *sgPairs,
5080 PSGPAGES sgPages) // link list of TL Ext. S/G pages from O/S Pool
5083 ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
5084 ULONG* alPair = SESTalPairStart;
5085 ULONG alignedPageAddress; // TL hardware alignment requirement
5086 int PairCount;
5087 unsigned long ulBuff;
5088 ULONG total_data_len=0; // (in bytes)
5089 ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
5090 ULONG thisMappingLen;
5091 struct scatterlist *sgl; // S/G list (Linux format)
5095 if( !Cmnd->use_sg ) // no S/G list?
5097 *sgPairs = 1; // use "local" S/G pair in SEST entry
5098 // (for now, ignore address bits above #31)
5099 *alPair++ = bytes_to_go & 0x7ffff; // bits 18-0, length
5100 ulBuff = virt_to_bus( Cmnd->request_buffer);
5101 #if BITS_PER_LONG > 32
5102 if( ulBuff >>32 )
5104 printk("FATAL! Tachyon DMA address %p exceeds 32 bits\n", (void*)ulBuff );
5105 return 0;
5107 #endif
5108 *alPair = (ULONG)ulBuff;
5109 return bytes_to_go;
5113 // [TBD - update for Linux to support > 32 bits addressing]
5114 // since the format for local & extended S/G lists is different,
5115 // check if S/G pairs exceeds 3.
5116 *sgPairs = Cmnd->use_sg;
5117 sgl = (struct scatterlist*)Cmnd->request_buffer;
5119 if( *sgPairs <= 3 ) // need "local" SEST list
5121 while( bytes_to_go)
5123 thisMappingLen = sgl->length; // we want them ALL on every pass
5124 bytes_to_go = bytes_to_go - thisMappingLen;
5126 // we have L/A pair; L = thisMappingLen, A = physicalAddress
5127 // load into SEST...
5128 total_data_len += thisMappingLen & 0x7ffff; // mask in valid bits
5129 // per SEST format
5130 *alPair = thisMappingLen & 0x7ffff; // bits 18-0, length
5131 // physicalAddress.HighPart <= 19; // shift to bit 19
5133 // pick up bits 44-32 of upper 64-bit address
5134 // and load into 31-19 LBAU (upper addr) of SEST entry
5135 // *alPair++ |=(ULONG)((physicalAddress.HighPart & 0xFFF8));
5136 // on Tachlite TS's local S/G, we can handle 13 extra address bits
5137 // i.e., bits 31-19 are actually bits 44-32 of physicalAddress
5139 alPair++;
5141 ulBuff = virt_to_bus( sgl->address);
5142 #if BITS_PER_LONG > 32
5143 if( ulBuff >>32 )
5145 printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff );
5146 return 0;
5148 #endif
5149 *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
5151 ++sgl; // next S/G pair
5152 #ifdef DBG_SEST_SGLIST
5153 printk(" thisLen %d ", thisMappingLen);
5154 printk(" remain %d\n", bytes_to_go);
5155 #endif
5163 else // more than 3 pairs requires Extended S/G page (Pool Allocation)
5165 // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
5169 for( i=2; i<6; i++)
5170 alPair[i] = 0;
5172 PairCount = TL_EXT_SG_PAGE_COUNT; // forces initial page allocation
5174 while( bytes_to_go )
5178 // Per SEST format, we can support 524287 byte lenghts per
5179 // S/G pair. Typical user buffers are 4k, and very rarely
5180 // exceed 12k due to fragmentation of physical memory pages.
5181 // However, on certain O/S system (not "user") buffers (on platforms
5182 // with huge memories like 256Meg), it's possible to exceed this
5183 // length in a single S/G address/len mapping.
5185 // Check for Tachyon length boundary
5187 if( sgl->length > 0x7ffff )
5189 // never ask for more than we can handle
5190 thisMappingLen = sgl->length & 0x7ffff;
5192 else
5193 thisMappingLen = sgl->length;
5197 // should we load into "this" extended S/G page, or allocate
5198 // new page?
5200 if( PairCount >= TL_EXT_SG_PAGE_COUNT )
5202 // have we exceeded the max possible extended pages?
5203 if( AllocatedPages >= TL_MAX_SGPAGES)
5205 printk("Error: aborted loop on %d Ext. S/G page allocations\n",
5206 AllocatedPages);
5208 total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
5209 break; // failed
5212 // Allocate the TL Extended S/G list page from O/S pool. We have
5213 // to allocated twice what we want to ensure required TL alignment
5214 // (Tachlite TL/TS User Man. Rev 6.0, p 168)
5215 // We store the original allocated PVOID so we can free later
5217 sgPages->PoolPage[ AllocatedPages] =
5218 kmalloc( TL_EXT_SG_PAGE_BYTELEN*2,GFP_ATOMIC); // double for alignment
5221 if( !sgPages->PoolPage[ AllocatedPages] ) // Allocation failed?
5224 printk("Error: Allocation failed @ %d S/G page allocations\n",
5225 AllocatedPages);
5227 total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
5228 break; // give up
5230 // clear out memory we just allocated
5231 memset( sgPages->PoolPage[AllocatedPages], 0,
5232 TL_EXT_SG_PAGE_BYTELEN*2);
5235 // align the memory - TL requires sizeof() Ext. S/G page alignment.
5236 // We doubled the actual required size so we could mask off LSBs
5237 // to get desired offset
5239 ulBuff = virt_to_bus( sgPages->PoolPage[AllocatedPages]);
5241 #if BITS_PER_LONG > 32
5242 if( ulBuff >>32 )
5244 printk("cqpfcTS: Tach ext. S/G DMA address %p > 32 bits\n",
5245 (void*)ulBuff );
5246 return 0;
5248 #endif
5250 ulBuff += TL_EXT_SG_PAGE_BYTELEN; // ensures we pass align. boundary
5251 ulBuff &= (0xFFFFFFFF - (TL_EXT_SG_PAGE_BYTELEN -1) );// mask off LSBs
5253 alignedPageAddress = (ULONG)ulBuff;
5254 #ifdef DBG_SEST_SGLIST
5255 printk("new PoolPage: %p, alignedPageAddress %lXh\n",
5256 sgPages->PoolPage[AllocatedPages], ulBuff);
5257 #endif
5260 // set pointer, in SEST if first Ext. S/G page, or in last pair
5261 // of linked Ext. S/G pages...
5262 // (Only 32-bit PVOIDs, so just load lower 32 bits)
5263 // NOTE: the Len field must be '0' if this is the first Ext. S/G
5264 // pointer in SEST, and not 0 otherwise.
5265 if( alPair == SESTalPairStart) // initial Ext. S/G list?
5266 *alPair = 0;
5267 else // not the SEST entry... Len must be non-0, so
5268 // arbitrarily set it to number bytes remaining
5269 *alPair = ( bytes_to_go & 0x7ffff);
5271 #ifdef DBG_SEST_SGLIST
5272 printk("PairCount %d @%p even %Xh, ",
5273 PairCount, alPair, *alPair);
5274 #endif
5275 alPair++; // next DWORD
5277 *alPair = alignedPageAddress; // TL needs 32-bit physical
5278 #ifdef DBG_SEST_SGLIST
5279 printk("odd %Xh\n", *alPair);
5280 #endif
5282 // now reset the pointer to the ACTUAL (Extended) S/G page
5283 // which will accept the Len/ PhysicalAddress pairs
5284 alPair = bus_to_virt(alignedPageAddress);
5286 AllocatedPages++;
5287 PairCount = 1; // starting new Ext. S/G page
5288 } // end of new TL Ext. S/G page allocation
5291 *alPair = thisMappingLen; // bits 18-0, length (range check above)
5294 // physicalAddress.HighPart <= 19; // shift to bit 19
5296 // pick up bits 44-32 of upper 64-bit address
5297 // and load into 31-19 LBAU (upper addr) of SEST entry
5298 // *alPair |=(ULONG)((physicalAddress.HighPart & 0xFFF8));
5301 #ifdef DBG_SEST_SGLIST
5302 printk("PairCount %d @%p, even %Xh, ",
5303 PairCount, alPair, *alPair);
5304 #endif
5306 alPair++; // next DWORD
5307 // on Tachlite TS's local S/G, we can handle 13 extra address bits
5308 // i.e., bits 31-19 are actually bits 44-32 of physicalAddress
5311 ulBuff = virt_to_bus( sgl->address);
5312 #if BITS_PER_LONG > 32
5313 if( ulBuff >>32 )
5315 printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff );
5316 return 0;
5318 #endif
5319 *alPair = (ULONG)ulBuff; // lower 32 bits (31-0)
5322 #ifdef DBG_SEST_SGLIST
5323 printk("odd %Xh\n", *alPair);
5324 #endif
5325 alPair++; // next DWORD
5328 PairCount++; // next Length/Address pair
5329 bytes_to_go -= thisMappingLen;
5330 total_data_len += thisMappingLen;
5331 sgl++; // next S/G pair
5334 return total_data_len;
5339 // The Tachlite SEST table is referenced to OX_ID (or RX_ID). To optimize
5340 // performance and debuggability, we index the Exchange structure to FC X_ID
5341 // This enables us to build exchanges for later en-queing to Tachyon,
5342 // provided we have an open X_ID slot. At Tachyon queing time, we only
5343 // need an ERQ slot; then "fix-up" references in the
5344 // IRB, FCHS, etc. as needed.
5345 // RETURNS:
5346 // 0 if successful
5347 // non-zero on error
5348 //sstartex
5349 ULONG cpqfcTSStartExchange(
5350 CPQFCHBA *cpqfcHBAdata,
5351 LONG ExchangeID )
5353 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
5354 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5355 FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
5356 USHORT producer, consumer;
5357 ULONG ulStatus=0;
5358 short int ErqIndex;
5359 BOOLEAN CompleteExchange = FALSE; // e.g. ACC replies are complete
5360 BOOLEAN SestType=FALSE;
5361 ULONG InboundData=0;
5363 // We will manipulate Tachlite chip registers here to successfully
5364 // start exchanges.
5366 // Check that link is not down -- we can't start an exchange on a
5367 // down link!
5369 if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
5371 printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n",
5372 fcChip->Registers.FMstatus.value & 0xFF,
5373 ExchangeID,
5374 pExchange->type,
5375 pExchange->fchs.d_id);
5377 if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame?
5379 // Our most popular LinkService commands are port discovery types
5380 // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
5381 // events, so it makes no sense to Que them. However, ABTS should
5382 // be queued, since exchange sequences are likely destroyed by
5383 // Link Down events, and we want to notify other ports of broken
5384 // sequences by aborting the corresponding exchanges.
5385 if( pExchange->type != BLS_ABTS )
5387 ulStatus = LNKDWN_OSLS;
5388 goto Done;
5389 // don't Que most LinkServ exchanges on LINK DOWN
5393 printk("fcStartExchange: Que x_ID %Xh, type %Xh\n",
5394 ExchangeID, pExchange->type);
5395 pExchange->status |= EXCHANGE_QUEUED;
5396 ulStatus = EXCHANGE_QUEUED;
5397 goto Done;
5400 // Make sure ERQ has available space.
5402 producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
5403 consumer = (USHORT)fcChip->ERQ->consumerIndex;
5404 producer++; // We are testing for full que by incrementing
5406 if( producer >= ERQ_LEN ) // rollover condition?
5407 producer = 0;
5408 if( consumer != producer ) // ERQ not full?
5410 // ****************** Need Atomic access to chip registers!!********
5412 // remember ERQ PI for copying IRB
5413 ErqIndex = (USHORT)fcChip->ERQ->producerIndex;
5414 fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
5415 // we have an ERQ slot! If SCSI command, need SEST slot
5416 // otherwise we are done.
5418 // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
5419 // set according to direction of data to/from Tachyon for SEST assists.
5420 // For consistency, enforce this rule for Link Service (non-SEST)
5421 // exchanges as well.
5423 // fix-up the X_ID field in IRB
5424 pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
5426 // fix-up the X_ID field in fchs -- depends on Originator or Responder,
5427 // outgoing or incoming data?
5428 switch( pExchange->type )
5430 // ORIGINATOR types... we're setting our OX_ID and
5431 // defaulting the responder's RX_ID to 0xFFFF
5433 case SCSI_IRE:
5434 // Requirement: set MSB of x_ID for Incoming TL data
5435 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5436 InboundData = 0x8000;
5438 case SCSI_IWE:
5439 SestType = TRUE;
5440 pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
5441 pExchange->fchs.ox_rx_id <<= 16; // MSW shift
5442 pExchange->fchs.ox_rx_id |= 0xffff; // add default RX_ID
5444 // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
5445 // (not necessary for IRE -- data buffer unused)
5446 if( pExchange->type == SCSI_IWE)
5448 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id =
5449 pExchange->fchs.ox_rx_id;
5453 break;
5456 case FCS_NSR: // ext. link service Name Service Request
5457 case ELS_SCR: // ext. link service State Change Registration
5458 case ELS_FDISC:// ext. link service login
5459 case ELS_FLOGI:// ext. link service login
5460 case ELS_LOGO: // FC-PH extended link service logout
5461 case BLS_NOP: // Basic link service No OPeration
5462 case ELS_PLOGI:// ext. link service login (PLOGI)
5463 case ELS_PDISC:// ext. link service login (PDISC)
5464 case ELS_PRLI: // ext. link service process login
5466 pExchange->fchs.ox_rx_id = ExchangeID;
5467 pExchange->fchs.ox_rx_id <<= 16; // MSW shift
5468 pExchange->fchs.ox_rx_id |= 0xffff; // and RX_ID
5470 break;
5475 // RESPONDER types... we must set our RX_ID while preserving
5476 // sender's OX_ID
5477 // outgoing (or no) data
5478 case ELS_RJT: // extended link service reject
5479 case ELS_LOGO_ACC: // FC-PH extended link service logout accept
5480 case ELS_ACC: // ext. generic link service accept
5481 case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
5482 case ELS_PRLI_ACC: // ext. link service process login accept
5484 CompleteExchange = TRUE; // Reply (ACC or RJT) is end of exchange
5485 pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
5487 break;
5490 // since we are a Responder, OX_ID should already be set by
5491 // cpqfcTSBuildExchange(). We need to -OR- in RX_ID
5492 case SCSI_TWE:
5493 SestType = TRUE;
5494 // Requirement: set MSB of x_ID for Incoming TL data
5495 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5497 pExchange->fchs.ox_rx_id &= 0xFFFF0000; // clear RX_ID
5498 // Requirement: set MSB of RX_ID for Incoming TL data
5499 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5500 pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
5501 break;
5504 case SCSI_TRE:
5505 SestType = TRUE;
5507 // there is no XRDY for SEST target read; the data
5508 // header needs to be updated. Also update the RSP
5509 // exchange IDs for the status frame, in case it is sent automatically
5510 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
5511 fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id =
5512 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5514 // for easier FCP response logic (works for TWE and TRE),
5515 // copy exchange IDs. (Not needed if TRE 'RSP' bit set)
5516 pExchange->fchs.ox_rx_id =
5517 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5519 break;
5522 case FCP_RESPONSE: // using existing OX_ID/ RX_ID pair,
5523 // start SFS FCP-RESPONSE frame
5524 // OX/RX_ID should already be set! (See "fcBuild" above)
5525 CompleteExchange = TRUE; // RSP is end of FCP-SCSI exchange
5528 break;
5531 case BLS_ABTS_RJT: // uses new RX_ID, since SEST x_ID non-existent
5532 case BLS_ABTS_ACC: // using existing OX_ID/ RX_ID pair from SEST entry
5533 CompleteExchange = TRUE; // ACC or RJT marks end of FCP-SCSI exchange
5534 case BLS_ABTS: // using existing OX_ID/ RX_ID pair from SEST entry
5537 break;
5540 default:
5541 printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
5542 pExchange->type, pExchange->type);
5543 return INVALID_ARGS;
5547 // X_ID fields are entered -- copy IRB to Tachyon's ERQ
5550 memcpy(
5551 &fcChip->ERQ->QEntry[ ErqIndex ], // dest.
5552 &pExchange->IRB,
5553 32); // fixed (hardware) length!
5555 PCI_TRACEO( ExchangeID, 0xA0)
5557 // ACTION! May generate INT and IMQ entry
5558 writel( fcChip->ERQ->producerIndex,
5559 fcChip->Registers.ERQproducerIndex.address);
5562 if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame?
5565 // wait for completion! (TDB -- timeout and chip reset)
5568 PCI_TRACEO( ExchangeID, 0xA4)
5570 enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
5572 down_interruptible( cpqfcHBAdata->TYOBcomplete);
5574 disable_irq( cpqfcHBAdata->HostAdapter->irq);
5575 PCI_TRACE( 0xA4)
5577 // On login exchanges, BAD_ALPA (non-existent port_id) results in
5578 // FTO (Frame Time Out) on the Outbound Completion message.
5579 // If we got an FTO status, complete the exchange (free up slot)
5580 if( CompleteExchange || // flag from Reply frames
5581 pExchange->status ) // typically, can get FRAME_TO
5583 cpqfcTSCompleteExchange( fcChip, ExchangeID);
5587 else // SEST Exchange
5589 ulStatus = 0; // ship & pray success (e.g. FCP-SCSI)
5591 if( CompleteExchange ) // by Type of exchange (e.g. end-of-xchng)
5593 cpqfcTSCompleteExchange( fcChip, ExchangeID);
5596 else
5597 pExchange->status &= ~EXCHANGE_QUEUED; // clear ExchangeQueued flag
5603 else // ERQ 'producer' = 'consumer' and QUE is full
5605 ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
5608 Done:
5609 PCI_TRACE( 0xA0)
5610 return ulStatus;
5617 // Scan fcController->fcExchanges array for a usuable index (a "free"
5618 // exchange).
5619 // Inputs:
5620 // fcChip - pointer to TachLite chip structure
5621 // Return:
5622 // index - exchange array element where exchange can be built
5623 // -1 - exchange array is full
5624 // REMARKS:
5625 // Although this is a (yuk!) linear search, we presume
5626 // that the system will complete exchanges about as quickly as
5627 // they are submitted. A full Exchange array (and hence, max linear
5628 // search time for free exchange slot) almost guarantees a Fibre problem
5629 // of some sort.
5630 // In the interest of making exchanges easier to debug, we want a LRU
5631 // (Least Recently Used) scheme.
5634 static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
5636 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5637 ULONG i;
5638 ULONG ulStatus=-1; // assume failure
5641 if( type == SCSI_IRE ||
5642 type == SCSI_TRE ||
5643 type == SCSI_IWE ||
5644 type == SCSI_TWE)
5646 // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
5647 if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
5648 fcChip->fcSestExchangeLRU = 0;
5649 i = fcChip->fcSestExchangeLRU; // typically it's already free!
5651 if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5653 ulStatus = 0; // success!
5656 else
5657 { // YUK! we need to do a linear search for free element.
5658 // Fragmentation of the fcExchange array is due to excessively
5659 // long completions or timeouts.
5661 while( TRUE )
5663 if( ++i >= TACH_SEST_LEN ) // rollover check
5664 i = 0; // beginning of SEST X_IDs
5666 // printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n",
5667 // i, Exchanges->fcExchange[i].type);
5669 if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5671 ulStatus = 0; // success!
5672 break;
5674 if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
5676 printk( "SEST X_ID space full\n");
5677 break; // failed - prevent inf. loop
5681 fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
5686 else // Link Service type - X_IDs should be from TACH_SEST_LEN
5687 // to TACH_MAX_XID
5689 if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
5690 fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
5691 fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
5693 i = fcChip->fcLsExchangeLRU; // typically it's already free!
5694 if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5696 ulStatus = 0; // success!
5699 else
5700 { // YUK! we need to do a linear search for free element
5701 // Fragmentation of the fcExchange array is due to excessively
5702 // long completions or timeouts.
5704 while( TRUE )
5706 if( ++i >= TACH_MAX_XID ) // rollover check
5707 i = TACH_SEST_LEN;// beginning of Link Service X_IDs
5709 // printk( "looping for xchng ID: i=%d, type=%Xh\n",
5710 // i, Exchanges->fcExchange[i].type);
5712 if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5714 ulStatus = 0; // success!
5715 break;
5717 if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
5719 printk( "LinkService X_ID space full\n");
5720 break; // failed - prevent inf. loop
5724 fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
5728 if( !ulStatus ) // success?
5729 Exchanges->fcExchange[i].type = type; // allocate it.
5731 else
5732 i = -1; // error - all exchanges "open"
5734 return i;
5741 // We call this routine to free an Exchange for any reason:
5742 // completed successfully, completed with error, aborted, etc.
5744 // returns FALSE if Exchange failed and "retry" is acceptable
5745 // returns TRUE if Exchange was successful, or retry is impossible
5746 // (e.g. port/device gone).
5747 //scompleteexchange
5749 void cpqfcTSCompleteExchange(
5750 PTACHYON fcChip,
5751 ULONG x_ID)
5753 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5755 if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
5757 if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
5759 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
5760 printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
5761 Exchanges->fcExchange[ x_ID ].type);
5763 goto CleanUpSestResources; // this path should be very rare.
5766 // we have Linux Scsi Cmnd ptr..., now check our Exchange status
5767 // to decide how to complete this SEST FCP exchange
5769 if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
5770 // or abnormal exchange completion
5772 // set FCP Link statistics
5774 if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
5775 fcChip->fcStats.timeouts++;
5776 if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
5777 fcChip->fcStats.FC4aborted++;
5778 if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
5779 fcChip->fcStats.CntErrors++;
5780 if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
5781 fcChip->fcStats.linkFailTX++;
5782 if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
5783 fcChip->fcStats.linkFailRX++;
5784 if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
5785 fcChip->fcStats.CntErrors++;
5787 // First, see if the Scsi upper level initiated an ABORT on this
5788 // exchange...
5789 if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
5791 printk(" DID_ABORT, x_ID %Xh, Cmnd %p ",
5792 x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5793 goto CleanUpSestResources; // (we don't expect Linux _aborts)
5796 // Did our driver timeout the Exchange, or did Tachyon indicate
5797 // a failure during transmission? Ask for retry with "SOFT_ERROR"
5798 else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
5800 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
5801 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5802 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5805 // Did frame(s) for an open exchange arrive in the SFQ,
5806 // meaning the SEST was unable to process them?
5807 else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME)
5809 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
5810 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5811 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5814 // Did our driver timeout the Exchange, or did Tachyon indicate
5815 // a failure during transmission? Ask for retry with "SOFT_ERROR"
5816 else if(
5817 (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
5818 (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) ||
5819 (Exchanges->fcExchange[ x_ID ].status & FRAME_TO) ||
5820 (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY) ||
5821 (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY) )
5825 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
5826 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5827 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5832 // e.g., a LOGOut happened, or device never logged back in.
5833 else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED)
5835 // printk(" *LOGOut or timeout on login!* ");
5836 // trigger?
5837 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
5839 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
5843 // Did Tachyon indicate a CNT error? We need further analysis
5844 // to determine if the exchange is acceptable
5845 else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
5847 UCHAR ScsiStatus;
5848 FCP_STATUS_RESPONSE *pFcpStatus =
5849 (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
5851 ScsiStatus = pFcpStatus->fcp_status >>24;
5853 // If the command is a SCSI Read/Write type, we don't tolerate
5854 // count errors of any kind; assume the count error is due to
5855 // a dropped frame and ask for retry...
5857 if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) ||
5858 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) ||
5859 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) ||
5860 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) )
5862 ScsiStatus == 0 )
5864 // ask for retry
5865 /* printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n",
5866 x_ID, Exchanges->fcExchange[ x_ID ].status,
5867 Exchanges->fcExchange[ x_ID ].Cmnd);*/
5868 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5871 else // need more analysis
5873 cpqfcTSCheckandSnoopFCP(fcChip, x_ID); // (will set ->result)
5877 // default: NOTE! We don't ever want to get here. Getting here
5878 // implies something new is happening that we've never had a test
5879 // case for. Need code maintenance! Return "ERROR"
5880 else
5882 printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p\n",
5883 Exchanges->fcExchange[ x_ID ].status, x_ID,
5884 Exchanges->fcExchange[ x_ID ].Cmnd);
5885 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
5888 else // definitely no Tach problem, but perhaps an FCP problem
5890 // set FCP Link statistic
5891 fcChip->fcStats.ok++;
5892 cpqfcTSCheckandSnoopFCP( fcChip, x_ID); // (will set ->result)
5895 // OK, we've set the Scsi "->result" field, so proceed with calling
5896 // Linux Scsi "done" (if not NULL), and free any kernel memory we
5897 // may have allocated for the exchange.
5899 PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
5900 // complete the command back to upper Scsi drivers
5901 if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
5903 // Calling "done" on an Linux _abort() aborted
5904 // Cmnd causes a kernel panic trying to re-free mem.
5905 // Actually, we shouldn't do anything with an _abort CMND
5906 if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
5908 PCI_TRACE(0xAC)
5909 (*Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done)
5910 (Exchanges->fcExchange[ x_ID ].Cmnd);
5912 else
5915 // printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
5916 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5919 else{
5920 printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
5921 Exchanges->fcExchange[ x_ID ].type,
5922 Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);
5923 printk(" cpqfcTS: Null scsi_done function pointer!\n");
5927 // Now, clean up non-Scsi_Cmnd items...
5928 CleanUpSestResources:
5930 // Was an Extended Scatter/Gather page allocated? We know
5931 // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
5932 if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
5934 int i = 0;
5936 // extended S/G list was used -- Free the allocated ext. S/G pages
5938 while( fcChip->SEST->sgPages[x_ID].PoolPage[i] &&
5939 (i < TL_MAX_SGPAGES) )
5941 kfree( fcChip->SEST->sgPages[x_ID].PoolPage[i]);
5942 fcChip->SEST->sgPages[x_ID].PoolPage[i] = NULL;
5943 i++;
5947 Exchanges->fcExchange[ x_ID ].Cmnd = NULL;
5948 } // Done with FCP (SEST) exchanges
5951 // the remaining logic is common to ALL Exchanges:
5952 // FCP(SEST) and LinkServ.
5954 Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!
5955 Exchanges->fcExchange[ x_ID ].status = 0;
5957 PCI_TRACEO( x_ID, 0xAC)
5960 return;
5961 } // (END of CompleteExchange function)
5966 // Unfortunately, we must snoop all command completions in
5967 // order to manipulate certain return fields, and take note of
5968 // device types, etc., to facilitate the Fibre-Channel to SCSI
5969 // "mapping".
5970 // (Watch for BIG Endian confusion on some payload fields)
5971 void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
5973 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5974 Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
5975 FCP_STATUS_RESPONSE *pFcpStatus =
5976 (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
5977 UCHAR ScsiStatus;
5979 ScsiStatus = pFcpStatus->fcp_status >>24;
5981 #ifdef FCP_COMPLETION_DBG
5982 printk("ScsiStatus = 0x%X\n", ScsiStatus);
5983 #endif
5985 // First, check FCP status
5986 if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
5988 // check response code (RSP_CODE) -- most popular is bad len
5989 // 1st 4 bytes of rsp info -- only byte 3 interesting
5990 if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
5993 // do we EVER get here?
5994 printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
5998 // for now, go by the ScsiStatus, and manipulate certain
5999 // commands when necessary...
6000 if( ScsiStatus == 0) // SCSI status byte "good"?
6002 Cmnd->result = 0; // everything's OK
6004 if( (Cmnd->cmnd[0] == INQUIRY))
6006 UCHAR *InquiryData = Cmnd->request_buffer;
6007 PFC_LOGGEDIN_PORT pLoggedInPort;
6009 // We need to manipulate INQUIRY
6010 // strings for COMPAQ RAID controllers to force
6011 // Linux to scan additional LUNs. Namely, set
6012 // the Inquiry string byte 2 (ANSI-approved version)
6013 // to 2.
6015 if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
6017 InquiryData[2] = 0x2; // claim SCSI-2 compliance,
6018 // so multiple LUNs may be scanned.
6019 // (no SCSI-2 problems known in CPQ)
6022 // snoop the Inquiry to detect Disk, Tape, etc. type
6023 // (search linked list for the port_id we sent INQUIRY to)
6024 pLoggedInPort = fcFindLoggedInPort( fcChip,
6025 NULL, // DON'T search Scsi Nexus (we will set it)
6026 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,
6027 NULL, // DON'T search linked list for FC WWN
6028 NULL); // DON'T care about end of list
6030 if( pLoggedInPort )
6032 pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
6034 else
6036 printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
6037 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
6043 // Scsi Status not good -- pass it back to caller
6045 else
6047 Cmnd->result = ScsiStatus; // SCSI status byte is 1st
6049 // check for valid "sense" data
6051 if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID )
6052 { // limit Scsi Sense field length!
6053 int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
6055 SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ?
6056 sizeof( Cmnd->sense_buffer) : SenseLen;
6059 #ifdef FCP_COMPLETION_DBG
6060 printk("copy sense_buffer %p, len %d, result %Xh\n",
6061 Cmnd->sense_buffer, SenseLen, Cmnd->result);
6062 #endif
6064 // NOTE: There is some dispute over the FCP response
6065 // format. Most FC devices assume that FCP_RSP_INFO
6066 // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
6067 // is (virtually) always 0 and the field is "invalid".
6068 // Some other devices assume that
6069 // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
6070 // when the FCP_RSP is invalid (this almost appears to be
6071 // one of those "religious" issues).
6072 // Consequently, we test the usual position of FCP_SNS_INFO
6073 // for 7Xh, since the SCSI sense format says the first
6074 // byte ("error code") should be 0x70 or 0x71. In practice,
6075 // we find that every device does in fact have 0x70 or 0x71
6076 // in the first byte position, so this test works for all
6077 // FC devices.
6078 // (This logic is especially effective for the CPQ/DEC HSG80
6079 // & HSG60 controllers).
6081 if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
6082 memcpy( Cmnd->sense_buffer,
6083 &pFcpStatus->fcp_sns_info[0], SenseLen);
6084 else
6086 unsigned char *sbPtr =
6087 (unsigned char *)&pFcpStatus->fcp_sns_info[0];
6088 sbPtr -= 8; // back up 8 bytes hoping to find the
6089 // start of the sense buffer
6090 memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
6093 // in the special case of Device Reset, tell upper layer
6094 // to immediately retry (with SOFT_ERROR status)
6095 // look for Sense Key Unit Attention (0x6) with ASC Device
6096 // Reset (0x29)
6097 // printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
6098 // SenseLen, Cmnd->sense_buffer[2],
6099 // Cmnd->sense_buffer[12]);
6100 if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
6101 (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
6103 Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
6106 // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
6107 else if( ((Cmnd->sense_buffer[2] & 0xF) == 0x4) && // "hardware error"
6108 (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code
6110 // printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
6111 // Cmnd->channel, Cmnd->target, Cmnd->lun);
6112 Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
6115 } // (end of sense len valid)
6117 // there is no sense data to help out Linux's Scsi layers...
6118 // We'll just return the Scsi status and hope he will "do the
6119 // right thing"
6120 else
6122 // as far as we know, the Scsi status is sufficient
6123 Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
6130 //PPPPPPPPPPPPPPPPPPPPPPPPP PAYLOAD PPPPPPPPP
6131 // build data PAYLOAD; SCSI FCP_CMND I.U.
6132 // remember BIG ENDIAN payload - DWord values must be byte-reversed
6133 // (hence the affinity for byte pointer building).
6135 static int build_FCP_payload( Scsi_Cmnd *Cmnd,
6136 UCHAR* payload, ULONG type, ULONG fcp_dl )
6138 int i;
6141 switch( type)
6144 case SCSI_IWE:
6145 case SCSI_IRE:
6146 // 8 bytes FCP_LUN
6147 // Peripheral Device or Volume Set addressing, and LUN mapping
6148 // When the FC port was looked up, we copied address mode
6149 // and any LUN mask to the scratch pad SCp.phase & .mode
6151 *payload++ = (UCHAR)Cmnd->SCp.phase;
6153 // Now, because of "lun masking"
6154 // (aka selective storage presentation),
6155 // the contiguous Linux Scsi lun number may not match the
6156 // device's lun number, so we may have to "map".
6158 *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
6160 // We don't know of anyone in the FC business using these
6161 // extra "levels" of addressing. In fact, confusion still exists
6162 // just using the FIRST level... ;-)
6164 *payload++ = 0; // 2nd level addressing
6165 *payload++ = 0;
6166 *payload++ = 0; // 3rd level addressing
6167 *payload++ = 0;
6168 *payload++ = 0; // 4th level addressing
6169 *payload++ = 0;
6171 // 4 bytes Control Field FCP_CNTL
6172 *payload++ = 0; // byte 0: (MSB) reserved
6173 *payload++ = 0; // byte 1: task codes
6174 *payload++ = 0; // byte 2: task management flags
6175 // byte 3: (LSB) execution management codes
6176 // bit 0 write, bit 1 read (don't set together)
6178 if( fcp_dl != 0 )
6180 if( type == SCSI_IWE ) // WRITE
6181 *payload++ = 1;
6182 else // READ
6183 *payload++ = 2;
6185 else
6187 // On some devices, if RD or WR bits are set,
6188 // and fcp_dl is 0, they will generate an error on the command.
6189 // (i.e., if direction is specified, they insist on a length).
6190 *payload++ = 0; // no data (necessary for CPQ)
6194 // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
6195 // FCP_CDB allows 16 byte SCSI command descriptor blk;
6196 // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
6197 for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
6198 *payload++ = Cmnd->cmnd[i];
6200 if( Cmnd->cmd_len == 16 )
6202 memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
6204 payload+= (16 - i);
6206 // FCP_DL is largest number of expected data bytes
6207 // per CDB (i.e. read/write command)
6208 *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL
6209 *payload++ = (UCHAR)(fcp_dl >>16);
6210 *payload++ = (UCHAR)(fcp_dl >>8);
6211 *payload++ = (UCHAR)fcp_dl; // (LSB)
6212 break;
6214 case SCSI_TWE: // need FCP_XFER_RDY
6215 *payload++ = 0; // (4 bytes) DATA_RO (MSB byte 0)
6216 *payload++ = 0;
6217 *payload++ = 0;
6218 *payload++ = 0; // LSB (byte 3)
6219 // (4 bytes) BURST_LEN
6220 // size of following FCP_DATA payload
6221 *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL
6222 *payload++ = (UCHAR)(fcp_dl >>16);
6223 *payload++ = (UCHAR)(fcp_dl >>8);
6224 *payload++ = (UCHAR)fcp_dl; // (LSB)
6225 // 4 bytes RESERVED
6226 *payload++ = 0;
6227 *payload++ = 0;
6228 *payload++ = 0;
6229 *payload++ = 0;
6230 break;
6232 default:
6233 break;
6236 return 0;