From: jbarnes@sgi.com
[wrt350n-kernel.git] / drivers / scsi / cpqfcTSworker.c
blobd822ddcc52b2cad83260fa8eed310542ec09933c
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/slab.h>
26 #include <linux/ioport.h>
27 #include <linux/kernel.h>
28 #include <linux/stat.h>
29 #include <linux/blkdev.h>
30 #include <linux/interrupt.h>
31 #include <linux/delay.h>
32 #include <linux/smp_lock.h>
33 #include <linux/pci.h>
35 #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
37 #include <asm/system.h>
38 #include <asm/irq.h>
39 #include <asm/dma.h>
41 #include "scsi.h"
42 #include <scsi/scsi_host.h> // struct Scsi_Host definition for T handler
43 #include "cpqfcTSchip.h"
44 #include "cpqfcTSstructs.h"
45 #include "cpqfcTStrigger.h"
47 //#define LOGIN_DBG 1
49 // REMARKS:
50 // Since Tachyon chips may be permitted to wait from 500ms up to 2 sec
51 // to empty an outgoing frame from its FIFO to the Fibre Channel stream,
52 // we cannot do everything we need to in the interrupt handler. Specifically,
53 // every time a link re-init (e.g. LIP) takes place, all SCSI I/O has to be
54 // suspended until the login sequences have been completed. Login commands
55 // are frames just like SCSI commands are frames; they are subject to the same
56 // timeout issues and delays. Also, various specs provide up to 2 seconds for
57 // devices to log back in (i.e. respond with ACC to a login frame), so I/O to
58 // that device has to be suspended.
59 // A serious problem here occurs on highly loaded FC-AL systems. If our FC port
60 // has a low priority (e.g. high arbitrated loop physical address, alpa), and
61 // some other device is hogging bandwidth (permissible under FC-AL), we might
62 // time out thinking the link is hung, when it's simply busy. Many such
63 // considerations complicate the design. Although Tachyon assumes control
64 // (in silicon) for many link-specific issues, the Linux driver is left with the
65 // rest, which turns out to be a difficult, time critical chore.
67 // These "worker" functions will handle things like FC Logins; all
68 // processes with I/O to our device must wait for the Login to complete
69 // and (if successful) I/O to resume. In the event of a malfunctioning or
70 // very busy loop, it may take hundreds of millisecs or even seconds to complete
71 // a frame send. We don't want to hang up the entire server (and all
72 // processes which don't depend on Fibre) during this wait.
74 // The Tachyon chip can have around 30,000 I/O operations ("exchanges")
75 // open at one time. However, each exchange must be initiated
76 // synchronously (i.e. each of the 30k I/O had to be started one at a
77 // time by sending a starting frame via Tachyon's outbound que).
79 // To accommodate kernel "module" build, this driver limits the exchanges
80 // to 256, because of the contiguous physical memory limitation of 128M.
82 // Typical FC Exchanges are opened presuming the FC frames start without errors,
83 // while Exchange completion is handled in the interrupt handler. This
84 // optimizes performance for the "everything's working" case.
85 // However, when we have FC related errors or hot plugging of FC ports, we pause
86 // I/O and handle FC-specific tasks in the worker thread. These FC-specific
87 // functions will handle things like FC Logins and Aborts. As the Login sequence
88 // completes to each and every target, I/O can resume to that target.
90 // Our kernel "worker thread" must share the HBA with threads calling
91 // "queuecommand". We define a "BoardLock" semaphore which indicates
92 // to "queuecommand" that the HBA is unavailable, and Cmnds are added to a
93 // board lock Q. When the worker thread finishes with the board, the board
94 // lock Q commands are completed with status causing immediate retry.
95 // Typically, the board is locked while Logins are in progress after an
96 // FC Link Down condition. When Cmnds are re-queued after board lock, the
97 // particular Scsi channel/target may or may not have logged back in. When
98 // the device is waiting for login, the "prli" flag is clear, in which case
99 // commands are passed to a Link Down Q. Whenever the login finally completes,
100 // the LinkDown Q is completed, again with status causing immediate retry.
101 // When FC devices are logged in, we build and start FC commands to the
102 // devices.
104 // NOTE!! As of May 2000, kernel 2.2.14, the error recovery logic for devices
105 // that never log back in (e.g. physically removed) is NOT completely
106 // understood. I've still seen instances of system hangs on failed Write
107 // commands (possibly from the ext2 layer?) on device removal. Such special
108 // cases need to be evaluated from a system/application view - e.g., how
109 // exactly does the system want me to complete commands when the device is
110 // physically removed??
112 // local functions
114 static void SetLoginFields(
115 PFC_LOGGEDIN_PORT pLoggedInPort,
116 TachFCHDR_GCMND* fchs,
117 BOOLEAN PDisc,
118 BOOLEAN Originator);
120 static void AnalyzeIncomingFrame(
121 CPQFCHBA *cpqfcHBAdata,
122 ULONG QNdx );
124 static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
126 static int verify_PLOGI( PTACHYON fcChip,
127 TachFCHDR_GCMND* fchs, ULONG* reject_explain);
128 static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
130 static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
131 static void BuildLinkServicePayload(
132 PTACHYON fcChip, ULONG type, void* payload);
134 static void UnblockScsiDevice( struct Scsi_Host *HostAdapter,
135 PFC_LOGGEDIN_PORT pLoggedInPort);
137 static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
139 static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
141 static void RevalidateSEST( struct Scsi_Host *HostAdapter,
142 PFC_LOGGEDIN_PORT pLoggedInPort);
144 static void IssueReportLunsCommand(
145 CPQFCHBA* cpqfcHBAdata,
146 TachFCHDR_GCMND* fchs);
148 // (see scsi_error.c comments on kernel task creation)
150 void cpqfcTSWorkerThread( void *host)
152 struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
153 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
154 #ifdef PCI_KERNEL_TRACE
155 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
156 #endif
157 DECLARE_MUTEX_LOCKED(fcQueReady);
158 DECLARE_MUTEX_LOCKED(fcTYOBcomplete);
159 DECLARE_MUTEX_LOCKED(TachFrozen);
160 DECLARE_MUTEX_LOCKED(BoardLock);
162 ENTER("WorkerThread");
164 lock_kernel();
165 daemonize("cpqfcTS_wt_%d", HostAdapter->host_no);
166 siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
169 cpqfcHBAdata->fcQueReady = &fcQueReady; // primary wait point
170 cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
171 cpqfcHBAdata->TachFrozen = &TachFrozen;
174 cpqfcHBAdata->worker_thread = current;
176 unlock_kernel();
178 if( cpqfcHBAdata->notify_wt != NULL )
179 up( cpqfcHBAdata->notify_wt); // OK to continue
181 while(1)
183 unsigned long flags;
185 down_interruptible( &fcQueReady); // wait for something to do
187 if (signal_pending(current) )
188 break;
190 PCI_TRACE( 0x90)
191 // first, take the IO lock so the SCSI upper layers can't call
192 // into our _quecommand function (this also disables INTs)
193 spin_lock_irqsave( HostAdapter->host_lock, flags); // STOP _que function
194 PCI_TRACE( 0x90)
196 CPQ_SPINLOCK_HBA( cpqfcHBAdata)
197 // next, set this pointer to indicate to the _quecommand function
198 // that the board is in use, so it should que the command and
199 // immediately return (we don't actually require the semaphore function
200 // in this driver rev)
202 cpqfcHBAdata->BoardLock = &BoardLock;
204 PCI_TRACE( 0x90)
206 // release the IO lock (and re-enable interrupts)
207 spin_unlock_irqrestore( HostAdapter->host_lock, flags);
209 // disable OUR HBA interrupt (keep them off as much as possible
210 // during error recovery)
211 disable_irq( cpqfcHBAdata->HostAdapter->irq);
213 // OK, let's process the Fibre Channel Link Q and do the work
214 cpqfcTS_WorkTask( HostAdapter);
216 // hopefully, no more "work" to do;
217 // re-enable our INTs for "normal" completion processing
218 enable_irq( cpqfcHBAdata->HostAdapter->irq);
221 cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
222 CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
225 // Now, complete any Cmnd we Q'd up while BoardLock was held
227 CompleteBoardLockCmnd( cpqfcHBAdata);
231 // hopefully, the signal was for our module exit...
232 if( cpqfcHBAdata->notify_wt != NULL )
233 up( cpqfcHBAdata->notify_wt); // yep, we're outta here
237 // Freeze Tachyon routine.
238 // If Tachyon is already frozen, return FALSE
239 // If Tachyon is not frozen, call freeze function, return TRUE
241 static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
243 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
244 BOOLEAN FrozeTach = FALSE;
245 // It's possible that the chip is already frozen; if so,
246 // "Freezing" again will NOT! generate another Freeze
247 // Completion Message.
249 if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
250 { // (need to freeze...)
251 fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
253 // 2. Get Tach freeze confirmation
254 // (synchronize SEST manipulation with Freeze Completion Message)
255 // we need INTs on so semaphore can be set.
256 enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
257 down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
258 // can we TIMEOUT semaphore wait?? TBD
259 disable_irq( cpqfcHBAdata->HostAdapter->irq);
261 FrozeTach = TRUE;
262 } // (else, already frozen)
264 return FrozeTach;
270 // This is the kernel worker thread task, which processes FC
271 // tasks which were queued by the Interrupt handler or by
272 // other WorkTask functions.
274 #define DBG 1
275 //#undef DBG
276 void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
278 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
279 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
280 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
281 ULONG QconsumerNdx;
282 LONG ExchangeID;
283 ULONG ulStatus=0;
284 TachFCHDR_GCMND fchs;
285 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
287 ENTER("WorkTask");
289 // copy current index to work on
290 QconsumerNdx = fcLQ->consumer;
292 PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
295 // NOTE: when this switch completes, we will "consume" the Que item
296 // printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
297 switch( fcLQ->Qitem[QconsumerNdx].Type )
299 // incoming frame - link service (ACC, UNSOL REQ, etc.)
300 // or FCP-SCSI command
301 case SFQ_UNKNOWN:
302 AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
304 break;
308 case EXCHANGE_QUEUED: // an Exchange (i.e. FCP-SCSI) was previously
309 // Queued because the link was down. The
310 // heartbeat timer detected it and Queued it here.
311 // We attempt to start it again, and if
312 // successful we clear the EXCHANGE_Q flag.
313 // If the link doesn't come up, the Exchange
314 // will eventually time-out.
316 ExchangeID = (LONG) // x_ID copied from DPC timeout function
317 fcLQ->Qitem[QconsumerNdx].ulBuff[0];
319 // It's possible that a Q'd exchange could have already
320 // been started by other logic (e.g. ABTS process)
321 // Don't start if already started (Q'd flag clear)
323 if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
325 // printk(" *Start Q'd x_ID %Xh: type %Xh ",
326 // ExchangeID, Exchanges->fcExchange[ExchangeID].type);
328 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
329 if( !ulStatus )
331 // printk("success* ");
333 else
335 #ifdef DBG
337 if( ulStatus == EXCHANGE_QUEUED)
338 printk("Queued* ");
339 else
340 printk("failed* ");
342 #endif
345 break;
348 case LINKDOWN:
349 // (lots of things already done in INT handler) future here?
350 break;
353 case LINKACTIVE: // Tachyon set the Lup bit in FM status
354 // NOTE: some misbehaving FC ports (like Tach2.1)
355 // can re-LIP immediately after a LIP completes.
357 // if "initiator", need to verify LOGs with ports
358 // printk("\n*LNKUP* ");
360 if( fcChip->Options.initiator )
361 SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
362 // if SendLogins successfully completes, PortDiscDone
363 // will be set.
366 // If SendLogins was successful, then we expect to get incoming
367 // ACCepts or REJECTs, which are handled below.
369 break;
371 // LinkService and Fabric request/reply processing
372 case ELS_FDISC: // need to send Fabric Discovery (Login)
373 case ELS_FLOGI: // need to send Fabric Login
374 case ELS_SCR: // need to send State Change Registration
375 case FCS_NSR: // need to send Name Service Request
376 case ELS_PLOGI: // need to send PLOGI
377 case ELS_ACC: // send generic ACCept
378 case ELS_PLOGI_ACC: // need to send ELS ACCept frame to recv'd PLOGI
379 case ELS_PRLI_ACC: // need to send ELS ACCept frame to recv'd PRLI
380 case ELS_LOGO: // need to send ELS LOGO (logout)
381 case ELS_LOGO_ACC: // need to send ELS ACCept frame to recv'd PLOGI
382 case ELS_RJT: // ReJecT reply
383 case ELS_PRLI: // need to send ELS PRLI
386 // printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
387 // if PortDiscDone is not set, it means the SendLogins routine
388 // failed to complete -- assume that LDn occurred, so login frames
389 // are invalid
390 if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
392 printk("Discard Q'd ELS login frame\n");
393 break;
396 ulStatus = cpqfcTSBuildExchange(
397 cpqfcHBAdata,
398 fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
399 (TachFCHDR_GCMND*)
400 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
401 NULL, // no data (no scatter/gather list)
402 &ExchangeID );// fcController->fcExchanges index, -1 if failed
404 if( !ulStatus ) // Exchange setup?
406 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
407 if( !ulStatus )
409 // submitted to Tach's Outbound Que (ERQ PI incremented)
410 // waited for completion for ELS type (Login frames issued
411 // synchronously)
413 else
414 // check reason for Exchange not being started - we might
415 // want to Queue and start later, or fail with error
421 else // Xchange setup failed...
422 printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
424 break;
426 case SCSI_REPORT_LUNS:
427 // pass the incoming frame (actually, it's a PRLI frame)
428 // so we can send REPORT_LUNS, in order to determine VSA/PDU
429 // FCP-SCSI Lun address mode
430 IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
431 fcLQ->Qitem[QconsumerNdx].ulBuff);
433 break;
438 case BLS_ABTS: // need to ABORT one or more exchanges
440 LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
441 BOOLEAN FrozeTach = FALSE;
443 if ( x_ID >= TACH_SEST_LEN ) // (in)sanity check
445 // printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
446 break;
450 if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
452 // printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
454 break; // nothing to abort!
457 //#define ABTS_DBG
458 #ifdef ABTS_DBG
459 printk("INV SEST[%X] ", x_ID);
460 if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
462 printk("FC2TO");
464 if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
466 printk("IA");
468 if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
470 printk("PORTID");
472 if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
474 printk("DEVRM");
476 if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
478 printk("LKF");
480 if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
482 printk("FRMTO");
484 if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
486 printk("ABSQ");
488 if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
490 printk("SFQFR");
493 if( Exchanges->fcExchange[ x_ID].type == 0x2000)
494 printk(" WR");
495 else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
496 printk(" RD");
497 else if( Exchanges->fcExchange[ x_ID].type == 0x10)
498 printk(" ABTS");
499 else
500 printk(" %Xh", Exchanges->fcExchange[ x_ID].type);
502 if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
504 printk(" Cmd %p, ",
505 Exchanges->fcExchange[ x_ID].Cmnd);
507 printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n",
508 cpqfcHBAdata->HBAnum,
509 Exchanges->fcExchange[ x_ID].Cmnd->channel,
510 Exchanges->fcExchange[ x_ID].Cmnd->target,
511 Exchanges->fcExchange[ x_ID].Cmnd->lun,
512 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
514 else // assume that Cmnd ptr is invalid on _abort()
516 printk(" Cmd ptr invalid\n");
519 #endif
522 // Steps to ABORT a SEST exchange:
523 // 1. Freeze TL SCSI assists & ERQ (everything)
524 // 2. Receive FROZEN inbound CM (must succeed!)
525 // 3. Invalidate x_ID SEST entry
526 // 4. Resume TL SCSI assists & ERQ (everything)
527 // 5. Build/start on exchange - change "type" to BLS_ABTS,
528 // timeout to X sec (RA_TOV from PLDA is actually 0)
529 // 6. Set Exchange Q'd status if ABTS cannot be started,
530 // or simply complete Exchange in "Terminate" condition
532 PCI_TRACEO( x_ID, 0xB4)
534 // 1 & 2 . Freeze Tach & get confirmation of freeze
535 FrozeTach = FreezeTach( cpqfcHBAdata);
537 // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
538 // FC2_TIMEOUT means we are originating the abort, while
539 // TARGET_ABORT means we are ACCepting an abort.
540 // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are
541 // all from Tachyon:
542 // Exchange was corrupted by LDn or other FC physical failure
543 // INITIATOR_ABORT means the upper layer driver/application
544 // requested the abort.
548 // clear bit 31 (VALid), to invalidate & take control from TL
549 fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
552 // examine and Tach's "Linked List" for IWEs that
553 // received (nearly) simultaneous transfer ready (XRDY)
554 // repair linked list if necessary (TBD!)
555 // (If we ignore the "Linked List", we will time out
556 // WRITE commands where we received the FCP-SCSI XFRDY
557 // frame (because Tachyon didn't processes it). Linked List
558 // management should be done as an optimization.
560 // readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
565 // 4. Resume all Tachlite functions (for other open Exchanges)
566 // as quickly as possible to allow other exchanges to other ports
567 // to resume. Freezing Tachyon may cause cascading errors, because
568 // any received SEST frame cannot be processed by the SEST.
569 // Don't "unfreeze" unless Link is operational
570 if( FrozeTach ) // did we just freeze it (above)?
571 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
574 PCI_TRACEO( x_ID, 0xB4)
576 // Note there is no confirmation that the chip is "unfrozen". Also,
577 // if the Link is down when unfreeze is called, it has no effect.
578 // Chip will unfreeze when the Link is back up.
580 // 5. Now send out Abort commands if possible
581 // Some Aborts can't be "sent" (Port_id changed or gone);
582 // if the device is gone, there is no port_id to send the ABTS to.
584 if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
586 !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
588 Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
589 fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
590 ulStatus = cpqfcTSBuildExchange(
591 cpqfcHBAdata,
592 BLS_ABTS,
593 &fchs, // (uses only s_id)
594 NULL, // (no scatter/gather list for ABTS)
595 &x_ID );// ABTS on this Exchange ID
597 if( !ulStatus ) // Exchange setup build OK?
600 // ABTS may be needed because an Exchange was corrupted
601 // by a Link disruption. If the Link is UP, we can
602 // presume that this ABTS can start immediately; otherwise,
603 // set Que'd status so the Login functions
604 // can restart it when the FC physical Link is restored
605 if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
607 // printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
608 Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
611 else // what FC device (port_id) does the Cmd belong to?
613 PFC_LOGGEDIN_PORT pLoggedInPort =
614 Exchanges->fcExchange[ x_ID].pLoggedInPort;
616 // if Port is logged in, we might start the abort.
618 if( (pLoggedInPort != NULL)
620 (pLoggedInPort->prli == TRUE) )
622 // it's possible that an Exchange has already been Queued
623 // to start after Login completes. Check and don't
624 // start it (again) here if Q'd status set
625 // printk(" ABTS xchg %Xh ", x_ID);
626 if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
628 // printk("already Q'd ");
630 else
632 // printk("starting ");
634 fcChip->fcStats.FC2aborted++;
635 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
636 if( !ulStatus )
638 // OK
639 // submitted to Tach's Outbound Que (ERQ PI incremented)
641 else
643 /* printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
644 ulStatus, x_ID);
649 else
651 /* printk(" ABTS NOT starting xchg %Xh, %p ",
652 x_ID, pLoggedInPort);
653 if( pLoggedInPort )
654 printk("prli %d ", pLoggedInPort->prli);
659 else // what the #@!
660 { // how do we fail to build an Exchange for ABTS??
661 printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
662 ulStatus, x_ID);
665 else // abort without ABTS -- just complete exchange/Cmnd to Linux
667 // printk(" *Terminating x_ID %Xh on %Xh* ",
668 // x_ID, Exchanges->fcExchange[x_ID].status);
669 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, x_ID);
672 } // end of ABTS case
673 break;
677 case BLS_ABTS_ACC: // need to ACCept one ABTS
678 // (NOTE! this code not updated for Linux yet..)
681 printk(" *ABTS_ACC* ");
682 // 1. Freeze TL
684 fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
686 memcpy( // copy the incoming ABTS frame
687 &fchs,
688 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
689 sizeof( fchs));
691 // 3. OK, Tachyon is frozen so we can invalidate SEST entry
692 // (if necessary)
693 // Status FC2_TIMEOUT means we are originating the abort, while
694 // TARGET_ABORT means we are ACCepting an abort
696 ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
697 // printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
700 // sanity check on received ExchangeID
701 if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
703 // clear bit 31 (VALid), to invalidate & take control from TL
704 // printk("Invalidating SEST exchange %Xh\n", ExchangeID);
705 fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
709 // 4. Resume all Tachlite functions (for other open Exchanges)
710 // as quickly as possible to allow other exchanges to other ports
711 // to resume. Freezing Tachyon for too long may royally screw
712 // up everything!
713 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
715 // Note there is no confirmation that the chip is "unfrozen". Also,
716 // if the Link is down when unfreeze is called, it has no effect.
717 // Chip will unfreeze when the Link is back up.
719 // 5. Now send out Abort ACC reply for this exchange
720 Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
722 fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
723 ulStatus = cpqfcTSBuildExchange(
724 cpqfcHBAdata,
725 BLS_ABTS_ACC,
726 &fchs,
727 NULL, // no data (no scatter/gather list)
728 &ExchangeID );// fcController->fcExchanges index, -1 if failed
730 if( !ulStatus ) // Exchange setup?
732 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
733 if( !ulStatus )
735 // submitted to Tach's Outbound Que (ERQ PI incremented)
736 // waited for completion for ELS type (Login frames issued
737 // synchronously)
739 else
740 // check reason for Exchange not being started - we might
741 // want to Queue and start later, or fail with error
746 break;
749 case BLS_ABTS_RJT: // need to ReJecT one ABTS; reject implies the
750 // exchange doesn't exist in the TARGET context.
751 // ExchangeID has to come from LinkService space.
753 printk(" *ABTS_RJT* ");
754 ulStatus = cpqfcTSBuildExchange(
755 cpqfcHBAdata,
756 BLS_ABTS_RJT,
757 (TachFCHDR_GCMND*)
758 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
759 NULL, // no data (no scatter/gather list)
760 &ExchangeID );// fcController->fcExchanges index, -1 if failed
762 if( !ulStatus ) // Exchange setup OK?
764 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
765 // If it fails, we aren't required to retry.
767 if( ulStatus )
769 printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
771 else
773 printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
777 break;
781 default:
782 break;
783 } // end switch
784 //doNothing:
785 // done with this item - now set the NEXT index
787 if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
789 fcLQ->consumer = 0;
791 else
793 fcLQ->consumer++;
796 PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
798 LEAVE("WorkTask");
799 return;
805 // When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login)
806 // commands come in, post to the LinkQ so that action can be taken outside the
807 // interrupt handler.
808 // This circular Q works like Tachyon's que - the producer points to the next
809 // (unused) entry. Called by Interrupt handler, WorkerThread, Timer
810 // sputlinkq
811 void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
812 int Type,
813 void *QueContent)
815 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
816 // FC_EXCHANGES *Exchanges = fcChip->Exchanges;
817 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
818 ULONG ndx;
820 ENTER("cpqfcTSPutLinkQ");
822 ndx = fcLQ->producer;
824 ndx += 1; // test for Que full
828 if( ndx >= FC_LINKQ_DEPTH ) // rollover test
829 ndx = 0;
831 if( ndx == fcLQ->consumer ) // QUE full test
833 // QUE was full! lost LK command (fatal to logic)
834 fcChip->fcStats.lnkQueFull++;
836 printk("*LinkQ Full!*");
837 TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
840 int i;
841 printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
842 fcLQ->consumer);
844 for( i=0; i< FC_LINKQ_DEPTH; )
846 printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
847 if( (++i %8) == 0) printk("\n");
852 printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
854 else // QUE next element
856 // Prevent certain multiple (back-to-back) requests.
857 // This is important in that we don't want to issue multiple
858 // ABTS for the same Exchange, or do multiple FM inits, etc.
859 // We can never be sure of the timing of events reported to
860 // us by Tach's IMQ, which can depend on system/bus speeds,
861 // FC physical link circumstances, etc.
863 if( (fcLQ->producer != fcLQ->consumer)
865 (Type == FMINIT) )
867 LONG lastNdx; // compute previous producer index
868 if( fcLQ->producer)
869 lastNdx = fcLQ->producer- 1;
870 else
871 lastNdx = FC_LINKQ_DEPTH-1;
874 if( fcLQ->Qitem[lastNdx].Type == FMINIT)
876 // printk(" *skip FMINIT Q post* ");
877 // goto DoneWithPutQ;
882 // OK, add the Q'd item...
884 fcLQ->Qitem[fcLQ->producer].Type = Type;
886 memcpy(
887 fcLQ->Qitem[fcLQ->producer].ulBuff,
888 QueContent,
889 sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
891 fcLQ->producer = ndx; // increment Que producer
893 // set semaphore to wake up Kernel (worker) thread
895 up( cpqfcHBAdata->fcQueReady );
898 //DoneWithPutQ:
900 LEAVE("cpqfcTSPutLinkQ");
906 // reset device ext FC link Q
907 void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
910 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
911 fcLQ->producer = 0;
912 fcLQ->consumer = 0;
920 // When Tachyon gets an unassisted FCP-SCSI frame, post here so
921 // an arbitrary context thread (e.g. IOCTL loopback test function)
922 // can process it.
924 // (NOTE: Not revised for Linux)
925 // This Q works like Tachyon's que - the producer points to the next
926 // (unused) entry.
927 void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
928 int Type,
929 void *QueContent)
931 // CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
932 // PTACHYON fcChip = &cpqfcHBAdata->fcChip;
934 // ULONG ndx;
936 // ULONG *pExchangeID;
937 // LONG ExchangeID;
940 KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
941 ndx = pDevExt->fcScsiQue.producer + 1; // test for Que full
943 if( ndx >= FC_SCSIQ_DEPTH ) // rollover test
944 ndx = 0;
946 if( ndx == pDevExt->fcScsiQue.consumer ) // QUE full test
948 // QUE was full! lost LK command (fatal to logic)
949 fcChip->fcStats.ScsiQueFull++;
950 #ifdef DBG
951 printk( "fcPutScsiQue - FULL!\n");
952 #endif
955 else // QUE next element
957 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].Type = Type;
959 if( Type == FCP_RSP )
961 // this TL inbound message type means that a TL SEST exchange has
962 // copied an FCP response frame into a buffer pointed to by the SEST
963 // entry. That buffer is allocated in the SEST structure at ->RspHDR.
964 // Copy the RspHDR for use by the Que handler.
965 pExchangeID = (ULONG *)QueContent;
967 memcpy(
968 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
969 &fcChip->SEST->RspHDR[ *pExchangeID ],
970 sizeof(pDevExt->fcScsiQue.Qitem[0].ulBuff)); // (any element for size)
973 else
975 memcpy(
976 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
977 QueContent,
978 sizeof(pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff));
981 pDevExt->fcScsiQue.producer = ndx; // increment Que
984 KeSetEvent( &pDevExt->TYIBscsi, // signal any waiting thread
985 0, // no priority boost
986 FALSE ); // no waiting later for this event
988 KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
998 static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
1000 static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
1002 static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
1004 void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
1005 PFC_LOGGEDIN_PORT pFcPort)
1007 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1009 if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
1011 fcChip->fcStats.logouts++;
1012 printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n",
1013 (ULONG)pFcPort->u.liWWN,
1014 (ULONG)(pFcPort->u.liWWN >>32),
1015 pFcPort->port_id);
1017 // Terminate I/O with this (Linux) Scsi target
1018 cpqfcTSTerminateExchange( cpqfcHBAdata,
1019 &pFcPort->ScsiNexus,
1020 DEVICE_REMOVED);
1023 // Do an "implicit logout" - we can't really Logout the device
1024 // (i.e. with LOGOut Request) because of port_id confusion
1025 // (i.e. the Other port has no port_id).
1026 // A new login for that WWN will have to re-write port_id (0 invalid)
1027 pFcPort->port_id = 0; // invalid!
1028 pFcPort->pdisc = FALSE;
1029 pFcPort->prli = FALSE;
1030 pFcPort->plogi = FALSE;
1031 pFcPort->flogi = FALSE;
1032 pFcPort->LOGO_timer = 0;
1033 pFcPort->device_blocked = TRUE; // block Scsi Requests
1034 pFcPort->ScsiNexus.VolumeSetAddressing=0;
1038 // On FC-AL, there is a chance that a previously known device can
1039 // be quietly removed (e.g. with non-managed hub),
1040 // while a NEW device (with different WWN) took the same alpa or
1041 // even 24-bit port_id. This chance is unlikely but we must always
1042 // check for it.
1043 static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
1044 PFC_LOGGEDIN_PORT pLoggedInPort)
1046 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1047 // set "other port" at beginning of fcPorts list
1048 PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
1049 while( pOtherPortWithPortId )
1051 if( (pOtherPortWithPortId->port_id ==
1052 pLoggedInPort->port_id)
1054 (pOtherPortWithPortId != pLoggedInPort) )
1056 // trouble! (Implicitly) Log the other guy out
1057 printk(" *port_id %Xh is duplicated!* ",
1058 pOtherPortWithPortId->port_id);
1059 cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId);
1061 pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
1070 // Dynamic Memory Allocation for newly discovered FC Ports.
1071 // For simplicity, maintain fcPorts structs for ALL
1072 // for discovered devices, including those we never do I/O with
1073 // (e.g. Fabric addresses)
1075 static PFC_LOGGEDIN_PORT CreateFcPort(
1076 CPQFCHBA* cpqfcHBAdata,
1077 PFC_LOGGEDIN_PORT pLastLoggedInPort,
1078 TachFCHDR_GCMND* fchs,
1079 LOGIN_PAYLOAD* plogi)
1081 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1082 PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
1083 int i;
1086 printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
1087 for( i=3; i>=0; i--) // copy the LOGIN port's WWN
1088 printk("%02X", plogi->port_name[i]);
1089 for( i=7; i>3; i--) // copy the LOGIN port's WWN
1090 printk("%02X", plogi->port_name[i]);
1093 // allocate mem for new port
1094 // (these are small and rare allocations...)
1095 pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
1098 // allocation succeeded? Fill out NEW PORT
1099 if( pNextLoggedInPort )
1101 // clear out any garbage (sometimes exists)
1102 memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
1105 // If we login to a Fabric, we don't want to treat it
1106 // as a SCSI device...
1107 if( (fchs->s_id & 0xFFF000) != 0xFFF000)
1109 int i;
1111 // create a unique "virtual" SCSI Nexus (for now, just a
1112 // new target ID) -- we will update channel/target on REPORT_LUNS
1113 // special case for very first SCSI target...
1114 if( cpqfcHBAdata->HostAdapter->max_id == 0)
1116 pNextLoggedInPort->ScsiNexus.target = 0;
1117 fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
1119 else
1121 pNextLoggedInPort->ScsiNexus.target =
1122 cpqfcHBAdata->HostAdapter->max_id;
1125 // initialize the lun[] Nexus struct for lun masking
1126 for( i=0; i< CPQFCTS_MAX_LUN; i++)
1127 pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
1129 pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
1131 printk(" SCSI Chan/Trgt %d/%d",
1132 pNextLoggedInPort->ScsiNexus.channel,
1133 pNextLoggedInPort->ScsiNexus.target);
1135 // tell Scsi layers about the new target...
1136 cpqfcHBAdata->HostAdapter->max_id++;
1137 // printk("HostAdapter->max_id = %d\n",
1138 // cpqfcHBAdata->HostAdapter->max_id);
1140 else
1142 // device is NOT SCSI (in case of Fabric)
1143 pNextLoggedInPort->ScsiNexus.target = -1; // invalid
1146 // create forward link to new port
1147 pLastLoggedInPort->pNextPort = pNextLoggedInPort;
1148 printk("\n");
1151 return pNextLoggedInPort; // NULL on allocation failure
1152 } // end NEW PORT (WWN) logic
1156 // For certain cases, we want to terminate exchanges without
1157 // sending ABTS to the device. Examples include when an FC
1158 // device changed it's port_id after Loop re-init, or when
1159 // the device sent us a logout. In the case of changed port_id,
1160 // we want to complete the command and return SOFT_ERROR to
1161 // force a re-try. In the case of LOGOut, we might return
1162 // BAD_TARGET if the device is really gone.
1163 // Since we must ensure that Tachyon is not operating on the
1164 // exchange, we have to freeze the chip
1165 // sterminateex
1166 void cpqfcTSTerminateExchange(
1167 CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
1169 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1170 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1171 ULONG x_ID;
1173 if( ScsiNexus )
1175 // printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
1176 // ScsiNexus->channel, ScsiNexus->target);
1180 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
1182 if( Exchanges->fcExchange[x_ID].type ) // in use?
1184 if( ScsiNexus == NULL ) // our HBA changed - term. all
1186 Exchanges->fcExchange[x_ID].status = TerminateStatus;
1187 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID );
1189 else
1191 // If a device, according to WWN, has been removed, it's
1192 // port_id may be used by another working device, so we
1193 // have to terminate by SCSI target, NOT port_id.
1194 if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
1196 if( (Exchanges->fcExchange[x_ID].Cmnd->device->id == ScsiNexus->target)
1198 (Exchanges->fcExchange[x_ID].Cmnd->device->channel == ScsiNexus->channel))
1200 Exchanges->fcExchange[x_ID].status = TerminateStatus;
1201 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
1205 // (in case we ever need it...)
1206 // all SEST structures have a remote node ID at SEST DWORD 2
1207 // if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
1208 // == port_id)
1215 static void ProcessELS_Request(
1216 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1218 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1219 // FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1220 // ULONG ox_id = (fchs->ox_rx_id >>16);
1221 PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
1222 BOOLEAN NeedReject = FALSE;
1223 ULONG ls_reject_code = 0; // default don'n know??
1226 // Check the incoming frame for a supported ELS type
1227 switch( fchs->pl[0] & 0xFFFF)
1229 case 0x0050: // PDISC?
1231 // Payload for PLOGI and PDISC is identical (request & reply)
1232 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1234 LOGIN_PAYLOAD logi; // FC-PH Port Login
1236 // PDISC payload OK. If critical login fields
1237 // (e.g. WWN) matches last login for this port_id,
1238 // we may resume any prior exchanges
1239 // with the other port
1242 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1244 pLoggedInPort = fcFindLoggedInPort(
1245 fcChip,
1246 NULL, // don't search Scsi Nexus
1247 0, // don't search linked list for port_id
1248 &logi.port_name[0], // search linked list for WWN
1249 &pLastLoggedInPort); // must return non-NULL; when a port_id
1250 // is not found, this pointer marks the
1251 // end of the singly linked list
1253 if( pLoggedInPort != NULL) // WWN found (prior login OK)
1256 if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1258 // Yes. We were expecting PDISC?
1259 if( pLoggedInPort->pdisc )
1261 // Yes; set fields accordingly. (PDISC, not Originator)
1262 SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
1264 // send 'ACC' reply
1265 cpqfcTSPutLinkQue( cpqfcHBAdata,
1266 ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1267 fchs );
1269 // OK to resume I/O...
1271 else
1273 printk("Not expecting PDISC (pdisc=FALSE)\n");
1274 NeedReject = TRUE;
1275 // set reject reason code
1276 ls_reject_code =
1277 LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1280 else
1282 if( pLoggedInPort->port_id != 0)
1284 printk("PDISC PortID change: old %Xh, new %Xh\n",
1285 pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1287 NeedReject = TRUE;
1288 // set reject reason code
1289 ls_reject_code =
1290 LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1294 else
1296 printk("PDISC Request from unknown WWN\n");
1297 NeedReject = TRUE;
1299 // set reject reason code
1300 ls_reject_code =
1301 LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
1305 else // Payload unacceptable
1307 printk("payload unacceptable\n");
1308 NeedReject = TRUE; // reject code already set
1312 if( NeedReject)
1314 ULONG port_id;
1315 // The PDISC failed. Set login struct flags accordingly,
1316 // terminate any I/O to this port, and Q a PLOGI
1317 if( pLoggedInPort )
1319 pLoggedInPort->pdisc = FALSE;
1320 pLoggedInPort->prli = FALSE;
1321 pLoggedInPort->plogi = FALSE;
1323 cpqfcTSTerminateExchange( cpqfcHBAdata,
1324 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1325 port_id = pLoggedInPort->port_id;
1327 else
1329 port_id = fchs->s_id &0xFFFFFF;
1331 fchs->reserved = ls_reject_code; // borrow this (unused) field
1332 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1335 break;
1339 case 0x0003: // PLOGI?
1341 // Payload for PLOGI and PDISC is identical (request & reply)
1342 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1344 LOGIN_PAYLOAD logi; // FC-PH Port Login
1345 BOOLEAN NeedReject = FALSE;
1347 // PDISC payload OK. If critical login fields
1348 // (e.g. WWN) matches last login for this port_id,
1349 // we may resume any prior exchanges
1350 // with the other port
1353 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1355 pLoggedInPort = fcFindLoggedInPort(
1356 fcChip,
1357 NULL, // don't search Scsi Nexus
1358 0, // don't search linked list for port_id
1359 &logi.port_name[0], // search linked list for WWN
1360 &pLastLoggedInPort); // must return non-NULL; when a port_id
1361 // is not found, this pointer marks the
1362 // end of the singly linked list
1364 if( pLoggedInPort == NULL) // WWN not found -New Port
1366 pLoggedInPort = CreateFcPort(
1367 cpqfcHBAdata,
1368 pLastLoggedInPort,
1369 fchs,
1370 &logi);
1371 if( pLoggedInPort == NULL )
1373 printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1374 // Now Q a LOGOut Request, since we won't be talking to that device
1376 NeedReject = TRUE;
1378 // set reject reason code
1379 ls_reject_code =
1380 LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
1384 if( !NeedReject )
1387 // OK - we have valid fcPort ptr; set fields accordingly.
1388 // (not PDISC, not Originator)
1389 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1391 // send 'ACC' reply
1392 cpqfcTSPutLinkQue( cpqfcHBAdata,
1393 ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1394 fchs );
1397 else // Payload unacceptable
1399 printk("payload unacceptable\n");
1400 NeedReject = TRUE; // reject code already set
1403 if( NeedReject)
1405 // The PDISC failed. Set login struct flags accordingly,
1406 // terminate any I/O to this port, and Q a PLOGI
1407 pLoggedInPort->pdisc = FALSE;
1408 pLoggedInPort->prli = FALSE;
1409 pLoggedInPort->plogi = FALSE;
1411 fchs->reserved = ls_reject_code; // borrow this (unused) field
1413 // send 'RJT' reply
1414 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1417 // terminate any exchanges with this device...
1418 if( pLoggedInPort )
1420 cpqfcTSTerminateExchange( cpqfcHBAdata,
1421 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1423 break;
1427 case 0x1020: // PRLI?
1429 BOOLEAN NeedReject = TRUE;
1430 pLoggedInPort = fcFindLoggedInPort(
1431 fcChip,
1432 NULL, // don't search Scsi Nexus
1433 (fchs->s_id & 0xFFFFFF), // search linked list for port_id
1434 NULL, // DON'T search linked list for WWN
1435 NULL); // don't care
1437 if( pLoggedInPort == NULL )
1439 // huh?
1440 printk(" Unexpected PRLI Request -not logged in!\n");
1442 // set reject reason code
1443 ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1445 // Q a LOGOut here?
1447 else
1449 // verify the PRLI ACC payload
1450 if( !verify_PRLI( fchs, &ls_reject_code) )
1452 // PRLI Reply is acceptable; were we expecting it?
1453 if( pLoggedInPort->plogi )
1455 // yes, we expected the PRLI ACC (not PDISC; not Originator)
1456 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1458 // Q an ACCept Reply
1459 cpqfcTSPutLinkQue( cpqfcHBAdata,
1460 ELS_PRLI_ACC,
1461 fchs );
1463 NeedReject = FALSE;
1465 else
1467 // huh?
1468 printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
1470 // set reject reason code
1471 ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1473 // Q a LOGOut here?
1477 else
1479 printk(" PRLI REQUEST payload failed verify\n");
1480 // (reject code set by "verify")
1482 // Q a LOGOut here?
1486 if( NeedReject )
1488 // Q a ReJecT Reply with reason code
1489 fchs->reserved = ls_reject_code;
1490 cpqfcTSPutLinkQue( cpqfcHBAdata,
1491 ELS_RJT, // Q Type
1492 fchs );
1495 break;
1500 case 0x0005: // LOGOut?
1502 // was this LOGOUT because we sent a ELS_PDISC to an FC device
1503 // with changed (or new) port_id, or does the port refuse
1504 // to communicate to us?
1505 // We maintain a logout counter - if we get 3 consecutive LOGOuts,
1506 // give up!
1507 LOGOUT_PAYLOAD logo;
1508 BOOLEAN GiveUpOnDevice = FALSE;
1509 ULONG ls_reject_code = 0;
1511 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
1513 pLoggedInPort = fcFindLoggedInPort(
1514 fcChip,
1515 NULL, // don't search Scsi Nexus
1516 0, // don't search linked list for port_id
1517 &logo.port_name[0], // search linked list for WWN
1518 NULL); // don't care about end of list
1520 if( pLoggedInPort ) // found the device?
1522 // Q an ACC reply
1523 cpqfcTSPutLinkQue( cpqfcHBAdata,
1524 ELS_LOGO_ACC, // Q Type
1525 fchs ); // device to respond to
1527 // set login struct fields (LOGO_counter increment)
1528 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1530 // are we an Initiator?
1531 if( fcChip->Options.initiator)
1533 // we're an Initiator, so check if we should
1534 // try (another?) login
1536 // Fabrics routinely log out from us after
1537 // getting device info - don't try to log them
1538 // back in.
1539 if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
1541 ; // do nothing
1543 else if( pLoggedInPort->LOGO_counter <= 3)
1545 // try (another) login (PLOGI request)
1547 cpqfcTSPutLinkQue( cpqfcHBAdata,
1548 ELS_PLOGI, // Q Type
1549 fchs );
1551 // Terminate I/O with "retry" potential
1552 cpqfcTSTerminateExchange( cpqfcHBAdata,
1553 &pLoggedInPort->ScsiNexus,
1554 PORTID_CHANGED);
1556 else
1558 printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
1559 fchs->s_id &&0xFFFFFF);
1560 GiveUpOnDevice = TRUE;
1563 else
1565 GiveUpOnDevice = TRUE;
1569 if( GiveUpOnDevice == TRUE )
1571 cpqfcTSTerminateExchange( cpqfcHBAdata,
1572 &pLoggedInPort->ScsiNexus,
1573 DEVICE_REMOVED);
1576 else // we don't know this WWN!
1578 // Q a ReJecT Reply with reason code
1579 fchs->reserved = ls_reject_code;
1580 cpqfcTSPutLinkQue( cpqfcHBAdata,
1581 ELS_RJT, // Q Type
1582 fchs );
1585 break;
1590 // FABRIC only case
1591 case 0x0461: // ELS RSCN (Registered State Change Notification)?
1593 int Ports;
1594 int i;
1595 __u32 Buff;
1596 // Typically, one or more devices have been added to or dropped
1597 // from the Fabric.
1598 // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
1599 // The first 32-bit word has a 2-byte Payload Length, which
1600 // includes the 4 bytes of the first word. Consequently,
1601 // this PL len must never be less than 4, must be a multiple of 4,
1602 // and has a specified max value 256.
1603 // (Endianess!)
1604 Ports = ((fchs->pl[0] >>24) - 4) / 4;
1605 Ports = Ports > 63 ? 63 : Ports;
1607 printk(" RSCN ports: %d\n", Ports);
1608 if( Ports <= 0 ) // huh?
1610 // ReJecT the command
1611 fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
1613 cpqfcTSPutLinkQue( cpqfcHBAdata,
1614 ELS_RJT, // Q Type
1615 fchs );
1617 break;
1619 else // Accept the command
1621 cpqfcTSPutLinkQue( cpqfcHBAdata,
1622 ELS_ACC, // Q Type
1623 fchs );
1626 // Check the "address format" to determine action.
1627 // We have 3 cases:
1628 // 0 = Port Address; 24-bit address of affected device
1629 // 1 = Area Address; MS 16 bits valid
1630 // 2 = Domain Address; MS 8 bits valid
1631 for( i=0; i<Ports; i++)
1633 BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
1634 switch( Buff & 0xFF000000)
1637 case 0: // Port Address?
1639 case 0x01000000: // Area Domain?
1640 case 0x02000000: // Domain Address
1641 // For example, "port_id" 0x201300
1642 // OK, let's try a Name Service Request (Query)
1643 fchs->s_id = 0xFFFFFC; // Name Server Address
1644 cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
1646 break;
1649 default: // huh? new value on version change?
1650 break;
1654 break;
1659 default: // don't support this request (yet)
1660 // set reject reason code
1661 fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM,
1662 REQUEST_NOT_SUPPORTED);
1664 cpqfcTSPutLinkQue( cpqfcHBAdata,
1665 ELS_RJT, // Q Type
1666 fchs );
1667 break;
1672 static void ProcessELS_Reply(
1673 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1675 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1676 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1677 ULONG ox_id = (fchs->ox_rx_id >>16);
1678 ULONG ls_reject_code;
1679 PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
1681 // If this is a valid reply, then we MUST have sent a request.
1682 // Verify that we can find a valid request OX_ID corresponding to
1683 // this reply
1686 if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
1688 printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ",
1689 ox_id, fchs->ox_rx_id & 0xffff);
1690 goto Quit; // exit this routine
1694 // Is the reply a RJT (reject)?
1695 if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
1697 // ****** REJECT REPLY ********
1698 switch( Exchanges->fcExchange[ox_id].type )
1701 case ELS_FDISC: // we sent out Fabric Discovery
1702 case ELS_FLOGI: // we sent out FLOGI
1704 printk("RJT received on Fabric Login from %Xh, reason %Xh\n",
1705 fchs->s_id, fchs->pl[1]);
1707 break;
1709 default:
1710 break;
1713 goto Done;
1716 // OK, we have an ACCept...
1717 // What's the ACC type? (according to what we sent)
1718 switch( Exchanges->fcExchange[ox_id].type )
1721 case ELS_PLOGI: // we sent out PLOGI
1722 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1724 LOGIN_PAYLOAD logi; // FC-PH Port Login
1726 // login ACC payload acceptable; search for WWN in our list
1727 // of fcPorts
1729 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1731 pLoggedInPort = fcFindLoggedInPort(
1732 fcChip,
1733 NULL, // don't search Scsi Nexus
1734 0, // don't search linked list for port_id
1735 &logi.port_name[0], // search linked list for WWN
1736 &pLastLoggedInPort); // must return non-NULL; when a port_id
1737 // is not found, this pointer marks the
1738 // end of the singly linked list
1740 if( pLoggedInPort == NULL) // WWN not found - new port
1743 pLoggedInPort = CreateFcPort(
1744 cpqfcHBAdata,
1745 pLastLoggedInPort,
1746 fchs,
1747 &logi);
1749 if( pLoggedInPort == NULL )
1751 printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1752 // Now Q a LOGOut Request, since we won't be talking to that device
1754 goto Done; // exit with error! dropped login frame
1757 else // WWN was already known. Ensure that any open
1758 // exchanges for this WWN are terminated.
1759 // NOTE: It's possible that a device can change its
1760 // 24-bit port_id after a Link init or Fabric change
1761 // (e.g. LIP or Fabric RSCN). In that case, the old
1762 // 24-bit port_id may be duplicated, or no longer exist.
1765 cpqfcTSTerminateExchange( cpqfcHBAdata,
1766 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1769 // We have an fcPort struct - set fields accordingly
1770 // not PDISC, originator
1771 SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1773 // We just set a "port_id"; is it duplicated?
1774 TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1776 // For Fabric operation, we issued PLOGI to 0xFFFFFC
1777 // so we can send SCR (State Change Registration)
1778 // Check for this special case...
1779 if( fchs->s_id == 0xFFFFFC )
1781 // PLOGI ACC was a Fabric response... issue SCR
1782 fchs->s_id = 0xFFFFFD; // address for SCR
1783 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
1786 else
1788 // Now we need a PRLI to enable FCP-SCSI operation
1789 // set flags and Q up a ELS_PRLI
1790 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
1793 else
1795 // login payload unacceptable - reason in ls_reject_code
1796 // Q up a Logout Request
1797 printk("Login Payload unacceptable\n");
1800 break;
1803 // PDISC logic very similar to PLOGI, except we never want
1804 // to allocate mem for "new" port, and we set flags differently
1805 // (might combine later with PLOGI logic for efficiency)
1806 case ELS_PDISC: // we sent out PDISC
1807 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1809 LOGIN_PAYLOAD logi; // FC-PH Port Login
1810 BOOLEAN NeedLogin = FALSE;
1812 // login payload acceptable; search for WWN in our list
1813 // of (previously seen) fcPorts
1815 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1817 pLoggedInPort = fcFindLoggedInPort(
1818 fcChip,
1819 NULL, // don't search Scsi Nexus
1820 0, // don't search linked list for port_id
1821 &logi.port_name[0], // search linked list for WWN
1822 &pLastLoggedInPort); // must return non-NULL; when a port_id
1823 // is not found, this pointer marks the
1824 // end of the singly linked list
1826 if( pLoggedInPort != NULL) // WWN found?
1828 // WWN has same port_id as last login? (Of course, a properly
1829 // working FC device should NEVER ACCept a PDISC if it's
1830 // port_id changed, but check just in case...)
1831 if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1833 // Yes. We were expecting PDISC?
1834 if( pLoggedInPort->pdisc )
1836 int i;
1839 // PDISC expected -- set fields. (PDISC, Originator)
1840 SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
1842 // We are ready to resume FCP-SCSI to this device...
1843 // Do we need to start anything that was Queued?
1845 for( i=0; i< TACH_SEST_LEN; i++)
1847 // see if any exchange for this PDISC'd port was queued
1848 if( ((fchs->s_id &0xFFFFFF) ==
1849 (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
1851 (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
1853 fchs->reserved = i; // copy ExchangeID
1854 // printk(" *Q x_ID %Xh after PDISC* ",i);
1856 cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
1860 // Complete commands Q'd while we were waiting for Login
1862 UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
1864 else
1866 printk("Not expecting PDISC (pdisc=FALSE)\n");
1867 NeedLogin = TRUE;
1870 else
1872 printk("PDISC PortID change: old %Xh, new %Xh\n",
1873 pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1874 NeedLogin = TRUE;
1878 else
1880 printk("PDISC ACC from unknown WWN\n");
1881 NeedLogin = TRUE;
1884 if( NeedLogin)
1887 // The PDISC failed. Set login struct flags accordingly,
1888 // terminate any I/O to this port, and Q a PLOGI
1889 if( pLoggedInPort ) // FC device previously known?
1892 cpqfcTSPutLinkQue( cpqfcHBAdata,
1893 ELS_LOGO, // Q Type
1894 fchs ); // has port_id to send to
1896 // There are a variety of error scenarios which can result
1897 // in PDISC failure, so as a catchall, add the check for
1898 // duplicate port_id.
1899 TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1901 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
1902 pLoggedInPort->pdisc = FALSE;
1903 pLoggedInPort->prli = FALSE;
1904 pLoggedInPort->plogi = FALSE;
1906 cpqfcTSTerminateExchange( cpqfcHBAdata,
1907 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1909 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
1912 else
1914 // login payload unacceptable - reason in ls_reject_code
1915 // Q up a Logout Request
1916 printk("ERROR: Login Payload unacceptable!\n");
1920 break;
1924 case ELS_PRLI: // we sent out PRLI
1927 pLoggedInPort = fcFindLoggedInPort(
1928 fcChip,
1929 NULL, // don't search Scsi Nexus
1930 (fchs->s_id & 0xFFFFFF), // search linked list for port_id
1931 NULL, // DON'T search linked list for WWN
1932 NULL); // don't care
1934 if( pLoggedInPort == NULL )
1936 // huh?
1937 printk(" Unexpected PRLI ACCept frame!\n");
1939 // Q a LOGOut here?
1941 goto Done;
1944 // verify the PRLI ACC payload
1945 if( !verify_PRLI( fchs, &ls_reject_code) )
1947 // PRLI Reply is acceptable; were we expecting it?
1948 if( pLoggedInPort->plogi )
1950 // yes, we expected the PRLI ACC (not PDISC; Originator)
1951 SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1953 // OK, let's send a REPORT_LUNS command to determine
1954 // whether VSA or PDA FCP-LUN addressing is used.
1956 cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
1958 // It's possible that a device we were talking to changed
1959 // port_id, and has logged back in. This function ensures
1960 // that I/O will resume.
1961 UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
1964 else
1966 // huh?
1967 printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
1969 // Q a LOGOut here?
1970 goto Done;
1973 else
1975 printk(" PRLI ACCept payload failed verify\n");
1977 // Q a LOGOut here?
1980 break;
1982 case ELS_FLOGI: // we sent out FLOGI (Fabric Login)
1984 // update the upper 16 bits of our port_id in Tachyon
1985 // the switch adds those upper 16 bits when responding
1986 // to us (i.e. we are the destination_id)
1987 fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
1988 writel( fcChip->Registers.my_al_pa,
1989 fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
1991 // now send out a PLOGI to the well known port_id 0xFFFFFC
1992 fchs->s_id = 0xFFFFFC;
1993 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
1995 break;
1998 case ELS_FDISC: // we sent out FDISC (Fabric Discovery (Login))
2000 printk( " ELS_FDISC success ");
2001 break;
2004 case ELS_SCR: // we sent out State Change Registration
2005 // now we can issue Name Service Request to find any
2006 // Fabric-connected devices we might want to login to.
2009 fchs->s_id = 0xFFFFFC; // Name Server Address
2010 cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
2013 break;
2016 default:
2017 printk(" *Discarding unknown ACC frame, xID %04X/%04X* ",
2018 ox_id, fchs->ox_rx_id & 0xffff);
2019 break;
2023 Done:
2024 // Regardless of whether the Reply is valid or not, the
2025 // the exchange is done - complete
2026 cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
2028 Quit:
2029 return;
2037 // **************** Fibre Channel Services **************
2038 // This is where we process the Directory (Name) Service Reply
2039 // to know which devices are on the Fabric
2041 static void ProcessFCS_Reply(
2042 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
2044 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2045 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2046 ULONG ox_id = (fchs->ox_rx_id >>16);
2047 // ULONG ls_reject_code;
2048 // PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
2050 // If this is a valid reply, then we MUST have sent a request.
2051 // Verify that we can find a valid request OX_ID corresponding to
2052 // this reply
2054 if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
2056 printk(" *Discarding Reply frame, xID %04X/%04X* ",
2057 ox_id, fchs->ox_rx_id & 0xffff);
2058 goto Quit; // exit this routine
2062 // OK, we were expecting it. Now check to see if it's a
2063 // "Name Service" Reply, and if so force a re-validation of
2064 // Fabric device logins (i.e. Start the login timeout and
2065 // send PDISC or PLOGI)
2066 // (Endianess Byte Swap?)
2067 if( fchs->pl[1] == 0x02FC ) // Name Service
2069 // got a new (or NULL) list of Fabric attach devices...
2070 // Invalidate current logins
2072 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
2073 while( pLoggedInPort ) // for all ports which are expecting
2074 // PDISC after the next LIP, set the
2075 // logoutTimer
2078 if( (pLoggedInPort->port_id & 0xFFFF00) // Fabric device?
2080 (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
2082 pLoggedInPort->LOGO_timer = 6; // what's the Fabric timeout??
2083 // suspend any I/O in progress until
2084 // PDISC received...
2085 pLoggedInPort->prli = FALSE; // block FCP-SCSI commands
2088 pLoggedInPort = pLoggedInPort->pNextPort;
2091 if( fchs->pl[2] == 0x0280) // ACCept?
2093 // Send PLOGI or PDISC to these Fabric devices
2094 SendLogins( cpqfcHBAdata, &fchs->pl[4] );
2098 // As of this writing, the only reason to reject is because NO
2099 // devices are left on the Fabric. We already started
2100 // "logged out" timers; if the device(s) don't come
2101 // back, we'll do the implicit logout in the heart beat
2102 // timer routine
2103 else // ReJecT
2105 // this just means no Fabric device is visible at this instant
2109 // Regardless of whether the Reply is valid or not, the
2110 // the exchange is done - complete
2111 cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
2113 Quit:
2114 return;
2123 static void AnalyzeIncomingFrame(
2124 CPQFCHBA *cpqfcHBAdata,
2125 ULONG QNdx )
2127 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2128 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2129 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
2130 TachFCHDR_GCMND* fchs =
2131 (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
2132 // ULONG ls_reject_code; // reason for rejecting login
2133 LONG ExchangeID;
2134 // FC_LOGGEDIN_PORT *pLoggedInPort;
2135 BOOLEAN AbortAccept;
2137 ENTER("AnalyzeIncomingFrame");
2141 switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
2144 case SFQ_UNKNOWN: // unknown frame (e.g. LIP position frame, NOP, etc.)
2147 // ********* FC-4 Device Data/ Fibre Channel Service *************
2148 if( ((fchs->d_id &0xF0000000) == 0) // R_CTL (upper nibble) 0x0?
2150 (fchs->f_ctl & 0x20000000) ) // TYPE 20h is Fibre Channel Service
2153 // ************** FCS Reply **********************
2155 if( (fchs->d_id & 0xff000000L) == 0x03000000L) // (31:23 R_CTL)
2157 ProcessFCS_Reply( cpqfcHBAdata, fchs );
2159 } // end of FCS logic
2164 // *********** Extended Link Service **************
2166 else if( fchs->d_id & 0x20000000 // R_CTL 0x2?
2168 (fchs->f_ctl & 0x01000000) ) // TYPE = 1
2171 // these frames are either a response to
2172 // something we sent (0x23) or "unsolicited"
2173 // frames (0x22).
2176 // **************Extended Link REPLY **********************
2177 // R_CTL Solicited Control Reply
2179 if( (fchs->d_id & 0xff000000L) == 0x23000000L) // (31:23 R_CTL)
2182 ProcessELS_Reply( cpqfcHBAdata, fchs );
2184 } // end of "R_CTL Solicited Control Reply"
2189 // **************Extended Link REQUEST **********************
2190 // (unsolicited commands from another port or task...)
2192 // R_CTL Ext Link REQUEST
2193 else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2194 (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
2199 ProcessELS_Request( cpqfcHBAdata, fchs );
2205 // ************** LILP **********************
2206 else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2207 (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
2210 // SANMark specifies that when available, we must use
2211 // the LILP frame to determine which ALPAs to send Port Discovery
2212 // to...
2214 if( fchs->pl[0] == 0x0711L) // ELS_PLOGI?
2216 // UCHAR *ptr = (UCHAR*)&fchs->pl[1];
2217 // printk(" %d ALPAs found\n", *ptr);
2218 memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
2219 fcChip->Options.LILPin = 1; // our LILPmap is valid!
2220 // now post to make Port Discovery happen...
2221 cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);
2227 // ***************** BASIC LINK SERVICE *****************
2229 else if( fchs->d_id & 0x80000000 // R_CTL:
2230 && // Basic Link Service Request
2231 !(fchs->f_ctl & 0xFF000000) ) // type=0 for BLS
2234 // Check for ABTS (Abort Sequence)
2235 if( (fchs->d_id & 0x8F000000) == 0x81000000)
2237 // look for OX_ID, S_ID pair that matches in our
2238 // fcExchanges table; if found, reply with ACCept and complete
2239 // the exchange
2241 // Per PLDA, an ABTS is sent by an initiator; therefore
2242 // assume that if we have an exhange open to the port who
2243 // sent ABTS, it will be the d_id of what we sent.
2244 for( ExchangeID = 0, AbortAccept=FALSE;
2245 ExchangeID < TACH_SEST_LEN; ExchangeID++)
2247 // Valid "target" exchange 24-bit port_id matches?
2248 // NOTE: For the case of handling Intiator AND Target
2249 // functions on the same chip, we can have TWO Exchanges
2250 // with the same OX_ID -- OX_ID/FFFF for the CMND, and
2251 // OX_ID/RX_ID for the XRDY or DATA frame(s). Ideally,
2252 // we would like to support ABTS from Initiators or Targets,
2253 // but it's not clear that can be supported on Tachyon for
2254 // all cases (requires more investigation).
2256 if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
2257 Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
2259 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2260 (fchs->s_id & 0xFFFFFF)) )
2263 // target xchnge port_id matches -- how about OX_ID?
2264 if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
2265 == (fchs->ox_rx_id & 0xFFFF0000) )
2266 // yes! post ACCept response; will be completed by fcStart
2268 Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
2270 // copy (add) rx_id field for simplified ACCept reply
2271 fchs->ox_rx_id =
2272 Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
2274 cpqfcTSPutLinkQue( cpqfcHBAdata,
2275 BLS_ABTS_ACC, // Q Type
2276 fchs ); // void QueContent
2277 AbortAccept = TRUE;
2278 printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n",
2279 fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
2280 break; // ABTS can affect only ONE exchange -exit loop
2283 } // end of FOR loop
2284 if( !AbortAccept ) // can't ACCept ABTS - send Reject
2286 printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n",
2287 fchs->ox_rx_id);
2288 if( Exchanges->fcExchange[ ExchangeID].type
2290 !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
2291 & 0x80000000))
2293 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
2295 else
2297 printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n",
2298 ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
2303 // Check for BLS {ABTS? (Abort Sequence)} ACCept
2304 else if( (fchs->d_id & 0x8F000000) == 0x84000000)
2306 // target has responded with ACC for our ABTS;
2307 // complete the indicated exchange with ABORTED status
2308 // Make no checks for correct RX_ID, since
2309 // all we need to conform ABTS ACC is the OX_ID.
2310 // Verify that the d_id matches!
2312 ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2313 // printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n",
2314 // fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
2315 // Exchanges->fcExchange[ExchangeID].status);
2319 if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2321 // Does "target" exchange 24-bit port_id match?
2322 // (See "NOTE" above for handling Intiator AND Target in
2323 // the same device driver)
2324 // First, if this is a target response, then we originated
2325 // (initiated) it with BLS_ABTS:
2327 if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2330 // Second, does the source of this ACC match the destination
2331 // of who we originally sent it to?
2332 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2333 (fchs->s_id & 0xFFFFFF)) )
2335 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
2339 // Check for BLS {ABTS? (Abort Sequence)} ReJecT
2340 else if( (fchs->d_id & 0x8F000000) == 0x85000000)
2342 // target has responded with RJT for our ABTS;
2343 // complete the indicated exchange with ABORTED status
2344 // Make no checks for correct RX_ID, since
2345 // all we need to conform ABTS ACC is the OX_ID.
2346 // Verify that the d_id matches!
2348 ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2349 // printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n",
2350 // fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
2352 if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2354 // Does "target" exchange 24-bit port_id match?
2355 // (See "NOTE" above for handling Intiator AND Target in
2356 // the same device driver)
2357 // First, if this is a target response, then we originated
2358 // (initiated) it with BLS_ABTS:
2360 if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2363 // Second, does the source of this ACC match the destination
2364 // of who we originally sent it to?
2365 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2366 (fchs->s_id & 0xFFFFFF)) )
2368 // YES! NOTE: There is a bug in CPQ's RA-4000 box
2369 // where the "reason code" isn't returned in the payload
2370 // For now, simply presume the reject is because the target
2371 // already completed the exchange...
2373 // printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
2374 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
2377 } // end of ABTS check
2378 } // end of Basic Link Service Request
2379 break;
2381 default:
2382 printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
2383 fcLQ->Qitem[QNdx].Type,
2384 fcLQ->Qitem[QNdx].Type);
2385 break;
2390 // Function for Port Discovery necessary after every FC
2391 // initialization (e.g. LIP).
2392 // Also may be called if from Fabric Name Service logic.
2394 static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
2396 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2397 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2398 ULONG ulStatus=0;
2399 TachFCHDR_GCMND fchs; // copy fields for transmission
2400 int i;
2401 ULONG loginType;
2402 LONG ExchangeID;
2403 PFC_LOGGEDIN_PORT pLoggedInPort;
2404 __u32 PortIds[ number_of_al_pa];
2405 int NumberOfPorts=0;
2407 // We're going to presume (for now) that our limit of Fabric devices
2408 // is the same as the number of alpa on a private loop (126 devices).
2409 // (Of course this could be changed to support however many we have
2410 // memory for).
2411 memset( &PortIds[0], 0, sizeof(PortIds));
2413 // First, check if this login is for our own Link Initialization
2414 // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
2415 // from a switch. If we are logging into Fabric devices, we'll
2416 // have a non-NULL FabricPortId pointer
2418 if( FabricPortIds != NULL) // may need logins
2420 int LastPort=FALSE;
2421 i = 0;
2422 while( !LastPort)
2424 // port IDs From NSR payload; byte swap needed?
2425 BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
2427 // printk("FPortId[%d] %Xh ", i, PortIds[i]);
2428 if( PortIds[i] & 0x80000000)
2429 LastPort = TRUE;
2431 PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
2432 // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
2433 // erroneously use ALPA 0.
2434 if( PortIds[i] ) // need non-zero port_id...
2435 i++;
2437 if( i >= number_of_al_pa ) // (in)sanity check
2438 break;
2439 FabricPortIds++; // next...
2442 NumberOfPorts = i;
2443 // printk("NumberOf Fabric ports %d", NumberOfPorts);
2446 else // need to send logins on our "local" link
2449 // are we a loop port? If so, check for reception of LILP frame,
2450 // and if received use it (SANMark requirement)
2451 if( fcChip->Options.LILPin )
2453 int j=0;
2454 // sanity check on number of ALPAs from LILP frame...
2455 // For format of LILP frame, see FC-AL specs or
2456 // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
2457 // First byte is number of ALPAs
2458 i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
2459 NumberOfPorts = i;
2460 // printk(" LILP alpa count %d ", i);
2461 while( i > 0)
2463 PortIds[j] = fcChip->LILPmap[1+ j];
2464 j++; i--;
2467 else // have to send login to everybody
2469 int j=0;
2470 i = number_of_al_pa;
2471 NumberOfPorts = i;
2472 while( i > 0)
2474 PortIds[j] = valid_al_pa[j]; // all legal ALPAs
2475 j++; i--;
2481 // Now we have a copy of the port_ids (and how many)...
2482 for( i = 0; i < NumberOfPorts; i++)
2484 // 24-bit FC Port ID
2485 fchs.s_id = PortIds[i]; // note: only 8-bits used for ALPA
2488 // don't log into ourselves (Linux Scsi disk scan will stop on
2489 // no TARGET support error on us, and quit trying for rest of devices)
2490 if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
2491 continue;
2493 // fabric login needed?
2494 if( (fchs.s_id == 0) ||
2495 (fcChip->Options.fabric == 1) )
2497 fcChip->Options.flogi = 1; // fabric needs longer for login
2498 // Do we need FLOGI or FDISC?
2499 pLoggedInPort = fcFindLoggedInPort(
2500 fcChip,
2501 NULL, // don't search SCSI Nexus
2502 0xFFFFFC, // search linked list for Fabric port_id
2503 NULL, // don't search WWN
2504 NULL); // (don't care about end of list)
2506 if( pLoggedInPort ) // If found, we have prior experience with
2507 // this port -- check whether PDISC is needed
2509 if( pLoggedInPort->flogi )
2511 // does the switch support FDISC?? (FLOGI for now...)
2512 loginType = ELS_FLOGI; // prior FLOGI still valid
2514 else
2515 loginType = ELS_FLOGI; // expired FLOGI
2517 else // first FLOGI?
2518 loginType = ELS_FLOGI;
2521 fchs.s_id = 0xFFFFFE; // well known F_Port address
2523 // Fabrics are not required to support FDISC, and
2524 // it's not clear if that helps us anyway, since
2525 // we'll want a Name Service Request to re-verify
2526 // visible devices...
2527 // Consequently, we always want our upper 16 bit
2528 // port_id to be zero (we'll be rejected if we
2529 // use our prior port_id if we've been plugged into
2530 // a different switch port).
2531 // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
2532 // If our ALPA is 55h for instance, we want the FC frame
2533 // s_id to be 0x000055, while Tach's my_al_pa register
2534 // must be 0x000155, to force an OPN at ALPA 0
2535 // (the Fabric port)
2536 fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
2537 writel( fcChip->Registers.my_al_pa | 0x0100,
2538 fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
2541 else // not FLOGI...
2543 // should we send PLOGI or PDISC? Check if any prior port_id
2544 // (e.g. alpa) completed a PLOGI/PRLI exchange by checking
2545 // the pdisc flag.
2547 pLoggedInPort = fcFindLoggedInPort(
2548 fcChip,
2549 NULL, // don't search SCSI Nexus
2550 fchs.s_id, // search linked list for al_pa
2551 NULL, // don't search WWN
2552 NULL); // (don't care about end of list)
2556 if( pLoggedInPort ) // If found, we have prior experience with
2557 // this port -- check whether PDISC is needed
2559 if( pLoggedInPort->pdisc )
2561 loginType = ELS_PDISC; // prior PLOGI and PRLI maybe still valid
2564 else
2565 loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
2567 else // never talked to this port_id before
2568 loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
2573 ulStatus = cpqfcTSBuildExchange(
2574 cpqfcHBAdata,
2575 loginType, // e.g. PLOGI
2576 &fchs, // no incoming frame (we are originator)
2577 NULL, // no data (no scatter/gather list)
2578 &ExchangeID );// fcController->fcExchanges index, -1 if failed
2580 if( !ulStatus ) // Exchange setup OK?
2582 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
2583 if( !ulStatus )
2585 // submitted to Tach's Outbound Que (ERQ PI incremented)
2586 // waited for completion for ELS type (Login frames issued
2587 // synchronously)
2589 if( loginType == ELS_PDISC )
2591 // now, we really shouldn't Revalidate SEST exchanges until
2592 // we get an ACC reply from our target and verify that
2593 // the target address/WWN is unchanged. However, when a fast
2594 // target gets the PDISC, they can send SEST Exchange data
2595 // before we even get around to processing the PDISC ACC.
2596 // Consequently, we lose the I/O.
2597 // To avoid this, go ahead and Revalidate when the PDISC goes
2598 // out, anticipating that the ACC will be truly acceptable
2599 // (this happens 99.9999....% of the time).
2600 // If we revalidate a SEST write, and write data goes to a
2601 // target that is NOT the one we originated the WRITE to,
2602 // that target is required (FCP-SCSI specs, etc) to discard
2603 // our WRITE data.
2605 // Re-validate SEST entries (Tachyon hardware assists)
2606 RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort);
2607 //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
2610 else // give up immediately on error
2612 #ifdef LOGIN_DBG
2613 printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
2614 #endif
2615 break;
2619 if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
2621 ulStatus = LNKDWN_OSLS;
2622 #ifdef LOGIN_DBG
2623 printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
2624 #endif
2625 break;
2627 // Check the exchange for bad status (i.e. FrameTimeOut),
2628 // and complete on bad status (most likely due to BAD_ALPA)
2629 // on LDn, DPC function may already complete (ABORT) a started
2630 // exchange, so check type first (type = 0 on complete).
2631 if( Exchanges->fcExchange[ExchangeID].status )
2633 #ifdef LOGIN_DBG
2634 printk("completing x_ID %X on status %Xh\n",
2635 ExchangeID, Exchanges->fcExchange[ExchangeID].status);
2636 #endif
2637 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
2640 else // Xchange setup failed...
2642 #ifdef LOGIN_DBG
2643 printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
2644 #endif
2645 break;
2648 if( !ulStatus )
2650 // set the event signifying that all ALPAs were sent out.
2651 #ifdef LOGIN_DBG
2652 printk("SendLogins: PortDiscDone\n");
2653 #endif
2654 cpqfcHBAdata->PortDiscDone = 1;
2657 // TL/TS UG, pg. 184
2658 // 0x0065 = 100ms for RT_TOV
2659 // 0x01f5 = 500ms for ED_TOV
2660 fcChip->Registers.ed_tov.value = 0x006501f5L;
2661 writel( fcChip->Registers.ed_tov.value,
2662 (fcChip->Registers.ed_tov.address));
2664 // set the LP_TOV back to ED_TOV (i.e. 500 ms)
2665 writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
2667 else
2669 printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n",
2670 ExchangeID, fchs.s_id, ulStatus);
2672 LEAVE("SendLogins");
2677 // for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
2678 // D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
2679 static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
2681 struct Scsi_Host *HostAdapter = Cmnd->device->host;
2682 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
2683 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2684 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2685 PFC_LOGGEDIN_PORT pLoggedInPort;
2686 int LunListLen=0;
2687 int i;
2688 ULONG x_ID = 0xFFFFFFFF;
2689 UCHAR *ucBuff = Cmnd->request_buffer;
2691 // printk("cpqfcTS: ReportLunsDone \n");
2692 // first, we need to find the Exchange for this command,
2693 // so we can find the fcPort struct to make the indicated
2694 // changes.
2695 for( i=0; i< TACH_SEST_LEN; i++)
2697 if( Exchanges->fcExchange[i].type // exchange defined?
2699 (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
2702 x_ID = i; // found exchange!
2703 break;
2706 if( x_ID == 0xFFFFFFFF)
2708 // printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
2709 goto Done; // Report Luns FC Exchange gone;
2710 // exchange probably Terminated by Implicit logout
2714 // search linked list for the port_id we sent INQUIRY to
2715 pLoggedInPort = fcFindLoggedInPort( fcChip,
2716 NULL, // DON'T search Scsi Nexus (we will set it)
2717 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,
2718 NULL, // DON'T search linked list for FC WWN
2719 NULL); // DON'T care about end of list
2721 if( !pLoggedInPort )
2723 // printk("cpqfcTS: ReportLuns failed - device gone\n");
2724 goto Done; // error! can't find logged in Port
2726 LunListLen = ucBuff[3];
2727 LunListLen += ucBuff[2]>>8;
2729 if( !LunListLen ) // failed
2731 // generically speaking, a soft error means we should retry...
2732 if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
2734 if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
2735 (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
2737 TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
2738 // did we fail because of "check condition, device reset?"
2739 // e.g. the device was reset (i.e., at every power up)
2740 // retry the Report Luns
2742 // who are we sending it to?
2743 // we know this because we have a copy of the command
2744 // frame from the original Report Lun command -
2745 // switch the d_id/s_id fields, because the Exchange Build
2746 // context is "reply to source".
2748 fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
2749 cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
2752 else // probably, the device doesn't support Report Luns
2753 pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;
2755 else // we have LUN info - check VSA mode
2757 // for now, assume all LUNs will have same addr mode
2758 // for VSA, payload byte 8 will be 0x40; otherwise, 0
2759 pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];
2761 // Since we got a Report Luns answer, set lun masking flag
2762 pLoggedInPort->ScsiNexus.LunMasking = 1;
2764 if( LunListLen > 8*CPQFCTS_MAX_LUN) // We expect CPQFCTS_MAX_LUN max
2765 LunListLen = 8*CPQFCTS_MAX_LUN;
2768 printk("Device WWN %08X%08X Reports Luns @: ",
2769 (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
2770 (ULONG)(pLoggedInPort->u.liWWN>>32));
2772 for( i=8; i<LunListLen+8; i+=8)
2774 printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
2776 printk("\n");
2779 // Since the device was kind enough to tell us where the
2780 // LUNs are, lets ensure they are contiguous for Linux's
2781 // SCSI driver scan, which expects them to start at 0.
2782 // Since Linux only supports 8 LUNs, only copy the first
2783 // eight from the report luns command
2785 // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
2786 // LUNs 4001, 4004, etc., because other LUNs are masked from
2787 // this HBA (owned by someone else). We'll make those appear as
2788 // LUN 0, 1... to Linux
2790 int j;
2791 int AppendLunList = 0;
2792 // Walk through the LUN list. The 'j' array number is
2793 // Linux's lun #, while the value of .lun[j] is the target's
2794 // lun #.
2795 // Once we build a LUN list, it's possible for a known device
2796 // to go offline while volumes (LUNs) are added. Later,
2797 // the device will do another PLOGI ... Report Luns command,
2798 // and we must not alter the existing Linux Lun map.
2799 // (This will be very rare).
2800 for( j=0; j < CPQFCTS_MAX_LUN; j++)
2802 if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
2804 AppendLunList = 1;
2805 break;
2808 if( AppendLunList )
2810 int k;
2811 int FreeLunIndex;
2812 // printk("cpqfcTS: AppendLunList\n");
2814 // If we get a new Report Luns, we cannot change
2815 // any existing LUN mapping! (Only additive entry)
2816 // For all LUNs in ReportLun list
2817 // if RL lun != ScsiNexus lun
2818 // if RL lun present in ScsiNexus lun[], continue
2819 // else find ScsiNexus lun[]==FF and add, continue
2821 for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2823 if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
2825 // something changed from the last Report Luns
2826 printk(" cpqfcTS: Report Lun change!\n");
2827 for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN;
2828 k < CPQFCTS_MAX_LUN; k++)
2830 if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
2832 FreeLunIndex = k;
2833 break;
2835 if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
2836 break; // we already masked this lun
2838 if( k >= CPQFCTS_MAX_LUN )
2840 printk(" no room for new LUN %d\n", ucBuff[i+1]);
2842 else if( k == FreeLunIndex ) // need to add LUN
2844 pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
2845 // printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
2848 else
2850 // lun already known
2852 break;
2855 // print out the new list...
2856 for( j=0; j< CPQFCTS_MAX_LUN; j++)
2858 if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
2859 break; // done
2860 // printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2863 else
2865 // printk("Linux SCSI LUNs[] -> Device LUNs: ");
2866 // first time - this is easy
2867 for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2869 pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
2870 // printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2872 // printk("\n");
2877 Done: ;
2880 extern int is_private_data_of_cpqfc(CPQFCHBA *hba, void * pointer);
2881 extern void cpqfc_free_private_data(CPQFCHBA *hba, cpqfc_passthru_private_t *data);
2883 static void
2884 call_scsi_done(Scsi_Cmnd *Cmnd)
2886 CPQFCHBA *hba;
2887 hba = (CPQFCHBA *) Cmnd->device->host->hostdata;
2888 // Was this command a cpqfc passthru ioctl ?
2889 if (Cmnd->sc_request != NULL && Cmnd->device->host != NULL &&
2890 Cmnd->device->host->hostdata != NULL &&
2891 is_private_data_of_cpqfc((CPQFCHBA *) Cmnd->device->host->hostdata,
2892 Cmnd->sc_request->upper_private_data)) {
2893 cpqfc_free_private_data(hba,
2894 Cmnd->sc_request->upper_private_data);
2895 Cmnd->sc_request->upper_private_data = NULL;
2896 Cmnd->result &= 0xff00ffff;
2897 Cmnd->result |= (DID_PASSTHROUGH << 16); // prevents retry
2899 if (Cmnd->scsi_done != NULL)
2900 (*Cmnd->scsi_done)(Cmnd);
2903 // After successfully getting a "Process Login" (PRLI) from an
2904 // FC port, we want to Discover the LUNs so that we know the
2905 // addressing type (e.g., FCP-SCSI Volume Set Address, Peripheral
2906 // Unit Device), and whether SSP (Selective Storage Presentation or
2907 // Lun Masking) has made the LUN numbers non-zero based or
2908 // non-contiguous. To remain backward compatible with the SCSI-2
2909 // driver model, which expects a contiguous LUNs starting at 0,
2910 // will use the ReportLuns info to map from "device" to "Linux"
2911 // LUNs.
2912 static void IssueReportLunsCommand(
2913 CPQFCHBA* cpqfcHBAdata,
2914 TachFCHDR_GCMND* fchs)
2916 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2917 PFC_LOGGEDIN_PORT pLoggedInPort;
2918 struct scsi_cmnd *Cmnd = NULL;
2919 struct scsi_device *ScsiDev = NULL;
2920 LONG x_ID;
2921 ULONG ulStatus;
2922 UCHAR *ucBuff;
2924 if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
2926 printk("Discard Q'd ReportLun command\n");
2927 goto Done;
2930 // find the device (from port_id) we're talking to
2931 pLoggedInPort = fcFindLoggedInPort( fcChip,
2932 NULL, // DON'T search Scsi Nexus
2933 fchs->s_id & 0xFFFFFF,
2934 NULL, // DON'T search linked list for FC WWN
2935 NULL); // DON'T care about end of list
2936 if( pLoggedInPort ) // we'd BETTER find it!
2940 if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
2941 goto Done; // forget it - FC device not a "target"
2944 ScsiDev = scsi_get_host_dev (cpqfcHBAdata->HostAdapter);
2945 if (!ScsiDev)
2946 goto Done;
2948 Cmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
2949 if (!Cmnd)
2950 goto Done;
2952 ucBuff = pLoggedInPort->ReportLunsPayload;
2954 memset( ucBuff, 0, REPORT_LUNS_PL);
2956 Cmnd->scsi_done = ScsiReportLunsDone;
2958 Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload;
2959 Cmnd->request_bufflen = REPORT_LUNS_PL;
2961 Cmnd->cmnd[0] = 0xA0;
2962 Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
2963 Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL;
2964 Cmnd->cmd_len = 12;
2966 Cmnd->device->channel = pLoggedInPort->ScsiNexus.channel;
2967 Cmnd->device->id = pLoggedInPort->ScsiNexus.target;
2970 ulStatus = cpqfcTSBuildExchange(
2971 cpqfcHBAdata,
2972 SCSI_IRE,
2973 fchs,
2974 Cmnd, // buffer for Report Lun data
2975 &x_ID );// fcController->fcExchanges index, -1 if failed
2977 if( !ulStatus ) // Exchange setup?
2979 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
2980 if( !ulStatus )
2982 // submitted to Tach's Outbound Que (ERQ PI incremented)
2983 // waited for completion for ELS type (Login frames issued
2984 // synchronously)
2986 else
2987 // check reason for Exchange not being started - we might
2988 // want to Queue and start later, or fail with error
2994 else // Xchange setup failed...
2995 printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
2997 else // like, we just got a PRLI ACC, and now the port is gone?
2999 printk(" can't send ReportLuns - no login for port_id %Xh\n",
3000 fchs->s_id & 0xFFFFFF);
3005 Done:
3007 if (Cmnd)
3008 scsi_put_command (Cmnd);
3009 if (ScsiDev)
3010 scsi_free_host_dev (ScsiDev);
3019 static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata)
3021 int i;
3022 for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--)
3024 if( cpqfcHBAdata->BoardLockCmnd[i] != NULL )
3026 Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i];
3027 cpqfcHBAdata->BoardLockCmnd[i] = NULL;
3028 Cmnd->result = (DID_SOFT_ERROR << 16); // ask for retry
3029 // printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
3030 // i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
3031 call_scsi_done(Cmnd);
3041 // runs every 1 second for FC exchange timeouts and implicit FC device logouts
3043 void cpqfcTSheartbeat( unsigned long ptr )
3045 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr;
3046 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
3047 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3048 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
3049 ULONG i;
3050 unsigned long flags;
3051 DECLARE_MUTEX_LOCKED(BoardLock);
3053 PCI_TRACE( 0xA8)
3055 if( cpqfcHBAdata->BoardLock) // Worker Task Running?
3056 goto Skip;
3058 // STOP _que function
3059 spin_lock_irqsave( cpqfcHBAdata->HostAdapter->host_lock, flags);
3061 PCI_TRACE( 0xA8)
3064 cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
3066 // release the IO lock (and re-enable interrupts)
3067 spin_unlock_irqrestore( cpqfcHBAdata->HostAdapter->host_lock, flags);
3069 // Ensure no contention from _quecommand or Worker process
3070 CPQ_SPINLOCK_HBA( cpqfcHBAdata)
3072 PCI_TRACE( 0xA8)
3075 disable_irq( cpqfcHBAdata->HostAdapter->irq); // our IRQ
3077 // Complete the "bad target" commands (normally only used during
3078 // initialization, since we aren't supposed to call "scsi_done"
3079 // inside the queuecommand() function). (this is overly contorted,
3080 // scsi_done can be safely called from queuecommand for
3081 // this bad target case. May want to simplify this later)
3083 for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
3085 if( cpqfcHBAdata->BadTargetCmnd[i] )
3087 Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
3088 cpqfcHBAdata->BadTargetCmnd[i] = NULL;
3089 Cmnd->result = (DID_BAD_TARGET << 16);
3090 call_scsi_done(Cmnd);
3092 else
3093 break;
3097 // logged in ports -- re-login check (ports required to verify login with
3098 // PDISC after LIP within 2 secs)
3100 // prevent contention
3101 while( pLoggedInPort ) // for all ports which are expecting
3102 // PDISC after the next LIP, check to see if
3103 // time is up!
3105 // Important: we only detect "timeout" condition on TRANSITION
3106 // from non-zero to zero
3107 if( pLoggedInPort->LOGO_timer ) // time-out "armed"?
3109 if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0?
3111 // LOGOUT time! Per PLDA, PDISC hasn't complete in 2 secs, so
3112 // issue LOGO request and destroy all I/O with other FC port(s).
3115 printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
3116 printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n",
3117 pLoggedInPort->ScsiNexus.channel,
3118 pLoggedInPort->ScsiNexus.target,
3119 pLoggedInPort->port_id,
3120 (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
3121 (ULONG)(pLoggedInPort->u.liWWN>>32));
3124 cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
3127 // else simply decremented - maybe next time...
3129 pLoggedInPort = pLoggedInPort->pNextPort;
3136 // ************ FC EXCHANGE TIMEOUT CHECK **************
3138 for( i=0; i< TACH_MAX_XID; i++)
3140 if( Exchanges->fcExchange[i].type ) // exchange defined?
3143 if( !Exchanges->fcExchange[i].timeOut ) // time expired
3145 // Set Exchange timeout status
3146 Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
3148 if( i >= TACH_SEST_LEN ) // Link Service Exchange
3150 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // Don't "abort" LinkService
3153 else // SEST Exchange TO -- may post ABTS to Worker Thread Que
3155 // (Make sure we don't keep timing it out; let other functions
3156 // complete it or set the timeOut as needed)
3157 Exchanges->fcExchange[i].timeOut = 30000; // seconds default
3159 if( Exchanges->fcExchange[i].type
3161 (BLS_ABTS | BLS_ABTS_ACC ) )
3163 // For BLS_ABTS*, an upper level might still have
3164 // an outstanding command waiting for low-level completion.
3165 // Also, in the case of a WRITE, we MUST get confirmation
3166 // of either ABTS ACC or RJT before re-using the Exchange.
3167 // It's possible that the RAID cache algorithm can hang
3168 // if we fail to complete a WRITE to a LBA, when a READ
3169 // comes later to that same LBA. Therefore, we must
3170 // ensure that the target verifies receipt of ABTS for
3171 // the exchange
3173 printk("~TO Q'd ABTS (x_ID %Xh)~ ", i);
3174 // TriggerHBA( fcChip->Registers.ReMapMemBase);
3176 // On timeout of a ABTS exchange, check to
3177 // see if the FC device has a current valid login.
3178 // If so, restart it.
3179 pLoggedInPort = fcFindLoggedInPort( fcChip,
3180 Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
3181 0, // DON'T search linked list for FC port id
3182 NULL, // DON'T search linked list for FC WWN
3183 NULL); // DON'T care about end of list
3185 // device exists?
3186 if( pLoggedInPort ) // device exists?
3188 if( pLoggedInPort->prli ) // logged in for FCP-SCSI?
3190 // attempt to restart the ABTS
3191 printk(" ~restarting ABTS~ ");
3192 cpqfcTSStartExchange( cpqfcHBAdata, i );
3197 else // not an ABTS
3200 // We expect the WorkerThread to change the xchng type to
3201 // abort and set appropriate timeout.
3202 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out
3206 else // time not expired...
3208 // decrement timeout: 1 or more seconds left
3209 --Exchanges->fcExchange[i].timeOut;
3215 enable_irq( cpqfcHBAdata->HostAdapter->irq);
3218 CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
3220 cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued
3222 // Now, complete any Cmnd we Q'd up while BoardLock was held
3224 CompleteBoardLockCmnd( cpqfcHBAdata);
3227 // restart the timer to run again (1 sec later)
3228 Skip:
3229 mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ);
3231 PCI_TRACEO( i, 0xA8)
3232 return;
3236 // put valid FC-AL physical address in spec order
3237 static const UCHAR valid_al_pa[]={
3238 0xef, 0xe8, 0xe4, 0xe2,
3239 0xe1, 0xE0, 0xDC, 0xDA,
3240 0xD9, 0xD6, 0xD5, 0xD4,
3241 0xD3, 0xD2, 0xD1, 0xCe,
3242 0xCd, 0xCc, 0xCb, 0xCa,
3243 0xC9, 0xC7, 0xC6, 0xC5,
3244 0xC3, 0xBc, 0xBa, 0xB9,
3245 0xB6, 0xB5, 0xB4, 0xB3,
3246 0xB2, 0xB1, 0xae, 0xad,
3247 0xAc, 0xAb, 0xAa, 0xA9,
3249 0xA7, 0xA6, 0xA5, 0xA3,
3250 0x9f, 0x9e, 0x9d, 0x9b,
3251 0x98, 0x97, 0x90, 0x8f,
3252 0x88, 0x84, 0x82, 0x81,
3253 0x80, 0x7c, 0x7a, 0x79,
3254 0x76, 0x75, 0x74, 0x73,
3255 0x72, 0x71, 0x6e, 0x6d,
3256 0x6c, 0x6b, 0x6a, 0x69,
3257 0x67, 0x66, 0x65, 0x63,
3258 0x5c, 0x5a, 0x59, 0x56,
3260 0x55, 0x54, 0x53, 0x52,
3261 0x51, 0x4e, 0x4d, 0x4c,
3262 0x4b, 0x4a, 0x49, 0x47,
3263 0x46, 0x45, 0x43, 0x3c,
3264 0x3a, 0x39, 0x36, 0x35,
3265 0x34, 0x33, 0x32, 0x31,
3266 0x2e, 0x2d, 0x2c, 0x2b,
3267 0x2a, 0x29, 0x27, 0x26,
3268 0x25, 0x23, 0x1f, 0x1E,
3269 0x1d, 0x1b, 0x18, 0x17,
3271 0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case
3273 const int number_of_al_pa = (sizeof(valid_al_pa) );
3277 // this function looks up an al_pa from the table of valid al_pa's
3278 // we decrement from the last decimal loop ID, because soft al_pa
3279 // (our typical case) are assigned with highest priority (and high al_pa)
3280 // first. See "In-Depth FC-AL", R. Kembel pg. 38
3281 // INPUTS:
3282 // al_pa - 24 bit port identifier (8 bit al_pa on private loop)
3283 // RETURN:
3284 // Loop ID - serves are index to array of logged in ports
3285 // -1 - invalid al_pa (not all 8 bit values are legal)
3287 #if (0)
3288 static int GetLoopID( ULONG al_pa )
3290 int i;
3292 for( i = number_of_al_pa -1; i >= 0; i--) // dec.
3294 if( valid_al_pa[i] == (UCHAR)al_pa ) // take lowest 8 bits
3295 return i; // success - found valid al_pa; return decimal LoopID
3297 return -1; // failed - not found
3299 #endif
3301 extern cpqfc_passthru_private_t *cpqfc_private(Scsi_Request *sr);
3303 // Search the singly (forward) linked list "fcPorts" looking for
3304 // either the SCSI target (if != -1), port_id (if not NULL),
3305 // or WWN (if not null), in that specific order.
3306 // If we find a SCSI nexus (from Cmnd arg), set the SCp.phase
3307 // field according to VSA or PDU
3308 // RETURNS:
3309 // Ptr to logged in port struct if found
3310 // (NULL if not found)
3311 // pLastLoggedInPort - ptr to last struct (for adding new ones)
3313 PFC_LOGGEDIN_PORT fcFindLoggedInPort(
3314 PTACHYON fcChip,
3315 Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
3316 ULONG port_id, // search linked list for al_pa, or
3317 UCHAR wwn[8], // search linked list for WWN, or...
3318 PFC_LOGGEDIN_PORT *pLastLoggedInPort )
3321 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
3322 BOOLEAN target_id_valid=FALSE;
3323 BOOLEAN port_id_valid=FALSE;
3324 BOOLEAN wwn_valid=FALSE;
3325 int i;
3328 if( Cmnd != NULL )
3329 target_id_valid = TRUE;
3331 else if( port_id ) // note! 24-bit NULL address is illegal
3332 port_id_valid = TRUE;
3334 else
3336 if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
3338 for( i=0; i<8; i++) // valid WWN passed? NULL WWN invalid
3340 if( wwn[i] != 0 )
3341 wwn_valid = TRUE; // any non-zero byte makes (presumably) valid
3345 // check other options ...
3348 // In case multiple search options are given, we use a priority
3349 // scheme:
3350 // While valid pLoggedIn Ptr
3351 // If port_id is valid
3352 // if port_id matches, return Ptr
3353 // If wwn is valid
3354 // if wwn matches, return Ptr
3355 // Next Ptr in list
3357 // Return NULL (not found)
3360 while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid)
3362 if( pLastLoggedInPort ) // caller's pointer valid?
3363 *pLastLoggedInPort = pLoggedInPort; // end of linked list
3365 if( target_id_valid )
3367 // check Linux Scsi Cmnd for channel/target Nexus match
3368 // (all luns are accessed through matching "pLoggedInPort")
3369 if( (pLoggedInPort->ScsiNexus.target == Cmnd->device->id)
3371 (pLoggedInPort->ScsiNexus.channel == Cmnd->device->channel))
3373 // For "passthru" modes, the IOCTL caller is responsible
3374 // for setting the FCP-LUN addressing
3375 if (Cmnd->sc_request != NULL && Cmnd->device->host != NULL &&
3376 Cmnd->device->host->hostdata != NULL &&
3377 is_private_data_of_cpqfc((CPQFCHBA *) Cmnd->device->host->hostdata,
3378 Cmnd->sc_request->upper_private_data)) {
3379 /* This is a passthru... */
3380 cpqfc_passthru_private_t *pd;
3381 pd = Cmnd->sc_request->upper_private_data;
3382 Cmnd->SCp.phase = pd->bus;
3383 // Cmnd->SCp.have_data_in = pd->pdrive;
3384 Cmnd->SCp.have_data_in = Cmnd->device->lun;
3385 } else {
3386 /* This is not a passthru... */
3388 // set the FCP-LUN addressing type
3389 Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;
3391 // set the Device Type we got from the snooped INQUIRY string
3392 Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
3394 // handle LUN masking; if not "default" (illegal) lun value,
3395 // the use it. These lun values are set by a successful
3396 // Report Luns command
3397 if( pLoggedInPort->ScsiNexus.LunMasking == 1)
3399 if (Cmnd->device->lun > sizeof(pLoggedInPort->ScsiNexus.lun))
3400 return NULL;
3401 // we KNOW all the valid LUNs... 0xFF is invalid!
3402 Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->device->lun];
3403 if (pLoggedInPort->ScsiNexus.lun[Cmnd->device->lun] == 0xFF)
3404 return NULL;
3405 // printk("xlating lun %d to 0x%02x\n", Cmnd->lun,
3406 // pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
3408 else
3409 Cmnd->SCp.have_data_in = Cmnd->device->lun; // Linux & target luns match
3411 break; // found it!
3415 if( port_id_valid ) // look for alpa first
3417 if( pLoggedInPort->port_id == port_id )
3418 break; // found it!
3420 if( wwn_valid ) // look for wwn second
3423 if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
3425 // all 8 bytes of WWN match
3426 break; // found it!
3430 pLoggedInPort = pLoggedInPort->pNextPort; // try next port
3433 return pLoggedInPort;
3440 // We need to examine the SEST table and re-validate
3441 // any open Exchanges for this LoggedInPort
3442 // To make Tachyon pay attention, Freeze FCP assists,
3443 // set VAL bits, Unfreeze FCP assists
3444 static void RevalidateSEST( struct Scsi_Host *HostAdapter,
3445 PFC_LOGGEDIN_PORT pLoggedInPort)
3447 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3448 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
3449 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3450 ULONG x_ID;
3451 BOOLEAN TachFroze = FALSE;
3454 // re-validate any SEST exchanges that are permitted
3455 // to survive the link down (e.g., good PDISC performed)
3456 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
3459 // If the SEST entry port_id matches the pLoggedInPort,
3460 // we need to re-validate
3461 if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
3463 (Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
3466 if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF) // (24-bit port ID)
3467 == pLoggedInPort->port_id)
3469 // printk(" re-val xID %Xh ", x_ID);
3470 if( !TachFroze ) // freeze if not already frozen
3471 TachFroze |= FreezeTach( cpqfcHBAdata);
3472 fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
3477 if( TachFroze)
3479 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
3484 // Complete an Linux Cmnds that we Queued because
3485 // our FC link was down (cause immediate retry)
3487 static void UnblockScsiDevice( struct Scsi_Host *HostAdapter,
3488 PFC_LOGGEDIN_PORT pLoggedInPort)
3490 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3491 Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
3492 Scsi_Cmnd *Cmnd;
3493 int indx;
3497 // if the device was previously "blocked", make sure
3498 // we unblock it so Linux SCSI will resume
3500 pLoggedInPort->device_blocked = FALSE; // clear our flag
3502 // check the Link Down command ptr buffer;
3503 // we can complete now causing immediate retry
3504 for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
3506 if( *SCptr != NULL ) // scsi command to complete?
3508 #ifdef DUMMYCMND_DBG
3509 printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
3510 #endif
3511 Cmnd = *SCptr;
3514 // Are there any Q'd commands for this target?
3515 if( (Cmnd->device->id == pLoggedInPort->ScsiNexus.target)
3517 (Cmnd->device->channel == pLoggedInPort->ScsiNexus.channel) )
3519 Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
3520 if( Cmnd->scsi_done == NULL)
3522 printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
3523 pLoggedInPort->port_id);
3525 else
3526 call_scsi_done(Cmnd);
3527 *SCptr = NULL; // free this slot for next use
3534 //#define WWN_DBG 1
3536 static void SetLoginFields(
3537 PFC_LOGGEDIN_PORT pLoggedInPort,
3538 TachFCHDR_GCMND* fchs,
3539 BOOLEAN PDisc,
3540 BOOLEAN Originator)
3542 LOGIN_PAYLOAD logi; // FC-PH Port Login
3543 PRLI_REQUEST prli; // copy for BIG ENDIAN switch
3544 int i;
3545 #ifdef WWN_DBG
3546 ULONG ulBuff;
3547 #endif
3549 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
3551 pLoggedInPort->Originator = Originator;
3552 pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
3554 switch( fchs->pl[0] & 0xffff )
3556 case 0x00000002: // PLOGI or PDISC ACCept?
3557 if( PDisc ) // PDISC accept
3558 goto PDISC_case;
3560 case 0x00000003: // ELS_PLOGI or ELS_PLOGI_ACC
3562 // Login BB_credit typically 0 for Tachyons
3563 pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
3565 // e.g. 128, 256, 1024, 2048 per FC-PH spec
3566 // We have to use this when setting up SEST Writes,
3567 // since that determines frame size we send.
3568 pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
3569 pLoggedInPort->plogi = TRUE;
3570 pLoggedInPort->pdisc = FALSE;
3571 pLoggedInPort->prli = FALSE; // ELS_PLOGI resets
3572 pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets
3573 pLoggedInPort->logo = FALSE; // ELS_PLOGI resets
3574 pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
3575 pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
3577 // was this PLOGI to a Fabric?
3578 if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
3579 pLoggedInPort->flogi = TRUE;
3582 for( i=0; i<8; i++) // copy the LOGIN port's WWN
3583 pLoggedInPort->u.ucWWN[i] = logi.port_name[i];
3585 #ifdef WWN_DBG
3586 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3587 if( pLoggedInPort->Originator)
3588 printk("o");
3589 else
3590 printk("r");
3591 printk("PLOGI port_id %Xh, WWN %08X",
3592 pLoggedInPort->port_id, ulBuff);
3594 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3595 printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
3596 #endif
3597 break;
3602 case 0x00000005: // ELS_LOGO (logout)
3605 pLoggedInPort->plogi = FALSE;
3606 pLoggedInPort->pdisc = FALSE;
3607 pLoggedInPort->prli = FALSE; // ELS_PLOGI resets
3608 pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets
3609 pLoggedInPort->logo = TRUE; // ELS_PLOGI resets
3610 pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
3611 pLoggedInPort->LOGO_timer = 0;
3612 #ifdef WWN_DBG
3613 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3614 if( pLoggedInPort->Originator)
3615 printk("o");
3616 else
3617 printk("r");
3618 printk("LOGO port_id %Xh, WWN %08X",
3619 pLoggedInPort->port_id, ulBuff);
3621 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3622 printk("%08Xh\n", ulBuff);
3623 #endif
3624 break;
3628 PDISC_case:
3629 case 0x00000050: // ELS_PDISC or ELS_PDISC_ACC
3630 pLoggedInPort->LOGO_timer = 0; // stop the time-out
3632 pLoggedInPort->prli = TRUE; // ready to accept FCP-SCSI I/O
3636 #ifdef WWN_DBG
3637 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3638 if( pLoggedInPort->Originator)
3639 printk("o");
3640 else
3641 printk("r");
3642 printk("PDISC port_id %Xh, WWN %08X",
3643 pLoggedInPort->port_id, ulBuff);
3645 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3646 printk("%08Xh\n", ulBuff);
3647 #endif
3651 break;
3655 case 0x1020L: // PRLI?
3656 case 0x1002L: // PRLI ACCept?
3657 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
3659 pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
3660 pLoggedInPort->prli = TRUE; // PLOGI resets, PDISC doesn't
3662 pLoggedInPort->pdisc = TRUE; // expect to send (or receive) PDISC
3663 // next time
3664 pLoggedInPort->LOGO_timer = 0; // will be set next LinkDown
3665 #ifdef WWN_DBG
3666 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3667 if( pLoggedInPort->Originator)
3668 printk("o");
3669 else
3670 printk("r");
3671 printk("PRLI port_id %Xh, WWN %08X",
3672 pLoggedInPort->port_id, ulBuff);
3674 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3675 printk("%08Xh\n", ulBuff);
3676 #endif
3678 break;
3682 return;
3690 static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
3692 LOGIN_PAYLOAD *plogi; // FC-PH Port Login
3693 LOGIN_PAYLOAD PlogiPayload; // copy for BIG ENDIAN switch
3694 PRLI_REQUEST *prli; // FCP-SCSI Process Login
3695 PRLI_REQUEST PrliPayload; // copy for BIG ENDIAN switch
3696 LOGOUT_PAYLOAD *logo;
3697 LOGOUT_PAYLOAD LogoutPayload;
3698 // PRLO_REQUEST *prlo;
3699 // PRLO_REQUEST PrloPayload;
3700 REJECT_MESSAGE rjt, *prjt;
3702 memset( &PlogiPayload, 0, sizeof( PlogiPayload));
3703 plogi = &PlogiPayload; // load into stack buffer,
3704 // then BIG-ENDIAN switch a copy to caller
3707 switch( type ) // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
3709 case ELS_FDISC:
3710 case ELS_FLOGI:
3711 case ELS_PLOGI_ACC: // FC-PH PORT Login Accept
3712 case ELS_PLOGI: // FC-PH PORT Login
3713 case ELS_PDISC: // FC-PH2 Port Discovery - same payload as ELS_PLOGI
3714 plogi->login_cmd = LS_PLOGI;
3715 if( type == ELS_PDISC)
3716 plogi->login_cmd = LS_PDISC;
3717 else if( type == ELS_PLOGI_ACC )
3718 plogi->login_cmd = LS_ACC;
3720 plogi->cmn_services.bb_credit = 0x00;
3721 plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
3722 plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
3723 plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
3724 plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
3725 RANDOM_RELATIVE_OFFSET;
3727 // fill in with World Wide Name based Port Name - 8 UCHARs
3728 // get from Tach registers WWN hi & lo
3729 LoadWWN( fcChip, plogi->port_name, 0);
3730 // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
3731 // get from Tach registers WWN hi & lo
3732 LoadWWN( fcChip, plogi->node_name, 1);
3734 // For Seagate Drives.
3736 plogi->cmn_services.common_features |= 0x800;
3737 plogi->cmn_services.rel_offset = 0xFE;
3738 plogi->cmn_services.concurrent_seq = 1;
3739 plogi->class1.service_options = 0x00;
3740 plogi->class2.service_options = 0x00;
3741 plogi->class3.service_options = CLASS_VALID;
3742 plogi->class3.initiator_control = 0x00;
3743 plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
3744 plogi->class3.recipient_control =
3745 ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
3746 plogi->class3.concurrent_sequences = 1;
3747 plogi->class3.open_sequences = 1;
3748 plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
3749 plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
3750 plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0';
3751 plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0';
3754 // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
3755 if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
3757 if( type == ELS_FLOGI )
3758 plogi->login_cmd = LS_FLOGI;
3759 else
3760 plogi->login_cmd = LS_FDISC;
3762 plogi->cmn_services.lowest_ver = 0x20;
3763 plogi->cmn_services.common_features = 0x0800;
3764 plogi->cmn_services.rel_offset = 0;
3765 plogi->cmn_services.concurrent_seq = 0;
3767 plogi->class3.service_options = 0x8800;
3768 plogi->class3.rx_data_size = 0;
3769 plogi->class3.recipient_control = 0;
3770 plogi->class3.concurrent_sequences = 0;
3771 plogi->class3.open_sequences = 0;
3774 // copy back to caller's buff, w/ BIG ENDIAN swap
3775 BigEndianSwap( (UCHAR*)&PlogiPayload, payload, sizeof(PlogiPayload));
3776 break;
3779 case ELS_ACC: // generic Extended Link Service ACCept
3780 plogi->login_cmd = LS_ACC;
3781 // copy back to caller's buff, w/ BIG ENDIAN swap
3782 BigEndianSwap( (UCHAR*)&PlogiPayload, payload, 4);
3783 break;
3787 case ELS_SCR: // Fabric State Change Registration
3789 SCR_PL scr; // state change registration
3791 memset( &scr, 0, sizeof(scr));
3793 scr.command = LS_SCR; // 0x62000000
3794 // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
3795 scr.function = 3; // 1 = Events detected by Fabric
3796 // 2 = N_Port detected registration
3797 // 3 = Full registration
3799 // copy back to caller's buff, w/ BIG ENDIAN swap
3800 BigEndianSwap( (UCHAR*)&scr, payload, sizeof(SCR_PL));
3803 break;
3806 case FCS_NSR: // Fabric Name Service Request
3808 NSR_PL nsr; // Name Server Req. payload
3810 memset( &nsr, 0, sizeof(NSR_PL));
3812 // see Brocade Fabric Programming Guide,
3813 // Rev 1.3, pg 4-44
3814 nsr.CT_Rev = 0x01000000;
3815 nsr.FCS_Type = 0xFC020000;
3816 nsr.Command_code = 0x01710000;
3817 nsr.FCP = 8;
3819 // copy back to caller's buff, w/ BIG ENDIAN swap
3820 BigEndianSwap( (UCHAR*)&nsr, payload, sizeof(NSR_PL));
3823 break;
3828 case ELS_LOGO: // FC-PH PORT LogOut
3829 logo = &LogoutPayload; // load into stack buffer,
3830 // then BIG-ENDIAN switch a copy to caller
3831 logo->cmd = LS_LOGO;
3832 // load the 3 UCHARs of the node name
3833 // (if private loop, upper two UCHARs 0)
3834 logo->reserved = 0;
3836 logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
3837 logo->n_port_identifier[1] =
3838 (UCHAR)(fcChip->Registers.my_al_pa>>8);
3839 logo->n_port_identifier[2] =
3840 (UCHAR)(fcChip->Registers.my_al_pa>>16);
3841 // fill in with World Wide Name based Port Name - 8 UCHARs
3842 // get from Tach registers WWN hi & lo
3843 LoadWWN( fcChip, logo->port_name, 0);
3845 BigEndianSwap( (UCHAR*)&LogoutPayload,
3846 payload, sizeof(LogoutPayload) ); // 16 UCHAR struct
3847 break;
3850 case ELS_LOGO_ACC: // Logout Accept (FH-PH pg 149, table 74)
3851 logo = &LogoutPayload; // load into stack buffer,
3852 // then BIG-ENDIAN switch a copy to caller
3853 logo->cmd = LS_ACC;
3854 BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 ); // 4 UCHAR cmnd
3855 break;
3858 case ELS_RJT: // ELS_RJT link service reject (FH-PH pg 155)
3860 prjt = (REJECT_MESSAGE*)payload; // pick up passed data
3861 rjt.command_code = ELS_RJT;
3862 // reverse fields, because of Swap that follows...
3863 rjt.vendor = prjt->reserved; // vendor specific
3864 rjt.explain = prjt->reason; //
3865 rjt.reason = prjt->explain; //
3866 rjt.reserved = prjt->vendor; //
3867 // BIG-ENDIAN switch a copy to caller
3868 BigEndianSwap( (UCHAR*)&rjt, payload, 8 ); // 8 UCHAR cmnd
3869 break;
3875 case ELS_PRLI_ACC: // Process Login ACCept
3876 case ELS_PRLI: // Process Login
3877 case ELS_PRLO: // Process Logout
3878 memset( &PrliPayload, 0, sizeof( PrliPayload));
3879 prli = &PrliPayload; // load into stack buffer,
3881 if( type == ELS_PRLI )
3882 prli->cmd = 0x20; // Login
3883 else if( type == ELS_PRLO )
3884 prli->cmd = 0x21; // Logout
3885 else if( type == ELS_PRLI_ACC )
3887 prli->cmd = 0x02; // Login ACCept
3888 prli->valid = REQUEST_EXECUTED;
3892 prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
3893 prli->fcp_info = READ_XFER_RDY;
3894 prli->page_length = 0x10;
3895 prli->payload_length = 20;
3896 // Can be initiator AND target
3898 if( fcChip->Options.initiator )
3899 prli->fcp_info |= INITIATOR_FUNCTION;
3900 if( fcChip->Options.target )
3901 prli->fcp_info |= TARGET_FUNCTION;
3903 BigEndianSwap( (UCHAR*)&PrliPayload, payload, prli->payload_length);
3904 break;
3908 default: // no can do - programming error
3909 printk(" BuildLinkServicePayload unknown!\n");
3910 break;
3914 // loads 8 UCHARs for PORT name or NODE name base on
3915 // controller's WWN.
3916 void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
3918 UCHAR* bPtr, i;
3920 switch( type )
3922 case 0: // Port_Name
3923 bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3924 for( i =0; i<4; i++)
3925 dest[i] = *bPtr++;
3926 bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3927 for( i =4; i<8; i++)
3928 dest[i] = *bPtr++;
3929 break;
3930 case 1: // Node/Fabric _Name
3931 bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3932 for( i =0; i<4; i++)
3933 dest[i] = *bPtr++;
3934 bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3935 for( i =4; i<8; i++)
3936 dest[i] = *bPtr++;
3937 break;
3944 // We check the Port Login payload for required values. Note that
3945 // ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
3948 int verify_PLOGI( PTACHYON fcChip,
3949 TachFCHDR_GCMND* fchs,
3950 ULONG* reject_explain)
3952 LOGIN_PAYLOAD login;
3954 // source, dest, len (should be mult. of 4)
3955 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login, sizeof(login));
3957 // check FC version
3958 // if other port's highest supported version
3959 // is less than our lowest, and
3960 // if other port's lowest
3961 if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
3962 login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
3964 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
3965 return LOGICAL_ERROR;
3968 // Receive Data Field Size must be >=128
3969 // per FC-PH
3970 if (login.cmn_services.bb_rx_size < 128)
3972 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
3973 return LOGICAL_ERROR;
3976 // Only check Class 3 params
3977 if( login.class3.service_options & CLASS_VALID)
3979 if (login.class3.rx_data_size < 128)
3981 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
3982 return LOGICAL_ERROR;
3984 if( login.class3.initiator_control & XID_REQUIRED)
3986 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
3987 return LOGICAL_ERROR;
3990 return 0; // success
3996 int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
3998 PRLI_REQUEST prli; // buffer for BIG ENDIAN
4000 // source, dest, len (should be mult. of 4)
4001 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
4003 if( prli.fcp_info == 0 ) // i.e., not target or initiator?
4005 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
4006 return LOGICAL_ERROR;
4009 return 0; // success
4013 // SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
4014 // INPUTS:
4015 // source - ptr to LITTLE ENDIAN ULONGS
4016 // cnt - number of UCHARs to switch (should be mult. of ULONG)
4017 // OUTPUTS:
4018 // dest - ptr to BIG ENDIAN copy
4019 // RETURN:
4020 // none
4022 void BigEndianSwap( UCHAR *source, UCHAR *dest, USHORT cnt)
4024 int i,j;
4026 source+=3; // start at MSB of 1st ULONG
4027 for( j=0; j < cnt; j+=4, source+=4, dest+=4) // every ULONG
4029 for( i=0; i<4; i++) // every UCHAR in ULONG
4030 *(dest+i) = *(source-i);
4037 // Build FC Exchanges............
4039 static void buildFCPstatus(
4040 PTACHYON fcChip,
4041 ULONG ExchangeID);
4043 static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
4045 static ULONG build_SEST_sgList(
4046 struct pci_dev *pcidev,
4047 ULONG *SESTalPairStart,
4048 Scsi_Cmnd *Cmnd,
4049 ULONG *sgPairs,
4050 PSGPAGES *sgPages_head // link list of TL Ext. S/G pages from O/S Pool
4053 static int build_FCP_payload( Scsi_Cmnd *Cmnd,
4054 UCHAR* payload, ULONG type, ULONG fcp_dl );
4059 ERQ __________________
4060 | | / | Req_A_SFS_Len | ____________________
4061 |----------| / | Req_A_SFS_Addr |------->| Reserved |
4062 | IRB | / | Req_A_D_ID | | SOF EOF TimeStamp |
4063 |-----------/ | Req_A_SEST_Index |-+ | R_CTL | D_ID |
4064 | IRB | | Req_B... | | | CS_CTL| S_ID |
4065 |-----------\ | | | | TYPE | F_CTL |
4066 | IRB | \ | | | | SEQ_ID | SEQ_CNT |
4067 |----------- \ | | +-->+--| OX_ID | RX_ID |
4068 | | \ |__________________| | | RO |
4069 | | pl (payload/cmnd) |
4070 | | ..... |
4071 | |___________________|
4074 +-------------------------------------------+
4077 | e.g. IWE
4078 | SEST __________________ for FCP_DATA
4079 | | | / | | Hdr_Len | ____________________
4080 | |----------| / | Hdr_Addr_Addr |------->| Reserved |
4081 | | [0] | / |Remote_ID| RSP_Len| | SOF EOF TimeStamp |
4082 | |-----------/ | RSP_Addr |---+ | R_CTL | D_ID |
4083 +-> [1] | | | Buff_Off | | | CS_CTL| S_ID |
4084 |-----------\ |BuffIndex| Link | | | TYPE | F_CTL |
4085 | [2] | \ | Rsvd | RX_ID | | | SEQ_ID | SEQ_CNT |
4086 |----------- \ | Data_Len | | | OX_ID | RX_ID |
4087 | ... | \ | Exp_RO | | | RO |
4088 |----------| | Exp_Byte_Cnt | | |___________________|
4089 | SEST_LEN | +--| Len | |
4090 |__________| | | Address | |
4091 | | ... | | for FCP_RSP
4092 | |__________________| | ____________________
4093 | +----| Reserved |
4094 | | SOF EOF TimeStamp |
4095 | | R_CTL | D_ID |
4096 | | CS_CTL| S_ID |
4097 +--- local or extended | .... |
4098 scatter/gather lists
4099 defining upper-layer
4100 data (e.g. from user's App)
4104 // All TachLite commands must start with a SFS (Single Frame Sequence)
4105 // command. In the simplest case (a NOP Basic Link command),
4106 // only one frame header and ERQ entry is required. The most complex
4107 // case is the SCSI assisted command, which requires an ERQ entry,
4108 // SEST entry, and several frame headers and data buffers all
4109 // logically linked together.
4110 // Inputs:
4111 // cpqfcHBAdata - controller struct
4112 // type - PLOGI, SCSI_IWE, etc.
4113 // InFCHS - Incoming Tachlite FCHS which prompted this exchange
4114 // (only s_id set if we are originating)
4115 // Data - PVOID to data struct consistent with "type"
4116 // fcExchangeIndex - pointer to OX/RD ID value of built exchange
4117 // Return:
4118 // fcExchangeIndex - OX/RD ID value if successful
4119 // 0 - success
4120 // INVALID_ARGS - NULL/ invalid passed args
4121 // BAD_ALPA - Bad source al_pa address
4122 // LNKDWN_OSLS - Link Down (according to this controller)
4123 // OUTQUE_FULL - Outbound Que full
4124 // DRIVERQ_FULL - controller's Exchange array full
4125 // SEST_FULL - SEST table full
4127 // Remarks:
4128 // Psuedo code:
4129 // Check for NULL pointers / bad args
4130 // Build outgoing FCHS - the header/payload struct
4131 // Build IRB (for ERQ entry)
4132 // if SCSI command, build SEST entry (e.g. IWE, TRE,...)
4133 // return success
4135 //sbuildex
4136 ULONG cpqfcTSBuildExchange(
4137 CPQFCHBA *cpqfcHBAdata,
4138 ULONG type, // e.g. PLOGI
4139 TachFCHDR_GCMND* InFCHS, // incoming FCHS
4140 void *Data, // the CDB, scatter/gather, etc.
4141 LONG *fcExchangeIndex ) // points to allocated exchange,
4143 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
4144 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
4145 ULONG ulStatus = 0; // assume OK
4146 USHORT ox_ID, rx_ID=0xFFFF;
4147 ULONG SfsLen=0L;
4148 TachLiteIRB* pIRB;
4149 IRBflags IRB_flags;
4150 UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
4151 TachFCHDR_GCMND* CMDfchs;
4152 TachFCHDR* dataHDR; // 32 byte HEADER ONLY FCP-DATA buffer
4153 TachFCHDR_RSP* rspHDR; // 32 byte header + RSP payload
4154 Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data; // Linux Scsi CDB, S/G, ...
4155 TachLiteIWE* pIWE;
4156 TachLiteIRE* pIRE;
4157 TachLiteTWE* pTWE;
4158 TachLiteTRE* pTRE;
4159 ULONG fcp_dl; // total byte length of DATA transferred
4160 ULONG fl; // frame length (FC frame size, 128, 256, 512, 1024)
4161 ULONG sgPairs; // number of valid scatter/gather pairs
4162 int FCP_SCSI_command;
4163 BA_ACC_PAYLOAD *ba_acc;
4164 BA_RJT_PAYLOAD *ba_rjt;
4166 // check passed ARGS
4167 if( !fcChip->ERQ ) // NULL ptr means uninitialized Tachlite chip
4168 return INVALID_ARGS;
4171 if( type == SCSI_IRE ||
4172 type == SCSI_TRE ||
4173 type == SCSI_IWE ||
4174 type == SCSI_TWE)
4175 FCP_SCSI_command = 1;
4177 else
4178 FCP_SCSI_command = 0;
4181 // for commands that pass payload data (e.g. SCSI write)
4182 // examine command struct - verify that the
4183 // length of s/g buffers is adequate for total payload
4184 // length (end of list is NULL address)
4186 if( FCP_SCSI_command )
4188 if( Data ) // must have data descriptor (S/G list -- at least
4189 // one address with at least 1 byte of data)
4191 // something to do (later)?
4194 else
4195 return INVALID_ARGS; // invalid DATA ptr
4200 // we can build an Exchange for later Queuing (on the TL chip)
4201 // if an empty slot is available in the DevExt for this controller
4202 // look for available Exchange slot...
4204 if( type != FCP_RESPONSE &&
4205 type != BLS_ABTS &&
4206 type != BLS_ABTS_ACC ) // already have Exchange slot!
4207 *fcExchangeIndex = FindFreeExchange( fcChip, type );
4209 if( *fcExchangeIndex != -1 ) // Exchange is available?
4211 // assign tmp ptr (shorthand)
4212 CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs;
4214 if( Cmnd != NULL ) // (necessary for ABTS cases)
4216 Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
4217 Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort =
4218 fcFindLoggedInPort( fcChip,
4219 Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
4220 0, // DON'T search linked list for FC port id
4221 NULL, // DON'T search linked list for FC WWN
4222 NULL); // DON'T care about end of list
4227 // Build the command frame header (& data) according
4228 // to command type
4230 // fields common for all SFS frame types
4231 CMDfchs->reserved = 0L; // must clear
4232 CMDfchs->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; LCr=0, no TS
4234 // get the destination port_id from incoming FCHS
4235 // (initialized before calling if we're Originator)
4236 // Frame goes to port it was from - the source_id
4238 CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
4239 CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4242 // now enter command-specific fields
4243 switch( type )
4246 case BLS_NOP: // FC defined basic link service command NO-OP
4247 // ensure unique X_IDs! (use tracking function)
4249 *pIRB_flags = 0; // clear IRB flags
4250 IRB_flags.SFA = 1; // send SFS (not SEST index)
4251 SfsLen = *pIRB_flags;
4253 SfsLen <<= 24; // shift flags to MSB
4254 SfsLen += 32L; // add len to LSB (header only - no payload)
4256 // TYPE[31-24] 00 Basic Link Service
4257 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4258 CMDfchs->d_id |= 0x80000000L; // R_CTL = 80 for NOP (Basic Link Ser.)
4259 CMDfchs->f_ctl = 0x00310000L; // xchng originator, 1st seq,....
4260 CMDfchs->seq_cnt = 0x0L;
4261 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID for now; OX_ID on start
4262 CMDfchs->ro = 0x0L; // relative offset (n/a)
4263 CMDfchs->pl[0] = 0xaabbccddL; // words 8-15 frame data payload (n/a)
4264 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
4265 // (NOP should complete ~instantly)
4266 break;
4271 case BLS_ABTS_ACC: // Abort Sequence ACCept
4272 *pIRB_flags = 0; // clear IRB flags
4273 IRB_flags.SFA = 1; // send SFS (not SEST index)
4274 SfsLen = *pIRB_flags;
4276 SfsLen <<= 24; // shift flags to MSB
4277 SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
4279 CMDfchs->d_id |= 0x84000000L; // R_CTL = 84 for BASIC ACCept
4280 // TYPE[31-24] 00 Basic Link Service
4281 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4282 CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
4283 // CMDfchs->seq_id & count might be set from DataHdr?
4284 CMDfchs->ro = 0x0L; // relative offset (n/a)
4285 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4286 // (Timeout in case of weird error)
4288 // now set the ACCept payload...
4289 ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
4290 memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
4291 // Since PLDA requires (only) entire Exchange aborts, we don't need
4292 // to worry about what the last sequence was.
4294 // We expect that a "target" task is accepting the abort, so we
4295 // can use the OX/RX ID pair
4296 ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
4298 // source, dest, #bytes
4299 BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
4301 ba_acc->low_seq_cnt = 0;
4302 ba_acc->high_seq_cnt = 0xFFFF;
4305 break;
4308 case BLS_ABTS_RJT: // Abort Sequence ACCept
4309 *pIRB_flags = 0; // clear IRB flags
4310 IRB_flags.SFA = 1; // send SFS (not SEST index)
4311 SfsLen = *pIRB_flags;
4313 SfsLen <<= 24; // shift flags to MSB
4314 SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
4316 CMDfchs->d_id |= 0x85000000L; // R_CTL = 85 for BASIC ReJecT
4317 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4318 // TYPE[31-24] 00 Basic Link Service
4319 CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
4320 // CMDfchs->seq_id & count might be set from DataHdr?
4321 CMDfchs->ro = 0x0L; // relative offset (n/a)
4322 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4323 // (Timeout in case of weird error)
4325 CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
4327 // now set the ReJecT payload...
4328 ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
4329 memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
4331 // We expect that a "target" task couldn't find the Exhange in the
4332 // array of active exchanges, so we use a new LinkService X_ID.
4333 // See Reject payload description in FC-PH (Rev 4.3), pg. 140
4334 ba_rjt->reason_code = 0x09; // "unable to perform command request"
4335 ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
4338 break;
4341 case BLS_ABTS: // FC defined basic link service command ABTS
4342 // Abort Sequence
4345 *pIRB_flags = 0; // clear IRB flags
4346 IRB_flags.SFA = 1; // send SFS (not SEST index)
4347 SfsLen = *pIRB_flags;
4349 SfsLen <<= 24; // shift flags to MSB
4350 SfsLen += 32L; // add len to LSB (header only - no payload)
4352 // TYPE[31-24] 00 Basic Link Service
4353 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4354 CMDfchs->d_id |= 0x81000000L; // R_CTL = 81 for ABTS
4355 CMDfchs->f_ctl = 0x00110000L; // xchnge originator, last seq, xfer SI
4356 // CMDfchs->seq_id & count might be set from DataHdr?
4357 CMDfchs->ro = 0x0L; // relative offset (n/a)
4358 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4359 // (ABTS must timeout when responder is gone)
4360 break;
4364 case FCS_NSR: // Fabric Name Service Request
4365 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4368 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4369 // OX_ID, linked to Driver Transaction ID
4370 // (fix-up at Queing time)
4371 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4372 // OX_ID set at ERQueing time
4373 *pIRB_flags = 0; // clear IRB flags
4374 IRB_flags.SFA = 1; // send SFS (not SEST index)
4375 SfsLen = *pIRB_flags;
4377 SfsLen <<= 24; // shift flags to MSB
4378 SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
4380 CMDfchs->d_id |= 0x02000000L; // R_CTL = 02 for -
4381 // Name Service Request: Unsolicited
4382 // TYPE[31-24] 01 Extended Link Service
4383 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4384 CMDfchs->f_ctl = 0x20210000L;
4385 // OX_ID will be fixed-up at Tachyon enqueing time
4386 CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4387 CMDfchs->ro = 0x0L; // relative offset (n/a)
4389 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4396 break;
4401 case ELS_PLOGI: // FC-PH extended link service command Port Login
4402 // (May, 2000)
4403 // NOTE! This special case facilitates SANMark testing. The SANMark
4404 // test script for initialization-timeout.fcal.SANMark-1.fc
4405 // "eats" the OPN() primitive without issuing an R_RDY, causing
4406 // Tachyon to report LST (loop state timeout), which causes a
4407 // LIP. To avoid this, simply send out the frame (i.e. assuming a
4408 // buffer credit of 1) without waiting for R_RDY. Many FC devices
4409 // (other than Tachyon) have been doing this for years. We don't
4410 // ever want to do this for non-Link Service frames unless the
4411 // other device really did report non-zero login BB credit (i.e.
4412 // in the PLOGI ACCept frame).
4413 // CMDfchs->sof_eof |= 0x00000400L; // LCr=1
4415 case ELS_FDISC: // Fabric Discovery (Login)
4416 case ELS_FLOGI: // Fabric Login
4417 case ELS_SCR: // Fabric State Change Registration
4418 case ELS_LOGO: // FC-PH extended link service command Port Logout
4419 case ELS_PDISC: // FC-PH extended link service cmnd Port Discovery
4420 case ELS_PRLI: // FC-PH extended link service cmnd Process Login
4422 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4425 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4426 // OX_ID, linked to Driver Transaction ID
4427 // (fix-up at Queing time)
4428 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4429 // OX_ID set at ERQueing time
4430 *pIRB_flags = 0; // clear IRB flags
4431 IRB_flags.SFA = 1; // send SFS (not SEST index)
4432 SfsLen = *pIRB_flags;
4434 SfsLen <<= 24; // shift flags to MSB
4435 if( type == ELS_LOGO )
4436 SfsLen += (32L + 16L); // add len (header & PLOGI payload)
4437 else if( type == ELS_PRLI )
4438 SfsLen += (32L + 20L); // add len (header & PRLI payload)
4439 else if( type == ELS_SCR )
4440 SfsLen += (32L + sizeof(SCR_PL)); // add len (header & SCR payload)
4441 else
4442 SfsLen += (32L + 116L); // add len (header & PLOGI payload)
4444 CMDfchs->d_id |= 0x22000000L; // R_CTL = 22 for -
4445 // Extended Link_Data: Unsolicited Control
4446 // TYPE[31-24] 01 Extended Link Service
4447 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4448 CMDfchs->f_ctl = 0x01210000L;
4449 // OX_ID will be fixed-up at Tachyon enqueing time
4450 CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4451 CMDfchs->ro = 0x0L; // relative offset (n/a)
4453 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4455 break;
4459 case ELS_LOGO_ACC: // FC-PH extended link service logout accept
4460 case ELS_RJT: // extended link service reject (add reason)
4461 case ELS_ACC: // ext. link service generic accept
4462 case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
4463 case ELS_PRLI_ACC: // ext. link service process login accept
4466 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
4467 // ensure unique X_IDs! (use tracking function)
4468 // OX_ID from initiator cmd
4469 ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16);
4470 rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
4472 *pIRB_flags = 0; // clear IRB flags
4473 IRB_flags.SFA = 1; // send SFS (not SEST index)
4474 SfsLen = *pIRB_flags;
4476 SfsLen <<= 24; // shift flags to MSB
4477 if( type == ELS_RJT )
4479 SfsLen += (32L + 8L); // add len (header + payload)
4481 // ELS_RJT reason codes (utilize unused "reserved" field)
4482 CMDfchs->pl[0] = 1;
4483 CMDfchs->pl[1] = InFCHS->reserved;
4486 else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC) )
4487 SfsLen += (32L + 4L); // add len (header + payload)
4488 else if( type == ELS_PLOGI_ACC )
4489 SfsLen += (32L + 116L); // add len (header + payload)
4490 else if( type == ELS_PRLI_ACC )
4491 SfsLen += (32L + 20L); // add len (header + payload)
4493 CMDfchs->d_id |= 0x23000000L; // R_CTL = 23 for -
4494 // Extended Link_Data: Control Reply
4495 // TYPE[31-24] 01 Extended Link Service
4496 // f_ctl[23:0] exchg responder, last seq, e_s, tsi
4497 CMDfchs->f_ctl = 0x01990000L;
4498 CMDfchs->seq_cnt = 0x0L;
4499 CMDfchs->ox_rx_id = 0L; // clear
4500 CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
4501 CMDfchs->ox_rx_id <<= 16; // shift them
4503 CMDfchs->ro = 0x0L; // relative offset (n/a)
4505 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4507 break;
4510 // Fibre Channel SCSI 'originator' sequences...
4511 // (originator means 'initiator' in FCP-SCSI)
4513 case SCSI_IWE: // TachLite Initiator Write Entry
4515 PFC_LOGGEDIN_PORT pLoggedInPort =
4516 Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
4518 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4519 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
4521 // first, build FCP_CMND
4522 // unique X_ID fix-ups in StartExchange
4524 *pIRB_flags = 0; // clear IRB flags
4525 IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
4527 // NOTE: unlike FC LinkService login frames, normal
4528 // SCSI commands are sent without outgoing verification
4529 IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
4530 SfsLen = *pIRB_flags;
4532 SfsLen <<= 24; // shift flags to MSB
4533 SfsLen += 64L; // add len to LSB (header & CMND payload)
4535 CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
4537 // TYPE[31-24] 8 for FCP SCSI
4538 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4539 // valid RO
4540 CMDfchs->f_ctl = 0x08210008L;
4541 CMDfchs->seq_cnt = 0x0L;
4542 CMDfchs->ox_rx_id = 0L; // clear for now (-or- in later)
4543 CMDfchs->ro = 0x0L; // relative offset (n/a)
4545 // now, fill out FCP-DATA header
4546 // (use buffer inside SEST object)
4547 dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4548 dataHDR->reserved = 0L; // must clear
4549 dataHDR->sof_eof = 0x75002000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4550 dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4551 dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4552 // TYPE[31-24] 8 for FCP SCSI
4553 // f_ctl[23:0] xfer S.I.| valid RO
4554 dataHDR->f_ctl = 0x08010008L;
4555 dataHDR->seq_cnt = 0x02000000L; // sequence ID: df_ctl : seqence count
4556 dataHDR->ox_rx_id = 0L; // clear; fix-up dataHDR fields later
4557 dataHDR->ro = 0x0L; // relative offset (n/a)
4559 // Now setup the SEST entry
4560 pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
4562 // fill out the IWE:
4564 // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
4565 pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
4568 // from login parameters with other port, what's the largest frame
4569 // we can send?
4570 if( pLoggedInPort == NULL)
4572 ulStatus = INVALID_ARGS; // failed! give up
4573 break;
4575 if( pLoggedInPort->rx_data_size >= 2048)
4576 fl = 0x00020000; // 2048 code (only support 1024!)
4577 else if( pLoggedInPort->rx_data_size >= 1024)
4578 fl = 0x00020000; // 1024 code
4579 else if( pLoggedInPort->rx_data_size >= 512)
4580 fl = 0x00010000; // 512 code
4581 else
4582 fl = 0; // 128 bytes -- should never happen
4585 pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
4586 pIWE->Hdr_Addr = fcChip->SEST->base +
4587 ((unsigned long)&fcChip->SEST->DataHDR[*fcExchangeIndex] -
4588 (unsigned long)fcChip->SEST);
4590 pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4591 pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4593 memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0,
4594 sizeof( FCP_STATUS_RESPONSE) ); // clear out previous status
4596 pIWE->RSP_Addr = fcChip->SEST->base +
4597 ((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] -
4598 (unsigned long)fcChip->SEST);
4600 // Do we need local or extended gather list?
4601 // depends on size - we can handle 3 len/addr pairs
4602 // locally.
4604 fcp_dl = build_SEST_sgList(
4605 cpqfcHBAdata->PciDev,
4606 &pIWE->GLen1,
4607 Cmnd, // S/G list
4608 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4609 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4611 if( !fcp_dl ) // error building S/G list?
4613 ulStatus = MEMPOOL_FAIL;
4614 break; // give up
4617 // Now that we know total data length in
4618 // the passed S/G buffer, set FCP CMND frame
4619 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4623 if( sgPairs > 3 ) // need extended s/g list
4624 pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
4625 else // local data pointers (in SEST)
4626 pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
4628 // ULONG 5
4629 pIWE->Link = 0x0000ffffL; // Buff_Index | Link
4631 pIWE->RX_ID = 0x0L; // DWord 6: RX_ID set by target XFER_RDY
4633 // DWord 7
4634 pIWE->Data_Len = 0L; // TL enters rcv'd XFER_RDY BURST_LEN
4635 pIWE->Exp_RO = 0L; // DWord 8
4636 // DWord 9
4637 pIWE->Exp_Byte_Cnt = fcp_dl; // sum of gather buffers
4639 break;
4645 case SCSI_IRE: // TachLite Initiator Read Entry
4647 if( Cmnd->timeout != 0)
4649 // printk("Cmnd->timeout %d\n", Cmnd->timeout);
4650 // per Linux Scsi
4651 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
4653 else // use our best guess, based on FC & device
4656 if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)
4658 // turn off our timeouts (for now...)
4659 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF;
4661 else
4663 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4664 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
4669 // first, build FCP_CMND
4672 *pIRB_flags = 0; // clear IRB flags
4673 IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
4674 // NOTE: unlike FC LinkService login frames,
4675 // normal SCSI commands are sent "open loop"
4676 IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
4677 SfsLen = *pIRB_flags;
4679 SfsLen <<= 24; // shift flags to MSB
4680 SfsLen += 64L; // add len to LSB (header & CMND payload)
4682 CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
4684 // TYPE[31-24] 8 for FCP SCSI
4685 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4686 // valid RO
4687 CMDfchs->f_ctl = 0x08210008L;
4688 CMDfchs->seq_cnt = 0x0L;
4689 // x_ID & data direction bit set later
4690 CMDfchs->ox_rx_id = 0xFFFF; // clear
4691 CMDfchs->ro = 0x0L; // relative offset (n/a)
4695 // Now setup the SEST entry
4696 pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
4698 // fill out the IRE:
4699 // VALid entry:Dir outbound:enable CM:enal INT:
4700 pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
4702 pIRE->reserved = 0L;
4703 pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4704 pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4706 pIRE->RSP_Addr = fcChip->SEST->base +
4707 ((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] -
4708 (unsigned long)fcChip->SEST);
4710 // Do we need local or extended gather list?
4711 // depends on size - we can handle 3 len/addr pairs
4712 // locally.
4714 fcp_dl = build_SEST_sgList(
4715 cpqfcHBAdata->PciDev,
4716 &pIRE->SLen1,
4717 Cmnd, // SCSI command Data desc. with S/G list
4718 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4719 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4722 if( !fcp_dl ) // error building S/G list?
4724 // It is permissible to have a ZERO LENGTH Read command.
4725 // If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
4726 // to 0 and continue.
4727 if( Cmnd->request_bufflen == 0 )
4729 fcp_dl = 0; // no FC DATA frames expected
4732 else
4734 ulStatus = MEMPOOL_FAIL;
4735 break; // give up
4739 // now that we know the S/G length, build CMND payload
4740 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4743 if( sgPairs > 3 ) // need extended s/g list
4744 pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
4745 else
4746 pIRE->Buff_Off = 0x80000000; // local data, no offset
4748 pIRE->Buff_Index = 0x0L; // DWord 5: Buff_Index | Reserved
4750 pIRE->Exp_RO = 0x0L; // DWord 6: Expected Rel. Offset
4752 pIRE->Byte_Count = 0; // DWord 7: filled in by TL on err
4753 pIRE->reserved_ = 0; // DWord 8: reserved
4754 // NOTE: 0 length READ is OK.
4755 pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
4757 break;
4762 // Fibre Channel SCSI 'responder' sequences...
4763 // (originator means 'target' in FCP-SCSI)
4764 case SCSI_TWE: // TachLite Target Write Entry
4766 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4768 // first, build FCP_CMND
4770 *pIRB_flags = 0; // clear IRB flags
4771 IRB_flags.SFA = 1; // send SFS (XFER_RDY)
4772 SfsLen = *pIRB_flags;
4774 SfsLen <<= 24; // shift flags to MSB
4775 SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4777 CMDfchs->d_id |= (0x05000000L); // R_CTL = 5 for XFER_RDY
4779 // TYPE[31-24] 8 for FCP SCSI
4780 // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
4781 // valid RO
4782 CMDfchs->f_ctl = 0x08810008L;
4783 CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
4784 // use originator (other port's) OX_ID
4785 CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // we want upper 16 bits
4786 CMDfchs->ro = 0x0L; // relative offset (n/a)
4788 // now, fill out FCP-RSP header
4789 // (use buffer inside SEST object)
4791 rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4792 rspHDR->reserved = 0L; // must clear
4793 rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4794 rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4795 rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4796 // TYPE[31-24] 8 for FCP SCSI
4797 // f_ctl[23:0] responder|last seq| xfer S.I.
4798 rspHDR->f_ctl = 0x08910000L;
4799 rspHDR->seq_cnt = 0x03000000; // sequence ID
4800 rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
4801 rspHDR->ro = 0x0L; // relative offset (n/a)
4804 // Now setup the SEST entry
4806 pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
4808 // fill out the TWE:
4810 // VALid entry:Dir outbound:enable CM:enal INT:
4811 pTWE->Seq_Accum = 0xC4000000L; // upper word flags
4812 pTWE->reserved = 0L;
4813 pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
4814 pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4817 // Do we need local or extended gather list?
4818 // depends on size - we can handle 3 len/addr pairs
4819 // locally.
4821 fcp_dl = build_SEST_sgList(
4822 cpqfcHBAdata->PciDev,
4823 &pTWE->SLen1,
4824 Cmnd, // S/G list
4825 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4826 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4829 if( !fcp_dl ) // error building S/G list?
4831 ulStatus = MEMPOOL_FAIL;
4832 break; // give up
4835 // now that we know the S/G length, build CMND payload
4836 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4839 if( sgPairs > 3 ) // need extended s/g list
4840 pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
4841 else
4842 pTWE->Buff_Off = 0x80000000; // local data, no offset
4844 pTWE->Buff_Index = 0; // Buff_Index | Link
4845 pTWE->Exp_RO = 0;
4846 pTWE->Byte_Count = 0; // filled in by TL on err
4847 pTWE->reserved_ = 0;
4848 pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
4850 break;
4857 case SCSI_TRE: // TachLite Target Read Entry
4859 // It doesn't make much sense for us to "time-out" a READ,
4860 // but we'll use it for design consistency and internal error recovery.
4861 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4863 // I/O request block settings...
4864 *pIRB_flags = 0; // clear IRB flags
4865 // check PRLI (process login) info
4866 // to see if Initiator Requires XFER_RDY
4867 // if not, don't send one!
4868 // { PRLI check...}
4869 IRB_flags.SFA = 0; // don't send XFER_RDY - start data
4870 SfsLen = *pIRB_flags;
4872 SfsLen <<= 24; // shift flags to MSB
4873 SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4877 // now, fill out FCP-DATA header
4878 // (use buffer inside SEST object)
4879 dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4881 dataHDR->reserved = 0L; // must clear
4882 dataHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
4883 dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4884 dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4887 // TYPE[31-24] 8 for FCP SCSI
4888 // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
4889 // valid RO
4890 dataHDR->f_ctl = 0x08810008L;
4891 dataHDR->seq_cnt = 0x01000000; // sequence ID (no XRDY)
4892 dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
4893 dataHDR->ro = 0x0L; // relative offset (n/a)
4895 // now, fill out FCP-RSP header
4896 // (use buffer inside SEST object)
4897 rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4899 rspHDR->reserved = 0L; // must clear
4900 rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4901 rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4902 rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4903 // TYPE[31-24] 8 for FCP SCSI
4904 // f_ctl[23:0] responder|last seq| xfer S.I.
4905 rspHDR->f_ctl = 0x08910000L;
4906 rspHDR->seq_cnt = 0x02000000; // sequence ID: df_ctl: sequence count
4908 rspHDR->ro = 0x0L; // relative offset (n/a)
4911 // Now setup the SEST entry
4912 pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
4915 // VALid entry:Dir outbound:enable CM:enal INT:
4916 pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
4917 pTRE->Hdr_Addr = // bus address of dataHDR;
4918 fcChip->SEST->base +
4919 ((unsigned long)&fcChip->SEST->DataHDR[ *fcExchangeIndex ] -
4920 (unsigned long)fcChip->SEST);
4922 pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
4923 pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4924 pTRE->RSP_Addr = // bus address of rspHDR
4925 fcChip->SEST->base +
4926 ((unsigned long)&fcChip->SEST->RspHDR[ *fcExchangeIndex ] -
4927 (unsigned long)fcChip->SEST);
4929 // Do we need local or extended gather list?
4930 // depends on size - we can handle 3 len/addr pairs
4931 // locally.
4933 fcp_dl = build_SEST_sgList(
4934 cpqfcHBAdata->PciDev,
4935 &pTRE->GLen1,
4936 Cmnd, // S/G list
4937 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4938 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4941 if( !fcp_dl ) // error building S/G list?
4943 ulStatus = MEMPOOL_FAIL;
4944 break; // give up
4947 // no payload or command to build -- READ doesn't need XRDY
4950 if( sgPairs > 3 ) // need extended s/g list
4951 pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
4952 else // local data pointers (in SEST)
4953 pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
4955 // ULONG 5
4956 pTRE->Buff_Index = 0L; // Buff_Index | reserved
4957 pTRE->reserved = 0x0L; // DWord 6
4959 // DWord 7: NOTE: zero length will
4960 // hang TachLite!
4961 pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
4963 pTRE->reserved_ = 0L; // DWord 8
4964 pTRE->reserved__ = 0L; // DWord 9
4966 break;
4974 case FCP_RESPONSE:
4975 // Target response frame: this sequence uses an OX/RX ID
4976 // pair from a completed SEST exchange. We built most
4977 // of the response frame when we created the TWE/TRE.
4979 *pIRB_flags = 0; // clear IRB flags
4980 IRB_flags.SFA = 1; // send SFS (RSP)
4981 SfsLen = *pIRB_flags;
4983 SfsLen <<= 24; // shift flags to MSB
4984 SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
4987 Exchanges->fcExchange[ *fcExchangeIndex].type =
4988 FCP_RESPONSE; // change Exchange type to "response" phase
4990 // take advantage of prior knowledge of OX/RX_ID pair from
4991 // previous XFER outbound frame (still in fchs of exchange)
4992 fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id =
4993 CMDfchs->ox_rx_id;
4995 // Check the status of the DATA phase of the exchange so we can report
4996 // status to the initiator
4997 buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
4999 memcpy(
5000 CMDfchs, // re-use same XFER fchs for Response frame
5001 &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
5002 sizeof( TachFCHDR_RSP ));
5005 break;
5007 default:
5008 printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
5009 break;
5015 if( !ulStatus) // no errors above?
5017 // FCHS is built; now build IRB
5019 // link the just built FCHS (the "command") to the IRB entry
5020 // for this Exchange.
5021 pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB;
5023 // len & flags according to command type above
5024 pIRB->Req_A_SFS_Len = SfsLen; // includes IRB flags & len
5025 pIRB->Req_A_SFS_Addr = // TL needs physical addr of frame to send
5026 fcChip->exch_dma_handle + (unsigned long)CMDfchs -
5027 (unsigned long)Exchanges;
5029 pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
5031 // Exchange is complete except for "fix-up" fields to be set
5032 // at Tachyon Queuing time:
5033 // IRB->Req_A_Trans_ID (OX_ID/ RX_ID):
5034 // for SEST entry, lower bits correspond to actual FC Exchange ID
5035 // fchs->OX_ID or RX_ID
5037 else
5039 #ifdef DBG
5040 printk( "FC Error: SEST build Pool Allocation failed\n");
5041 #endif
5042 // return resources...
5043 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, *fcExchangeIndex); // SEST build failed
5046 else // no Exchanges available
5048 ulStatus = SEST_FULL;
5049 printk( "FC Error: no fcExchanges available\n");
5051 return ulStatus;
5059 // set RSP payload fields
5060 static void buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID)
5062 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5063 FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID]; // shorthand
5064 PFCP_STATUS_RESPONSE pFcpStatus;
5066 memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
5067 sizeof( FCP_STATUS_RESPONSE) );
5068 if( pExchange->status ) // something wrong?
5070 pFcpStatus = (PFCP_STATUS_RESPONSE) // cast RSP buffer for this xchng
5071 &fcChip->SEST->RspHDR[ ExchangeID ].pl;
5072 if( pExchange->status & COUNT_ERROR )
5075 // set FCP response len valid (so we can report count error)
5076 pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
5077 pFcpStatus->fcp_rsp_len = 0x04000000; // 4 byte len (BIG Endian)
5079 pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
5085 static dma_addr_t
5086 cpqfc_pci_map_sg_page(
5087 struct pci_dev *pcidev,
5088 ULONG *hw_paddr, // where to put phys addr for HW use
5089 void *sgp_vaddr, // the virtual address of the sg page
5090 dma_addr_t *umap_paddr, // where to put phys addr for unmap
5091 unsigned int *maplen, // where to store sg entry length
5092 int PairCount) // number of sg pairs used in the page.
5094 unsigned long aligned_addr = (unsigned long) sgp_vaddr;
5096 *maplen = PairCount * 8;
5097 aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
5098 aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
5100 *umap_paddr = pci_map_single(pcidev, (void *) aligned_addr,
5101 *maplen, PCI_DMA_TODEVICE);
5102 *hw_paddr = (ULONG) *umap_paddr;
5104 # if BITS_PER_LONG > 32
5105 if( *umap_paddr >>32 ) {
5106 printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n",
5107 (void*)umap_paddr);
5108 return 0;
5110 # endif
5111 return *umap_paddr;
5114 static void
5115 cpqfc_undo_SEST_mappings(struct pci_dev *pcidev,
5116 unsigned long contigaddr, int len, int dir,
5117 struct scatterlist *sgl, int use_sg,
5118 PSGPAGES *sgPages_head,
5119 int allocated_pages)
5121 PSGPAGES i, next;
5123 if (contigaddr != (unsigned long) NULL)
5124 pci_unmap_single(pcidev, contigaddr, len, dir);
5126 if (sgl != NULL)
5127 pci_unmap_sg(pcidev, sgl, use_sg, dir);
5129 for (i=*sgPages_head; i != NULL ;i = next)
5131 pci_unmap_single(pcidev, i->busaddr, i->maplen,
5132 PCI_DMA_TODEVICE);
5133 i->busaddr = (dma_addr_t) NULL;
5134 i->maplen = 0L;
5135 next = i->next;
5136 kfree(i);
5138 *sgPages_head = NULL;
5141 // This routine builds scatter/gather lists into SEST entries
5142 // INPUTS:
5143 // SESTalPair - SEST address @DWordA "Local Buffer Length"
5144 // sgList - Scatter/Gather linked list of Len/Address data buffers
5145 // OUTPUT:
5146 // sgPairs - number of valid address/length pairs
5147 // Remarks:
5148 // The SEST data buffer pointers only depend on number of
5149 // length/ address pairs, NOT on the type (IWE, TRE,...)
5150 // Up to 3 pairs can be referenced in the SEST - more than 3
5151 // require this Extended S/G list page. The page holds 4, 8, 16...
5152 // len/addr pairs, per Scatter/Gather List Page Length Reg.
5153 // TachLite allows pages to be linked to any depth.
5155 //#define DBG_SEST_SGLIST 1 // for printing out S/G pairs with Ext. pages
5157 static int ap_hi_water = TL_DANGER_SGPAGES;
5159 static ULONG build_SEST_sgList(
5160 struct pci_dev *pcidev,
5161 ULONG *SESTalPairStart, // the 3 len/address buffers in SEST
5162 Scsi_Cmnd *Cmnd,
5163 ULONG *sgPairs,
5164 PSGPAGES *sgPages_head) // link list of TL Ext. S/G pages from O/S Pool
5167 ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
5168 ULONG* alPair = SESTalPairStart;
5169 ULONG* ext_sg_page_phys_addr_place = NULL;
5170 int PairCount;
5171 unsigned long ulBuff, contigaddr;
5172 ULONG total_data_len=0; // (in bytes)
5173 ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
5174 ULONG thisMappingLen;
5175 struct scatterlist *sgl = NULL; // S/G list (Linux format)
5176 int sg_count, totalsgs;
5177 dma_addr_t busaddr;
5178 unsigned long thislen, offset;
5179 PSGPAGES *sgpage = sgPages_head;
5180 PSGPAGES prev_page = NULL;
5182 # define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
5183 contigaddr = (unsigned long) NULL;
5185 if( !Cmnd->use_sg ) // no S/G list?
5187 if (bytes_to_go <= TL_MAX_SG_ELEM_LEN)
5189 *sgPairs = 1; // use "local" S/G pair in SEST entry
5190 // (for now, ignore address bits above #31)
5192 *alPair++ = bytes_to_go; // bits 18-0, length
5194 if (bytes_to_go != 0) {
5195 contigaddr = ulBuff = pci_map_single(pcidev,
5196 Cmnd->request_buffer,
5197 Cmnd->request_bufflen,
5198 Cmnd->sc_data_direction);
5199 // printk("ms %p ", ulBuff);
5201 else {
5202 // No data transfer, (e.g.: Test Unit Ready)
5203 // printk("btg=0 ");
5204 *sgPairs = 0;
5205 memset(alPair, 0, sizeof(*alPair));
5206 return 0;
5209 # if BITS_PER_LONG > 32
5210 if( ulBuff >>32 ) {
5211 printk("FATAL! Tachyon DMA address %p "
5212 "exceeds 32 bits\n", (void*)ulBuff );
5213 return 0;
5215 # endif
5216 *alPair = (ULONG)ulBuff;
5217 return bytes_to_go;
5219 else // We have a single large (too big) contiguous buffer.
5220 { // We will have to break it up. We'll use the scatter
5221 // gather code way below, but use contigaddr instead
5222 // of sg_dma_addr(). (this is a very rare case).
5224 unsigned long btg;
5225 contigaddr = pci_map_single(pcidev, Cmnd->request_buffer,
5226 Cmnd->request_bufflen,
5227 Cmnd->sc_data_direction);
5229 // printk("contigaddr = %p, len = %d\n",
5230 // (void *) contigaddr, bytes_to_go);
5231 totalsgs = 0;
5232 for (btg = bytes_to_go; btg > 0; ) {
5233 btg -= ( btg > TL_MAX_SG_ELEM_LEN ?
5234 TL_MAX_SG_ELEM_LEN : btg );
5235 totalsgs++;
5237 sgl = NULL;
5238 *sgPairs = totalsgs;
5241 else // we do have a scatter gather list
5243 // [TBD - update for Linux to support > 32 bits addressing]
5244 // since the format for local & extended S/G lists is different,
5245 // check if S/G pairs exceeds 3.
5246 // *sgPairs = Cmnd->use_sg; Nope, that's wrong.
5248 sgl = (struct scatterlist*)Cmnd->request_buffer;
5249 sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg,
5250 Cmnd->sc_data_direction);
5251 if( sg_count <= 3 ) {
5253 // we need to be careful here that no individual mapping
5254 // is too large, and if any is, that breaking it up
5255 // doesn't push us over 3 sgs, or, if it does, that we
5256 // handle that case. Tachyon can take 0x7FFFF bits for length,
5257 // but sg structure uses "unsigned int", on the face of it,
5258 // up to 0xFFFFFFFF or even more.
5260 int i;
5261 unsigned long thislen;
5263 totalsgs = 0;
5264 for (i=0;i<sg_count;i++) {
5265 thislen = sg_dma_len(&sgl[i]);
5266 while (thislen >= TL_MAX_SG_ELEM_LEN) {
5267 totalsgs++;
5268 thislen -= TL_MAX_SG_ELEM_LEN;
5270 if (thislen > 0) totalsgs++;
5272 *sgPairs = totalsgs;
5273 } else totalsgs = 999; // as a first estimate, definitely >3,
5275 // if (totalsgs != sg_count)
5276 // printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
5279 if( totalsgs <= 3 ) // can (must) use "local" SEST list
5281 while( bytes_to_go)
5283 offset = 0L;
5285 if ( WE_HAVE_SG_LIST )
5286 thisMappingLen = sg_dma_len(sgl);
5287 else // or contiguous buffer?
5288 thisMappingLen = bytes_to_go;
5290 while (thisMappingLen > 0)
5292 thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ?
5293 TL_MAX_SG_ELEM_LEN : thisMappingLen;
5294 bytes_to_go = bytes_to_go - thislen;
5296 // we have L/A pair; L = thislen, A = physicalAddress
5297 // load into SEST...
5299 total_data_len += thislen;
5300 *alPair = thislen; // bits 18-0, length
5302 alPair++;
5304 if ( WE_HAVE_SG_LIST )
5305 ulBuff = sg_dma_address(sgl) + offset;
5306 else
5307 ulBuff = contigaddr + offset;
5309 offset += thislen;
5311 # if BITS_PER_LONG > 32
5312 if( ulBuff >>32 ) {
5313 printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n",
5314 (void*)ulBuff );
5315 printk("%s = %p, offset = %ld\n",
5316 WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
5317 WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
5318 offset);
5319 return 0;
5321 # endif
5322 *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
5323 thisMappingLen -= thislen;
5326 if ( WE_HAVE_SG_LIST ) ++sgl; // next S/G pair
5327 else if (bytes_to_go != 0) printk("BTG not zero!\n");
5329 # ifdef DBG_SEST_SGLIST
5330 printk("L=%d ", thisMappingLen);
5331 printk("btg=%d ", bytes_to_go);
5332 # endif
5335 // printk("i:%d\n", *sgPairs);
5337 else // more than 3 pairs requires Extended S/G page (Pool Allocation)
5339 // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
5340 for( i=2; i<6; i++)
5341 alPair[i] = 0;
5343 PairCount = TL_EXT_SG_PAGE_COUNT; // forces initial page allocation
5344 totalsgs = 0;
5345 while( bytes_to_go )
5347 // Per SEST format, we can support 524287 byte lengths per
5348 // S/G pair. Typical user buffers are 4k, and very rarely
5349 // exceed 12k due to fragmentation of physical memory pages.
5350 // However, on certain O/S system (not "user") buffers (on platforms
5351 // with huge memories), it's possible to exceed this
5352 // length in a single S/G address/len mapping, so we have to handle
5353 // that.
5355 offset = 0L;
5356 if ( WE_HAVE_SG_LIST )
5357 thisMappingLen = sg_dma_len(sgl);
5358 else
5359 thisMappingLen = bytes_to_go;
5361 while (thisMappingLen > 0)
5363 thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ?
5364 TL_MAX_SG_ELEM_LEN : thisMappingLen;
5365 // printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
5367 // should we load into "this" extended S/G page, or allocate
5368 // new page?
5370 if( PairCount >= TL_EXT_SG_PAGE_COUNT )
5372 // Now, we have to map the previous page, (triggering buffer bounce)
5373 // The first time thru the loop, there won't be a previous page.
5374 if (prev_page != NULL) // is there a prev page?
5376 // this code is normally kind of hard to trigger,
5377 // you have to use up more than 256 scatter gather
5378 // elements to get here. Cranking down TL_MAX_SG_ELEM_LEN
5379 // to an absurdly low value (128 bytes or so) to artificially
5380 // break i/o's into a zillion pieces is how I tested it.
5381 busaddr = cpqfc_pci_map_sg_page(pcidev,
5382 ext_sg_page_phys_addr_place,
5383 prev_page->page,
5384 &prev_page->busaddr,
5385 &prev_page->maplen,
5386 PairCount);
5388 // Allocate the TL Extended S/G list page. We have
5389 // to allocate twice what we want to ensure required TL alignment
5390 // (Tachlite TL/TS User Man. Rev 6.0, p 168)
5391 // We store the original allocated PVOID so we can free later
5392 *sgpage = kmalloc( sizeof(SGPAGES), GFP_ATOMIC);
5393 if ( ! *sgpage )
5395 printk("cpqfc: Allocation failed @ %d S/G page allocations\n",
5396 AllocatedPages);
5397 total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
5399 // unmap the previous mappings, if any.
5401 cpqfc_undo_SEST_mappings(pcidev, contigaddr,
5402 Cmnd->request_bufflen,
5403 Cmnd->sc_data_direction,
5404 sgl, Cmnd->use_sg, sgPages_head, AllocatedPages+1);
5406 // FIXME: testing shows that if we get here,
5407 // it's bad news. (this has been this way for a long
5408 // time though, AFAIK. Not that that excuses it.)
5410 return 0; // give up (and probably hang the system)
5412 // clear out memory we just allocated
5413 memset( (*sgpage)->page,0,TL_EXT_SG_PAGE_BYTELEN*2);
5414 (*sgpage)->next = NULL;
5415 (*sgpage)->busaddr = (dma_addr_t) NULL;
5416 (*sgpage)->maplen = 0L;
5418 // align the memory - TL requires sizeof() Ext. S/G page alignment.
5419 // We doubled the actual required size so we could mask off LSBs
5420 // to get desired offset
5422 ulBuff = (unsigned long) (*sgpage)->page;
5423 ulBuff += TL_EXT_SG_PAGE_BYTELEN;
5424 ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
5426 // set pointer, in SEST if first Ext. S/G page, or in last pair
5427 // of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just
5428 // load lower 32 bits)
5429 // NOTE: the Len field must be '0' if this is the first Ext. S/G
5430 // pointer in SEST, and not 0 otherwise (we know thislen != 0).
5432 *alPair = (alPair != SESTalPairStart) ? thislen : 0;
5434 # ifdef DBG_SEST_SGLIST
5435 printk("PairCount %d @%p even %Xh, ",
5436 PairCount, alPair, *alPair);
5437 # endif
5439 // Save the place where we need to store the physical
5440 // address of this scatter gather page which we get when we map it
5441 // (and mapping we can do only after we fill it in.)
5442 alPair++; // next DWORD, will contain phys addr of the ext page
5443 ext_sg_page_phys_addr_place = alPair;
5445 // Now, set alPair = the virtual addr of the (Extended) S/G page
5446 // which will accept the Len/ PhysicalAddress pairs
5447 alPair = (ULONG *) ulBuff;
5449 AllocatedPages++;
5450 if (AllocatedPages >= ap_hi_water)
5452 // This message should rarely, if ever, come out.
5453 // Previously (cpqfc version <= 2.0.5) the driver would
5454 // just puke if more than 4 SG pages were used, and nobody
5455 // ever complained about that. This only comes out if
5456 // more than 8 pages are used.
5458 printk(KERN_WARNING
5459 "cpqfc: Possible danger. %d scatter gather pages used.\n"
5460 "cpqfc: detected seemingly extreme memory "
5461 "fragmentation or huge data transfers.\n",
5462 AllocatedPages);
5463 ap_hi_water = AllocatedPages+1;
5466 PairCount = 1; // starting new Ext. S/G page
5467 prev_page = (*sgpage); // remember this page, for next time thru
5468 sgpage = &((*sgpage)->next);
5469 } // end of new TL Ext. S/G page allocation
5471 *alPair = thislen; // bits 18-0, length (range check above)
5473 # ifdef DBG_SEST_SGLIST
5474 printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
5475 # endif
5477 alPair++; // next DWORD, physical address
5479 if ( WE_HAVE_SG_LIST )
5480 ulBuff = sg_dma_address(sgl) + offset;
5481 else
5482 ulBuff = contigaddr + offset;
5483 offset += thislen;
5485 # if BITS_PER_LONG > 32
5486 if( ulBuff >>32 )
5488 printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void*)ulBuff );
5489 printk("%s = %p, offset = %ld\n",
5490 WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
5491 WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
5492 offset);
5493 return 0;
5495 # endif
5497 *alPair = (ULONG) ulBuff; // lower 32 bits (31-0)
5499 # ifdef DBG_SEST_SGLIST
5500 printk("odd %Xh\n", *alPair);
5501 # endif
5502 alPair++; // next DWORD, next address/length pair
5504 PairCount++; // next Length/Address pair
5506 // if (PairCount > pc_hi_water)
5507 // {
5508 // printk("pc hi = %d ", PairCount);
5509 // pc_hi_water = PairCount;
5510 // }
5511 bytes_to_go -= thislen;
5512 total_data_len += thislen;
5513 thisMappingLen -= thislen;
5514 totalsgs++;
5515 } // while (thisMappingLen > 0)
5516 if ( WE_HAVE_SG_LIST ) sgl++; // next S/G pair
5517 } // while (bytes_to_go)
5519 // printk("Totalsgs=%d\n", totalsgs);
5520 *sgPairs = totalsgs;
5522 // PCI map (and bounce) the last (and usually only) extended SG page
5523 busaddr = cpqfc_pci_map_sg_page(pcidev,
5524 ext_sg_page_phys_addr_place,
5525 prev_page->page,
5526 &prev_page->busaddr,
5527 &prev_page->maplen,
5528 PairCount);
5530 return total_data_len;
5535 // The Tachlite SEST table is referenced to OX_ID (or RX_ID). To optimize
5536 // performance and debuggability, we index the Exchange structure to FC X_ID
5537 // This enables us to build exchanges for later en-queing to Tachyon,
5538 // provided we have an open X_ID slot. At Tachyon queing time, we only
5539 // need an ERQ slot; then "fix-up" references in the
5540 // IRB, FCHS, etc. as needed.
5541 // RETURNS:
5542 // 0 if successful
5543 // non-zero on error
5544 //sstartex
5545 ULONG cpqfcTSStartExchange(
5546 CPQFCHBA *cpqfcHBAdata,
5547 LONG ExchangeID )
5549 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
5550 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5551 FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
5552 USHORT producer, consumer;
5553 ULONG ulStatus=0;
5554 short int ErqIndex;
5555 BOOLEAN CompleteExchange = FALSE; // e.g. ACC replies are complete
5556 BOOLEAN SestType=FALSE;
5557 ULONG InboundData=0;
5559 // We will manipulate Tachlite chip registers here to successfully
5560 // start exchanges.
5562 // Check that link is not down -- we can't start an exchange on a
5563 // down link!
5565 if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
5567 printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n",
5568 fcChip->Registers.FMstatus.value & 0xFF,
5569 ExchangeID,
5570 pExchange->type,
5571 pExchange->fchs.d_id);
5573 if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame?
5575 // Our most popular LinkService commands are port discovery types
5576 // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
5577 // events, so it makes no sense to Que them. However, ABTS should
5578 // be queued, since exchange sequences are likely destroyed by
5579 // Link Down events, and we want to notify other ports of broken
5580 // sequences by aborting the corresponding exchanges.
5581 if( pExchange->type != BLS_ABTS )
5583 ulStatus = LNKDWN_OSLS;
5584 goto Done;
5585 // don't Que most LinkServ exchanges on LINK DOWN
5589 printk("fcStartExchange: Que x_ID %Xh, type %Xh\n",
5590 ExchangeID, pExchange->type);
5591 pExchange->status |= EXCHANGE_QUEUED;
5592 ulStatus = EXCHANGE_QUEUED;
5593 goto Done;
5596 // Make sure ERQ has available space.
5598 producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
5599 consumer = (USHORT)fcChip->ERQ->consumerIndex;
5600 producer++; // We are testing for full que by incrementing
5602 if( producer >= ERQ_LEN ) // rollover condition?
5603 producer = 0;
5604 if( consumer != producer ) // ERQ not full?
5606 // ****************** Need Atomic access to chip registers!!********
5608 // remember ERQ PI for copying IRB
5609 ErqIndex = (USHORT)fcChip->ERQ->producerIndex;
5610 fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
5611 // we have an ERQ slot! If SCSI command, need SEST slot
5612 // otherwise we are done.
5614 // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
5615 // set according to direction of data to/from Tachyon for SEST assists.
5616 // For consistency, enforce this rule for Link Service (non-SEST)
5617 // exchanges as well.
5619 // fix-up the X_ID field in IRB
5620 pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
5622 // fix-up the X_ID field in fchs -- depends on Originator or Responder,
5623 // outgoing or incoming data?
5624 switch( pExchange->type )
5626 // ORIGINATOR types... we're setting our OX_ID and
5627 // defaulting the responder's RX_ID to 0xFFFF
5629 case SCSI_IRE:
5630 // Requirement: set MSB of x_ID for Incoming TL data
5631 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5632 InboundData = 0x8000;
5634 case SCSI_IWE:
5635 SestType = TRUE;
5636 pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
5637 pExchange->fchs.ox_rx_id <<= 16; // MSW shift
5638 pExchange->fchs.ox_rx_id |= 0xffff; // add default RX_ID
5640 // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
5641 // (not necessary for IRE -- data buffer unused)
5642 if( pExchange->type == SCSI_IWE)
5644 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id =
5645 pExchange->fchs.ox_rx_id;
5649 break;
5652 case FCS_NSR: // ext. link service Name Service Request
5653 case ELS_SCR: // ext. link service State Change Registration
5654 case ELS_FDISC:// ext. link service login
5655 case ELS_FLOGI:// ext. link service login
5656 case ELS_LOGO: // FC-PH extended link service logout
5657 case BLS_NOP: // Basic link service No OPeration
5658 case ELS_PLOGI:// ext. link service login (PLOGI)
5659 case ELS_PDISC:// ext. link service login (PDISC)
5660 case ELS_PRLI: // ext. link service process login
5662 pExchange->fchs.ox_rx_id = ExchangeID;
5663 pExchange->fchs.ox_rx_id <<= 16; // MSW shift
5664 pExchange->fchs.ox_rx_id |= 0xffff; // and RX_ID
5666 break;
5671 // RESPONDER types... we must set our RX_ID while preserving
5672 // sender's OX_ID
5673 // outgoing (or no) data
5674 case ELS_RJT: // extended link service reject
5675 case ELS_LOGO_ACC: // FC-PH extended link service logout accept
5676 case ELS_ACC: // ext. generic link service accept
5677 case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
5678 case ELS_PRLI_ACC: // ext. link service process login accept
5680 CompleteExchange = TRUE; // Reply (ACC or RJT) is end of exchange
5681 pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
5683 break;
5686 // since we are a Responder, OX_ID should already be set by
5687 // cpqfcTSBuildExchange(). We need to -OR- in RX_ID
5688 case SCSI_TWE:
5689 SestType = TRUE;
5690 // Requirement: set MSB of x_ID for Incoming TL data
5691 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5693 pExchange->fchs.ox_rx_id &= 0xFFFF0000; // clear RX_ID
5694 // Requirement: set MSB of RX_ID for Incoming TL data
5695 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5696 pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
5697 break;
5700 case SCSI_TRE:
5701 SestType = TRUE;
5703 // there is no XRDY for SEST target read; the data
5704 // header needs to be updated. Also update the RSP
5705 // exchange IDs for the status frame, in case it is sent automatically
5706 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
5707 fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id =
5708 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5710 // for easier FCP response logic (works for TWE and TRE),
5711 // copy exchange IDs. (Not needed if TRE 'RSP' bit set)
5712 pExchange->fchs.ox_rx_id =
5713 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5715 break;
5718 case FCP_RESPONSE: // using existing OX_ID/ RX_ID pair,
5719 // start SFS FCP-RESPONSE frame
5720 // OX/RX_ID should already be set! (See "fcBuild" above)
5721 CompleteExchange = TRUE; // RSP is end of FCP-SCSI exchange
5724 break;
5727 case BLS_ABTS_RJT: // uses new RX_ID, since SEST x_ID non-existent
5728 case BLS_ABTS_ACC: // using existing OX_ID/ RX_ID pair from SEST entry
5729 CompleteExchange = TRUE; // ACC or RJT marks end of FCP-SCSI exchange
5730 case BLS_ABTS: // using existing OX_ID/ RX_ID pair from SEST entry
5733 break;
5736 default:
5737 printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
5738 pExchange->type, pExchange->type);
5739 return INVALID_ARGS;
5743 // X_ID fields are entered -- copy IRB to Tachyon's ERQ
5746 memcpy(
5747 &fcChip->ERQ->QEntry[ ErqIndex ], // dest.
5748 &pExchange->IRB,
5749 32); // fixed (hardware) length!
5751 PCI_TRACEO( ExchangeID, 0xA0)
5753 // ACTION! May generate INT and IMQ entry
5754 writel( fcChip->ERQ->producerIndex,
5755 fcChip->Registers.ERQproducerIndex.address);
5758 if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame?
5761 // wait for completion! (TDB -- timeout and chip reset)
5764 PCI_TRACEO( ExchangeID, 0xA4)
5766 enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
5768 down_interruptible( cpqfcHBAdata->TYOBcomplete);
5770 disable_irq( cpqfcHBAdata->HostAdapter->irq);
5771 PCI_TRACE( 0xA4)
5773 // On login exchanges, BAD_ALPA (non-existent port_id) results in
5774 // FTO (Frame Time Out) on the Outbound Completion message.
5775 // If we got an FTO status, complete the exchange (free up slot)
5776 if( CompleteExchange || // flag from Reply frames
5777 pExchange->status ) // typically, can get FRAME_TO
5779 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
5783 else // SEST Exchange
5785 ulStatus = 0; // ship & pray success (e.g. FCP-SCSI)
5787 if( CompleteExchange ) // by Type of exchange (e.g. end-of-xchng)
5789 cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
5792 else
5793 pExchange->status &= ~EXCHANGE_QUEUED; // clear ExchangeQueued flag
5799 else // ERQ 'producer' = 'consumer' and QUE is full
5801 ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
5804 Done:
5805 PCI_TRACE( 0xA0)
5806 return ulStatus;
5813 // Scan fcController->fcExchanges array for a usuable index (a "free"
5814 // exchange).
5815 // Inputs:
5816 // fcChip - pointer to TachLite chip structure
5817 // Return:
5818 // index - exchange array element where exchange can be built
5819 // -1 - exchange array is full
5820 // REMARKS:
5821 // Although this is a (yuk!) linear search, we presume
5822 // that the system will complete exchanges about as quickly as
5823 // they are submitted. A full Exchange array (and hence, max linear
5824 // search time for free exchange slot) almost guarantees a Fibre problem
5825 // of some sort.
5826 // In the interest of making exchanges easier to debug, we want a LRU
5827 // (Least Recently Used) scheme.
5830 static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
5832 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5833 ULONG i;
5834 ULONG ulStatus=-1; // assume failure
5837 if( type == SCSI_IRE ||
5838 type == SCSI_TRE ||
5839 type == SCSI_IWE ||
5840 type == SCSI_TWE)
5842 // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
5843 if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
5844 fcChip->fcSestExchangeLRU = 0;
5845 i = fcChip->fcSestExchangeLRU; // typically it's already free!
5847 if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5849 ulStatus = 0; // success!
5852 else
5853 { // YUK! we need to do a linear search for free element.
5854 // Fragmentation of the fcExchange array is due to excessively
5855 // long completions or timeouts.
5857 while( TRUE )
5859 if( ++i >= TACH_SEST_LEN ) // rollover check
5860 i = 0; // beginning of SEST X_IDs
5862 // printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n",
5863 // i, Exchanges->fcExchange[i].type);
5865 if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5867 ulStatus = 0; // success!
5868 break;
5870 if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
5872 printk( "SEST X_ID space full\n");
5873 break; // failed - prevent inf. loop
5877 fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
5882 else // Link Service type - X_IDs should be from TACH_SEST_LEN
5883 // to TACH_MAX_XID
5885 if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
5886 fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
5887 fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
5889 i = fcChip->fcLsExchangeLRU; // typically it's already free!
5890 if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5892 ulStatus = 0; // success!
5895 else
5896 { // YUK! we need to do a linear search for free element
5897 // Fragmentation of the fcExchange array is due to excessively
5898 // long completions or timeouts.
5900 while( TRUE )
5902 if( ++i >= TACH_MAX_XID ) // rollover check
5903 i = TACH_SEST_LEN;// beginning of Link Service X_IDs
5905 // printk( "looping for xchng ID: i=%d, type=%Xh\n",
5906 // i, Exchanges->fcExchange[i].type);
5908 if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5910 ulStatus = 0; // success!
5911 break;
5913 if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
5915 printk( "LinkService X_ID space full\n");
5916 break; // failed - prevent inf. loop
5920 fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
5924 if( !ulStatus ) // success?
5925 Exchanges->fcExchange[i].type = type; // allocate it.
5927 else
5928 i = -1; // error - all exchanges "open"
5930 return i;
5933 static void
5934 cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev,
5935 PTACHYON fcChip,
5936 ULONG x_ID)
5938 // Unmaps the memory regions used to hold the scatter gather lists
5940 PSGPAGES i;
5942 // Were there any such regions needing unmapping?
5943 if (! USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
5944 return; // No such regions, we're outta here.
5946 // for each extended scatter gather region needing unmapping...
5947 for (i=fcChip->SEST->sgPages[x_ID] ; i != NULL ; i = i->next)
5948 pci_unmap_single(pcidev, i->busaddr, i->maplen,
5949 PCI_DMA_TODEVICE);
5952 // Called also from cpqfcTScontrol.o, so can't be static
5953 void
5954 cpqfc_pci_unmap(struct pci_dev *pcidev,
5955 Scsi_Cmnd *cmd,
5956 PTACHYON fcChip,
5957 ULONG x_ID)
5959 // Undo the DMA mappings
5960 if (cmd->use_sg) { // Used scatter gather list for data buffer?
5961 cpqfc_pci_unmap_extended_sg(pcidev, fcChip, x_ID);
5962 pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg,
5963 cmd->sc_data_direction);
5964 // printk("umsg %d\n", cmd->use_sg);
5966 else if (cmd->request_bufflen) {
5967 // printk("ums %p ", fcChip->SEST->u[ x_ID ].IWE.GAddr1);
5968 pci_unmap_single(pcidev, fcChip->SEST->u[ x_ID ].IWE.GAddr1,
5969 cmd->request_bufflen,
5970 cmd->sc_data_direction);
5974 // We call this routine to free an Exchange for any reason:
5975 // completed successfully, completed with error, aborted, etc.
5977 // returns FALSE if Exchange failed and "retry" is acceptable
5978 // returns TRUE if Exchange was successful, or retry is impossible
5979 // (e.g. port/device gone).
5980 //scompleteexchange
5982 void cpqfcTSCompleteExchange(
5983 struct pci_dev *pcidev,
5984 PTACHYON fcChip,
5985 ULONG x_ID)
5987 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5988 int already_unmapped = 0;
5990 if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
5992 if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
5994 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
5995 printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
5996 Exchanges->fcExchange[ x_ID ].type);
5998 goto CleanUpSestResources; // this path should be very rare.
6001 // we have Linux Scsi Cmnd ptr..., now check our Exchange status
6002 // to decide how to complete this SEST FCP exchange
6004 if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
6005 // or abnormal exchange completion
6007 // set FCP Link statistics
6009 if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
6010 fcChip->fcStats.timeouts++;
6011 if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
6012 fcChip->fcStats.FC4aborted++;
6013 if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
6014 fcChip->fcStats.CntErrors++;
6015 if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
6016 fcChip->fcStats.linkFailTX++;
6017 if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
6018 fcChip->fcStats.linkFailRX++;
6019 if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
6020 fcChip->fcStats.CntErrors++;
6022 // First, see if the Scsi upper level initiated an ABORT on this
6023 // exchange...
6024 if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
6026 printk(" DID_ABORT, x_ID %Xh, Cmnd %p ",
6027 x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
6028 goto CleanUpSestResources; // (we don't expect Linux _aborts)
6031 // Did our driver timeout the Exchange, or did Tachyon indicate
6032 // a failure during transmission? Ask for retry with "SOFT_ERROR"
6033 else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
6035 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
6036 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
6037 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
6040 // Did frame(s) for an open exchange arrive in the SFQ,
6041 // meaning the SEST was unable to process them?
6042 else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME)
6044 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
6045 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
6046 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
6049 // Did our driver timeout the Exchange, or did Tachyon indicate
6050 // a failure during transmission? Ask for retry with "SOFT_ERROR"
6051 else if(
6052 (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
6053 (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) ||
6054 (Exchanges->fcExchange[ x_ID ].status & FRAME_TO) ||
6055 (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY) ||
6056 (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY) )
6060 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
6061 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
6062 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
6067 // e.g., a LOGOut happened, or device never logged back in.
6068 else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED)
6070 // printk(" *LOGOut or timeout on login!* ");
6071 // trigger?
6072 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
6074 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
6078 // Did Tachyon indicate a CNT error? We need further analysis
6079 // to determine if the exchange is acceptable
6080 else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
6082 UCHAR ScsiStatus;
6083 FCP_STATUS_RESPONSE *pFcpStatus =
6084 (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
6086 ScsiStatus = pFcpStatus->fcp_status >>24;
6088 // If the command is a SCSI Read/Write type, we don't tolerate
6089 // count errors of any kind; assume the count error is due to
6090 // a dropped frame and ask for retry...
6092 if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) ||
6093 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) ||
6094 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) ||
6095 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) )
6097 ScsiStatus == 0 )
6099 // ask for retry
6100 /* printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n",
6101 x_ID, Exchanges->fcExchange[ x_ID ].status,
6102 Exchanges->fcExchange[ x_ID ].Cmnd);*/
6103 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
6106 else // need more analysis
6108 cpqfcTSCheckandSnoopFCP(fcChip, x_ID); // (will set ->result)
6112 // default: NOTE! We don't ever want to get here. Getting here
6113 // implies something new is happening that we've never had a test
6114 // case for. Need code maintenance! Return "ERROR"
6115 else
6117 unsigned int stat = Exchanges->fcExchange[ x_ID ].status;
6118 printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p",
6119 Exchanges->fcExchange[ x_ID ].status, x_ID,
6120 Exchanges->fcExchange[ x_ID ].Cmnd);
6122 if (stat & INVALID_ARGS) printk(" INVALID_ARGS ");
6123 if (stat & LNKDWN_OSLS) printk(" LNKDWN_OSLS ");
6124 if (stat & LNKDWN_LASER) printk(" LNKDWN_LASER ");
6125 if (stat & OUTQUE_FULL) printk(" OUTQUE_FULL ");
6126 if (stat & DRIVERQ_FULL) printk(" DRIVERQ_FULL ");
6127 if (stat & SEST_FULL) printk(" SEST_FULL ");
6128 if (stat & BAD_ALPA) printk(" BAD_ALPA ");
6129 if (stat & OVERFLOW) printk(" OVERFLOW ");
6130 if (stat & COUNT_ERROR) printk(" COUNT_ERROR ");
6131 if (stat & LINKFAIL_RX) printk(" LINKFAIL_RX ");
6132 if (stat & ABORTSEQ_NOTIFY) printk(" ABORTSEQ_NOTIFY ");
6133 if (stat & LINKFAIL_TX) printk(" LINKFAIL_TX ");
6134 if (stat & HOSTPROG_ERR) printk(" HOSTPROG_ERR ");
6135 if (stat & FRAME_TO) printk(" FRAME_TO ");
6136 if (stat & INV_ENTRY) printk(" INV_ENTRY ");
6137 if (stat & SESTPROG_ERR) printk(" SESTPROG_ERR ");
6138 if (stat & OUTBOUND_TIMEOUT) printk(" OUTBOUND_TIMEOUT ");
6139 if (stat & INITIATOR_ABORT) printk(" INITIATOR_ABORT ");
6140 if (stat & MEMPOOL_FAIL) printk(" MEMPOOL_FAIL ");
6141 if (stat & FC2_TIMEOUT) printk(" FC2_TIMEOUT ");
6142 if (stat & TARGET_ABORT) printk(" TARGET_ABORT ");
6143 if (stat & EXCHANGE_QUEUED) printk(" EXCHANGE_QUEUED ");
6144 if (stat & PORTID_CHANGED) printk(" PORTID_CHANGED ");
6145 if (stat & DEVICE_REMOVED) printk(" DEVICE_REMOVED ");
6146 if (stat & SFQ_FRAME) printk(" SFQ_FRAME ");
6147 printk("\n");
6149 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
6152 else // definitely no Tach problem, but perhaps an FCP problem
6154 // set FCP Link statistic
6155 fcChip->fcStats.ok++;
6156 cpqfcTSCheckandSnoopFCP( fcChip, x_ID); // (will set ->result)
6159 cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd,
6160 fcChip, x_ID); // undo DMA mappings.
6161 already_unmapped = 1;
6163 // OK, we've set the Scsi "->result" field, so proceed with calling
6164 // Linux Scsi "done" (if not NULL), and free any kernel memory we
6165 // may have allocated for the exchange.
6167 PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
6168 // complete the command back to upper Scsi drivers
6169 if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
6171 // Calling "done" on an Linux _abort() aborted
6172 // Cmnd causes a kernel panic trying to re-free mem.
6173 // Actually, we shouldn't do anything with an _abort CMND
6174 if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
6176 PCI_TRACE(0xAC)
6177 call_scsi_done(Exchanges->fcExchange[ x_ID ].Cmnd);
6179 else
6181 // printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
6182 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
6185 else{
6186 printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
6187 Exchanges->fcExchange[ x_ID ].type,
6188 Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);
6189 printk(" cpqfcTS: Null scsi_done function pointer!\n");
6193 // Now, clean up non-Scsi_Cmnd items...
6194 CleanUpSestResources:
6196 if (!already_unmapped)
6197 cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd,
6198 fcChip, x_ID); // undo DMA mappings.
6200 // Was an Extended Scatter/Gather page allocated? We know
6201 // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
6202 if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
6204 PSGPAGES p, next;
6206 // extended S/G list was used -- Free the allocated ext. S/G pages
6207 for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
6208 next = p->next;
6209 kfree(p);
6211 fcChip->SEST->sgPages[x_ID] = NULL;
6214 Exchanges->fcExchange[ x_ID ].Cmnd = NULL;
6215 } // Done with FCP (SEST) exchanges
6218 // the remaining logic is common to ALL Exchanges:
6219 // FCP(SEST) and LinkServ.
6221 Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!
6222 Exchanges->fcExchange[ x_ID ].status = 0;
6224 PCI_TRACEO( x_ID, 0xAC)
6227 return;
6228 } // (END of CompleteExchange function)
6233 // Unfortunately, we must snoop all command completions in
6234 // order to manipulate certain return fields, and take note of
6235 // device types, etc., to facilitate the Fibre-Channel to SCSI
6236 // "mapping".
6237 // (Watch for BIG Endian confusion on some payload fields)
6238 void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
6240 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
6241 Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
6242 FCP_STATUS_RESPONSE *pFcpStatus =
6243 (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
6244 UCHAR ScsiStatus;
6246 ScsiStatus = pFcpStatus->fcp_status >>24;
6248 #ifdef FCP_COMPLETION_DBG
6249 printk("ScsiStatus = 0x%X\n", ScsiStatus);
6250 #endif
6252 // First, check FCP status
6253 if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
6255 // check response code (RSP_CODE) -- most popular is bad len
6256 // 1st 4 bytes of rsp info -- only byte 3 interesting
6257 if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
6260 // do we EVER get here?
6261 printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
6265 // for now, go by the ScsiStatus, and manipulate certain
6266 // commands when necessary...
6267 if( ScsiStatus == 0) // SCSI status byte "good"?
6269 Cmnd->result = 0; // everything's OK
6271 if( (Cmnd->cmnd[0] == INQUIRY))
6273 UCHAR *InquiryData = Cmnd->request_buffer;
6274 PFC_LOGGEDIN_PORT pLoggedInPort;
6276 // We need to manipulate INQUIRY
6277 // strings for COMPAQ RAID controllers to force
6278 // Linux to scan additional LUNs. Namely, set
6279 // the Inquiry string byte 2 (ANSI-approved version)
6280 // to 2.
6282 if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
6284 InquiryData[2] = 0x2; // claim SCSI-2 compliance,
6285 // so multiple LUNs may be scanned.
6286 // (no SCSI-2 problems known in CPQ)
6289 // snoop the Inquiry to detect Disk, Tape, etc. type
6290 // (search linked list for the port_id we sent INQUIRY to)
6291 pLoggedInPort = fcFindLoggedInPort( fcChip,
6292 NULL, // DON'T search Scsi Nexus (we will set it)
6293 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,
6294 NULL, // DON'T search linked list for FC WWN
6295 NULL); // DON'T care about end of list
6297 if( pLoggedInPort )
6299 pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
6301 else
6303 printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
6304 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
6310 // Scsi Status not good -- pass it back to caller
6312 else
6314 Cmnd->result = ScsiStatus; // SCSI status byte is 1st
6316 // check for valid "sense" data
6318 if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID )
6319 { // limit Scsi Sense field length!
6320 int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
6322 SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ?
6323 sizeof( Cmnd->sense_buffer) : SenseLen;
6326 #ifdef FCP_COMPLETION_DBG
6327 printk("copy sense_buffer %p, len %d, result %Xh\n",
6328 Cmnd->sense_buffer, SenseLen, Cmnd->result);
6329 #endif
6331 // NOTE: There is some dispute over the FCP response
6332 // format. Most FC devices assume that FCP_RSP_INFO
6333 // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
6334 // is (virtually) always 0 and the field is "invalid".
6335 // Some other devices assume that
6336 // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
6337 // when the FCP_RSP is invalid (this almost appears to be
6338 // one of those "religious" issues).
6339 // Consequently, we test the usual position of FCP_SNS_INFO
6340 // for 7Xh, since the SCSI sense format says the first
6341 // byte ("error code") should be 0x70 or 0x71. In practice,
6342 // we find that every device does in fact have 0x70 or 0x71
6343 // in the first byte position, so this test works for all
6344 // FC devices.
6345 // (This logic is especially effective for the CPQ/DEC HSG80
6346 // & HSG60 controllers).
6348 if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
6349 memcpy( Cmnd->sense_buffer,
6350 &pFcpStatus->fcp_sns_info[0], SenseLen);
6351 else
6353 unsigned char *sbPtr =
6354 (unsigned char *)&pFcpStatus->fcp_sns_info[0];
6355 sbPtr -= 8; // back up 8 bytes hoping to find the
6356 // start of the sense buffer
6357 memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
6360 // in the special case of Device Reset, tell upper layer
6361 // to immediately retry (with SOFT_ERROR status)
6362 // look for Sense Key Unit Attention (0x6) with ASC Device
6363 // Reset (0x29)
6364 // printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
6365 // SenseLen, Cmnd->sense_buffer[2],
6366 // Cmnd->sense_buffer[12]);
6367 if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
6368 (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
6370 Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
6373 // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
6374 else if( ((Cmnd->sense_buffer[2] & 0xF) == 0x4) && // "hardware error"
6375 (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code
6377 // printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
6378 // Cmnd->channel, Cmnd->target, Cmnd->lun);
6379 Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
6382 } // (end of sense len valid)
6384 // there is no sense data to help out Linux's Scsi layers...
6385 // We'll just return the Scsi status and hope he will "do the
6386 // right thing"
6387 else
6389 // as far as we know, the Scsi status is sufficient
6390 Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
6397 //PPPPPPPPPPPPPPPPPPPPPPPPP PAYLOAD PPPPPPPPP
6398 // build data PAYLOAD; SCSI FCP_CMND I.U.
6399 // remember BIG ENDIAN payload - DWord values must be byte-reversed
6400 // (hence the affinity for byte pointer building).
6402 static int build_FCP_payload( Scsi_Cmnd *Cmnd,
6403 UCHAR* payload, ULONG type, ULONG fcp_dl )
6405 int i;
6408 switch( type)
6411 case SCSI_IWE:
6412 case SCSI_IRE:
6413 // 8 bytes FCP_LUN
6414 // Peripheral Device or Volume Set addressing, and LUN mapping
6415 // When the FC port was looked up, we copied address mode
6416 // and any LUN mask to the scratch pad SCp.phase & .mode
6418 *payload++ = (UCHAR)Cmnd->SCp.phase;
6420 // Now, because of "lun masking"
6421 // (aka selective storage presentation),
6422 // the contiguous Linux Scsi lun number may not match the
6423 // device's lun number, so we may have to "map".
6425 *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
6427 // We don't know of anyone in the FC business using these
6428 // extra "levels" of addressing. In fact, confusion still exists
6429 // just using the FIRST level... ;-)
6431 *payload++ = 0; // 2nd level addressing
6432 *payload++ = 0;
6433 *payload++ = 0; // 3rd level addressing
6434 *payload++ = 0;
6435 *payload++ = 0; // 4th level addressing
6436 *payload++ = 0;
6438 // 4 bytes Control Field FCP_CNTL
6439 *payload++ = 0; // byte 0: (MSB) reserved
6440 *payload++ = 0; // byte 1: task codes
6442 // byte 2: task management flags
6443 // another "use" of the spare field to accomplish TDR
6444 // note combination needed
6445 if( (Cmnd->cmnd[0] == RELEASE) &&
6446 (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
6448 Cmnd->cmnd[0] = 0; // issue "Test Unit Ready" for TDR
6449 *payload++ = 0x20; // target device reset bit
6451 else
6452 *payload++ = 0; // no TDR
6453 // byte 3: (LSB) execution management codes
6454 // bit 0 write, bit 1 read (don't set together)
6456 if( fcp_dl != 0 )
6458 if( type == SCSI_IWE ) // WRITE
6459 *payload++ = 1;
6460 else // READ
6461 *payload++ = 2;
6463 else
6465 // On some devices, if RD or WR bits are set,
6466 // and fcp_dl is 0, they will generate an error on the command.
6467 // (i.e., if direction is specified, they insist on a length).
6468 *payload++ = 0; // no data (necessary for CPQ)
6472 // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
6473 // FCP_CDB allows 16 byte SCSI command descriptor blk;
6474 // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
6475 for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
6476 *payload++ = Cmnd->cmnd[i];
6478 // if( Cmnd->cmd_len == 16 )
6479 // {
6480 // memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
6481 // }
6482 payload+= (16 - i);
6484 // FCP_DL is largest number of expected data bytes
6485 // per CDB (i.e. read/write command)
6486 *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL
6487 *payload++ = (UCHAR)(fcp_dl >>16);
6488 *payload++ = (UCHAR)(fcp_dl >>8);
6489 *payload++ = (UCHAR)fcp_dl; // (LSB)
6490 break;
6492 case SCSI_TWE: // need FCP_XFER_RDY
6493 *payload++ = 0; // (4 bytes) DATA_RO (MSB byte 0)
6494 *payload++ = 0;
6495 *payload++ = 0;
6496 *payload++ = 0; // LSB (byte 3)
6497 // (4 bytes) BURST_LEN
6498 // size of following FCP_DATA payload
6499 *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL
6500 *payload++ = (UCHAR)(fcp_dl >>16);
6501 *payload++ = (UCHAR)(fcp_dl >>8);
6502 *payload++ = (UCHAR)fcp_dl; // (LSB)
6503 // 4 bytes RESERVED
6504 *payload++ = 0;
6505 *payload++ = 0;
6506 *payload++ = 0;
6507 *payload++ = 0;
6508 break;
6510 default:
6511 break;
6514 return 0;