1 /* Copyright(c) 2000, Compaq Computer Corporation
2 * Fibre Channel Host Bus Adapter
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
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/blk.h>
30 #include <linux/interrupt.h>
31 #include <linux/delay.h>
32 #include <linux/smp_lock.h>
34 #define __KERNEL_SYSCALLS__
36 #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
38 #include <linux/unistd.h>
40 #include <asm/system.h>
47 #include "hosts.h" // struct Scsi_Host definition for T handler
48 #include "cpqfcTSchip.h"
49 #include "cpqfcTSstructs.h"
50 #include "cpqfcTStrigger.h"
51 static const __u8 valid_al_pa[];
56 // Since Tachyon chips may be permitted to wait from 500ms up to 2 sec
57 // to empty an outgoing frame from its FIFO to the Fibre Channel stream,
58 // we cannot do everything we need to in the interrupt handler. Specifically,
59 // every time a link re-init (e.g. LIP) takes place, all SCSI I/O has to be
60 // suspended until the login sequences have been completed. Login commands
61 // are frames just like SCSI commands are frames; they are subject to the same
62 // timeout issues and delays. Also, various specs provide up to 2 seconds for
63 // devices to log back in (i.e. respond with ACC to a login frame), so I/O to
64 // that device has to be suspended.
65 // A serious problem here occurs on highly loaded FC-AL systems. If our FC port
66 // has a low priority (e.g. high arbitrated loop physical address, alpa), and
67 // some other device is hogging bandwidth (permissible under FC-AL), we might
68 // time out thinking the link is hung, when it's simply busy. Many such
69 // considerations complicate the design. Although Tachyon assumes control
70 // (in silicon) for many link-specific issues, the Linux driver is left with the
71 // rest, which turns out to be a difficult, time critical chore.
73 // These "worker" functions will handle things like FC Logins; all
74 // processes with I/O to our device must wait for the Login to complete
75 // and (if successful) I/O to resume. In the event of a malfunctioning or
76 // very busy loop, it may take hundreds of millisecs or even seconds to complete
77 // a frame send. We don't want to hang up the entire server (and all
78 // processes which don't depend on Fibre) during this wait.
80 // The Tachyon chip can have around 30,000 I/O operations ("exchanges")
81 // open at one time. However, each exchange must be initiated
82 // synchronously (i.e. each of the 30k I/O had to be started one at a
83 // time by sending a starting frame via Tachyon's outbound que).
85 // To accomodate kernel "module" build, this driver limits the exchanges
86 // to 256, because of the contiguous physical memory limitation of 128M.
88 // Typical FC Exchanges are opened presuming the FC frames start without errors,
89 // while Exchange completion is handled in the interrupt handler. This
90 // optimizes performance for the "everything's working" case.
91 // However, when we have FC related errors or hot plugging of FC ports, we pause
92 // I/O and handle FC-specific tasks in the worker thread. These FC-specific
93 // functions will handle things like FC Logins and Aborts. As the Login sequence
94 // completes to each and every target, I/O can resume to that target.
96 // Our kernel "worker thread" must share the HBA with threads calling
97 // "queuecommand". We define a "BoardLock" semaphore which indicates
98 // to "queuecommand" that the HBA is unavailable, and Cmnds are added to a
99 // board lock Q. When the worker thread finishes with the board, the board
100 // lock Q commands are completed with status causing immediate retry.
101 // Typically, the board is locked while Logins are in progress after an
102 // FC Link Down condition. When Cmnds are re-queued after board lock, the
103 // particular Scsi channel/target may or may not have logged back in. When
104 // the device is waiting for login, the "prli" flag is clear, in which case
105 // commands are passed to a Link Down Q. Whenever the login finally completes,
106 // the LinkDown Q is completed, again with status causing immediate retry.
107 // When FC devices are logged in, we build and start FC commands to the
110 // NOTE!! As of May 2000, kernel 2.2.14, the error recovery logic for devices
111 // that never log back in (e.g. physically removed) is NOT completely
112 // understood. I've still seen instances of system hangs on failed Write
113 // commands (possibly from the ext2 layer?) on device removal. Such special
114 // cases need to be evaluated from a system/application view - e.g., how
115 // exactly does the system want me to complete commands when the device is
116 // physically removed??
120 static void SetLoginFields(PFC_LOGGEDIN_PORT pLoggedInPort, TachFCHDR_GCMND * fchs, u8 PDisc, u8 Originator);
122 static void AnalyzeIncomingFrame(CPQFCHBA * dev, u32 QNdx);
124 static void SendLogins(CPQFCHBA * dev, __u32 * FabricPortIds);
126 static int verify_PLOGI(PTACHYON fcChip, TachFCHDR_GCMND * fchs, u32 * reject_explain);
127 static int verify_PRLI(TachFCHDR_GCMND * fchs, u32 * reject_explain);
129 static void LoadWWN(PTACHYON fcChip, u8 * dest, u8 type);
130 static void BuildLinkServicePayload(PTACHYON fcChip, u32 type, void *payload);
132 static void UnblockScsiDevice(struct Scsi_Host *HostAdapter, PFC_LOGGEDIN_PORT pLoggedInPort);
134 static void cpqfcTSCheckandSnoopFCP(PTACHYON fcChip, u32 x_ID);
136 static void CompleteBoardLockCmnd(CPQFCHBA * dev);
138 static void RevalidateSEST(struct Scsi_Host *HostAdapter, PFC_LOGGEDIN_PORT pLoggedInPort);
140 static void IssueReportLunsCommand(CPQFCHBA * dev, TachFCHDR_GCMND * fchs);
142 // (see scsi_error.c comments on kernel task creation)
144 void cpqfcTSWorkerThread(void *host)
146 struct Scsi_Host *shpnt = (struct Scsi_Host *) host;
147 CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
148 #ifdef PCI_KERNEL_TRACE
149 PTACHYON fcChip = &dev->fcChip;
151 struct fs_struct *fs;
152 DECLARE_MUTEX_LOCKED(fcQueReady);
153 DECLARE_MUTEX_LOCKED(fcTYOBcomplete);
154 DECLARE_MUTEX_LOCKED(TachFrozen);
155 DECLARE_MUTEX_LOCKED(BoardLock);
157 ENTER("WorkerThread");
161 * If we were started as result of loading a module, close all of the
162 * user space pages. We don't need them, and if we didn't close them
163 * they would be locked into memory.
165 * FIXME: should use daemonize!
169 current->session = 1;
172 /* Become as one with the init task */
174 exit_fs(current); /* current->fs->count--; */
177 atomic_inc(&fs->count);
179 siginitsetinv(¤t->blocked, SHUTDOWN_SIGS);
183 * Set the name of this process.
185 sprintf(current->comm, "cpqfcTS_wt_%d", shpnt->host_no);
187 dev->fcQueReady = &fcQueReady; // primary wait point
188 dev->TYOBcomplete = &fcTYOBcomplete;
189 dev->TachFrozen = &TachFrozen;
192 dev->worker_thread = current;
196 if (dev->notify_wt != NULL)
197 up(dev->notify_wt); // OK to continue
202 down_interruptible(&fcQueReady); // wait for something to do
204 if (signal_pending(current))
208 // first, take the IO lock so the SCSI upper layers can't call
209 // into our _quecommand function (this also disables INTs)
210 spin_lock_irqsave(&io_request_lock, flags); // STOP _que function
213 CPQ_SPINLOCK_HBA(dev)
214 // next, set this pointer to indicate to the _quecommand function
215 // that the board is in use, so it should que the command and
216 // immediately return (we don't actually require the semaphore function
217 // in this driver rev)
218 dev->BoardLock = &BoardLock;
221 // release the IO lock (and re-enable interrupts)
222 spin_unlock_irqrestore(&io_request_lock, flags);
224 // disable OUR HBA interrupt (keep them off as much as possible
225 // during error recovery)
226 disable_irq(dev->HostAdapter->irq);
228 // OK, let's process the Fibre Channel Link Q and do the work
229 cpqfcTS_WorkTask(shpnt);
231 // hopefully, no more "work" to do;
232 // re-enable our INTs for "normal" completion processing
233 enable_irq(dev->HostAdapter->irq);
236 dev->BoardLock = NULL; // allow commands to be queued
237 CPQ_SPINUNLOCK_HBA(dev)
239 // Now, complete any Cmnd we Q'd up while BoardLock was held
240 CompleteBoardLockCmnd(dev);
244 // hopefully, the signal was for our module exit...
245 if (dev->notify_wt != NULL)
246 up(dev->notify_wt); // yep, we're outta here
250 // Freeze Tachyon routine.
251 // If Tachyon is already frozen, return 0
252 // If Tachyon is not frozen, call freeze function, return 1
254 static u8 FreezeTach(CPQFCHBA * dev)
256 PTACHYON fcChip = &dev->fcChip;
258 // It's possible that the chip is already frozen; if so,
259 // "Freezing" again will NOT! generate another Freeze
260 // Completion Message.
262 if ((fcChip->Registers.TYstatus.value & 0x70000) != 0x70000) { // (need to freeze...)
263 fcChip->FreezeTachyon(fcChip, 2); // both ERQ and FCP assists
264 // 2. Get Tach freeze confirmation
265 // (synchronize SEST manipulation with Freeze Completion Message)
266 // we need INTs on so semaphore can be set.
267 enable_irq(dev->HostAdapter->irq); // only way to get Semaphore
268 down_interruptible(dev->TachFrozen); // wait for INT handler sem.
269 // can we TIMEOUT semaphore wait?? TBD
270 disable_irq(dev->HostAdapter->irq);
272 } // (else, already frozen)
276 // This is the kernel worker thread task, which processes FC
277 // tasks which were queued by the Interrupt handler or by
278 // other WorkTask functions.
283 void cpqfcTS_WorkTask(struct Scsi_Host *shpnt)
285 CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
286 PTACHYON fcChip = &dev->fcChip;
287 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
291 TachFCHDR_GCMND fchs;
292 PFC_LINK_QUE fcLQ = dev->fcLQ;
296 // copy current index to work on
297 QconsumerNdx = fcLQ->consumer;
299 PCI_TRACEO(fcLQ->Qitem[QconsumerNdx].Type, 0x90)
301 // NOTE: when this switch completes, we will "consume" the Que item
302 // printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
303 switch (fcLQ->Qitem[QconsumerNdx].Type)
305 // incoming frame - link service (ACC, UNSOL REQ, etc.)
306 // or FCP-SCSI command
308 AnalyzeIncomingFrame(dev, QconsumerNdx);
311 case EXCHANGE_QUEUED:
312 // an Exchange (i.e. FCP-SCSI) was previously
313 // Queued because the link was down. The
314 // heartbeat timer detected it and Queued it here.
315 // We attempt to start it again, and if
316 // successful we clear the EXCHANGE_Q flag.
317 // If the link doesn't come up, the Exchange
318 // will eventually time-out.
320 ExchangeID = (s32) fcLQ->Qitem[QconsumerNdx].ulBuff[0]; // x_ID copied from DPC timeout function
322 // It's possible that a Q'd exchange could have already
323 // been started by other logic (e.g. ABTS process)
324 // Don't start if already started (Q'd flag clear)
326 if (Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED) {
327 // printk(" *Start Q'd x_ID %Xh: type %Xh ",
328 // ExchangeID, Exchanges->fcExchange[ExchangeID].type);
330 ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
332 // printk("success* ");
335 if (ulStatus == EXCHANGE_QUEUED)
345 // (lots of things already done in INT handler) future here?
348 case LINKACTIVE: // Tachyon set the Lup bit in FM status
349 // NOTE: some misbehaving FC ports (like Tach2.1)
350 // can re-LIP immediately after a LIP completes.
351 // if "initiator", need to verify LOGs with ports
352 // printk("\n*LNKUP* ");
354 if (fcChip->Options.initiator)
355 SendLogins(dev, NULL); // PLOGI or PDISC, based on fcPort data
356 // if SendLogins successfully completes, PortDiscDone
358 // If SendLogins was successful, then we expect to get incoming
359 // ACCepts or REJECTs, which are handled below.
362 // LinkService and Fabric request/reply processing
363 case ELS_FDISC: // need to send Fabric Discovery (Login)
364 case ELS_FLOGI: // need to send Fabric Login
365 case ELS_SCR: // need to send State Change Registration
366 case FCS_NSR: // need to send Name Service Request
367 case ELS_PLOGI: // need to send PLOGI
368 case ELS_ACC: // send generic ACCept
369 case ELS_PLOGI_ACC: // need to send ELS ACCept frame to recv'd PLOGI
370 case ELS_PRLI_ACC: // need to send ELS ACCept frame to recv'd PRLI
371 case ELS_LOGO: // need to send ELS LOGO (logout)
372 case ELS_LOGO_ACC: // need to send ELS ACCept frame to recv'd PLOGI
373 case ELS_RJT: // ReJecT reply
374 case ELS_PRLI: // need to send ELS PRLI
377 // printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
378 // if PortDiscDone is not set, it means the SendLogins routine
379 // failed to complete -- assume that LDn occurred, so login frames
381 if (!dev->PortDiscDone) // cleared by LDn
383 printk("Discard Q'd ELS login frame\n");
387 ulStatus = cpqfcTSBuildExchange(dev, fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
389 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
390 NULL, // no data (no scatter/gather list)
391 &ExchangeID); // fcController->fcExchanges index, -1 if failed
393 if (!ulStatus) // Exchange setup?
395 ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
397 // submitted to Tach's Outbound Que (ERQ PI incremented)
398 // waited for completion for ELS type (Login frames issued
401 // check reason for Exchange not being started - we might
402 // want to Queue and start later, or fail with error
408 else // Xchange setup failed...
409 printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
413 case SCSI_REPORT_LUNS:
414 // pass the incoming frame (actually, it's a PRLI frame)
415 // so we can send REPORT_LUNS, in order to determine VSA/PDU
416 // FCP-SCSI Lun address mode
417 IssueReportLunsCommand(dev, (TachFCHDR_GCMND *)
418 fcLQ->Qitem[QconsumerNdx].ulBuff);
422 case BLS_ABTS: // need to ABORT one or more exchanges
424 s32 x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
427 if (x_ID > TACH_SEST_LEN) // (in)sanity check
429 // printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
432 if (Exchanges->fcExchange[x_ID].Cmnd == NULL) // should be RARE
434 // printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
435 break; // nothing to abort!
439 printk("INV SEST[%X] ", x_ID);
440 if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) {
443 if (Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT) {
446 if (Exchanges->fcExchange[x_ID].status & PORTID_CHANGED) {
449 if (Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) {
452 if (Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) {
455 if (Exchanges->fcExchange[x_ID].status & FRAME_TO) {
458 if (Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY) {
461 if (Exchanges->fcExchange[x_ID].status & SFQ_FRAME) {
465 if (Exchanges->fcExchange[x_ID].type == 0x2000)
467 else if (Exchanges->fcExchange[x_ID].type == 0x3000)
469 else if (Exchanges->fcExchange[x_ID].type == 0x10)
472 printk(" %Xh", Exchanges->fcExchange[x_ID].type);
474 if (!(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)) {
475 printk(" Cmd %p, ", Exchanges->fcExchange[x_ID].Cmnd);
477 printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n",
478 dev->HBAnum, Exchanges->fcExchange[x_ID].Cmnd->channel, Exchanges->fcExchange[x_ID].Cmnd->target, Exchanges->fcExchange[x_ID].Cmnd->lun, Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF);
479 } else // assume that Cmnd ptr is invalid on _abort()
481 printk(" Cmd ptr invalid\n");
484 // Steps to ABORT a SEST exchange:
485 // 1. Freeze TL SCSI assists & ERQ (everything)
486 // 2. Receive FROZEN inbound CM (must succeed!)
487 // 3. Invalidate x_ID SEST entry
488 // 4. Resume TL SCSI assists & ERQ (everything)
489 // 5. Build/start on exchange - change "type" to BLS_ABTS,
490 // timeout to X sec (RA_TOV from PLDA is actually 0)
491 // 6. Set Exchange Q'd status if ABTS cannot be started,
492 // or simply complete Exchange in "Terminate" condition
494 PCI_TRACEO(x_ID, 0xB4)
495 // 1 & 2 . Freeze Tach & get confirmation of freeze
496 FrozeTach = FreezeTach(dev);
498 // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
499 // FC2_TIMEOUT means we are originating the abort, while
500 // TARGET_ABORT means we are ACCepting an abort.
501 // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are
503 // Exchange was corrupted by LDn or other FC physical failure
504 // INITIATOR_ABORT means the upper layer driver/application
505 // requested the abort.
507 // clear bit 31 (VALid), to invalidate & take control from TL
508 fcChip->SEST->u[x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
510 // examine and Tach's "Linked List" for IWEs that
511 // received (nearly) simultaneous transfer ready (XRDY)
512 // repair linked list if necessary (TBD!)
513 // (If we ignore the "Linked List", we will time out
514 // WRITE commands where we received the FCP-SCSI XFRDY
515 // frame (because Tachyon didn't processes it). Linked List
516 // management should be done as an optimization.
518 // readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
520 // 4. Resume all Tachlite functions (for other open Exchanges)
521 // as quickly as possible to allow other exchanges to other ports
522 // to resume. Freezing Tachyon may cause cascading errors, because
523 // any received SEST frame cannot be processed by the SEST.
524 // Don't "unfreeze" unless Link is operational
525 if (FrozeTach) // did we just freeze it (above)?
526 fcChip->UnFreezeTachyon(fcChip, 2); // both ERQ and FCP assists
528 PCI_TRACEO(x_ID, 0xB4)
529 // Note there is no confirmation that the chip is "unfrozen". Also,
530 // if the Link is down when unfreeze is called, it has no effect.
531 // Chip will unfreeze when the Link is back up.
532 // 5. Now send out Abort commands if possible
533 // Some Aborts can't be "sent" (Port_id changed or gone);
534 // if the device is gone, there is no port_id to send the ABTS to.
535 if (!(Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
536 && !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)) {
537 Exchanges->fcExchange[x_ID].type = BLS_ABTS;
538 fchs.s_id = Exchanges->fcExchange[x_ID].fchs.d_id;
539 ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS, &fchs, // (uses only s_id)
540 NULL, // (no scatter/gather list for ABTS)
541 &x_ID); // ABTS on this Exchange ID
543 if (!ulStatus) // Exchange setup build OK?
546 // ABTS may be needed because an Exchange was corrupted
547 // by a Link disruption. If the Link is UP, we can
548 // presume that this ABTS can start immediately; otherwise,
549 // set Que'd status so the Login functions
550 // can restart it when the FC physical Link is restored
551 if (((fcChip->Registers.FMstatus.value & 0xF0) & 0x80)) // loop init?
553 // printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
554 Exchanges->fcExchange[x_ID].status |= EXCHANGE_QUEUED;
557 else // what FC device (port_id) does the Cmd belong to?
559 PFC_LOGGEDIN_PORT pLoggedInPort = Exchanges->fcExchange[x_ID].pLoggedInPort;
561 // if Port is logged in, we might start the abort.
563 if ((pLoggedInPort != NULL)
564 && (pLoggedInPort->prli == 1)) {
565 // it's possible that an Exchange has already been Queued
566 // to start after Login completes. Check and don't
567 // start it (again) here if Q'd status set
568 // printk(" ABTS xchg %Xh ", x_ID);
569 if (Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED) {
570 // printk("already Q'd ");
572 // printk("starting ");
573 fcChip->fcStats.FC2aborted++;
574 ulStatus = cpqfcTSStartExchange(dev, x_ID);
577 // submitted to Tach's Outbound Que (ERQ PI incremented)
579 // printk("ABTS exchange start failed -status %Xh, x_ID %Xh ", ulStatus, x_ID);
584 } else // what the #@!
585 { // how do we fail to build an Exchange for ABTS??
586 printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n", ulStatus, x_ID);
588 } else // abort without ABTS -- just complete exchange/Cmnd to Linux
590 // printk(" *Terminating x_ID %Xh on %Xh* ",
591 // x_ID, Exchanges->fcExchange[x_ID].status);
592 cpqfcTSCompleteExchange(dev->PciDev, fcChip, x_ID);
595 } // end of ABTS case
598 case BLS_ABTS_ACC: // need to ACCept one ABTS
599 // (NOTE! this code not updated for Linux yet..)
600 printk(" *ABTS_ACC* ");
603 fcChip->FreezeTachyon(fcChip, 2); // both ERQ and FCP assists
604 memcpy( // copy the incoming ABTS frame
605 &fchs, fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
608 // 3. OK, Tachyon is frozen so we can invalidate SEST entry
610 // Status FC2_TIMEOUT means we are originating the abort, while
611 // TARGET_ABORT means we are ACCepting an abort
613 ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
614 // printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
616 // sanity check on received ExchangeID
617 if (Exchanges->fcExchange[ExchangeID].status == TARGET_ABORT) {
618 // clear bit 31 (VALid), to invalidate & take control from TL
619 // printk("Invalidating SEST exchange %Xh\n", ExchangeID);
620 fcChip->SEST->u[ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
623 // 4. Resume all Tachlite functions (for other open Exchanges)
624 // as quickly as possible to allow other exchanges to other ports
625 // to resume. Freezing Tachyon for too long may royally screw
627 fcChip->UnFreezeTachyon(fcChip, 2); // both ERQ and FCP assists
629 // Note there is no confirmation that the chip is "unfrozen". Also,
630 // if the Link is down when unfreeze is called, it has no effect.
631 // Chip will unfreeze when the Link is back up.
633 // 5. Now send out Abort ACC reply for this exchange
634 Exchanges->fcExchange[ExchangeID].type = BLS_ABTS_ACC;
636 fchs.s_id = Exchanges->fcExchange[ExchangeID].fchs.d_id;
637 ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS_ACC, &fchs, NULL, // no data (no scatter/gather list)
638 &ExchangeID); // fcController->fcExchanges index, -1 if failed
640 if (!ulStatus) // Exchange setup?
642 ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
644 // submitted to Tach's Outbound Que (ERQ PI incremented)
645 // waited for completion for ELS type (Login frames issued
648 // check reason for Exchange not being started - we might
649 // want to Queue and start later, or fail with error
656 case BLS_ABTS_RJT: // need to ReJecT one ABTS; reject implies the
657 // exchange doesn't exist in the TARGET context.
658 // ExchangeID has to come from LinkService space.
660 printk(" *ABTS_RJT* ");
661 ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS_RJT, (TachFCHDR_GCMND *)
662 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
663 NULL, // no data (no scatter/gather list)
664 &ExchangeID); // fcController->fcExchanges index, -1 if failed
666 if (!ulStatus) // Exchange setup OK?
668 ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
669 // If it fails, we aren't required to retry.
672 printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
674 printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
682 // done with this item - now set the NEXT index
684 if (QconsumerNdx + 1 >= FC_LINKQ_DEPTH) // rollover test
689 PCI_TRACEO(fcLQ->Qitem[QconsumerNdx].Type, 0x94)
698 // When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login)
699 // commands come in, post to the LinkQ so that action can be taken outside the
700 // interrupt handler.
701 // This circular Q works like Tachyon's que - the producer points to the next
702 // (unused) entry. Called by Interrupt handler, WorkerThread, Timer
704 void cpqfcTSPutLinkQue(CPQFCHBA * dev, int Type, void *QueContent)
706 PTACHYON fcChip = &dev->fcChip;
707 // FC_EXCHANGES *Exchanges = fcChip->Exchanges;
708 PFC_LINK_QUE fcLQ = dev->fcLQ;
711 ENTER("cpqfcTSPutLinkQ");
713 ndx = fcLQ->producer;
715 ndx += 1; // test for Que full
719 if (ndx >= FC_LINKQ_DEPTH) // rollover test
722 if (ndx == fcLQ->consumer) // QUE full test
724 // QUE was full! lost LK command (fatal to logic)
725 fcChip->fcStats.lnkQueFull++;
727 printk("*LinkQ Full!*");
728 TriggerHBA(fcChip->Registers.ReMapMemBase, 1);
732 printk("LinkQ PI %d, CI %d\n", fcLQ->producer, fcLQ->consumer);
734 for( i=0; i< FC_LINKQ_DEPTH; )
736 printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
742 printk("cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
744 else // QUE next element
746 // Prevent certain multiple (back-to-back) requests.
747 // This is important in that we don't want to issue multiple
748 // ABTS for the same Exchange, or do multiple FM inits, etc.
749 // We can never be sure of the timing of events reported to
750 // us by Tach's IMQ, which can depend on system/bus speeds,
751 // FC physical link circumstances, etc.
753 if ((fcLQ->producer != fcLQ->consumer)
754 && (Type == FMINIT)) {
755 s32 lastNdx; // compute previous producer index
757 lastNdx = fcLQ->producer - 1;
759 lastNdx = FC_LINKQ_DEPTH - 1;
762 if (fcLQ->Qitem[lastNdx].Type == FMINIT) {
763 // printk(" *skip FMINIT Q post* ");
764 // goto DoneWithPutQ;
768 // OK, add the Q'd item...
769 fcLQ->Qitem[fcLQ->producer].Type = Type;
770 memcpy(fcLQ->Qitem[fcLQ->producer].ulBuff, QueContent, sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
771 fcLQ->producer = ndx; // increment Que producer
772 // set semaphore to wake up Kernel (worker) thread
776 LEAVE("cpqfcTSPutLinkQ");
779 // reset device ext FC link Q
780 void cpqfcTSLinkQReset(CPQFCHBA * dev)
782 PFC_LINK_QUE fcLQ = dev->fcLQ;
787 // When Tachyon gets an unassisted FCP-SCSI frame, post here so
788 // an arbitrary context thread (e.g. IOCTL loopback test function)
791 // (NOTE: Not revised for Linux)
792 // This Q works like Tachyon's que - the producer points to the next
794 void cpqfcTSPutScsiQue(CPQFCHBA * dev, int Type, void *QueContent)
796 // CPQFCHBA *dev = (CPQFCHBA *)shpnt->hostdata;
797 // PTACHYON fcChip = &dev->fcChip;
805 KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
806 ndx = pDevExt->fcScsiQue.producer + 1; // test for Que full
808 if( ndx >= FC_SCSIQ_DEPTH ) // rollover test
811 if( ndx == pDevExt->fcScsiQue.consumer ) // QUE full test
813 // QUE was full! lost LK command (fatal to logic)
814 fcChip->fcStats.ScsiQueFull++;
816 printk( "fcPutScsiQue - FULL!\n");
820 else // QUE next element
822 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].Type = Type;
824 if( Type == FCP_RSP )
826 // this TL inbound message type means that a TL SEST exchange has
827 // copied an FCP response frame into a buffer pointed to by the SEST
828 // entry. That buffer is allocated in the SEST structure at ->RspHDR.
829 // Copy the RspHDR for use by the Que handler.
830 pExchangeID = (u32 *)QueContent;
833 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
834 &fcChip->SEST->RspHDR[ *pExchangeID ],
835 sizeof(pDevExt->fcScsiQue.Qitem[0].ulBuff)); // (any element for size)
841 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
843 sizeof(pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff));
846 pDevExt->fcScsiQue.producer = ndx; // increment Que
849 KeSetEvent( &pDevExt->TYIBscsi, // signal any waiting thread
850 0, // no priority boost
851 0 ); // no waiting later for this event
853 KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
857 static void ProcessELS_Request(CPQFCHBA *, TachFCHDR_GCMND *);
858 static void ProcessELS_Reply(CPQFCHBA *, TachFCHDR_GCMND *);
859 static void ProcessFCS_Reply(CPQFCHBA *, TachFCHDR_GCMND *);
861 void cpqfcTSImplicitLogout(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pFcPort)
863 PTACHYON fcChip = &dev->fcChip;
865 if (pFcPort->port_id != 0xFFFC01) // don't care about Fabric
867 fcChip->fcStats.logouts++;
868 printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", (u32) pFcPort->u.liWWN, (u32) (pFcPort->u.liWWN >> 32), pFcPort->port_id);
870 // Terminate I/O with this (Linux) Scsi target
871 cpqfcTSTerminateExchange(dev, &pFcPort->ScsiNexus, DEVICE_REMOVED);
873 // Do an "implicit logout" - we can't really Logout the device
874 // (i.e. with LOGOut Request) because of port_id confusion
875 // (i.e. the Other port has no port_id).
876 // A new login for that WWN will have to re-write port_id (0 invalid)
877 pFcPort->port_id = 0; // invalid!
882 pFcPort->LOGO_timer = 0;
883 pFcPort->device_blocked = 1; // block Scsi Requests
884 pFcPort->ScsiNexus.VolumeSetAddressing = 0;
888 // On FC-AL, there is a chance that a previously known device can
889 // be quietly removed (e.g. with non-managed hub),
890 // while a NEW device (with different WWN) took the same alpa or
891 // even 24-bit port_id. This chance is unlikely but we must always
894 static void TestDuplicatePortId(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pLoggedInPort)
896 PTACHYON fcChip = &dev->fcChip;
897 // set "other port" at beginning of fcPorts list
898 PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
899 while (pOtherPortWithPortId) {
900 if ((pOtherPortWithPortId->port_id == pLoggedInPort->port_id)
901 && (pOtherPortWithPortId != pLoggedInPort)) {
902 // trouble! (Implicitly) Log the other guy out
903 printk(" *port_id %Xh is duplicated!* ", pOtherPortWithPortId->port_id);
904 cpqfcTSImplicitLogout(dev, pOtherPortWithPortId);
906 pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
910 // Dynamic Memory Allocation for newly discovered FC Ports.
911 // For simplicity, maintain fcPorts structs for ALL
912 // for discovered devices, including those we never do I/O with
913 // (e.g. Fabric addresses)
915 static PFC_LOGGEDIN_PORT CreateFcPort(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pLastLoggedInPort, TachFCHDR_GCMND * fchs, LOGIN_PAYLOAD * plogi)
917 PTACHYON fcChip = &dev->fcChip;
918 PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
921 printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
922 for (i = 3; i >= 0; i--) // copy the LOGIN port's WWN
923 printk("%02X", plogi->port_name[i]);
924 for (i = 7; i > 3; i--) // copy the LOGIN port's WWN
925 printk("%02X", plogi->port_name[i]);
927 // allocate mem for new port
928 // (these are small and rare allocations...)
929 pNextLoggedInPort = kmalloc(sizeof(FC_LOGGEDIN_PORT), GFP_ATOMIC);
931 // allocation succeeded? Fill out NEW PORT
932 if (pNextLoggedInPort) {
933 // clear out any garbage (sometimes exists)
934 memset(pNextLoggedInPort, 0, sizeof(FC_LOGGEDIN_PORT));
935 // If we login to a Fabric, we don't want to treat it
936 // as a SCSI device...
937 if ((fchs->s_id & 0xFFF000) != 0xFFF000) {
940 // create a unique "virtual" SCSI Nexus (for now, just a
941 // new target ID) -- we will update channel/target on REPORT_LUNS
942 // special case for very first SCSI target...
943 if (dev->HostAdapter->max_id == 0) {
944 pNextLoggedInPort->ScsiNexus.target = 0;
945 fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
947 pNextLoggedInPort->ScsiNexus.target = dev->HostAdapter->max_id;
950 // initialize the lun[] Nexus struct for lun masking
951 for (i = 0; i < CPQFCTS_MAX_LUN; i++)
952 pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
954 pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
955 printk(" SCSI Chan/Trgt %d/%d", pNextLoggedInPort->ScsiNexus.channel, pNextLoggedInPort->ScsiNexus.target);
956 // tell Scsi layers about the new target...
957 dev->HostAdapter->max_id++;
958 // printk("HostAdapter->max_id = %d\n",
959 // dev->HostAdapter->max_id);
961 // device is NOT SCSI (in case of Fabric)
962 pNextLoggedInPort->ScsiNexus.target = -1; // invalid
965 // create forward link to new port
966 pLastLoggedInPort->pNextPort = pNextLoggedInPort;
970 return pNextLoggedInPort; // NULL on allocation failure
971 } // end NEW PORT (WWN) logic
973 // For certain cases, we want to terminate exchanges without
974 // sending ABTS to the device. Examples include when an FC
975 // device changed it's port_id after Loop re-init, or when
976 // the device sent us a logout. In the case of changed port_id,
977 // we want to complete the command and return SOFT_ERROR to
978 // force a re-try. In the case of LOGOut, we might return
979 // BAD_TARGET if the device is really gone.
980 // Since we must ensure that Tachyon is not operating on the
981 // exchange, we have to freeze the chip
984 void cpqfcTSTerminateExchange(CPQFCHBA * dev, SCSI_NEXUS * ScsiNexus, int TerminateStatus)
986 PTACHYON fcChip = &dev->fcChip;
987 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
991 // printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
992 // ScsiNexus->channel, ScsiNexus->target);
994 for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
995 if (Exchanges->fcExchange[x_ID].type) // in use?
997 if (ScsiNexus == NULL) // our HBA changed - term. all
999 Exchanges->fcExchange[x_ID].status = TerminateStatus;
1000 cpqfcTSPutLinkQue(dev, BLS_ABTS, &x_ID);
1002 // If a device, according to WWN, has been removed, it's
1003 // port_id may be used by another working device, so we
1004 // have to terminate by SCSI target, NOT port_id.
1005 if (Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
1007 if ((Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
1008 && (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel)) {
1009 Exchanges->fcExchange[x_ID].status = TerminateStatus;
1010 cpqfcTSPutLinkQue(dev, BLS_ABTS, &x_ID); // timed-out
1013 // (in case we ever need it...)
1014 // all SEST structures have a remote node ID at SEST DWORD 2
1015 // if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
1022 static void ProcessELS_Request(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
1024 PTACHYON fcChip = &dev->fcChip;
1025 // FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1026 // u32 ox_id = (fchs->ox_rx_id >>16);
1027 PFC_LOGGEDIN_PORT pLoggedInPort = NULL, pLastLoggedInPort;
1029 u32 ls_reject_code = 0; // default don'n know??
1032 // Check the incoming frame for a supported ELS type
1033 switch (fchs->pl[0] & 0xFFFF)
1037 // Payload for PLOGI and PDISC is identical (request & reply)
1038 if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) // valid payload?
1040 LOGIN_PAYLOAD logi; // FC-PH Port Login
1042 // PDISC payload OK. If critical login fields
1043 // (e.g. WWN) matches last login for this port_id,
1044 // we may resume any prior exchanges
1045 // with the other port
1047 BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
1049 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
1050 0, // don't search linked list for port_id
1051 &logi.port_name[0], // search linked list for WWN
1052 &pLastLoggedInPort); // must return non-NULL; when a port_id
1053 // is not found, this pointer marks the
1054 // end of the singly linked list
1056 if (pLoggedInPort != NULL) // WWN found (prior login OK)
1058 if ((fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) {
1059 // Yes. We were expecting PDISC?
1060 if (pLoggedInPort->pdisc) {
1061 // Yes; set fields accordingly. (PDISC, not Originator)
1062 SetLoginFields(pLoggedInPort, fchs, 1, 0);
1064 cpqfcTSPutLinkQue(dev, ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1066 // OK to resume I/O...
1068 printk("Not expecting PDISC (pdisc=0)\n");
1070 // set reject reason code
1071 ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1074 if (pLoggedInPort->port_id != 0) {
1075 printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id & 0xFFFFFF);
1078 // set reject reason code
1079 ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1082 printk("PDISC Request from unknown WWN\n");
1084 // set reject reason code
1085 ls_reject_code = LS_RJT_REASON(LOGICAL_ERROR, INVALID_PORT_NAME);
1089 else // Payload unacceptable
1091 printk("payload unacceptable\n");
1092 NeedReject = 1; // reject code already set
1097 // The PDISC failed. Set login struct flags accordingly,
1098 // terminate any I/O to this port, and Q a PLOGI
1099 if (pLoggedInPort) {
1100 pLoggedInPort->pdisc = 0;
1101 pLoggedInPort->prli = 0;
1102 pLoggedInPort->plogi = 0;
1104 cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1105 port_id = pLoggedInPort->port_id;
1107 port_id = fchs->s_id & 0xFFFFFF;
1109 fchs->reserved = ls_reject_code; // borrow this (unused) field
1110 cpqfcTSPutLinkQue(dev, ELS_RJT, fchs);
1116 // Payload for PLOGI and PDISC is identical (request & reply)
1117 if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) // valid payload?
1119 LOGIN_PAYLOAD logi; // FC-PH Port Login
1122 // PDISC payload OK. If critical login fields
1123 // (e.g. WWN) matches last login for this port_id,
1124 // we may resume any prior exchanges
1125 // with the other port
1127 BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
1128 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
1129 0, // don't search linked list for port_id
1130 &logi.port_name[0], // search linked list for WWN
1131 &pLastLoggedInPort); // must return non-NULL; when a port_id
1132 // is not found, this pointer marks the
1133 // end of the singly linked list
1134 if (pLoggedInPort == NULL) // WWN not found -New Port
1136 pLoggedInPort = CreateFcPort(dev, pLastLoggedInPort, fchs, &logi);
1137 if (pLoggedInPort == NULL) {
1138 printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1139 // Now Q a LOGOut Request, since we won't be talking to that device
1141 // set reject reason code
1142 ls_reject_code = LS_RJT_REASON(LOGICAL_ERROR, NO_LOGIN_RESOURCES);
1146 // OK - we have valid fcPort ptr; set fields accordingly.
1147 // (not PDISC, not Originator)
1148 SetLoginFields(pLoggedInPort, fchs, 0, 0);
1150 cpqfcTSPutLinkQue(dev, ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1154 else // Payload unacceptable
1156 printk("payload unacceptable\n");
1157 NeedReject = 1; // reject code already set
1160 // The PDISC failed. Set login struct flags accordingly,
1161 // terminate any I/O to this port, and Q a PLOGI
1162 pLoggedInPort->pdisc = 0;
1163 pLoggedInPort->prli = 0;
1164 pLoggedInPort->plogi = 0;
1166 fchs->reserved = ls_reject_code; // borrow this (unused) field
1169 cpqfcTSPutLinkQue(dev, ELS_RJT, fchs);
1171 // terminate any exchanges with this device...
1172 if (pLoggedInPort) {
1173 cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1177 case 0x1020: // PRLI?
1180 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
1181 (fchs->s_id & 0xFFFFFF), // search linked list for port_id
1182 NULL, // DON'T search linked list for WWN
1183 NULL); // don't care
1185 if (pLoggedInPort == NULL) {
1187 printk(" Unexpected PRLI Request -not logged in!\n");
1188 // set reject reason code
1189 ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1192 // verify the PRLI ACC payload
1193 if (!verify_PRLI(fchs, &ls_reject_code)) {
1194 // PRLI Reply is acceptable; were we expecting it?
1195 if (pLoggedInPort->plogi) {
1196 // yes, we expected the PRLI ACC (not PDISC; not Originator)
1197 SetLoginFields(pLoggedInPort, fchs, 0, 0);
1198 // Q an ACCept Reply
1199 cpqfcTSPutLinkQue(dev, ELS_PRLI_ACC, fchs);
1203 printk(" (unexpected) PRLI REQEST with plogi 0\n");
1204 // set reject reason code
1205 ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1209 printk(" PRLI REQUEST payload failed verify\n");
1210 // (reject code set by "verify")
1216 // Q a ReJecT Reply with reason code
1217 fchs->reserved = ls_reject_code;
1218 cpqfcTSPutLinkQue(dev, ELS_RJT, // Q Type
1224 case 0x0005: // LOGOut?
1226 // was this LOGOUT because we sent a ELS_PDISC to an FC device
1227 // with changed (or new) port_id, or does the port refuse
1228 // to communicate to us?
1229 // We maintain a logout counter - if we get 3 consecutive LOGOuts,
1231 LOGOUT_PAYLOAD logo;
1232 u8 GiveUpOnDevice = 0;
1233 u32 ls_reject_code = 0;
1235 BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logo, sizeof(logo));
1236 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
1237 0, // don't search linked list for port_id
1238 &logo.port_name[0], // search linked list for WWN
1239 NULL); // don't care about end of list
1241 if (pLoggedInPort) // found the device?
1244 cpqfcTSPutLinkQue(dev, ELS_LOGO_ACC, // Q Type
1245 fchs); // device to respond to
1246 // set login struct fields (LOGO_counter increment)
1247 SetLoginFields(pLoggedInPort, fchs, 0, 0);
1248 // are we an Initiator?
1249 if (fcChip->Options.initiator) {
1250 // we're an Initiator, so check if we should
1251 // try (another?) login
1252 // Fabrics routinely log out from us after
1253 // getting device info - don't try to log them
1255 if ((fchs->s_id & 0xFFF000) == 0xFFF000) {
1257 } else if (pLoggedInPort->LOGO_counter <= 3) {
1258 // try (another) login (PLOGI request)
1259 cpqfcTSPutLinkQue(dev, ELS_PLOGI, // Q Type
1261 // Terminate I/O with "retry" potential
1262 cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1264 printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n", fchs->s_id & 0xFFFFFF);
1271 if (GiveUpOnDevice == 1) {
1272 cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, DEVICE_REMOVED);
1274 } else // we don't know this WWN!
1276 // Q a ReJecT Reply with reason code
1277 fchs->reserved = ls_reject_code;
1278 cpqfcTSPutLinkQue(dev, ELS_RJT, // Q Type
1285 case 0x0461: // ELS RSCN (Registered State Change Notification)?
1290 // Typically, one or more devices have been added to or dropped
1292 // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
1293 // The first 32-bit word has a 2-byte Payload Length, which
1294 // includes the 4 bytes of the first word. Consequently,
1295 // this PL len must never be less than 4, must be a multiple of 4,
1296 // and has a specified max value 256.
1298 Ports = ((fchs->pl[0] >> 24) - 4) / 4;
1299 Ports = Ports > 63 ? 63 : Ports;
1301 printk(" RSCN ports: %d\n", Ports);
1302 if (Ports <= 0) // huh?
1304 // ReJecT the command
1305 fchs->reserved = LS_RJT_REASON(UNABLE_TO_PERFORM, 0);
1307 cpqfcTSPutLinkQue(dev, ELS_RJT, // Q Type
1311 } else // Accept the command
1313 cpqfcTSPutLinkQue(dev, ELS_ACC, // Q Type
1317 // Check the "address format" to determine action.
1319 // 0 = Port Address; 24-bit address of affected device
1320 // 1 = Area Address; MS 16 bits valid
1321 // 2 = Domain Address; MS 8 bits valid
1322 for (i = 0; i < Ports; i++) {
1323 BigEndianSwap((u8 *) & fchs->pl[i + 1], (u8 *) & Buff, 4);
1324 switch (Buff & 0xFF000000) {
1325 case 0: // Port Address?
1326 case 0x01000000: // Area Domain?
1327 case 0x02000000: // Domain Address
1328 // For example, "port_id" 0x201300
1329 // OK, let's try a Name Service Request (Query)
1330 fchs->s_id = 0xFFFFFC; // Name Server Address
1331 cpqfcTSPutLinkQue(dev, FCS_NSR, fchs);
1333 default: // huh? new value on version change?
1340 // don't support this request (yet)
1341 // set reject reason code
1342 fchs->reserved = LS_RJT_REASON(UNABLE_TO_PERFORM, REQUEST_NOT_SUPPORTED);
1343 cpqfcTSPutLinkQue(dev, ELS_RJT, fchs); // Q Type
1349 static void ProcessELS_Reply(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
1351 PTACHYON fcChip = &dev->fcChip;
1352 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1353 u32 ox_id = (fchs->ox_rx_id >> 16);
1355 PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
1357 // If this is a valid reply, then we MUST have sent a request.
1358 // Verify that we can find a valid request OX_ID corresponding to
1361 if (Exchanges->fcExchange[(fchs->ox_rx_id >> 16)].type == 0) {
1362 printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
1363 goto Quit; // exit this routine
1366 // Is the reply a RJT (reject)?
1367 if ((fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
1369 // ****** REJECT REPLY ********
1370 switch (Exchanges->fcExchange[ox_id].type) {
1371 case ELS_FDISC: // we sent out Fabric Discovery
1372 case ELS_FLOGI: // we sent out FLOGI
1373 printk("RJT received on Fabric Login from %Xh, reason %Xh\n", fchs->s_id, fchs->pl[1]);
1380 // OK, we have an ACCept...
1381 // What's the ACC type? (according to what we sent)
1382 switch (Exchanges->fcExchange[ox_id].type) {
1383 case ELS_PLOGI: // we sent out PLOGI
1384 if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) {
1385 LOGIN_PAYLOAD logi; // FC-PH Port Login
1386 // login ACC payload acceptable; search for WWN in our list
1388 BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
1389 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
1390 0, // don't search linked list for port_id
1391 &logi.port_name[0], // search linked list for WWN
1392 &pLastLoggedInPort); // must return non-NULL; when a port_id
1393 // is not found, this pointer marks the
1394 // end of the singly linked list
1395 if (pLoggedInPort == NULL) // WWN not found - new port
1397 pLoggedInPort = CreateFcPort(dev, pLastLoggedInPort, fchs, &logi);
1398 if (pLoggedInPort == NULL) {
1399 printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1400 // Now Q a LOGOut Request, since we won't be talking to that device
1401 goto Done; // exit with error! dropped login frame
1403 } else // WWN was already known. Ensure that any open
1404 // exchanges for this WWN are terminated.
1405 // NOTE: It's possible that a device can change its
1406 // 24-bit port_id after a Link init or Fabric change
1407 // (e.g. LIP or Fabric RSCN). In that case, the old
1408 // 24-bit port_id may be duplicated, or no longer exist.
1410 cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1413 // We have an fcPort struct - set fields accordingly
1414 // not PDISC, originator
1415 SetLoginFields(pLoggedInPort, fchs, 0, 1);
1416 // We just set a "port_id"; is it duplicated?
1417 TestDuplicatePortId(dev, pLoggedInPort);
1418 // For Fabric operation, we issued PLOGI to 0xFFFFFC
1419 // so we can send SCR (State Change Registration)
1420 // Check for this special case...
1421 if (fchs->s_id == 0xFFFFFC) {
1422 // PLOGI ACC was a Fabric response... issue SCR
1423 fchs->s_id = 0xFFFFFD; // address for SCR
1424 cpqfcTSPutLinkQue(dev, ELS_SCR, fchs);
1427 // Now we need a PRLI to enable FCP-SCSI operation
1428 // set flags and Q up a ELS_PRLI
1429 cpqfcTSPutLinkQue(dev, ELS_PRLI, fchs);
1432 // login payload unacceptable - reason in ls_reject_code
1433 // Q up a Logout Request
1434 printk("Login Payload unacceptable\n");
1438 // PDISC logic very similar to PLOGI, except we never want
1439 // to allocate mem for "new" port, and we set flags differently
1440 // (might combine later with PLOGI logic for efficiency)
1441 case ELS_PDISC: // we sent out PDISC
1442 if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) {
1443 LOGIN_PAYLOAD logi; // FC-PH Port Login
1446 // login payload acceptable; search for WWN in our list
1447 // of (previously seen) fcPorts
1448 BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
1450 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
1451 0, // don't search linked list for port_id
1452 &logi.port_name[0], // search linked list for WWN
1453 &pLastLoggedInPort); // must return non-NULL; when a port_id
1454 // is not found, this pointer marks the
1455 // end of the singly linked list
1456 if (pLoggedInPort != NULL) // WWN found?
1458 // WWN has same port_id as last login? (Of course, a properly
1459 // working FC device should NEVER ACCept a PDISC if it's
1460 // port_id changed, but check just in case...)
1461 if ((fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) {
1462 // Yes. We were expecting PDISC?
1463 if (pLoggedInPort->pdisc) {
1467 // PDISC expected -- set fields. (PDISC, Originator)
1468 SetLoginFields(pLoggedInPort, fchs, 1, 1);
1470 // We are ready to resume FCP-SCSI to this device...
1471 // Do we need to start anything that was Queued?
1473 for (i = 0; i < TACH_SEST_LEN; i++) {
1474 // see if any exchange for this PDISC'd port was queued
1475 if (((fchs->s_id & 0xFFFFFF) == (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
1476 && (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED)) {
1477 fchs->reserved = i; // copy ExchangeID
1478 // printk(" *Q x_ID %Xh after PDISC* ",i);
1480 cpqfcTSPutLinkQue(dev, EXCHANGE_QUEUED, fchs);
1483 // Complete commands Q'd while we were waiting for Login
1484 UnblockScsiDevice(dev->HostAdapter, pLoggedInPort);
1486 printk("Not expecting PDISC (pdisc=0)\n");
1490 printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id & 0xFFFFFF);
1494 printk("PDISC ACC from unknown WWN\n");
1499 // The PDISC failed. Set login struct flags accordingly,
1500 // terminate any I/O to this port, and Q a PLOGI
1501 if (pLoggedInPort) // FC device previously known?
1503 cpqfcTSPutLinkQue(dev, ELS_LOGO, fchs); // Qtype has port_id to send to
1504 // There are a variety of error scenarios which can result
1505 // in PDISC failure, so as a catchall, add the check for
1506 // duplicate port_id.
1507 TestDuplicatePortId(dev, pLoggedInPort);
1509 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
1510 pLoggedInPort->pdisc = 0;
1511 pLoggedInPort->prli = 0;
1512 pLoggedInPort->plogi = 0;
1514 cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1516 cpqfcTSPutLinkQue(dev, ELS_PLOGI, fchs);
1519 // login payload unacceptable - reason in ls_reject_code
1520 // Q up a Logout Request
1521 printk("ERROR: Login Payload unacceptable!\n");
1526 case ELS_PRLI: // we sent out PRLI
1527 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
1528 (fchs->s_id & 0xFFFFFF), // search linked list for port_id
1529 NULL, // DON'T search linked list for WWN
1530 NULL); // don't care
1532 if (pLoggedInPort == NULL) {
1534 printk(" Unexpected PRLI ACCept frame!\n");
1538 // verify the PRLI ACC payload
1539 if (!verify_PRLI(fchs, &ls_reject_code)) {
1540 // PRLI Reply is acceptable; were we expecting it?
1541 if (pLoggedInPort->plogi) {
1542 // yes, we expected the PRLI ACC (not PDISC; Originator)
1543 SetLoginFields(pLoggedInPort, fchs, 0, 1);
1544 // OK, let's send a REPORT_LUNS command to determine
1545 // whether VSA or PDA FCP-LUN addressing is used.
1546 cpqfcTSPutLinkQue(dev, SCSI_REPORT_LUNS, fchs);
1547 // It's possible that a device we were talking to changed
1548 // port_id, and has logged back in. This function ensures
1549 // that I/O will resume.
1550 UnblockScsiDevice(dev->HostAdapter, pLoggedInPort);
1553 printk(" (unexpected) PRLI ACCept with plogi 0\n");
1558 printk(" PRLI ACCept payload failed verify\n");
1563 case ELS_FLOGI: // we sent out FLOGI (Fabric Login)
1564 // update the upper 16 bits of our port_id in Tachyon
1565 // the switch adds those upper 16 bits when responding
1566 // to us (i.e. we are the destination_id)
1567 fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
1568 writel(fcChip->Registers.my_al_pa, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
1570 // now send out a PLOGI to the well known port_id 0xFFFFFC
1571 fchs->s_id = 0xFFFFFC;
1572 cpqfcTSPutLinkQue(dev, ELS_PLOGI, fchs);
1576 case ELS_FDISC: // we sent out FDISC (Fabric Discovery (Login))
1577 printk(" ELS_FDISC success ");
1580 case ELS_SCR: // we sent out State Change Registration
1581 // now we can issue Name Service Request to find any
1582 // Fabric-connected devices we might want to login to.
1583 fchs->s_id = 0xFFFFFC; // Name Server Address
1584 cpqfcTSPutLinkQue(dev, FCS_NSR, fchs);
1588 printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
1592 // Regardless of whether the Reply is valid or not, the
1593 // the exchange is done - complete
1594 cpqfcTSCompleteExchange(dev->PciDev, fcChip, (fchs->ox_rx_id >> 16));
1604 // **************** Fibre Channel Services **************
1605 // This is where we process the Directory (Name) Service Reply
1606 // to know which devices are on the Fabric
1608 static void ProcessFCS_Reply(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
1610 PTACHYON fcChip = &dev->fcChip;
1611 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1612 u32 ox_id = (fchs->ox_rx_id >> 16);
1613 // u32 ls_reject_code;
1614 // PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
1616 // If this is a valid reply, then we MUST have sent a request.
1617 // Verify that we can find a valid request OX_ID corresponding to
1620 if (Exchanges->fcExchange[(fchs->ox_rx_id >> 16)].type == 0) {
1621 printk(" *Discarding Reply frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
1622 goto Quit; // exit this routine
1625 // OK, we were expecting it. Now check to see if it's a
1626 // "Name Service" Reply, and if so force a re-validation of
1627 // Fabric device logins (i.e. Start the login timeout and
1628 // send PDISC or PLOGI)
1629 // (Endianess Byte Swap?)
1630 if (fchs->pl[1] == 0x02FC) // Name Service
1632 // got a new (or NULL) list of Fabric attach devices...
1633 // Invalidate current logins
1635 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
1636 while (pLoggedInPort) // for all ports which are expecting
1637 // PDISC after the next LIP, set the
1641 if ((pLoggedInPort->port_id & 0xFFFF00) // Fabric device?
1642 && (pLoggedInPort->port_id != 0xFFFFFC)) // NOT the F_Port
1644 pLoggedInPort->LOGO_timer = 6; // what's the Fabric timeout??
1645 // suspend any I/O in progress until
1646 // PDISC received...
1647 pLoggedInPort->prli = 0; // block FCP-SCSI commands
1650 pLoggedInPort = pLoggedInPort->pNextPort;
1653 if (fchs->pl[2] == 0x0280) // ACCept?
1655 // Send PLOGI or PDISC to these Fabric devices
1656 SendLogins(dev, &fchs->pl[4]);
1658 // As of this writing, the only reason to reject is because NO
1659 // devices are left on the Fabric. We already started
1660 // "logged out" timers; if the device(s) don't come
1661 // back, we'll do the implicit logout in the heart beat
1665 // this just means no Fabric device is visible at this instant
1668 // Regardless of whether the Reply is valid or not, the
1669 // the exchange is done - complete
1670 cpqfcTSCompleteExchange(dev->PciDev, fcChip, (fchs->ox_rx_id >> 16));
1676 static void AnalyzeIncomingFrame(CPQFCHBA * dev, u32 QNdx)
1678 PTACHYON fcChip = &dev->fcChip;
1679 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1680 PFC_LINK_QUE fcLQ = dev->fcLQ;
1681 TachFCHDR_GCMND *fchs = (TachFCHDR_GCMND *) fcLQ->Qitem[QNdx].ulBuff;
1682 // u32 ls_reject_code; // reason for rejecting login
1684 // FC_LOGGEDIN_PORT *pLoggedInPort;
1687 ENTER("AnalyzeIncomingFrame");
1689 switch (fcLQ->Qitem[QNdx].Type) // FCP or Unknown
1691 case SFQ_UNKNOWN: // unknown frame (e.g. LIP position frame, NOP, etc.)
1692 // ********* FC-4 Device Data/ Fibre Channel Service *************
1693 if (((fchs->d_id & 0xF0000000) == 0) // R_CTL (upper nibble) 0x0?
1694 && (fchs->f_ctl & 0x20000000)) // TYPE 20h is Fibre Channel Service
1696 // ************** FCS Reply **********************
1697 if ((fchs->d_id & 0xff000000L) == 0x03000000L) // (31:23 R_CTL)
1699 ProcessFCS_Reply(dev, fchs);
1700 } // end of FCS logic
1702 // *********** Extended Link Service **************
1703 else if (fchs->d_id & 0x20000000 // R_CTL 0x2?
1704 && (fchs->f_ctl & 0x01000000)) // TYPE = 1
1706 // these frames are either a response to
1707 // something we sent (0x23) or "unsolicited"
1709 // **************Extended Link REPLY **********************
1710 // R_CTL Solicited Control Reply
1711 if ((fchs->d_id & 0xff000000L) == 0x23000000L) // (31:23 R_CTL)
1713 ProcessELS_Reply(dev, fchs);
1714 } // end of "R_CTL Solicited Control Reply"
1715 // **************Extended Link REQUEST **********************
1716 // (unsolicited commands from another port or task...)
1717 // R_CTL Ext Link REQUEST
1718 else if ((fchs->d_id & 0xff000000L) == 0x22000000L && (fchs->ox_rx_id != 0xFFFFFFFFL)) // (ignore LIP frame)
1720 ProcessELS_Request(dev, fchs);
1722 // ************** LILP **********************
1723 else if ((fchs->d_id & 0xff000000L) == 0x22000000L && (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
1725 // SANMark specifies that when available, we must use
1726 // the LILP frame to determine which ALPAs to send Port Discovery
1728 if (fchs->pl[0] == 0x0711L) // ELS_PLOGI?
1730 // u8 *ptr = (u8*)&fchs->pl[1];
1731 // printk(" %d ALPAs found\n", *ptr);
1732 memcpy(fcChip->LILPmap, &fchs->pl[1], 32 * 4); // 32 DWORDs
1733 fcChip->Options.LILPin = 1; // our LILPmap is valid!
1734 // now post to make Port Discovery happen...
1735 cpqfcTSPutLinkQue(dev, LINKACTIVE, fchs);
1739 // ***************** BASIC LINK SERVICE *****************
1740 else if (fchs->d_id & 0x80000000 // R_CTL:
1741 && // Basic Link Service Request
1742 !(fchs->f_ctl & 0xFF000000)) // type=0 for BLS
1744 // Check for ABTS (Abort Sequence)
1745 if ((fchs->d_id & 0x8F000000) == 0x81000000) {
1746 // look for OX_ID, S_ID pair that matches in our
1747 // fcExchanges table; if found, reply with ACCept and complete
1750 // Per PLDA, an ABTS is sent by an initiator; therefore
1751 // assume that if we have an exhange open to the port who
1752 // sent ABTS, it will be the d_id of what we sent.
1753 for (ExchangeID = 0, AbortAccept = 0; ExchangeID < TACH_SEST_LEN; ExchangeID++) {
1754 // Valid "target" exchange 24-bit port_id matches?
1755 // NOTE: For the case of handling Intiator AND Target
1756 // functions on the same chip, we can have TWO Exchanges
1757 // with the same OX_ID -- OX_ID/FFFF for the CMND, and
1758 // OX_ID/RX_ID for the XRDY or DATA frame(s). Ideally,
1759 // we would like to support ABTS from Initiators or Targets,
1760 // but it's not clear that can be supported on Tachyon for
1761 // all cases (requires more investigation).
1763 if ((Exchanges->fcExchange[ExchangeID].type == SCSI_TWE || Exchanges->fcExchange[ExchangeID].type == SCSI_TRE)
1764 && ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
1766 // target xchnge port_id matches -- how about OX_ID?
1767 if ((Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id & 0xFFFF0000)
1768 == (fchs->ox_rx_id & 0xFFFF0000))
1769 // yes! post ACCept response; will be completed by fcStart
1771 Exchanges->fcExchange[ExchangeID].status = TARGET_ABORT;
1773 // copy (add) rx_id field for simplified ACCept reply
1774 fchs->ox_rx_id = Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id;
1776 cpqfcTSPutLinkQue(dev, BLS_ABTS_ACC, // Q Type
1777 fchs); // void QueContent
1779 printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", fchs->ox_rx_id, Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id);
1780 break; // ABTS can affect only ONE exchange -exit loop
1783 } // end of FOR loop
1784 if (!AbortAccept) // can't ACCept ABTS - send Reject
1786 printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", fchs->ox_rx_id);
1787 if (Exchanges->fcExchange[ExchangeID].type && !(fcChip->SEST->u[ExchangeID].IWE.Hdr_Len & 0x80000000)) {
1788 cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
1790 printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", ExchangeID, fcChip->SEST->u[ExchangeID].IWE.Hdr_Len);
1794 // Check for BLS {ABTS? (Abort Sequence)} ACCept
1795 else if ((fchs->d_id & 0x8F000000) == 0x84000000) {
1796 // target has responded with ACC for our ABTS;
1797 // complete the indicated exchange with ABORTED status
1798 // Make no checks for correct RX_ID, since
1799 // all we need to conform ABTS ACC is the OX_ID.
1800 // Verify that the d_id matches!
1802 ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
1803 // printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n",
1804 // fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
1805 // Exchanges->fcExchange[ExchangeID].status);
1806 if (ExchangeID < TACH_SEST_LEN) // x_ID makes sense
1808 // Does "target" exchange 24-bit port_id match?
1809 // (See "NOTE" above for handling Intiator AND Target in
1810 // the same device driver)
1811 // First, if this is a target response, then we originated
1812 // (initiated) it with BLS_ABTS:
1814 if ((Exchanges->fcExchange[ExchangeID].type == BLS_ABTS) &&
1815 // Second, does the source of this ACC match the destination
1816 // of who we originally sent it to?
1817 ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
1818 cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
1822 // Check for BLS {ABTS? (Abort Sequence)} ReJecT
1823 else if ((fchs->d_id & 0x8F000000) == 0x85000000) {
1824 // target has responded with RJT for our ABTS;
1825 // complete the indicated exchange with ABORTED status
1826 // Make no checks for correct RX_ID, since
1827 // all we need to conform ABTS ACC is the OX_ID.
1828 // Verify that the d_id matches!
1830 ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
1831 // printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n",
1832 // fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
1834 if (ExchangeID < TACH_SEST_LEN) // x_ID makes sense
1836 // Does "target" exchange 24-bit port_id match?
1837 // (See "NOTE" above for handling Intiator AND Target in
1838 // the same device driver)
1839 // First, if this is a target response, then we originated
1840 // (initiated) it with BLS_ABTS:
1842 if ((Exchanges->fcExchange[ExchangeID].type == BLS_ABTS)
1845 // Second, does the source of this ACC match the destination
1846 // of who we originally sent it to?
1847 ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
1848 // YES! NOTE: There is a bug in CPQ's RA-4000 box
1849 // where the "reason code" isn't returned in the payload
1850 // For now, simply presume the reject is because the target
1851 // already completed the exchange...
1853 // printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
1854 cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
1857 } // end of ABTS check
1858 } // end of Basic Link Service Request
1862 printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n", fcLQ->Qitem[QNdx].Type, fcLQ->Qitem[QNdx].Type);
1868 // Function for Port Discovery necessary after every FC
1869 // initialization (e.g. LIP).
1870 // Also may be called if from Fabric Name Service logic.
1872 static void SendLogins(CPQFCHBA * dev, __u32 * FabricPortIds)
1874 PTACHYON fcChip = &dev->fcChip;
1875 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1877 TachFCHDR_GCMND fchs; // copy fields for transmission
1881 PFC_LOGGEDIN_PORT pLoggedInPort;
1882 __u32 PortIds[number_of_al_pa];
1883 int NumberOfPorts = 0;
1885 // We're going to presume (for now) that our limit of Fabric devices
1886 // is the same as the number of alpa on a private loop (126 devices).
1887 // (Of course this could be changed to support however many we have
1889 memset(&PortIds[0], 0, sizeof(PortIds));
1891 // First, check if this login is for our own Link Initialization
1892 // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
1893 // from a switch. If we are logging into Fabric devices, we'll
1894 // have a non-NULL FabricPortId pointer
1896 if (FabricPortIds != NULL) // may need logins
1901 // port IDs From NSR payload; byte swap needed?
1902 BigEndianSwap((u8 *) FabricPortIds, (u8 *) & PortIds[i], 4);
1904 // printk("FPortId[%d] %Xh ", i, PortIds[i]);
1905 if (PortIds[i] & 0x80000000)
1908 PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
1909 // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
1910 // erroneously use ALPA 0.
1911 if (PortIds[i]) // need non-zero port_id...
1914 if (i >= number_of_al_pa) // (in)sanity check
1916 FabricPortIds++; // next...
1920 // printk("NumberOf Fabric ports %d", NumberOfPorts);
1922 else // need to send logins on our "local" link
1924 // are we a loop port? If so, check for reception of LILP frame,
1925 // and if received use it (SANMark requirement)
1926 if (fcChip->Options.LILPin) {
1928 // sanity check on number of ALPAs from LILP frame...
1929 // For format of LILP frame, see FC-AL specs or
1930 // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
1931 // First byte is number of ALPAs
1932 i = fcChip->LILPmap[0] >= (32 * 4) ? 32 * 4 : fcChip->LILPmap[0];
1934 // printk(" LILP alpa count %d ", i);
1936 PortIds[j] = fcChip->LILPmap[1 + j];
1941 else // have to send login to everybody
1944 i = number_of_al_pa;
1947 PortIds[j] = valid_al_pa[j]; // all legal ALPAs
1954 // Now we have a copy of the port_ids (and how many)...
1955 for (i = 0; i < NumberOfPorts; i++) {
1956 // 24-bit FC Port ID
1957 fchs.s_id = PortIds[i]; // note: only 8-bits used for ALPA
1958 // don't log into ourselves (Linux Scsi disk scan will stop on
1959 // no TARGET support error on us, and quit trying for rest of devices)
1960 if ((fchs.s_id & 0xFF) == (fcChip->Registers.my_al_pa & 0xFF))
1962 // fabric login needed?
1963 if ((fchs.s_id == 0) || (fcChip->Options.fabric == 1)) {
1964 fcChip->Options.flogi = 1; // fabric needs longer for login
1965 // Do we need FLOGI or FDISC?
1966 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search SCSI Nexus
1967 0xFFFFFC, // search linked list for Fabric port_id
1968 NULL, // don't search WWN
1969 NULL); // (don't care about end of list)
1971 if (pLoggedInPort) // If found, we have prior experience with
1972 // this port -- check whether PDISC is needed
1974 if (pLoggedInPort->flogi) {
1975 // does the switch support FDISC?? (FLOGI for now...)
1976 loginType = ELS_FLOGI; // prior FLOGI still valid
1978 loginType = ELS_FLOGI; // expired FLOGI
1979 } else // first FLOGI?
1980 loginType = ELS_FLOGI;
1982 fchs.s_id = 0xFFFFFE; // well known F_Port address
1984 // Fabrics are not required to support FDISC, and
1985 // it's not clear if that helps us anyway, since
1986 // we'll want a Name Service Request to re-verify
1987 // visible devices...
1988 // Consequently, we always want our upper 16 bit
1989 // port_id to be zero (we'll be rejected if we
1990 // use our prior port_id if we've been plugged into
1991 // a different switch port).
1992 // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
1993 // If our ALPA is 55h for instance, we want the FC frame
1994 // s_id to be 0x000055, while Tach's my_al_pa register
1995 // must be 0x000155, to force an OPN at ALPA 0
1996 // (the Fabric port)
1997 fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
1998 writel(fcChip->Registers.my_al_pa | 0x0100, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
2000 else // not FLOGI...
2002 // should we send PLOGI or PDISC? Check if any prior port_id
2003 // (e.g. alpa) completed a PLOGI/PRLI exchange by checking
2006 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search SCSI Nexus
2007 fchs.s_id, // search linked list for al_pa
2008 NULL, // don't search WWN
2009 NULL); // (don't care about end of list)
2011 if (pLoggedInPort) // If found, we have prior experience with
2012 // this port -- check whether PDISC is needed
2014 if (pLoggedInPort->pdisc) {
2015 loginType = ELS_PDISC; // prior PLOGI and PRLI maybe still valid
2017 loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
2018 } else // never talked to this port_id before
2019 loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
2022 ulStatus = cpqfcTSBuildExchange(dev, loginType, // e.g. PLOGI
2023 &fchs, // no incoming frame (we are originator)
2024 NULL, // no data (no scatter/gather list)
2025 &ExchangeID); // fcController->fcExchanges index, -1 if failed
2027 if (!ulStatus) // Exchange setup OK?
2029 ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
2031 // submitted to Tach's Outbound Que (ERQ PI incremented)
2032 // waited for completion for ELS type (Login frames issued
2035 if (loginType == ELS_PDISC) {
2036 // now, we really shouldn't Revalidate SEST exchanges until
2037 // we get an ACC reply from our target and verify that
2038 // the target address/WWN is unchanged. However, when a fast
2039 // target gets the PDISC, they can send SEST Exchange data
2040 // before we even get around to processing the PDISC ACC.
2041 // Consequently, we lose the I/O.
2042 // To avoid this, go ahead and Revalidate when the PDISC goes
2043 // out, anticipating that the ACC will be truly acceptable
2044 // (this happens 99.9999....% of the time).
2045 // If we revalidate a SEST write, and write data goes to a
2046 // target that is NOT the one we originated the WRITE to,
2047 // that target is required (FCP-SCSI specs, etc) to discard
2050 // Re-validate SEST entries (Tachyon hardware assists)
2051 RevalidateSEST(dev->HostAdapter, pLoggedInPort);
2052 //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
2054 } else // give up immediately on error
2057 printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus);
2063 if (fcChip->Registers.FMstatus.value & 0x080) // LDn during Port Disc.
2065 ulStatus = LNKDWN_OSLS;
2067 printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
2071 // Check the exchange for bad status (i.e. FrameTimeOut),
2072 // and complete on bad status (most likely due to BAD_ALPA)
2073 // on LDn, DPC function may already complete (ABORT) a started
2074 // exchange, so check type first (type = 0 on complete).
2075 if (Exchanges->fcExchange[ExchangeID].status) {
2077 printk("completing x_ID %X on status %Xh\n", ExchangeID, Exchanges->fcExchange[ExchangeID].status);
2079 cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
2081 } else // Xchange setup failed...
2084 printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
2090 // set the event signifying that all ALPAs were sent out.
2092 printk("SendLogins: PortDiscDone\n");
2094 dev->PortDiscDone = 1;
2095 // TL/TS UG, pg. 184
2096 // 0x0065 = 100ms for RT_TOV
2097 // 0x01f5 = 500ms for ED_TOV
2098 fcChip->Registers.ed_tov.value = 0x006501f5L;
2099 writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
2101 // set the LP_TOV back to ED_TOV (i.e. 500 ms)
2102 writel(0x00000010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
2104 printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", ExchangeID, fchs.s_id, ulStatus);
2106 LEAVE("SendLogins");
2110 // for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
2111 // D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
2112 static void ScsiReportLunsDone(Scsi_Cmnd * Cmnd)
2114 struct Scsi_Host *shpnt = Cmnd->host;
2115 CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
2116 PTACHYON fcChip = &dev->fcChip;
2117 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2118 PFC_LOGGEDIN_PORT pLoggedInPort;
2121 u32 x_ID = 0xFFFFFFFF;
2122 u8 *ucBuff = Cmnd->request_buffer;
2124 // printk("cpqfcTS: ReportLunsDone \n");
2125 // first, we need to find the Exchange for this command,
2126 // so we can find the fcPort struct to make the indicated
2128 for (i = 0; i < TACH_SEST_LEN; i++) {
2129 if (Exchanges->fcExchange[i].type // exchange defined?
2130 && (Exchanges->fcExchange[i].Cmnd == Cmnd)) // matches?
2133 x_ID = i; // found exchange!
2137 if (x_ID == 0xFFFFFFFF) {
2138 // printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
2139 goto Done; // Report Luns FC Exchange gone;
2140 // exchange probably Terminated by Implicit logout
2143 // search linked list for the port_id we sent INQUIRY to
2144 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // DON'T search Scsi Nexus (we will set it)
2145 Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF, NULL, // DON'T search linked list for FC WWN
2146 NULL); // DON'T care about end of list
2148 if (!pLoggedInPort) {
2149 // printk("cpqfcTS: ReportLuns failed - device gone\n");
2150 goto Done; // error! can't find logged in Port
2152 LunListLen = ucBuff[3];
2153 LunListLen += ucBuff[2] >> 8;
2155 if (!LunListLen) // failed
2157 // generically speaking, a soft error means we should retry...
2158 if ((Cmnd->result >> 16) == DID_SOFT_ERROR) {
2159 if (((Cmnd->sense_buffer[2] & 0xF) == 0x6) && (Cmnd->sense_buffer[12] == 0x29)) // Sense Code "reset"
2161 TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[x_ID].fchs;
2162 // did we fail because of "check condition, device reset?"
2163 // e.g. the device was reset (i.e., at every power up)
2164 // retry the Report Luns
2166 // who are we sending it to?
2167 // we know this because we have a copy of the command
2168 // frame from the original Report Lun command -
2169 // switch the d_id/s_id fields, because the Exchange Build
2170 // context is "reply to source".
2172 fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
2173 cpqfcTSPutLinkQue(dev, SCSI_REPORT_LUNS, fchs);
2175 } else // probably, the device doesn't support Report Luns
2176 pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;
2177 } else // we have LUN info - check VSA mode
2179 // for now, assume all LUNs will have same addr mode
2180 // for VSA, payload byte 8 will be 0x40; otherwise, 0
2181 pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];
2183 // Since we got a Report Luns answer, set lun masking flag
2184 pLoggedInPort->ScsiNexus.LunMasking = 1;
2186 if (LunListLen > 8 * CPQFCTS_MAX_LUN) // We expect CPQFCTS_MAX_LUN max
2187 LunListLen = 8 * CPQFCTS_MAX_LUN;
2190 printk("Device WWN %08X%08X Reports Luns @: ",
2191 (u32)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
2192 (u32)(pLoggedInPort->u.liWWN>>32));
2194 for( i=8; i<LunListLen+8; i+=8)
2196 printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
2201 // Since the device was kind enough to tell us where the
2202 // LUNs are, lets ensure they are contiguous for Linux's
2203 // SCSI driver scan, which expects them to start at 0.
2204 // Since Linux only supports 8 LUNs, only copy the first
2205 // eight from the report luns command
2207 // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
2208 // LUNs 4001, 4004, etc., because other LUNs are masked from
2209 // this HBA (owned by someone else). We'll make those appear as
2210 // LUN 0, 1... to Linux
2213 int AppendLunList = 0;
2214 // Walk through the LUN list. The 'j' array number is
2215 // Linux's lun #, while the value of .lun[j] is the target's
2217 // Once we build a LUN list, it's possible for a known device
2218 // to go offline while volumes (LUNs) are added. Later,
2219 // the device will do another PLOGI ... Report Luns command,
2220 // and we must not alter the existing Linux Lun map.
2221 // (This will be very rare).
2222 for (j = 0; j < CPQFCTS_MAX_LUN; j++) {
2223 if (pLoggedInPort->ScsiNexus.lun[j] != 0xFF) {
2228 if (AppendLunList) {
2231 // printk("cpqfcTS: AppendLunList\n");
2233 // If we get a new Report Luns, we cannot change
2234 // any existing LUN mapping! (Only additive entry)
2235 // For all LUNs in ReportLun list
2236 // if RL lun != ScsiNexus lun
2237 // if RL lun present in ScsiNexus lun[], continue
2238 // else find ScsiNexus lun[]==FF and add, continue
2240 for (i = 8, j = 0; i < LunListLen + 8 && j < CPQFCTS_MAX_LUN; i += 8, j++) {
2241 if (pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i + 1]) {
2242 // something changed from the last Report Luns
2243 printk(" cpqfcTS: Report Lun change!\n");
2244 for (k = 0, FreeLunIndex = CPQFCTS_MAX_LUN; k < CPQFCTS_MAX_LUN; k++) {
2245 if (pLoggedInPort->ScsiNexus.lun[k] == 0xFF) {
2249 if (pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i + 1])
2250 break; // we already masked this lun
2252 if (k >= CPQFCTS_MAX_LUN) {
2253 printk(" no room for new LUN %d\n", ucBuff[i + 1]);
2254 } else if (k == FreeLunIndex) // need to add LUN
2256 pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i + 1];
2257 // printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
2260 // lun already known
2265 // print out the new list...
2266 for (j = 0; j < CPQFCTS_MAX_LUN; j++) {
2267 if (pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
2269 // printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2272 // printk("Linux SCSI LUNs[] -> Device LUNs: ");
2273 // first time - this is easy
2274 for (i = 8, j = 0; i < LunListLen + 8 && j < CPQFCTS_MAX_LUN; i += 8, j++) {
2275 pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i + 1];
2276 // printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2286 static void call_scsi_done(Scsi_Cmnd * Cmnd)
2288 // We have to reinitialize sent_command here, so the scsi-mid
2289 // layer won't re-use the scsi command leaving it set incorrectly.
2290 // (incorrectly for our purposes...it's normally unused.)
2292 if (Cmnd->SCp.sent_command != 0) { // was it a passthru?
2293 Cmnd->SCp.sent_command = 0;
2294 Cmnd->result &= 0xff00ffff;
2295 Cmnd->result |= (DID_PASSTHROUGH << 16); // prevents retry
2297 if (Cmnd->scsi_done != NULL)
2298 (*Cmnd->scsi_done) (Cmnd);
2301 // After successfully getting a "Process Login" (PRLI) from an
2302 // FC port, we want to Discover the LUNs so that we know the
2303 // addressing type (e.g., FCP-SCSI Volume Set Address, Peripheral
2304 // Unit Device), and whether SSP (Selective Storage Presentation or
2305 // Lun Masking) has made the LUN numbers non-zero based or
2306 // non-contiguous. To remain backward compatible with the SCSI-2
2307 // driver model, which expects a contiguous LUNs starting at 0,
2308 // will use the ReportLuns info to map from "device" to "Linux"
2310 static void IssueReportLunsCommand(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
2312 PTACHYON fcChip = &dev->fcChip;
2313 PFC_LOGGEDIN_PORT pLoggedInPort;
2319 if (!dev->PortDiscDone) // cleared by LDn
2321 printk("Discard Q'd ReportLun command\n");
2324 // find the device (from port_id) we're talking to
2325 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // DON'T search Scsi Nexus
2326 fchs->s_id & 0xFFFFFF, NULL, // DON'T search linked list for FC WWN
2327 NULL); // DON'T care about end of list
2328 if (pLoggedInPort) // we'd BETTER find it!
2332 if (!(pLoggedInPort->fcp_info & TARGET_FUNCTION))
2333 goto Done; // forget it - FC device not a "target"
2335 // now use the port's Scsi Command buffer for the
2336 // Report Luns Command
2338 Cmnd = &pLoggedInPort->ScsiCmnd;
2339 ucBuff = pLoggedInPort->ReportLunsPayload;
2341 memset(Cmnd, 0, sizeof(Scsi_Cmnd));
2342 memset(ucBuff, 0, REPORT_LUNS_PL);
2344 Cmnd->scsi_done = ScsiReportLunsDone;
2345 Cmnd->host = dev->HostAdapter;
2347 Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload;
2348 Cmnd->request_bufflen = REPORT_LUNS_PL;
2350 Cmnd->cmnd[0] = 0xA0;
2351 Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
2352 Cmnd->cmnd[9] = (u8) REPORT_LUNS_PL;
2355 Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
2356 Cmnd->target = pLoggedInPort->ScsiNexus.target;
2359 ulStatus = cpqfcTSBuildExchange(dev, SCSI_IRE, fchs, Cmnd, // buffer for Report Lun data
2360 &x_ID); // fcController->fcExchanges index, -1 if failed
2362 if (!ulStatus) // Exchange setup?
2364 ulStatus = cpqfcTSStartExchange(dev, x_ID);
2366 // submitted to Tach's Outbound Que (ERQ PI incremented)
2367 // waited for completion for ELS type (Login frames issued
2370 // check reason for Exchange not being started - we might
2371 // want to Queue and start later, or fail with error
2376 else // Xchange setup failed...
2377 printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
2378 } else // like, we just got a PRLI ACC, and now the port is gone?
2380 printk(" can't send ReportLuns - no login for port_id %Xh\n", fchs->s_id & 0xFFFFFF);
2385 static void CompleteBoardLockCmnd(CPQFCHBA * dev)
2388 for (i = CPQFCTS_REQ_QUEUE_LEN - 1; i >= 0; i--) {
2389 if (dev->BoardLockCmnd[i] != NULL) {
2390 Scsi_Cmnd *Cmnd = dev->BoardLockCmnd[i];
2391 dev->BoardLockCmnd[i] = NULL;
2392 Cmnd->result = (DID_SOFT_ERROR << 16); // ask for retry
2393 // printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
2394 // i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
2395 call_scsi_done(Cmnd);
2400 // runs every 1 second for FC exchange timeouts and implicit FC device logouts
2402 void cpqfcTSheartbeat(unsigned long ptr)
2404 CPQFCHBA *dev = (CPQFCHBA *) ptr;
2405 PTACHYON fcChip = &dev->fcChip;
2406 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2407 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
2409 unsigned long flags;
2410 DECLARE_MUTEX_LOCKED(BoardLock);
2414 if (dev->BoardLock) // Worker Task Running?
2417 spin_lock_irqsave(&io_request_lock, flags); // STOP _que function
2421 dev->BoardLock = &BoardLock; // stop Linux SCSI command queuing
2423 // release the IO lock (and re-enable interrupts)
2424 spin_unlock_irqrestore(&io_request_lock, flags);
2426 // Ensure no contention from _quecommand or Worker process
2427 CPQ_SPINLOCK_HBA(dev)
2431 disable_irq(dev->HostAdapter->irq); // our IRQ
2433 // Complete the "bad target" commands (normally only used during
2434 // initialization, since we aren't supposed to call "scsi_done"
2435 // inside the queuecommand() function). (this is overly contorted,
2436 // scsi_done can be safely called from queuecommand for
2437 // this bad target case. May want to simplify this later)
2439 for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {
2440 if (dev->BadTargetCmnd[i]) {
2441 Scsi_Cmnd *Cmnd = dev->BadTargetCmnd[i];
2442 dev->BadTargetCmnd[i] = NULL;
2443 Cmnd->result = (DID_BAD_TARGET << 16);
2444 call_scsi_done(Cmnd);
2450 // logged in ports -- re-login check (ports required to verify login with
2451 // PDISC after LIP within 2 secs)
2453 // prevent contention
2454 while (pLoggedInPort) // for all ports which are expecting
2455 // PDISC after the next LIP, check to see if
2458 // Important: we only detect "timeout" condition on TRANSITION
2459 // from non-zero to zero
2460 if (pLoggedInPort->LOGO_timer) // time-out "armed"?
2462 if (!(--pLoggedInPort->LOGO_timer)) // DEC from 1 to 0?
2464 // LOGOUT time! Per PLDA, PDISC hasn't complete in 2 secs, so
2465 // issue LOGO request and destroy all I/O with other FC port(s).
2468 printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
2469 printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n",
2470 pLoggedInPort->ScsiNexus.channel,
2471 pLoggedInPort->ScsiNexus.target,
2472 pLoggedInPort->port_id,
2473 (u32)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
2474 (u32)(pLoggedInPort->u.liWWN>>32));
2476 cpqfcTSImplicitLogout(dev, pLoggedInPort);
2479 // else simply decremented - maybe next time...
2481 pLoggedInPort = pLoggedInPort->pNextPort;
2484 // ************ FC EXCHANGE TIMEOUT CHECK **************
2486 for (i = 0; i < TACH_MAX_XID; i++) {
2487 if (Exchanges->fcExchange[i].type) // exchange defined?
2490 if (!Exchanges->fcExchange[i].timeOut) // time expired
2492 // Set Exchange timeout status
2493 Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
2495 if (i >= TACH_SEST_LEN) // Link Service Exchange
2497 cpqfcTSCompleteExchange(dev->PciDev, fcChip, i); // Don't "abort" LinkService
2499 else // SEST Exchange TO -- may post ABTS to Worker Thread Que
2501 // (Make sure we don't keep timing it out; let other functions
2502 // complete it or set the timeOut as needed)
2503 Exchanges->fcExchange[i].timeOut = 30000; // seconds default
2505 if (Exchanges->fcExchange[i].type & (BLS_ABTS | BLS_ABTS_ACC)) {
2506 // For BLS_ABTS*, an upper level might still have
2507 // an outstanding command waiting for low-level completion.
2508 // Also, in the case of a WRITE, we MUST get confirmation
2509 // of either ABTS ACC or RJT before re-using the Exchange.
2510 // It's possible that the RAID cache algorithm can hang
2511 // if we fail to complete a WRITE to a LBA, when a READ
2512 // comes later to that same LBA. Therefore, we must
2513 // ensure that the target verifies receipt of ABTS for
2516 printk("~TO Q'd ABTS (x_ID %Xh)~ ", i);
2517 // TriggerHBA( fcChip->Registers.ReMapMemBase);
2519 // On timeout of a ABTS exchange, check to
2520 // see if the FC device has a current valid login.
2521 // If so, restart it.
2522 pLoggedInPort = fcFindLoggedInPort(fcChip, Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
2523 0, // DON'T search linked list for FC port id
2524 NULL, // DON'T search linked list for FC WWN
2525 NULL); // DON'T care about end of list
2527 if (pLoggedInPort) // device exists?
2529 if (pLoggedInPort->prli) // logged in for FCP-SCSI?
2531 // attempt to restart the ABTS
2532 printk(" ~restarting ABTS~ ");
2533 cpqfcTSStartExchange(dev, i);
2537 } else // not an ABTS
2540 // We expect the WorkerThread to change the xchng type to
2541 // abort and set appropriate timeout.
2542 cpqfcTSPutLinkQue(dev, BLS_ABTS, &i); // timed-out
2545 } else // time not expired...
2547 // decrement timeout: 1 or more seconds left
2548 --Exchanges->fcExchange[i].timeOut;
2553 enable_irq(dev->HostAdapter->irq);
2554 CPQ_SPINUNLOCK_HBA(dev)
2555 dev->BoardLock = NULL; // Linux SCSI commands may be queued
2556 // Now, complete any Cmnd we Q'd up while BoardLock was held
2557 CompleteBoardLockCmnd(dev);
2558 // restart the timer to run again (1 sec later)
2560 mod_timer(&dev->cpqfcTStimer, jiffies + HZ);
2566 // put valid FC-AL physical address in spec order
2567 static const u8 valid_al_pa[] = {
2568 0xef, 0xe8, 0xe4, 0xe2,
2569 0xe1, 0xE0, 0xDC, 0xDA,
2570 0xD9, 0xD6, 0xD5, 0xD4,
2571 0xD3, 0xD2, 0xD1, 0xCe,
2572 0xCd, 0xCc, 0xCb, 0xCa,
2573 0xC9, 0xC7, 0xC6, 0xC5,
2574 0xC3, 0xBc, 0xBa, 0xB9,
2575 0xB6, 0xB5, 0xB4, 0xB3,
2576 0xB2, 0xB1, 0xae, 0xad,
2577 0xAc, 0xAb, 0xAa, 0xA9,
2579 0xA7, 0xA6, 0xA5, 0xA3,
2580 0x9f, 0x9e, 0x9d, 0x9b,
2581 0x98, 0x97, 0x90, 0x8f,
2582 0x88, 0x84, 0x82, 0x81,
2583 0x80, 0x7c, 0x7a, 0x79,
2584 0x76, 0x75, 0x74, 0x73,
2585 0x72, 0x71, 0x6e, 0x6d,
2586 0x6c, 0x6b, 0x6a, 0x69,
2587 0x67, 0x66, 0x65, 0x63,
2588 0x5c, 0x5a, 0x59, 0x56,
2590 0x55, 0x54, 0x53, 0x52,
2591 0x51, 0x4e, 0x4d, 0x4c,
2592 0x4b, 0x4a, 0x49, 0x47,
2593 0x46, 0x45, 0x43, 0x3c,
2594 0x3a, 0x39, 0x36, 0x35,
2595 0x34, 0x33, 0x32, 0x31,
2596 0x2e, 0x2d, 0x2c, 0x2b,
2597 0x2a, 0x29, 0x27, 0x26,
2598 0x25, 0x23, 0x1f, 0x1E,
2599 0x1d, 0x1b, 0x18, 0x17,
2601 0x10, 0x0f, 8, 4, 2, 1
2602 }; // ALPA 0 (Fabric) is special case
2604 const int number_of_al_pa = (sizeof(valid_al_pa));
2606 // this function looks up an al_pa from the table of valid al_pa's
2607 // we decrement from the last decimal loop ID, because soft al_pa
2608 // (our typical case) are assigned with highest priority (and high al_pa)
2609 // first. See "In-Depth FC-AL", R. Kembel pg. 38
2611 // al_pa - 24 bit port identifier (8 bit al_pa on private loop)
2613 // Loop ID - serves are index to array of logged in ports
2614 // -1 - invalid al_pa (not all 8 bit values are legal)
2617 static int GetLoopID(u32 al_pa)
2621 for (i = number_of_al_pa - 1; i >= 0; i--) // dec.
2623 if (valid_al_pa[i] == (u8) al_pa) // take lowest 8 bits
2624 return i; // success - found valid al_pa; return decimal LoopID
2626 return -1; // failed - not found
2631 // Search the singly (forward) linked list "fcPorts" looking for
2632 // either the SCSI target (if != -1), port_id (if not NULL),
2633 // or WWN (if not null), in that specific order.
2634 // If we find a SCSI nexus (from Cmnd arg), set the SCp.phase
2635 // field according to VSA or PDU
2637 // Ptr to logged in port struct if found
2638 // (NULL if not found)
2639 // pLastLoggedInPort - ptr to last struct (for adding new ones)
2641 PFC_LOGGEDIN_PORT fcFindLoggedInPort(PTACHYON fcChip, Scsi_Cmnd * Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
2642 u32 port_id, // search linked list for al_pa, or
2643 u8 wwn[8], // search linked list for WWN, or...
2644 PFC_LOGGEDIN_PORT * pLastLoggedInPort)
2646 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
2647 u8 target_id_valid = 0;
2648 u8 port_id_valid = 0;
2654 target_id_valid = 1;
2656 else if (port_id) // note! 24-bit NULL address is illegal
2660 if (wwn) // non-null arg? (OK to pass NULL when not searching WWN)
2662 for (i = 0; i < 8; i++) // valid WWN passed? NULL WWN invalid
2665 wwn_valid = 1; // any non-zero byte makes (presumably) valid
2669 // check other options ...
2672 // In case multiple search options are given, we use a priority
2674 // While valid pLoggedIn Ptr
2675 // If port_id is valid
2676 // if port_id matches, return Ptr
2678 // if wwn matches, return Ptr
2681 // Return NULL (not found)
2684 while (pLoggedInPort) // NULL marks end of list (1st ptr always valid)
2686 if (pLastLoggedInPort) // caller's pointer valid?
2687 *pLastLoggedInPort = pLoggedInPort; // end of linked list
2689 if (target_id_valid) {
2690 // check Linux Scsi Cmnd for channel/target Nexus match
2691 // (all luns are accessed through matching "pLoggedInPort")
2692 if ((pLoggedInPort->ScsiNexus.target == Cmnd->target)
2693 && (pLoggedInPort->ScsiNexus.channel == Cmnd->channel)) {
2694 // For "passthru" modes, the IOCTL caller is responsible
2695 // for setting the FCP-LUN addressing
2696 if (!Cmnd->SCp.sent_command) // NOT passthru?
2699 // set the FCP-LUN addressing type
2700 Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;
2702 // set the Device Type we got from the snooped INQUIRY string
2703 Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
2705 // handle LUN masking; if not "default" (illegal) lun value,
2706 // the use it. These lun values are set by a successful
2707 // Report Luns command
2708 if (pLoggedInPort->ScsiNexus.LunMasking == 1) {
2709 // we KNOW all the valid LUNs... 0xFF is invalid!
2710 if (Cmnd->lun > sizeof(pLoggedInPort->ScsiNexus.lun)){
2711 // printk("cpqfcTS FATAL: Invalid LUN index !!!!\n ");
2714 Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
2715 if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
2717 // printk("xlating lun %d to 0x%02x\n", Cmnd->lun,
2718 // pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
2720 Cmnd->SCp.have_data_in = Cmnd->lun; // Linux & target luns match
2726 if (port_id_valid) // look for alpa first
2728 if (pLoggedInPort->port_id == port_id)
2731 if (wwn_valid) // look for wwn second
2734 if (!memcmp(&pLoggedInPort->u.ucWWN[0], &wwn[0], 8)) {
2735 // all 8 bytes of WWN match
2740 pLoggedInPort = pLoggedInPort->pNextPort; // try next port
2743 return pLoggedInPort;
2747 // We need to examine the SEST table and re-validate
2748 // any open Exchanges for this LoggedInPort
2749 // To make Tachyon pay attention, Freeze FCP assists,
2750 // set VAL bits, Unfreeze FCP assists
2751 static void RevalidateSEST(struct Scsi_Host *shpnt, PFC_LOGGEDIN_PORT pLoggedInPort)
2753 CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
2754 PTACHYON fcChip = &dev->fcChip;
2755 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2760 // re-validate any SEST exchanges that are permitted
2761 // to survive the link down (e.g., good PDISC performed)
2762 for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
2764 // If the SEST entry port_id matches the pLoggedInPort,
2765 // we need to re-validate
2766 if ((Exchanges->fcExchange[x_ID].type == SCSI_IRE)
2767 || (Exchanges->fcExchange[x_ID].type == SCSI_IWE)) {
2768 if ((Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) == pLoggedInPort->port_id) // (24-bit port ID)
2770 // printk(" re-val xID %Xh ", x_ID);
2771 if (!TachFroze) // freeze if not already frozen
2772 TachFroze |= FreezeTach(dev);
2773 fcChip->SEST->u[x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
2778 fcChip->UnFreezeTachyon(fcChip, 2); // both ERQ and FCP assists
2783 // Complete an Linux Cmnds that we Queued because
2784 // our FC link was down (cause immediate retry)
2786 static void UnblockScsiDevice(struct Scsi_Host *shpnt, PFC_LOGGEDIN_PORT pLoggedInPort)
2788 // Scsi_Device *sdev = shpnt->host_queue;
2789 CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
2790 Scsi_Cmnd **SCptr = &dev->LinkDnCmnd[0];
2794 // if the device was previously "blocked", make sure
2795 // we unblock it so Linux SCSI will resume
2797 pLoggedInPort->device_blocked = 0; // clear our flag
2799 // check the Link Down command ptr buffer;
2800 // we can complete now causing immediate retry
2801 for (indx = 0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++) {
2802 if (*SCptr != NULL) // scsi command to complete?
2804 #ifdef DUMMYCMND_DBG
2805 printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr, indx);
2809 // Are there any Q'd commands for this target?
2810 if ((Cmnd->target == pLoggedInPort->ScsiNexus.target)
2811 && (Cmnd->channel == pLoggedInPort->ScsiNexus.channel)) {
2812 Cmnd->result = (DID_SOFT_ERROR << 16); // force retry
2813 if (Cmnd->scsi_done == NULL) {
2814 printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n", pLoggedInPort->port_id);
2815 Cmnd->SCp.sent_command = 0;
2817 call_scsi_done(Cmnd);
2818 *SCptr = NULL; // free this slot for next use
2827 static void SetLoginFields(PFC_LOGGEDIN_PORT pLoggedInPort, TachFCHDR_GCMND * fchs, u8 PDisc, u8 Originator)
2829 LOGIN_PAYLOAD logi; // FC-PH Port Login
2830 PRLI_REQUEST prli; // copy for BIG ENDIAN switch
2836 BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
2838 pLoggedInPort->Originator = Originator;
2839 pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
2841 switch (fchs->pl[0] & 0xffff) {
2842 case 0x00000002: // PLOGI or PDISC ACCept?
2843 if (PDisc) // PDISC accept
2846 case 0x00000003: // ELS_PLOGI or ELS_PLOGI_ACC
2848 // Login BB_credit typically 0 for Tachyons
2849 pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
2851 // e.g. 128, 256, 1024, 2048 per FC-PH spec
2852 // We have to use this when setting up SEST Writes,
2853 // since that determines frame size we send.
2854 pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
2855 pLoggedInPort->plogi = 1;
2856 pLoggedInPort->pdisc = 0;
2857 pLoggedInPort->prli = 0; // ELS_PLOGI resets
2858 pLoggedInPort->flogi = 0; // ELS_PLOGI resets
2859 pLoggedInPort->logo = 0; // ELS_PLOGI resets
2860 pLoggedInPort->LOGO_counter = 0; // ELS_PLOGI resets
2861 pLoggedInPort->LOGO_timer = 0; // ELS_PLOGI resets
2863 // was this PLOGI to a Fabric?
2864 if (pLoggedInPort->port_id == 0xFFFFFC) // well know address
2865 pLoggedInPort->flogi = 1;
2868 for (i = 0; i < 8; i++) // copy the LOGIN port's WWN
2869 pLoggedInPort->u.ucWWN[i] = logi.port_name[i];
2872 ulBuff = (u32) pLoggedInPort->u.liWWN;
2873 if (pLoggedInPort->Originator)
2877 printk("PLOGI port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
2879 ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
2880 printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
2884 case 0x00000005: // ELS_LOGO (logout)
2885 pLoggedInPort->plogi = 0;
2886 pLoggedInPort->pdisc = 0;
2887 pLoggedInPort->prli = 0; // ELS_PLOGI resets
2888 pLoggedInPort->flogi = 0; // ELS_PLOGI resets
2889 pLoggedInPort->logo = 1; // ELS_PLOGI resets
2890 pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
2891 pLoggedInPort->LOGO_timer = 0;
2893 ulBuff = (u32) pLoggedInPort->u.liWWN;
2894 if (pLoggedInPort->Originator)
2898 printk("LOGO port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
2900 ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
2901 printk("%08Xh\n", ulBuff);
2906 case 0x00000050: // ELS_PDISC or ELS_PDISC_ACC
2907 pLoggedInPort->LOGO_timer = 0; // stop the time-out
2909 pLoggedInPort->prli = 1; // ready to accept FCP-SCSI I/O
2911 ulBuff = (u32) pLoggedInPort->u.liWWN;
2912 if (pLoggedInPort->Originator)
2916 printk("PDISC port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
2918 ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
2919 printk("%08Xh\n", ulBuff);
2923 case 0x1020L: // PRLI?
2924 case 0x1002L: // PRLI ACCept?
2925 BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & prli, sizeof(prli));
2927 pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
2928 pLoggedInPort->prli = 1; // PLOGI resets, PDISC doesn't
2930 pLoggedInPort->pdisc = 1; // expect to send (or receive) PDISC
2932 pLoggedInPort->LOGO_timer = 0; // will be set next LinkDown
2934 ulBuff = (u32) pLoggedInPort->u.liWWN;
2935 if (pLoggedInPort->Originator)
2939 printk("PRLI port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
2941 ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
2942 printk("%08Xh\n", ulBuff);
2949 static void BuildLinkServicePayload(PTACHYON fcChip, u32 type, void *payload)
2951 LOGIN_PAYLOAD *plogi; // FC-PH Port Login
2952 LOGIN_PAYLOAD PlogiPayload; // copy for BIG ENDIAN switch
2953 PRLI_REQUEST *prli; // FCP-SCSI Process Login
2954 PRLI_REQUEST PrliPayload; // copy for BIG ENDIAN switch
2955 LOGOUT_PAYLOAD *logo;
2956 LOGOUT_PAYLOAD LogoutPayload;
2957 // PRLO_REQUEST *prlo;
2958 // PRLO_REQUEST PrloPayload;
2959 REJECT_MESSAGE rjt, *prjt;
2961 memset(&PlogiPayload, 0, sizeof(PlogiPayload));
2962 plogi = &PlogiPayload; // load into stack buffer,
2963 // then BIG-ENDIAN switch a copy to caller
2965 switch (type) // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
2969 case ELS_PLOGI_ACC: // FC-PH PORT Login Accept
2970 case ELS_PLOGI: // FC-PH PORT Login
2971 case ELS_PDISC: // FC-PH2 Port Discovery - same payload as ELS_PLOGI
2972 plogi->login_cmd = LS_PLOGI;
2973 if (type == ELS_PDISC)
2974 plogi->login_cmd = LS_PDISC;
2975 else if (type == ELS_PLOGI_ACC)
2976 plogi->login_cmd = LS_ACC;
2978 plogi->cmn_services.bb_credit = 0x00;
2979 plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
2980 plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
2981 plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
2982 plogi->cmn_services.common_features = CONTINUOSLY_INCREASING | RANDOM_RELATIVE_OFFSET;
2984 // fill in with World Wide Name based Port Name - 8 u8s
2985 // get from Tach registers WWN hi & lo
2986 LoadWWN(fcChip, plogi->port_name, 0);
2987 // fill in with World Wide Name based Node/Fabric Name - 8 u8s
2988 // get from Tach registers WWN hi & lo
2989 LoadWWN(fcChip, plogi->node_name, 1);
2991 // For Seagate Drives.
2993 plogi->cmn_services.common_features |= 0x800;
2994 plogi->cmn_services.rel_offset = 0xFE;
2995 plogi->cmn_services.concurrent_seq = 1;
2996 plogi->class1.service_options = 0x00;
2997 plogi->class2.service_options = 0x00;
2998 plogi->class3.service_options = CLASS_VALID;
2999 plogi->class3.initiator_control = 0x00;
3000 plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
3001 plogi->class3.recipient_control = ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
3002 plogi->class3.concurrent_sequences = 1;
3003 plogi->class3.open_sequences = 1;
3004 plogi->vendor_id[0] = 'C';
3005 plogi->vendor_id[1] = 'Q';
3006 plogi->vendor_version[0] = 'C';
3007 plogi->vendor_version[1] = 'Q';
3008 plogi->vendor_version[2] = ' ';
3009 plogi->vendor_version[3] = '0';
3010 plogi->vendor_version[4] = '0';
3011 plogi->vendor_version[5] = '0';
3013 // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
3014 if ((type == ELS_FLOGI) || (type == ELS_FDISC)) {
3015 if (type == ELS_FLOGI)
3016 plogi->login_cmd = LS_FLOGI;
3018 plogi->login_cmd = LS_FDISC;
3020 plogi->cmn_services.lowest_ver = 0x20;
3021 plogi->cmn_services.common_features = 0x0800;
3022 plogi->cmn_services.rel_offset = 0;
3023 plogi->cmn_services.concurrent_seq = 0;
3025 plogi->class3.service_options = 0x8800;
3026 plogi->class3.rx_data_size = 0;
3027 plogi->class3.recipient_control = 0;
3028 plogi->class3.concurrent_sequences = 0;
3029 plogi->class3.open_sequences = 0;
3031 // copy back to caller's buff, w/ BIG ENDIAN swap
3032 BigEndianSwap((u8 *) & PlogiPayload, payload, sizeof(PlogiPayload));
3035 case ELS_ACC: // generic Extended Link Service ACCept
3036 plogi->login_cmd = LS_ACC;
3037 // copy back to caller's buff, w/ BIG ENDIAN swap
3038 BigEndianSwap((u8 *) & PlogiPayload, payload, 4);
3041 case ELS_SCR: // Fabric State Change Registration
3043 SCR_PL scr; // state change registration
3045 memset(&scr, 0, sizeof(scr));
3047 scr.command = LS_SCR; // 0x62000000
3048 // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
3049 scr.function = 3; // 1 = Events detected by Fabric
3050 // 2 = N_Port detected registration
3051 // 3 = Full registration
3053 // copy back to caller's buff, w/ BIG ENDIAN swap
3054 BigEndianSwap((u8 *) & scr, payload, sizeof(SCR_PL));
3058 case FCS_NSR: // Fabric Name Service Request
3060 NSR_PL nsr; // Name Server Req. payload
3062 memset(&nsr, 0, sizeof(NSR_PL));
3064 // see Brocade Fabric Programming Guide,
3066 nsr.CT_Rev = 0x01000000;
3067 nsr.FCS_Type = 0xFC020000;
3068 nsr.Command_code = 0x01710000;
3071 // copy back to caller's buff, w/ BIG ENDIAN swap
3072 BigEndianSwap((u8 *) & nsr, payload, sizeof(NSR_PL));
3076 case ELS_LOGO: // FC-PH PORT LogOut
3077 logo = &LogoutPayload; // load into stack buffer,
3078 // then BIG-ENDIAN switch a copy to caller
3079 logo->cmd = LS_LOGO;
3080 // load the 3 u8s of the node name
3081 // (if private loop, upper two u8s 0)
3084 logo->n_port_identifier[0] = (u8) (fcChip->Registers.my_al_pa);
3085 logo->n_port_identifier[1] = (u8) (fcChip->Registers.my_al_pa >> 8);
3086 logo->n_port_identifier[2] = (u8) (fcChip->Registers.my_al_pa >> 16);
3087 // fill in with World Wide Name based Port Name - 8 u8s
3088 // get from Tach registers WWN hi & lo
3089 LoadWWN(fcChip, logo->port_name, 0);
3091 BigEndianSwap((u8 *) & LogoutPayload, payload, sizeof(LogoutPayload)); // 16 u8 struct
3094 case ELS_LOGO_ACC: // Logout Accept (FH-PH pg 149, table 74)
3095 logo = &LogoutPayload; // load into stack buffer,
3096 // then BIG-ENDIAN switch a copy to caller
3098 BigEndianSwap((u8 *) & LogoutPayload, payload, 4); // 4 u8 cmnd
3101 case ELS_RJT: // ELS_RJT link service reject (FH-PH pg 155)
3102 prjt = (REJECT_MESSAGE *) payload; // pick up passed data
3103 rjt.command_code = ELS_RJT;
3104 // reverse fields, because of Swap that follows...
3105 rjt.vendor = prjt->reserved; // vendor specific
3106 rjt.explain = prjt->reason; //
3107 rjt.reason = prjt->explain; //
3108 rjt.reserved = prjt->vendor; //
3109 // BIG-ENDIAN switch a copy to caller
3110 BigEndianSwap((u8 *) & rjt, payload, 8); // 8 u8 cmnd
3113 case ELS_PRLI_ACC: // Process Login ACCept
3114 case ELS_PRLI: // Process Login
3115 case ELS_PRLO: // Process Logout
3116 memset(&PrliPayload, 0, sizeof(PrliPayload));
3117 prli = &PrliPayload; // load into stack buffer,
3119 if (type == ELS_PRLI)
3120 prli->cmd = 0x20; // Login
3121 else if (type == ELS_PRLO)
3122 prli->cmd = 0x21; // Logout
3123 else if (type == ELS_PRLI_ACC) {
3124 prli->cmd = 0x02; // Login ACCept
3125 prli->valid = REQUEST_EXECUTED;
3127 prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
3128 prli->fcp_info = READ_XFER_RDY;
3129 prli->page_length = 0x10;
3130 prli->payload_length = 20;
3131 // Can be initiator AND target
3133 if (fcChip->Options.initiator)
3134 prli->fcp_info |= INITIATOR_FUNCTION;
3135 if (fcChip->Options.target)
3136 prli->fcp_info |= TARGET_FUNCTION;
3138 BigEndianSwap((u8 *) & PrliPayload, payload, prli->payload_length);
3141 default: // no can do - programming error
3142 printk(" BuildLinkServicePayload unknown!\n");
3147 // loads 8 u8s for PORT name or NODE name base on
3148 // controller's WWN.
3149 void LoadWWN(PTACHYON fcChip, u8 * dest, u8 type)
3154 case 0: // Port_Name
3155 bPtr = (u8 *) & fcChip->Registers.wwn_hi;
3156 for (i = 0; i < 4; i++)
3158 bPtr = (u8 *) & fcChip->Registers.wwn_lo;
3159 for (i = 4; i < 8; i++)
3162 case 1: // Node/Fabric _Name
3163 bPtr = (u8 *) & fcChip->Registers.wwn_hi;
3164 for (i = 0; i < 4; i++)
3166 bPtr = (u8 *) & fcChip->Registers.wwn_lo;
3167 for (i = 4; i < 8; i++)
3174 // We check the Port Login payload for required values. Note that
3175 // ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
3177 int verify_PLOGI(PTACHYON fcChip, TachFCHDR_GCMND * fchs, u32 * reject_explain)
3179 LOGIN_PAYLOAD login;
3181 // source, dest, len (should be mult. of 4)
3182 BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & login, sizeof(login));
3185 // if other port's highest supported version
3186 // is less than our lowest, and
3187 // if other port's lowest
3188 if (login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver || login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver) {
3189 *reject_explain = LS_RJT_REASON(LOGICAL_ERROR, OPTIONS_ERROR);
3190 return LOGICAL_ERROR;
3192 // Receive Data Field Size must be >=128
3194 if (login.cmn_services.bb_rx_size < 128) {
3195 *reject_explain = LS_RJT_REASON(LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
3196 return LOGICAL_ERROR;
3198 // Only check Class 3 params
3199 if (login.class3.service_options & CLASS_VALID) {
3200 if (login.class3.rx_data_size < 128) {
3201 *reject_explain = LS_RJT_REASON(LOGICAL_ERROR, INVALID_CSP);
3202 return LOGICAL_ERROR;
3204 if (login.class3.initiator_control & XID_REQUIRED) {
3205 *reject_explain = LS_RJT_REASON(LOGICAL_ERROR, INITIATOR_CTL_ERROR);
3206 return LOGICAL_ERROR;
3209 return 0; // success
3212 int verify_PRLI(TachFCHDR_GCMND * fchs, u32 * reject_explain)
3214 PRLI_REQUEST prli; // buffer for BIG ENDIAN
3216 // source, dest, len (should be mult. of 4)
3217 BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & prli, sizeof(prli));
3219 if (prli.fcp_info == 0) // i.e., not target or initiator?
3221 *reject_explain = LS_RJT_REASON(LOGICAL_ERROR, OPTIONS_ERROR);
3222 return LOGICAL_ERROR;
3225 return 0; // success
3228 // SWAP u8s as required by Fibre Channel (i.e. BIG ENDIAN)
3230 // source - ptr to LITTLE ENDIAN u32S
3231 // cnt - number of u8s to switch (should be mult. of u32)
3233 // dest - ptr to BIG ENDIAN copy
3237 void BigEndianSwap(u8 * source, u8 * dest, u16 cnt)
3241 source += 3; // start at MSB of 1st u32
3242 for (j = 0; j < cnt; j += 4, source += 4, dest += 4) // every u32
3244 for (i = 0; i < 4; i++) // every u8 in u32
3245 *(dest + i) = *(source - i);
3249 // Build FC Exchanges............
3251 static void buildFCPstatus(PTACHYON fcChip, u32 ExchangeID);
3252 static s32 FindFreeExchange(PTACHYON fcChip, u32 type);
3253 static u32 build_SEST_sgList(struct pci_dev *pcidev, u32 * SESTalPairStart, Scsi_Cmnd * Cmnd, u32 * sgPairs, PSGPAGES * sgPages_head); // link list of TL Ext. S/G pages from O/S Pool
3254 static int build_FCP_payload(Scsi_Cmnd * Cmnd, u8 * payload, u32 type, u32 fcp_dl);
3258 ERQ __________________
3259 | | / | Req_A_SFS_Len | ____________________
3260 |----------| / | Req_A_SFS_Addr |------->| Reserved |
3261 | IRB | / | Req_A_D_ID | | SOF EOF TimeStamp |
3262 |-----------/ | Req_A_SEST_Index |-+ | R_CTL | D_ID |
3263 | IRB | | Req_B... | | | CS_CTL| S_ID |
3264 |-----------\ | | | | TYPE | F_CTL |
3265 | IRB | \ | | | | SEQ_ID | SEQ_CNT |
3266 |----------- \ | | +-->+--| OX_ID | RX_ID |
3267 | | \ |__________________| | | RO |
3268 | | pl (payload/cmnd) |
3270 | |___________________|
3273 +-------------------------------------------+
3277 | SEST __________________ for FCP_DATA
3278 | | | / | | Hdr_Len | ____________________
3279 | |----------| / | Hdr_Addr_Addr |------->| Reserved |
3280 | | [0] | / |Remote_ID| RSP_Len| | SOF EOF TimeStamp |
3281 | |-----------/ | RSP_Addr |---+ | R_CTL | D_ID |
3282 +-> [1] | | | Buff_Off | | | CS_CTL| S_ID |
3283 |-----------\ |BuffIndex| Link | | | TYPE | F_CTL |
3284 | [2] | \ | Rsvd | RX_ID | | | SEQ_ID | SEQ_CNT |
3285 |----------- \ | Data_Len | | | OX_ID | RX_ID |
3286 | ... | \ | Exp_RO | | | RO |
3287 |----------| | Exp_Byte_Cnt | | |___________________|
3288 | SEST_LEN | +--| Len | |
3289 |__________| | | Address | |
3290 | | ... | | for FCP_RSP
3291 | |__________________| | ____________________
3293 | | SOF EOF TimeStamp |
3296 +--- local or extended | .... |
3297 scatter/gather lists
3298 defining upper-layer
3299 data (e.g. from user's App)
3303 // All TachLite commands must start with a SFS (Single Frame Sequence)
3304 // command. In the simplest case (a NOP Basic Link command),
3305 // only one frame header and ERQ entry is required. The most complex
3306 // case is the SCSI assisted command, which requires an ERQ entry,
3307 // SEST entry, and several frame headers and data buffers all
3308 // logically linked together.
3310 // dev - controller struct
3311 // type - PLOGI, SCSI_IWE, etc.
3312 // InFCHS - Incoming Tachlite FCHS which prompted this exchange
3313 // (only s_id set if we are originating)
3314 // Data - PVOID to data struct consistent with "type"
3315 // fcExchangeIndex - pointer to OX/RD ID value of built exchange
3317 // fcExchangeIndex - OX/RD ID value if successful
3319 // INVALID_ARGS - NULL/ invalid passed args
3320 // BAD_ALPA - Bad source al_pa address
3321 // LNKDWN_OSLS - Link Down (according to this controller)
3322 // OUTQUE_FULL - Outbound Que full
3323 // DRIVERQ_FULL - controller's Exchange array full
3324 // SEST_FULL - SEST table full
3328 // Check for NULL pointers / bad args
3329 // Build outgoing FCHS - the header/payload struct
3330 // Build IRB (for ERQ entry)
3331 // if SCSI command, build SEST entry (e.g. IWE, TRE,...)
3335 u32 cpqfcTSBuildExchange(CPQFCHBA * dev, u32 type, // e.g. PLOGI
3336 TachFCHDR_GCMND * InFCHS, // incoming FCHS
3337 void *Data, // the CDB, scatter/gather, etc.
3338 s32 * fcExchangeIndex) // points to allocated exchange,
3340 PTACHYON fcChip = &dev->fcChip;
3341 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3342 u32 ulStatus = 0; // assume OK
3343 u16 ox_ID, rx_ID = 0xFFFF;
3347 u8 *pIRB_flags = (u8 *) & IRB_flags;
3348 TachFCHDR_GCMND *CMDfchs;
3349 TachFCHDR *dataHDR; // 32 byte HEADER ONLY FCP-DATA buffer
3350 TachFCHDR_RSP *rspHDR; // 32 byte header + RSP payload
3351 Scsi_Cmnd *Cmnd = (Scsi_Cmnd *) Data; // Linux Scsi CDB, S/G, ...
3356 u32 fcp_dl; // total byte length of DATA transferred
3357 u32 fl; // frame length (FC frame size, 128, 256, 512, 1024)
3358 u32 sgPairs; // number of valid scatter/gather pairs
3359 int FCP_SCSI_command;
3360 BA_ACC_PAYLOAD *ba_acc;
3361 BA_RJT_PAYLOAD *ba_rjt;
3363 // check passed ARGS
3364 if (!fcChip->ERQ) // NULL ptr means uninitialized Tachlite chip
3365 return INVALID_ARGS;
3367 if (type == SCSI_IRE || type == SCSI_TRE || type == SCSI_IWE || type == SCSI_TWE)
3368 FCP_SCSI_command = 1;
3370 FCP_SCSI_command = 0;
3372 // for commands that pass payload data (e.g. SCSI write)
3373 // examine command struct - verify that the
3374 // length of s/g buffers is adequate for total payload
3375 // length (end of list is NULL address)
3377 if (FCP_SCSI_command) {
3378 if (Data) // must have data descriptor (S/G list -- at least
3379 // one address with at least 1 byte of data)
3381 // something to do (later)?
3384 return INVALID_ARGS; // invalid DATA ptr
3387 // we can build an Exchange for later Queuing (on the TL chip)
3388 // if an empty slot is available in the DevExt for this controller
3389 // look for available Exchange slot...
3391 if (type != FCP_RESPONSE && type != BLS_ABTS && type != BLS_ABTS_ACC) // already have Exchange slot!
3392 *fcExchangeIndex = FindFreeExchange(fcChip, type);
3394 if (*fcExchangeIndex != -1) // Exchange is available?
3396 // assign tmp ptr (shorthand)
3397 CMDfchs = &Exchanges->fcExchange[*fcExchangeIndex].fchs;
3399 if (Cmnd != NULL) // (necessary for ABTS cases)
3401 Exchanges->fcExchange[*fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
3402 Exchanges->fcExchange[*fcExchangeIndex].pLoggedInPort = fcFindLoggedInPort(fcChip, Exchanges->fcExchange[*fcExchangeIndex].Cmnd, // find Scsi Nexus
3403 0, // DON'T search linked list for FC port id
3404 NULL, // DON'T search linked list for FC WWN
3405 NULL); // DON'T care about end of list
3408 // Build the command frame header (& data) according
3411 // fields common for all SFS frame types
3412 CMDfchs->reserved = 0L; // must clear
3413 CMDfchs->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; LCr=0, no TS
3415 // get the destination port_id from incoming FCHS
3416 // (initialized before calling if we're Originator)
3417 // Frame goes to port it was from - the source_id
3419 CMDfchs->d_id = InFCHS->s_id & 0xFFFFFF; // destination (add R_CTL later)
3420 CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
3422 // now enter command-specific fields
3424 case BLS_NOP: // FC defined basic link service command NO-OP
3425 // ensure unique X_IDs! (use tracking function)
3426 *pIRB_flags = 0; // clear IRB flags
3427 IRB_flags.SFA = 1; // send SFS (not SEST index)
3428 SfsLen = *pIRB_flags;
3430 SfsLen <<= 24; // shift flags to MSB
3431 SfsLen += 32L; // add len to LSB (header only - no payload)
3433 // TYPE[31-24] 00 Basic Link Service
3434 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
3435 CMDfchs->d_id |= 0x80000000L; // R_CTL = 80 for NOP (Basic Link Ser.)
3436 CMDfchs->f_ctl = 0x00310000L; // xchng originator, 1st seq,....
3437 CMDfchs->seq_cnt = 0x0L;
3438 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID for now; OX_ID on start
3439 CMDfchs->ro = 0x0L; // relative offset (n/a)
3440 CMDfchs->pl[0] = 0xaabbccddL; // words 8-15 frame data payload (n/a)
3441 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 1; // seconds
3442 // (NOP should complete ~instantly)
3445 case BLS_ABTS_ACC: // Abort Sequence ACCept
3446 *pIRB_flags = 0; // clear IRB flags
3447 IRB_flags.SFA = 1; // send SFS (not SEST index)
3448 SfsLen = *pIRB_flags;
3450 SfsLen <<= 24; // shift flags to MSB
3451 SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
3453 CMDfchs->d_id |= 0x84000000L; // R_CTL = 84 for BASIC ACCept
3454 // TYPE[31-24] 00 Basic Link Service
3455 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
3456 CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
3457 // CMDfchs->seq_id & count might be set from DataHdr?
3458 CMDfchs->ro = 0x0L; // relative offset (n/a)
3459 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 5; // seconds
3460 // (Timeout in case of weird error)
3462 // now set the ACCept payload...
3463 ba_acc = (BA_ACC_PAYLOAD *) & CMDfchs->pl[0];
3464 memset(ba_acc, 0, sizeof(BA_ACC_PAYLOAD));
3465 // Since PLDA requires (only) entire Exchange aborts, we don't need
3466 // to worry about what the last sequence was.
3468 // We expect that a "target" task is accepting the abort, so we
3469 // can use the OX/RX ID pair
3470 ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
3472 // source, dest, #bytes
3473 BigEndianSwap((u8 *) & CMDfchs->ox_rx_id, (u8 *) & ba_acc->ox_rx_id, 4);
3475 ba_acc->low_seq_cnt = 0;
3476 ba_acc->high_seq_cnt = 0xFFFF;
3479 case BLS_ABTS_RJT: // Abort Sequence ACCept
3480 *pIRB_flags = 0; // clear IRB flags
3481 IRB_flags.SFA = 1; // send SFS (not SEST index)
3482 SfsLen = *pIRB_flags;
3484 SfsLen <<= 24; // shift flags to MSB
3485 SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
3487 CMDfchs->d_id |= 0x85000000L; // R_CTL = 85 for BASIC ReJecT
3488 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
3489 // TYPE[31-24] 00 Basic Link Service
3490 CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
3491 // CMDfchs->seq_id & count might be set from DataHdr?
3492 CMDfchs->ro = 0x0L; // relative offset (n/a)
3493 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 5; // seconds
3494 // (Timeout in case of weird error)
3496 CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
3498 // now set the ReJecT payload...
3499 ba_rjt = (BA_RJT_PAYLOAD *) & CMDfchs->pl[0];
3500 memset(ba_rjt, 0, sizeof(BA_RJT_PAYLOAD));
3502 // We expect that a "target" task couldn't find the Exhange in the
3503 // array of active exchanges, so we use a new LinkService X_ID.
3504 // See Reject payload description in FC-PH (Rev 4.3), pg. 140
3505 ba_rjt->reason_code = 0x09; // "unable to perform command request"
3506 ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
3509 case BLS_ABTS: // FC defined basic link service command ABTS
3511 *pIRB_flags = 0; // clear IRB flags
3512 IRB_flags.SFA = 1; // send SFS (not SEST index)
3513 SfsLen = *pIRB_flags;
3515 SfsLen <<= 24; // shift flags to MSB
3516 SfsLen += 32L; // add len to LSB (header only - no payload)
3518 // TYPE[31-24] 00 Basic Link Service
3519 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
3520 CMDfchs->d_id |= 0x81000000L; // R_CTL = 81 for ABTS
3521 CMDfchs->f_ctl = 0x00110000L; // xchnge originator, last seq, xfer SI
3522 // CMDfchs->seq_id & count might be set from DataHdr?
3523 CMDfchs->ro = 0x0L; // relative offset (n/a)
3524 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2; // seconds
3525 // (ABTS must timeout when responder is gone)
3528 case FCS_NSR: // Fabric Name Service Request
3529 Exchanges->fcExchange[*fcExchangeIndex].reTries = 2;
3530 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2; // seconds
3531 // OX_ID, linked to Driver Transaction ID
3532 // (fix-up at Queing time)
3533 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
3534 // OX_ID set at ERQueing time
3535 *pIRB_flags = 0; // clear IRB flags
3536 IRB_flags.SFA = 1; // send SFS (not SEST index)
3537 SfsLen = *pIRB_flags;
3538 SfsLen <<= 24; // shift flags to MSB
3539 SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
3540 CMDfchs->d_id |= 0x02000000L; // R_CTL = 02 for -
3541 // Name Service Request: Unsolicited
3542 // TYPE[31-24] 01 Extended Link Service
3543 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
3544 CMDfchs->f_ctl = 0x20210000L;
3545 // OX_ID will be fixed-up at Tachyon enqueing time
3546 CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
3547 CMDfchs->ro = 0x0L; // relative offset (n/a)
3548 BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
3551 case ELS_PLOGI: // FC-PH extended link service command Port Login
3553 // NOTE! This special case facilitates SANMark testing. The SANMark
3554 // test script for initialization-timeout.fcal.SANMark-1.fc
3555 // "eats" the OPN() primitive without issuing an R_RDY, causing
3556 // Tachyon to report LST (loop state timeout), which causes a
3557 // LIP. To avoid this, simply send out the frame (i.e. assuming a
3558 // buffer credit of 1) without waiting for R_RDY. Many FC devices
3559 // (other than Tachyon) have been doing this for years. We don't
3560 // ever want to do this for non-Link Service frames unless the
3561 // other device really did report non-zero login BB credit (i.e.
3562 // in the PLOGI ACCept frame).
3563 // CMDfchs->sof_eof |= 0x00000400L; // LCr=1
3565 case ELS_FDISC: // Fabric Discovery (Login)
3566 case ELS_FLOGI: // Fabric Login
3567 case ELS_SCR: // Fabric State Change Registration
3568 case ELS_LOGO: // FC-PH extended link service command Port Logout
3569 case ELS_PDISC: // FC-PH extended link service cmnd Port Discovery
3570 case ELS_PRLI: // FC-PH extended link service cmnd Process Login
3571 Exchanges->fcExchange[*fcExchangeIndex].reTries = 2;
3572 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2; // seconds
3573 // OX_ID, linked to Driver Transaction ID
3574 // (fix-up at Queing time)
3575 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
3576 // OX_ID set at ERQueing time
3577 *pIRB_flags = 0; // clear IRB flags
3578 IRB_flags.SFA = 1; // send SFS (not SEST index)
3579 SfsLen = *pIRB_flags;
3580 SfsLen <<= 24; // shift flags to MSB
3581 if (type == ELS_LOGO)
3582 SfsLen += (32L + 16L); // add len (header & PLOGI payload)
3583 else if (type == ELS_PRLI)
3584 SfsLen += (32L + 20L); // add len (header & PRLI payload)
3585 else if (type == ELS_SCR)
3586 SfsLen += (32L + sizeof(SCR_PL)); // add len (header & SCR payload)
3588 SfsLen += (32L + 116L); // add len (header & PLOGI payload)
3590 CMDfchs->d_id |= 0x22000000L; // R_CTL = 22 for -
3591 // Extended Link_Data: Unsolicited Control
3592 // TYPE[31-24] 01 Extended Link Service
3593 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
3594 CMDfchs->f_ctl = 0x01210000L;
3595 // OX_ID will be fixed-up at Tachyon enqueing time
3596 CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
3597 CMDfchs->ro = 0x0L; // relative offset (n/a)
3599 BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
3602 case ELS_LOGO_ACC: // FC-PH extended link service logout accept
3603 case ELS_RJT: // extended link service reject (add reason)
3604 case ELS_ACC: // ext. link service generic accept
3605 case ELS_PLOGI_ACC: // ext. link service login accept (PLOGI or PDISC)
3606 case ELS_PRLI_ACC: // ext. link service process login accept
3607 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 1; // assume done
3608 // ensure unique X_IDs! (use tracking function)
3609 // OX_ID from initiator cmd
3610 ox_ID = (u16) (InFCHS->ox_rx_id >> 16);
3611 rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
3613 *pIRB_flags = 0; // clear IRB flags
3614 IRB_flags.SFA = 1; // send SFS (not SEST index)
3615 SfsLen = *pIRB_flags;
3617 SfsLen <<= 24; // shift flags to MSB
3618 if (type == ELS_RJT) {
3619 SfsLen += (32L + 8L); // add len (header + payload)
3621 // ELS_RJT reason codes (utilize unused "reserved" field)
3623 CMDfchs->pl[1] = InFCHS->reserved;
3625 } else if ((type == ELS_LOGO_ACC) || (type == ELS_ACC))
3626 SfsLen += (32L + 4L); // add len (header + payload)
3627 else if (type == ELS_PLOGI_ACC)
3628 SfsLen += (32L + 116L); // add len (header + payload)
3629 else if (type == ELS_PRLI_ACC)
3630 SfsLen += (32L + 20L); // add len (header + payload)
3632 CMDfchs->d_id |= 0x23000000L; // R_CTL = 23 for -
3633 // Extended Link_Data: Control Reply
3634 // TYPE[31-24] 01 Extended Link Service
3635 // f_ctl[23:0] exchg responder, last seq, e_s, tsi
3636 CMDfchs->f_ctl = 0x01990000L;
3637 CMDfchs->seq_cnt = 0x0L;
3638 CMDfchs->ox_rx_id = 0L; // clear
3639 CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
3640 CMDfchs->ox_rx_id <<= 16; // shift them
3642 CMDfchs->ro = 0x0L; // relative offset (n/a)
3644 BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
3647 // Fibre Channel SCSI 'originator' sequences...
3648 // (originator means 'initiator' in FCP-SCSI)
3649 case SCSI_IWE: // TachLite Initiator Write Entry
3651 PFC_LOGGEDIN_PORT pLoggedInPort = Exchanges->fcExchange[*fcExchangeIndex].pLoggedInPort;
3653 Exchanges->fcExchange[*fcExchangeIndex].reTries = 1;
3654 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 7; // FC2 timeout
3656 // first, build FCP_CMND
3657 // unique X_ID fix-ups in StartExchange
3659 *pIRB_flags = 0; // clear IRB flags
3660 IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
3662 // NOTE: unlike FC LinkService login frames, normal
3663 // SCSI commands are sent without outgoing verification
3664 IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
3665 SfsLen = *pIRB_flags;
3667 SfsLen <<= 24; // shift flags to MSB
3668 SfsLen += 64L; // add len to LSB (header & CMND payload)
3670 CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
3672 // TYPE[31-24] 8 for FCP SCSI
3673 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
3675 CMDfchs->f_ctl = 0x08210008L;
3676 CMDfchs->seq_cnt = 0x0L;
3677 CMDfchs->ox_rx_id = 0L; // clear for now (-or- in later)
3678 CMDfchs->ro = 0x0L; // relative offset (n/a)
3680 // now, fill out FCP-DATA header
3681 // (use buffer inside SEST object)
3682 dataHDR = &fcChip->SEST->DataHDR[*fcExchangeIndex];
3683 dataHDR->reserved = 0L; // must clear
3684 dataHDR->sof_eof = 0x75002000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
3685 dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
3686 dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
3687 // TYPE[31-24] 8 for FCP SCSI
3688 // f_ctl[23:0] xfer S.I.| valid RO
3689 dataHDR->f_ctl = 0x08010008L;
3690 dataHDR->seq_cnt = 0x02000000L; // sequence ID: df_ctl : seqence count
3691 dataHDR->ox_rx_id = 0L; // clear; fix-up dataHDR fields later
3692 dataHDR->ro = 0x0L; // relative offset (n/a)
3694 // Now setup the SEST entry
3695 pIWE = &fcChip->SEST->u[*fcExchangeIndex].IWE;
3697 // fill out the IWE:
3699 // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
3700 pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
3703 // from login parameters with other port, what's the largest frame
3705 if (pLoggedInPort == NULL) {
3706 ulStatus = INVALID_ARGS; // failed! give up
3709 if (pLoggedInPort->rx_data_size >= 2048)
3710 fl = 0x00020000; // 2048 code (only support 1024!)
3711 else if (pLoggedInPort->rx_data_size >= 1024)
3712 fl = 0x00020000; // 1024 code
3713 else if (pLoggedInPort->rx_data_size >= 512)
3714 fl = 0x00010000; // 512 code
3716 fl = 0; // 128 bytes -- should never happen
3719 pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
3720 pIWE->Hdr_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->DataHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
3722 pIWE->RSP_Len = sizeof(TachFCHDR_RSP); // hdr+data (recv'd RSP frame)
3723 pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
3725 memset(&fcChip->SEST->RspHDR[*fcExchangeIndex].pl, 0, sizeof(FCP_STATUS_RESPONSE)); // clear out previous status
3727 pIWE->RSP_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
3729 // Do we need local or extended gather list?
3730 // depends on size - we can handle 3 len/addr pairs
3733 fcp_dl = build_SEST_sgList(dev->PciDev, &pIWE->GLen1, Cmnd, // S/G list
3734 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
3735 &fcChip->SEST->sgPages[*fcExchangeIndex]); // (for Freeing later)
3737 if (!fcp_dl) // error building S/G list?
3739 ulStatus = MEMPOOL_FAIL;
3742 // Now that we know total data length in
3743 // the passed S/G buffer, set FCP CMND frame
3744 build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
3748 if (sgPairs > 3) // need extended s/g list
3749 pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
3750 else // local data pointers (in SEST)
3751 pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
3754 pIWE->Link = 0x0000ffffL; // Buff_Index | Link
3756 pIWE->RX_ID = 0x0L; // DWord 6: RX_ID set by target XFER_RDY
3759 pIWE->Data_Len = 0L; // TL enters rcv'd XFER_RDY BURST_LEN
3760 pIWE->Exp_RO = 0L; // DWord 8
3762 pIWE->Exp_Byte_Cnt = fcp_dl; // sum of gather buffers
3766 case SCSI_IRE: // TachLite Initiator Read Entry
3767 if (Cmnd->timeout != 0) {
3768 // printk("Cmnd->timeout %d\n", Cmnd->timeout);
3770 Exchanges->fcExchange[*fcExchangeIndex].timeOut = Cmnd->timeout;
3771 } else // use our best guess, based on FC & device
3774 if (Cmnd->SCp.Message == 1) // Tape device? (from INQUIRY)
3776 // turn off our timeouts (for now...)
3777 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 0xFFFFFFFF;
3779 Exchanges->fcExchange[*fcExchangeIndex].reTries = 1;
3780 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 7; // per SCSI req.
3783 // first, build FCP_CMND
3784 *pIRB_flags = 0; // clear IRB flags
3785 IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
3786 // NOTE: unlike FC LinkService login frames,
3787 // normal SCSI commands are sent "open loop"
3788 IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
3789 SfsLen = *pIRB_flags;
3791 SfsLen <<= 24; // shift flags to MSB
3792 SfsLen += 64L; // add len to LSB (header & CMND payload)
3794 CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
3796 // TYPE[31-24] 8 for FCP SCSI
3797 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
3799 CMDfchs->f_ctl = 0x08210008L;
3800 CMDfchs->seq_cnt = 0x0L;
3801 // x_ID & data direction bit set later
3802 CMDfchs->ox_rx_id = 0xFFFF; // clear
3803 CMDfchs->ro = 0x0L; // relative offset (n/a)
3804 // Now setup the SEST entry
3805 pIRE = &fcChip->SEST->u[*fcExchangeIndex].IRE;
3806 // fill out the IRE:
3807 // VALid entry:Dir outbound:enable CM:enal INT:
3808 pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
3810 pIRE->reserved = 0L;
3811 pIRE->RSP_Len = sizeof(TachFCHDR_RSP); // hdr+data (recv'd RSP frame)
3812 pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
3814 pIRE->RSP_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
3816 // Do we need local or extended gather list?
3817 // depends on size - we can handle 3 len/addr pairs
3820 fcp_dl = build_SEST_sgList(dev->PciDev, &pIRE->SLen1, Cmnd, // SCSI command Data desc. with S/G list
3821 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
3822 &fcChip->SEST->sgPages[*fcExchangeIndex]); // (for Freeing later)
3825 if (!fcp_dl) // error building S/G list?
3827 // It is permissible to have a ZERO LENGTH Read command.
3828 // If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
3829 // to 0 and continue.
3830 if (Cmnd->request_bufflen == 0) {
3831 fcp_dl = 0; // no FC DATA frames expected
3834 ulStatus = MEMPOOL_FAIL;
3838 // now that we know the S/G length, build CMND payload
3839 build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
3842 if (sgPairs > 3) // need extended s/g list
3843 pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
3845 pIRE->Buff_Off = 0x80000000; // local data, no offset
3847 pIRE->Buff_Index = 0x0L; // DWord 5: Buff_Index | Reserved
3849 pIRE->Exp_RO = 0x0L; // DWord 6: Expected Rel. Offset
3851 pIRE->Byte_Count = 0; // DWord 7: filled in by TL on err
3852 pIRE->reserved_ = 0; // DWord 8: reserved
3853 // NOTE: 0 length READ is OK.
3854 pIRE->Exp_Byte_Cnt = fcp_dl; // DWord 9: sum of scatter buffers
3857 // Fibre Channel SCSI 'responder' sequences...
3858 // (originator means 'target' in FCP-SCSI)
3859 case SCSI_TWE: // TachLite Target Write Entry
3860 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 10; // per SCSI req.
3861 // first, build FCP_CMND
3862 *pIRB_flags = 0; // clear IRB flags
3863 IRB_flags.SFA = 1; // send SFS (XFER_RDY)
3864 SfsLen = *pIRB_flags;
3865 SfsLen <<= 24; // shift flags to MSB
3866 SfsLen += (32L + 12L); // add SFS len (header & XFER_RDY payload)
3868 CMDfchs->d_id |= (0x05000000L); // R_CTL = 5 for XFER_RDY
3870 // TYPE[31-24] 8 for FCP SCSI
3871 // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
3873 CMDfchs->f_ctl = 0x08810008L;
3874 CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
3875 // use originator (other port's) OX_ID
3876 CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // we want upper 16 bits
3877 CMDfchs->ro = 0x0L; // relative offset (n/a)
3879 // now, fill out FCP-RSP header
3880 // (use buffer inside SEST object)
3882 rspHDR = &fcChip->SEST->RspHDR[*fcExchangeIndex];
3883 rspHDR->reserved = 0L; // must clear
3884 rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
3885 rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
3886 rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
3887 // TYPE[31-24] 8 for FCP SCSI
3888 // f_ctl[23:0] responder|last seq| xfer S.I.
3889 rspHDR->f_ctl = 0x08910000L;
3890 rspHDR->seq_cnt = 0x03000000; // sequence ID
3891 rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
3892 rspHDR->ro = 0x0L; // relative offset (n/a)
3893 // Now setup the SEST entry
3895 pTWE = &fcChip->SEST->u[*fcExchangeIndex].TWE;
3896 // fill out the TWE:
3898 // VALid entry:Dir outbound:enable CM:enal INT:
3899 pTWE->Seq_Accum = 0xC4000000L; // upper word flags
3900 pTWE->reserved = 0L;
3901 pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
3902 pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
3904 // Do we need local or extended gather list?
3905 // depends on size - we can handle 3 len/addr pairs
3908 fcp_dl = build_SEST_sgList(dev->PciDev, &pTWE->SLen1, Cmnd, // S/G list
3909 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
3910 &fcChip->SEST->sgPages[*fcExchangeIndex]); // (for Freeing later)
3912 if (!fcp_dl) // error building S/G list?
3914 ulStatus = MEMPOOL_FAIL;
3917 // now that we know the S/G length, build CMND payload
3918 build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
3920 if (sgPairs > 3) // need extended s/g list
3921 pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
3923 pTWE->Buff_Off = 0x80000000; // local data, no offset
3925 pTWE->Buff_Index = 0; // Buff_Index | Link
3927 pTWE->Byte_Count = 0; // filled in by TL on err
3928 pTWE->reserved_ = 0;
3929 pTWE->Exp_Byte_Cnt = fcp_dl; // sum of scatter buffers
3932 case SCSI_TRE: // TachLite Target Read Entry
3933 // It doesn't make much sense for us to "time-out" a READ,
3934 // but we'll use it for design consistency and internal error recovery.
3935 Exchanges->fcExchange[*fcExchangeIndex].timeOut = 10; // per SCSI req.
3936 // I/O request block settings...
3937 *pIRB_flags = 0; // clear IRB flags
3938 // check PRLI (process login) info
3939 // to see if Initiator Requires XFER_RDY
3940 // if not, don't send one!
3942 IRB_flags.SFA = 0; // don't send XFER_RDY - start data
3943 SfsLen = *pIRB_flags;
3944 SfsLen <<= 24; // shift flags to MSB
3945 SfsLen += (32L + 12L); // add SFS len (header & XFER_RDY payload)
3947 // now, fill out FCP-DATA header
3948 // (use buffer inside SEST object)
3949 dataHDR = &fcChip->SEST->DataHDR[*fcExchangeIndex];
3951 dataHDR->reserved = 0L; // must clear
3952 dataHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
3953 dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
3954 dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
3956 // TYPE[31-24] 8 for FCP SCSI
3957 // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
3959 dataHDR->f_ctl = 0x08810008L;
3960 dataHDR->seq_cnt = 0x01000000; // sequence ID (no XRDY)
3961 dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
3962 dataHDR->ro = 0x0L; // relative offset (n/a)
3964 // now, fill out FCP-RSP header
3965 // (use buffer inside SEST object)
3966 rspHDR = &fcChip->SEST->RspHDR[*fcExchangeIndex];
3968 rspHDR->reserved = 0L; // must clear
3969 rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
3970 rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
3971 rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
3972 // TYPE[31-24] 8 for FCP SCSI
3973 // f_ctl[23:0] responder|last seq| xfer S.I.
3974 rspHDR->f_ctl = 0x08910000L;
3975 rspHDR->seq_cnt = 0x02000000; // sequence ID: df_ctl: sequence count
3976 rspHDR->ro = 0x0L; // relative offset (n/a)
3978 // Now setup the SEST entry
3979 pTRE = &fcChip->SEST->u[*fcExchangeIndex].TRE;
3981 // VALid entry:Dir outbound:enable CM:enal INT:
3982 pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
3983 pTRE->Hdr_Addr = // bus address of dataHDR;
3984 fcChip->SEST->base + ((unsigned long) &fcChip->SEST->DataHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
3986 pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
3987 pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
3988 pTRE->RSP_Addr = // bus address of rspHDR
3989 fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
3991 // Do we need local or extended gather list?
3992 // depends on size - we can handle 3 len/addr pairs
3995 fcp_dl = build_SEST_sgList(dev->PciDev, &pTRE->GLen1, Cmnd, // S/G list
3996 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
3997 &fcChip->SEST->sgPages[*fcExchangeIndex]); // (for Freeing later)
3999 if (!fcp_dl) // error building S/G list?
4001 ulStatus = MEMPOOL_FAIL;
4004 // no payload or command to build -- READ doesn't need XRDY
4005 if (sgPairs > 3) // need extended s/g list
4006 pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
4007 else // local data pointers (in SEST)
4008 pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
4011 pTRE->Buff_Index = 0L; // Buff_Index | reserved
4012 pTRE->reserved = 0x0L; // DWord 6
4014 // DWord 7: NOTE: zero length will
4016 pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
4018 pTRE->reserved_ = 0L; // DWord 8
4019 pTRE->reserved__ = 0L; // DWord 9
4024 // Target response frame: this sequence uses an OX/RX ID
4025 // pair from a completed SEST exchange. We built most
4026 // of the response frame when we created the TWE/TRE.
4028 *pIRB_flags = 0; // clear IRB flags
4029 IRB_flags.SFA = 1; // send SFS (RSP)
4030 SfsLen = *pIRB_flags;
4032 SfsLen <<= 24; // shift flags to MSB
4033 SfsLen += sizeof(TachFCHDR_RSP); // add SFS len (header & RSP payload)
4034 Exchanges->fcExchange[*fcExchangeIndex].type = FCP_RESPONSE; // change Exchange type to "response" phase
4036 // take advantage of prior knowledge of OX/RX_ID pair from
4037 // previous XFER outbound frame (still in fchs of exchange)
4038 fcChip->SEST->RspHDR[*fcExchangeIndex].ox_rx_id = CMDfchs->ox_rx_id;
4040 // Check the status of the DATA phase of the exchange so we can report
4041 // status to the initiator
4042 buildFCPstatus(fcChip, *fcExchangeIndex); // set RSP payload fields
4044 memcpy(CMDfchs, // re-use same XFER fchs for Response frame
4045 &fcChip->SEST->RspHDR[*fcExchangeIndex], sizeof(TachFCHDR_RSP));
4049 printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type, type);
4052 if (!ulStatus) // no errors above?
4054 // FCHS is built; now build IRB
4056 // link the just built FCHS (the "command") to the IRB entry
4057 // for this Exchange.
4058 pIRB = &Exchanges->fcExchange[*fcExchangeIndex].IRB;
4060 // len & flags according to command type above
4061 pIRB->Req_A_SFS_Len = SfsLen; // includes IRB flags & len
4062 pIRB->Req_A_SFS_Addr = // TL needs physical addr of frame to send
4063 fcChip->exch_dma_handle + (unsigned long) CMDfchs - (unsigned long) Exchanges;
4065 pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
4067 // Exchange is complete except for "fix-up" fields to be set
4068 // at Tachyon Queuing time:
4069 // IRB->Req_A_Trans_ID (OX_ID/ RX_ID):
4070 // for SEST entry, lower bits correspond to actual FC Exchange ID
4071 // fchs->OX_ID or RX_ID
4074 printk("FC Error: SEST build Pool Allocation failed\n");
4076 // return resources...
4077 cpqfcTSCompleteExchange(dev->PciDev, fcChip, *fcExchangeIndex); // SEST build failed
4079 } else // no Exchanges available
4081 ulStatus = SEST_FULL;
4082 printk("FC Error: no fcExchanges available\n");
4087 // set RSP payload fields
4088 static void buildFCPstatus(PTACHYON fcChip, u32 ExchangeID)
4090 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
4091 FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID]; // shorthand
4092 PFCP_STATUS_RESPONSE pFcpStatus;
4094 memset(&fcChip->SEST->RspHDR[ExchangeID].pl, 0, sizeof(FCP_STATUS_RESPONSE));
4095 if (pExchange->status) // something wrong?
4097 pFcpStatus = (PFCP_STATUS_RESPONSE) // cast RSP buffer for this xchng
4098 & fcChip->SEST->RspHDR[ExchangeID].pl;
4099 if (pExchange->status & COUNT_ERROR) {
4101 // set FCP response len valid (so we can report count error)
4102 pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
4103 pFcpStatus->fcp_rsp_len = 0x04000000; // 4 byte len (BIG Endian)
4105 pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
4111 static dma_addr_t cpqfc_pci_map_sg_page(struct pci_dev *pcidev, u32 * hw_paddr, // where to put phys addr for HW use
4112 void *sgp_vaddr, // the virtual address of the sg page
4113 dma_addr_t * umap_paddr, // where to put phys addr for unmap
4114 unsigned int *maplen, // where to store sg entry length
4115 int PairCount) // number of sg pairs used in the page.
4117 unsigned long aligned_addr = (unsigned long) sgp_vaddr;
4119 *maplen = PairCount * 8;
4120 aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
4121 aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN - 1);
4123 *umap_paddr = pci_map_single(pcidev, (void *) aligned_addr, *maplen, PCI_DMA_TODEVICE);
4124 *hw_paddr = (u32) * umap_paddr;
4126 # if BITS_PER_LONG > 32
4127 if (*umap_paddr >> 32) {
4128 printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n", (void *) umap_paddr);
4135 static void cpqfc_undo_SEST_mappings(struct pci_dev *pcidev, unsigned long contigaddr, int len, int dir, struct scatterlist *sgl, int use_sg, PSGPAGES * sgPages_head, int allocated_pages)
4139 if (contigaddr != (unsigned long) NULL)
4140 pci_unmap_single(pcidev, contigaddr, len, dir);
4143 pci_unmap_sg(pcidev, sgl, use_sg, dir);
4145 for (i = *sgPages_head; i != NULL; i = next) {
4146 pci_unmap_single(pcidev, i->busaddr, i->maplen, scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
4147 i->busaddr = (dma_addr_t) NULL;
4152 *sgPages_head = NULL;
4155 // This routine builds scatter/gather lists into SEST entries
4157 // SESTalPair - SEST address @DWordA "Local Buffer Length"
4158 // sgList - Scatter/Gather linked list of Len/Address data buffers
4160 // sgPairs - number of valid address/length pairs
4162 // The SEST data buffer pointers only depend on number of
4163 // length/ address pairs, NOT on the type (IWE, TRE,...)
4164 // Up to 3 pairs can be referenced in the SEST - more than 3
4165 // require this Extended S/G list page. The page holds 4, 8, 16...
4166 // len/addr pairs, per Scatter/Gather List Page Length Reg.
4167 // TachLite allows pages to be linked to any depth.
4169 //#define DBG_SEST_SGLIST 1 // for printing out S/G pairs with Ext. pages
4171 static int ap_hi_water = TL_DANGER_SGPAGES;
4173 static u32 build_SEST_sgList(struct pci_dev *pcidev, u32 * SESTalPairStart, // the 3 len/address buffers in SEST
4174 Scsi_Cmnd * Cmnd, u32 * sgPairs, PSGPAGES * sgPages_head) // link list of TL Ext. S/G pages from O/S Pool
4176 u32 i, AllocatedPages = 0; // Tach Ext. S/G page allocations
4177 u32 *alPair = SESTalPairStart;
4178 u32 *ext_sg_page_phys_addr_place = NULL;
4180 unsigned long ulBuff, contigaddr;
4181 u32 total_data_len = 0; // (in bytes)
4182 u32 bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
4184 struct scatterlist *sgl = NULL; // S/G list (Linux format)
4185 int sg_count, totalsgs;
4187 unsigned long thislen, offset;
4188 PSGPAGES *sgpage = sgPages_head;
4189 PSGPAGES prev_page = NULL;
4191 # define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
4192 contigaddr = (unsigned long) NULL;
4194 if (!Cmnd->use_sg) // no S/G list?
4196 if (bytes_to_go <= TL_MAX_SG_ELEM_LEN) {
4197 *sgPairs = 1; // use "local" S/G pair in SEST entry
4198 // (for now, ignore address bits above #31)
4200 *alPair++ = bytes_to_go; // bits 18-0, length
4202 if (bytes_to_go != 0) {
4203 contigaddr = ulBuff = pci_map_single(pcidev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
4204 // printk("ms %p ", ulBuff);
4206 // No data transfer, (e.g.: Test Unit Ready)
4207 // printk("btg=0 ");
4209 memset(alPair, 0, sizeof(*alPair));
4213 # if BITS_PER_LONG > 32
4215 printk("FATAL! Tachyon DMA address %p " "exceeds 32 bits\n", (void *) ulBuff);
4219 *alPair = (u32) ulBuff;
4221 } else // We have a single large (too big) contiguous buffer.
4222 { // We will have to break it up. We'll use the scatter
4223 // gather code way below, but use contigaddr instead
4224 // of sg_dma_addr(). (this is a very rare case).
4227 contigaddr = pci_map_single(pcidev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
4229 // printk("contigaddr = %p, len = %d\n",
4230 // (void *) contigaddr, bytes_to_go);
4232 for (btg = bytes_to_go; btg > 0;) {
4233 btg -= (btg > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : btg);
4237 *sgPairs = totalsgs;
4239 } else // we do have a scatter gather list
4241 // [TBD - update for Linux to support > 32 bits addressing]
4242 // since the format for local & extended S/G lists is different,
4243 // check if S/G pairs exceeds 3.
4244 // *sgPairs = Cmnd->use_sg; Nope, that's wrong.
4246 sgl = (struct scatterlist *) Cmnd->request_buffer;
4247 sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
4248 // printk("sgl = %p, sg_count = %d\n", (void *) sgl, sg_count);
4249 if (sg_count <= 3) {
4251 // we need to be careful here that no individual mapping
4252 // is too large, and if any is, that breaking it up
4253 // doesn't push us over 3 sgs, or, if it does, that we
4254 // handle that case. Tachyon can take 0x7FFFF bits for length,
4255 // but sg structure uses "unsigned int", on the face of it,
4256 // up to 0xFFFFFFFF or even more.
4259 unsigned long thislen;
4262 for (i = 0; i < sg_count; i++) {
4263 thislen = sg_dma_len(&sgl[i]);
4264 while (thislen >= TL_MAX_SG_ELEM_LEN) {
4266 thislen -= TL_MAX_SG_ELEM_LEN;
4271 *sgPairs = totalsgs;
4273 totalsgs = 999; // as a first estimate, definitely >3,
4275 // if (totalsgs != sg_count)
4276 // printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
4279 // printk("totalsgs = %d, sgcount=%d\n", totalsgs, sg_count);
4280 if (totalsgs <= 3) // can (must) use "local" SEST list
4282 while (bytes_to_go) {
4285 if (WE_HAVE_SG_LIST)
4286 thisMappingLen = sg_dma_len(sgl);
4287 else // or contiguous buffer?
4288 thisMappingLen = bytes_to_go;
4290 while (thisMappingLen > 0) {
4291 thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : thisMappingLen;
4292 bytes_to_go = bytes_to_go - thislen;
4294 // we have L/A pair; L = thislen, A = physicalAddress
4295 // load into SEST...
4297 total_data_len += thislen;
4298 *alPair = thislen; // bits 18-0, length
4302 if (WE_HAVE_SG_LIST)
4303 ulBuff = sg_dma_address(sgl) + offset;
4305 ulBuff = contigaddr + offset;
4309 # if BITS_PER_LONG > 32
4311 printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n", (void *) ulBuff);
4312 printk("%s = %p, offset = %ld\n", WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr", WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr, offset);
4316 *alPair++ = (u32) ulBuff; // lower 32 bits (31-0)
4317 thisMappingLen -= thislen;
4320 if (WE_HAVE_SG_LIST)
4321 ++sgl; // next S/G pair
4322 else if (bytes_to_go != 0)
4323 printk("BTG not zero!\n");
4325 # ifdef DBG_SEST_SGLIST
4326 printk("L=%d ", thisMappingLen);
4327 printk("btg=%d ", bytes_to_go);
4331 // printk("i:%d\n", *sgPairs);
4332 } else // more than 3 pairs requires Extended S/G page (Pool Allocation)
4334 // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
4335 for (i = 2; i < 6; i++)
4338 PairCount = TL_EXT_SG_PAGE_COUNT; // forces initial page allocation
4340 while (bytes_to_go) {
4341 // Per SEST format, we can support 524287 byte lengths per
4342 // S/G pair. Typical user buffers are 4k, and very rarely
4343 // exceed 12k due to fragmentation of physical memory pages.
4344 // However, on certain O/S system (not "user") buffers (on platforms
4345 // with huge memories), it's possible to exceed this
4346 // length in a single S/G address/len mapping, so we have to handle
4350 if (WE_HAVE_SG_LIST)
4351 thisMappingLen = sg_dma_len(sgl);
4353 thisMappingLen = bytes_to_go;
4355 while (thisMappingLen > 0) {
4356 thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : thisMappingLen;
4357 // printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
4359 // should we load into "this" extended S/G page, or allocate
4362 if (PairCount >= TL_EXT_SG_PAGE_COUNT) {
4363 // Now, we have to map the previous page, (triggering buffer bounce)
4364 // The first time thru the loop, there won't be a previous page.
4365 if (prev_page != NULL) // is there a prev page?
4367 // this code is normally kind of hard to trigger,
4368 // you have to use up more than 256 scatter gather
4369 // elements to get here. Cranking down TL_MAX_SG_ELEM_LEN
4370 // to an absurdly low value (128 bytes or so) to artificially
4371 // break i/o's into a zillion pieces is how I tested it.
4372 busaddr = cpqfc_pci_map_sg_page(pcidev, ext_sg_page_phys_addr_place, prev_page->page, &prev_page->busaddr, &prev_page->maplen, PairCount);
4374 // Allocate the TL Extended S/G list page. We have
4375 // to allocate twice what we want to ensure required TL alignment
4376 // (Tachlite TL/TS User Man. Rev 6.0, p 168)
4377 // We store the original allocated PVOID so we can free later
4378 *sgpage = kmalloc(sizeof(SGPAGES), GFP_ATOMIC);
4380 printk("cpqfc: Allocation failed @ %d S/G page allocations\n", AllocatedPages);
4381 total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
4383 // unmap the previous mappings, if any.
4385 cpqfc_undo_SEST_mappings(pcidev, contigaddr, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction), sgl, Cmnd->use_sg, sgPages_head, AllocatedPages + 1);
4387 // FIXME: testing shows that if we get here,
4388 // it's bad news. (this has been this way for a long
4389 // time though, AFAIK. Not that that excuses it.)
4391 return 0; // give up (and probably hang the system)
4393 // clear out memory we just allocated
4394 memset((*sgpage)->page, 0, TL_EXT_SG_PAGE_BYTELEN * 2);
4395 (*sgpage)->next = NULL;
4396 (*sgpage)->busaddr = (dma_addr_t) NULL;
4397 (*sgpage)->maplen = 0L;
4399 // align the memory - TL requires sizeof() Ext. S/G page alignment.
4400 // We doubled the actual required size so we could mask off LSBs
4401 // to get desired offset
4403 ulBuff = (unsigned long) (*sgpage)->page;
4404 ulBuff += TL_EXT_SG_PAGE_BYTELEN;
4405 ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN - 1);
4407 // set pointer, in SEST if first Ext. S/G page, or in last pair
4408 // of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just
4409 // load lower 32 bits)
4410 // NOTE: the Len field must be '0' if this is the first Ext. S/G
4411 // pointer in SEST, and not 0 otherwise (we know thislen != 0).
4413 *alPair = (alPair != SESTalPairStart) ? thislen : 0;
4415 # ifdef DBG_SEST_SGLIST
4416 printk("PairCount %d @%p even %Xh, ", PairCount, alPair, *alPair);
4419 // Save the place where we need to store the physical
4420 // address of this scatter gather page which we get when we map it
4421 // (and mapping we can do only after we fill it in.)
4422 alPair++; // next DWORD, will contain phys addr of the ext page
4423 ext_sg_page_phys_addr_place = alPair;
4425 // Now, set alPair = the virtual addr of the (Extended) S/G page
4426 // which will accept the Len/ PhysicalAddress pairs
4427 alPair = (u32 *) ulBuff;
4430 if (AllocatedPages >= ap_hi_water) {
4431 // This message should rarely, if ever, come out.
4432 // Previously (cpqfc version <= 2.0.5) the driver would
4433 // just puke if more than 4 SG pages were used, and nobody
4434 // ever complained about that. This only comes out if
4435 // more than 8 pages are used.
4437 printk(KERN_WARNING "cpqfc: Possible danger. %d scatter gather pages used.\n" "cpqfc: detected seemingly extreme memory " "fragmentation or huge data transfers.\n", AllocatedPages);
4438 ap_hi_water = AllocatedPages + 1;
4441 PairCount = 1; // starting new Ext. S/G page
4442 prev_page = (*sgpage); // remember this page, for next time thru
4443 sgpage = &((*sgpage)->next);
4444 } // end of new TL Ext. S/G page allocation
4446 *alPair = thislen; // bits 18-0, length (range check above)
4448 # ifdef DBG_SEST_SGLIST
4449 printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
4452 alPair++; // next DWORD, physical address
4454 if (WE_HAVE_SG_LIST)
4455 ulBuff = sg_dma_address(sgl) + offset;
4457 ulBuff = contigaddr + offset;
4460 # if BITS_PER_LONG > 32
4462 printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void *) ulBuff);
4463 printk("%s = %p, offset = %ld\n", WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr", WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr, offset);
4468 *alPair = (u32) ulBuff; // lower 32 bits (31-0)
4470 # ifdef DBG_SEST_SGLIST
4471 printk("odd %Xh\n", *alPair);
4473 alPair++; // next DWORD, next address/length pair
4475 PairCount++; // next Length/Address pair
4477 // if (PairCount > pc_hi_water)
4479 // printk("pc hi = %d ", PairCount);
4480 // pc_hi_water = PairCount;
4482 bytes_to_go -= thislen;
4483 total_data_len += thislen;
4484 thisMappingLen -= thislen;
4486 } // while (thisMappingLen > 0)
4487 if (WE_HAVE_SG_LIST)
4488 sgl++; // next S/G pair
4489 } // while (bytes_to_go)
4491 // printk("Totalsgs=%d\n", totalsgs);
4492 *sgPairs = totalsgs;
4494 // PCI map (and bounce) the last (and usually only) extended SG page
4495 busaddr = cpqfc_pci_map_sg_page(pcidev, ext_sg_page_phys_addr_place, prev_page->page, &prev_page->busaddr, &prev_page->maplen, PairCount);
4497 return total_data_len;
4502 // The Tachlite SEST table is referenced to OX_ID (or RX_ID). To optimize
4503 // performance and debuggability, we index the Exchange structure to FC X_ID
4504 // This enables us to build exchanges for later en-queing to Tachyon,
4505 // provided we have an open X_ID slot. At Tachyon queing time, we only
4506 // need an ERQ slot; then "fix-up" references in the
4507 // IRB, FCHS, etc. as needed.
4510 // non-zero on error
4513 u32 cpqfcTSStartExchange(CPQFCHBA * dev, s32 ExchangeID)
4515 PTACHYON fcChip = &dev->fcChip;
4516 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
4517 FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID]; // shorthand
4518 u16 producer, consumer;
4521 u8 CompleteExchange = 0; // e.g. ACC replies are complete
4523 u32 InboundData = 0;
4525 // We will manipulate Tachlite chip registers here to successfully
4528 // Check that link is not down -- we can't start an exchange on a
4531 if (fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
4533 printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n", fcChip->Registers.FMstatus.value & 0xFF, ExchangeID, pExchange->type, pExchange->fchs.d_id);
4535 if (ExchangeID >= TACH_SEST_LEN) // Link Service Outbound frame?
4537 // Our most popular LinkService commands are port discovery types
4538 // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
4539 // events, so it makes no sense to Que them. However, ABTS should
4540 // be queued, since exchange sequences are likely destroyed by
4541 // Link Down events, and we want to notify other ports of broken
4542 // sequences by aborting the corresponding exchanges.
4543 if (pExchange->type != BLS_ABTS) {
4544 ulStatus = LNKDWN_OSLS;
4546 // don't Que most LinkServ exchanges on LINK DOWN
4550 printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", ExchangeID, pExchange->type);
4551 pExchange->status |= EXCHANGE_QUEUED;
4552 ulStatus = EXCHANGE_QUEUED;
4555 // Make sure ERQ has available space.
4557 producer = (u16) fcChip->ERQ->producerIndex; // copies for logical arith.
4558 consumer = (u16) fcChip->ERQ->consumerIndex;
4559 producer++; // We are testing for full que by incrementing
4561 if (producer >= ERQ_LEN) // rollover condition?
4563 if (consumer != producer) // ERQ not full?
4565 // ****************** Need Atomic access to chip registers!!********
4567 // remember ERQ PI for copying IRB
4568 ErqIndex = (u16) fcChip->ERQ->producerIndex;
4569 fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
4570 // we have an ERQ slot! If SCSI command, need SEST slot
4571 // otherwise we are done.
4573 // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
4574 // set according to direction of data to/from Tachyon for SEST assists.
4575 // For consistency, enforce this rule for Link Service (non-SEST)
4576 // exchanges as well.
4578 // fix-up the X_ID field in IRB
4579 pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
4581 // fix-up the X_ID field in fchs -- depends on Originator or Responder,
4582 // outgoing or incoming data?
4583 switch (pExchange->type) {
4584 // ORIGINATOR types... we're setting our OX_ID and
4585 // defaulting the responder's RX_ID to 0xFFFF
4588 // Requirement: set MSB of x_ID for Incoming TL data
4589 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
4590 InboundData = 0x8000;
4594 pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
4595 pExchange->fchs.ox_rx_id <<= 16; // MSW shift
4596 pExchange->fchs.ox_rx_id |= 0xffff; // add default RX_ID
4598 // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
4599 // (not necessary for IRE -- data buffer unused)
4600 if (pExchange->type == SCSI_IWE) {
4601 fcChip->SEST->DataHDR[ExchangeID].ox_rx_id = pExchange->fchs.ox_rx_id;
4608 case FCS_NSR: // ext. link service Name Service Request
4609 case ELS_SCR: // ext. link service State Change Registration
4610 case ELS_FDISC: // ext. link service login
4611 case ELS_FLOGI: // ext. link service login
4612 case ELS_LOGO: // FC-PH extended link service logout
4613 case BLS_NOP: // Basic link service No OPeration
4614 case ELS_PLOGI: // ext. link service login (PLOGI)
4615 case ELS_PDISC: // ext. link service login (PDISC)
4616 case ELS_PRLI: // ext. link service process login
4618 pExchange->fchs.ox_rx_id = ExchangeID;
4619 pExchange->fchs.ox_rx_id <<= 16; // MSW shift
4620 pExchange->fchs.ox_rx_id |= 0xffff; // and RX_ID
4627 // RESPONDER types... we must set our RX_ID while preserving
4629 // outgoing (or no) data
4630 case ELS_RJT: // extended link service reject
4631 case ELS_LOGO_ACC: // FC-PH extended link service logout accept
4632 case ELS_ACC: // ext. generic link service accept
4633 case ELS_PLOGI_ACC: // ext. link service login accept (PLOGI or PDISC)
4634 case ELS_PRLI_ACC: // ext. link service process login accept
4636 CompleteExchange = 1; // Reply (ACC or RJT) is end of exchange
4637 pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
4642 // since we are a Responder, OX_ID should already be set by
4643 // cpqfcTSBuildExchange(). We need to -OR- in RX_ID
4646 // Requirement: set MSB of x_ID for Incoming TL data
4647 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
4649 pExchange->fchs.ox_rx_id &= 0xFFFF0000; // clear RX_ID
4650 // Requirement: set MSB of RX_ID for Incoming TL data
4651 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
4652 pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
4659 // there is no XRDY for SEST target read; the data
4660 // header needs to be updated. Also update the RSP
4661 // exchange IDs for the status frame, in case it is sent automatically
4662 fcChip->SEST->DataHDR[ExchangeID].ox_rx_id |= ExchangeID;
4663 fcChip->SEST->RspHDR[ExchangeID].ox_rx_id = fcChip->SEST->DataHDR[ExchangeID].ox_rx_id;
4665 // for easier FCP response logic (works for TWE and TRE),
4666 // copy exchange IDs. (Not needed if TRE 'RSP' bit set)
4667 pExchange->fchs.ox_rx_id = fcChip->SEST->DataHDR[ExchangeID].ox_rx_id;
4672 case FCP_RESPONSE: // using existing OX_ID/ RX_ID pair,
4673 // start SFS FCP-RESPONSE frame
4674 // OX/RX_ID should already be set! (See "fcBuild" above)
4675 CompleteExchange = 1; // RSP is end of FCP-SCSI exchange
4681 case BLS_ABTS_RJT: // uses new RX_ID, since SEST x_ID non-existent
4682 case BLS_ABTS_ACC: // using existing OX_ID/ RX_ID pair from SEST entry
4683 CompleteExchange = 1; // ACC or RJT marks end of FCP-SCSI exchange
4684 case BLS_ABTS: // using existing OX_ID/ RX_ID pair from SEST entry
4691 printk("Error on fcStartExchange: undefined type %Xh(%d)\n", pExchange->type, pExchange->type);
4692 return INVALID_ARGS;
4696 // X_ID fields are entered -- copy IRB to Tachyon's ERQ
4699 memcpy(&fcChip->ERQ->QEntry[ErqIndex], // dest.
4700 &pExchange->IRB, 32); // fixed (hardware) length!
4702 PCI_TRACEO(ExchangeID, 0xA0)
4703 // ACTION! May generate INT and IMQ entry
4704 writel(fcChip->ERQ->producerIndex, fcChip->Registers.ERQproducerIndex.address);
4707 if (ExchangeID >= TACH_SEST_LEN) // Link Service Outbound frame?
4710 // wait for completion! (TDB -- timeout and chip reset)
4713 PCI_TRACEO(ExchangeID, 0xA4)
4715 enable_irq(dev->HostAdapter->irq); // only way to get Sem.
4717 down_interruptible(dev->TYOBcomplete);
4719 disable_irq(dev->HostAdapter->irq);
4721 // On login exchanges, BAD_ALPA (non-existent port_id) results in
4722 // FTO (Frame Time Out) on the Outbound Completion message.
4723 // If we got an FTO status, complete the exchange (free up slot)
4724 if (CompleteExchange || // flag from Reply frames
4725 pExchange->status) // typically, can get FRAME_TO
4727 cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
4731 else // SEST Exchange
4733 ulStatus = 0; // ship & pray success (e.g. FCP-SCSI)
4735 if (CompleteExchange) // by Type of exchange (e.g. end-of-xchng)
4737 cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
4741 pExchange->status &= ~EXCHANGE_QUEUED; // clear ExchangeQueued flag
4747 else // ERQ 'producer' = 'consumer' and QUE is full
4749 ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
4761 // Scan fcController->fcExchanges array for a usuable index (a "free"
4764 // fcChip - pointer to TachLite chip structure
4766 // index - exchange array element where exchange can be built
4767 // -1 - exchange array is full
4769 // Although this is a (yuk!) linear search, we presume
4770 // that the system will complete exchanges about as quickly as
4771 // they are submitted. A full Exchange array (and hence, max linear
4772 // search time for free exchange slot) almost guarantees a Fibre problem
4774 // In the interest of making exchanges easier to debug, we want a LRU
4775 // (Least Recently Used) scheme.
4778 static s32 FindFreeExchange(PTACHYON fcChip, u32 type)
4780 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
4782 u32 ulStatus = -1; // assume failure
4785 if (type == SCSI_IRE || type == SCSI_TRE || type == SCSI_IWE || type == SCSI_TWE) {
4786 // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
4787 if (fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
4788 fcChip->fcSestExchangeLRU = 0;
4789 i = fcChip->fcSestExchangeLRU; // typically it's already free!
4791 if (Exchanges->fcExchange[i].type == 0) // check for "free" element
4793 ulStatus = 0; // success!
4796 else { // YUK! we need to do a linear search for free element.
4797 // Fragmentation of the fcExchange array is due to excessively
4798 // long completions or timeouts.
4801 if (++i >= TACH_SEST_LEN) // rollover check
4802 i = 0; // beginning of SEST X_IDs
4804 // printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n",
4805 // i, Exchanges->fcExchange[i].type);
4807 if (Exchanges->fcExchange[i].type == 0) // "free"?
4809 ulStatus = 0; // success!
4812 if (i == fcChip->fcSestExchangeLRU) // wrapped-around array?
4814 printk("SEST X_ID space full\n");
4815 break; // failed - prevent inf. loop
4819 fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
4821 else // Link Service type - X_IDs should be from TACH_SEST_LEN
4824 if (fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
4825 fcChip->fcLsExchangeLRU < TACH_SEST_LEN) // (e.g. startup)
4826 fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
4828 i = fcChip->fcLsExchangeLRU; // typically it's already free!
4829 if (Exchanges->fcExchange[i].type == 0) // check for "free" element
4831 ulStatus = 0; // success!
4834 else { // YUK! we need to do a linear search for free element
4835 // Fragmentation of the fcExchange array is due to excessively
4836 // long completions or timeouts.
4839 if (++i >= TACH_MAX_XID) // rollover check
4840 i = TACH_SEST_LEN; // beginning of Link Service X_IDs
4842 // printk( "looping for xchng ID: i=%d, type=%Xh\n",
4843 // i, Exchanges->fcExchange[i].type);
4845 if (Exchanges->fcExchange[i].type == 0) // "free"?
4847 ulStatus = 0; // success!
4850 if (i == fcChip->fcLsExchangeLRU) // wrapped-around array?
4852 printk("LinkService X_ID space full\n");
4853 break; // failed - prevent inf. loop
4857 fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
4861 if (!ulStatus) // success?
4862 Exchanges->fcExchange[i].type = type; // allocate it.
4865 i = -1; // error - all exchanges "open"
4870 static void cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev, PTACHYON fcChip, u32 x_ID)
4872 // Unmaps the memory regions used to hold the scatter gather lists
4876 // Were there any such regions needing unmapping?
4877 if (!USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
4878 return; // No such regions, we're outta here.
4880 // for each extended scatter gather region needing unmapping...
4881 for (i = fcChip->SEST->sgPages[x_ID]; i != NULL; i = i->next)
4882 pci_unmap_single(pcidev, i->busaddr, i->maplen, scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
4885 // Called also from cpqfcTScontrol.o, so can't be static
4886 void cpqfc_pci_unmap(struct pci_dev *pcidev, Scsi_Cmnd * cmd, PTACHYON fcChip, u32 x_ID)
4888 // Undo the DMA mappings
4889 if (cmd->use_sg) { // Used scatter gather list for data buffer?
4890 cpqfc_pci_unmap_extended_sg(pcidev, fcChip, x_ID);
4891 pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
4892 // printk("umsg %d\n", cmd->use_sg);
4893 } else if (cmd->request_bufflen) {
4894 // printk("ums %p ", fcChip->SEST->u[ x_ID ].IWE.GAddr1);
4895 pci_unmap_single(pcidev, fcChip->SEST->u[x_ID].IWE.GAddr1, cmd->request_bufflen, scsi_to_pci_dma_dir(cmd->sc_data_direction));
4899 // We call this routine to free an Exchange for any reason:
4900 // completed successfully, completed with error, aborted, etc.
4902 // returns 0 if Exchange failed and "retry" is acceptable
4903 // returns 1 if Exchange was successful, or retry is impossible
4904 // (e.g. port/device gone).
4907 void cpqfcTSCompleteExchange(struct pci_dev *pcidev, PTACHYON fcChip, u32 x_ID)
4909 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
4910 int already_unmapped = 0;
4912 if (x_ID < TACH_SEST_LEN) // SEST-based (or LinkServ for FCP exchange)
4914 if (Exchanges->fcExchange[x_ID].Cmnd == NULL) // what#@!
4916 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
4917 printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID, Exchanges->fcExchange[x_ID].type);
4919 goto CleanUpSestResources; // this path should be very rare.
4921 // we have Linux Scsi Cmnd ptr..., now check our Exchange status
4922 // to decide how to complete this SEST FCP exchange
4924 if (Exchanges->fcExchange[x_ID].status) // perhaps a Tach indicated problem,
4925 // or abnormal exchange completion
4927 // set FCP Link statistics
4929 if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
4930 fcChip->fcStats.timeouts++;
4931 if (Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
4932 fcChip->fcStats.FC4aborted++;
4933 if (Exchanges->fcExchange[x_ID].status & COUNT_ERROR)
4934 fcChip->fcStats.CntErrors++;
4935 if (Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
4936 fcChip->fcStats.linkFailTX++;
4937 if (Exchanges->fcExchange[x_ID].status & LINKFAIL_RX)
4938 fcChip->fcStats.linkFailRX++;
4939 if (Exchanges->fcExchange[x_ID].status & OVERFLOW)
4940 fcChip->fcStats.CntErrors++;
4942 // First, see if the Scsi upper level initiated an ABORT on this
4944 if (Exchanges->fcExchange[x_ID].status == INITIATOR_ABORT) {
4945 printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", x_ID, Exchanges->fcExchange[x_ID].Cmnd);
4946 goto CleanUpSestResources; // (we don't expect Linux _aborts)
4948 // Did our driver timeout the Exchange, or did Tachyon indicate
4949 // a failure during transmission? Ask for retry with "SOFT_ERROR"
4950 else if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) {
4951 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
4952 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
4953 Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
4955 // Did frame(s) for an open exchange arrive in the SFQ,
4956 // meaning the SEST was unable to process them?
4957 else if (Exchanges->fcExchange[x_ID].status & SFQ_FRAME) {
4958 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
4959 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
4960 Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
4962 // Did our driver timeout the Exchange, or did Tachyon indicate
4963 // a failure during transmission? Ask for retry with "SOFT_ERROR"
4964 else if ((Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) ||
4965 (Exchanges->fcExchange[x_ID].status & PORTID_CHANGED) || (Exchanges->fcExchange[x_ID].status & FRAME_TO) || (Exchanges->fcExchange[x_ID].status & INV_ENTRY) || (Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY))
4968 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
4969 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
4970 Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
4974 // e.g., a LOGOut happened, or device never logged back in.
4975 else if (Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) {
4976 // printk(" *LOGOut or timeout on login!* ");
4978 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
4979 Exchanges->fcExchange[x_ID].Cmnd->result = (DID_BAD_TARGET << 16);
4982 // Did Tachyon indicate a CNT error? We need further analysis
4983 // to determine if the exchange is acceptable
4984 else if (Exchanges->fcExchange[x_ID].status == COUNT_ERROR) {
4986 FCP_STATUS_RESPONSE *pFcpStatus = (PFCP_STATUS_RESPONSE) & fcChip->SEST->RspHDR[x_ID].pl;
4988 ScsiStatus = pFcpStatus->fcp_status >> 24;
4990 // If the command is a SCSI Read/Write type, we don't tolerate
4991 // count errors of any kind; assume the count error is due to
4992 // a dropped frame and ask for retry...
4994 if (((Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x8) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x28) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0xA) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x2A))
4995 && ScsiStatus == 0) {
4997 // printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n",
4998 // x_ID, Exchanges->fcExchange[ x_ID ].status,
4999 // Exchanges->fcExchange[ x_ID ].Cmnd);
5000 Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
5003 else // need more analysis
5005 cpqfcTSCheckandSnoopFCP(fcChip, x_ID); // (will set ->result)
5008 // default: NOTE! We don't ever want to get here. Getting here
5009 // implies something new is happening that we've never had a test
5010 // case for. Need code maintenance! Return "ERROR"
5012 unsigned int stat = Exchanges->fcExchange[x_ID].status;
5013 printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p", Exchanges->fcExchange[x_ID].status, x_ID, Exchanges->fcExchange[x_ID].Cmnd);
5015 if (stat & INVALID_ARGS)
5016 printk(" INVALID_ARGS ");
5017 if (stat & LNKDWN_OSLS)
5018 printk(" LNKDWN_OSLS ");
5019 if (stat & LNKDWN_LASER)
5020 printk(" LNKDWN_LASER ");
5021 if (stat & OUTQUE_FULL)
5022 printk(" OUTQUE_FULL ");
5023 if (stat & DRIVERQ_FULL)
5024 printk(" DRIVERQ_FULL ");
5025 if (stat & SEST_FULL)
5026 printk(" SEST_FULL ");
5027 if (stat & BAD_ALPA)
5028 printk(" BAD_ALPA ");
5029 if (stat & OVERFLOW)
5030 printk(" OVERFLOW ");
5031 if (stat & COUNT_ERROR)
5032 printk(" COUNT_ERROR ");
5033 if (stat & LINKFAIL_RX)
5034 printk(" LINKFAIL_RX ");
5035 if (stat & ABORTSEQ_NOTIFY)
5036 printk(" ABORTSEQ_NOTIFY ");
5037 if (stat & LINKFAIL_TX)
5038 printk(" LINKFAIL_TX ");
5039 if (stat & HOSTPROG_ERR)
5040 printk(" HOSTPROG_ERR ");
5041 if (stat & FRAME_TO)
5042 printk(" FRAME_TO ");
5043 if (stat & INV_ENTRY)
5044 printk(" INV_ENTRY ");
5045 if (stat & SESTPROG_ERR)
5046 printk(" SESTPROG_ERR ");
5047 if (stat & OUTBOUND_TIMEOUT)
5048 printk(" OUTBOUND_TIMEOUT ");
5049 if (stat & INITIATOR_ABORT)
5050 printk(" INITIATOR_ABORT ");
5051 if (stat & MEMPOOL_FAIL)
5052 printk(" MEMPOOL_FAIL ");
5053 if (stat & FC2_TIMEOUT)
5054 printk(" FC2_TIMEOUT ");
5055 if (stat & TARGET_ABORT)
5056 printk(" TARGET_ABORT ");
5057 if (stat & EXCHANGE_QUEUED)
5058 printk(" EXCHANGE_QUEUED ");
5059 if (stat & PORTID_CHANGED)
5060 printk(" PORTID_CHANGED ");
5061 if (stat & DEVICE_REMOVED)
5062 printk(" DEVICE_REMOVED ");
5063 if (stat & SFQ_FRAME)
5064 printk(" SFQ_FRAME ");
5067 Exchanges->fcExchange[x_ID].Cmnd->result = (DID_ERROR << 16);
5069 } else // definitely no Tach problem, but perhaps an FCP problem
5071 // set FCP Link statistic
5072 fcChip->fcStats.ok++;
5073 cpqfcTSCheckandSnoopFCP(fcChip, x_ID); // (will set ->result)
5076 cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, fcChip, x_ID); // undo DMA mappings.
5077 already_unmapped = 1;
5079 // OK, we've set the Scsi "->result" field, so proceed with calling
5080 // Linux Scsi "done" (if not NULL), and free any kernel memory we
5081 // may have allocated for the exchange.
5083 PCI_TRACEO((u32) Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
5084 // complete the command back to upper Scsi drivers
5085 if (Exchanges->fcExchange[x_ID].Cmnd->scsi_done != NULL) {
5086 // Calling "done" on an Linux _abort() aborted
5087 // Cmnd causes a kernel panic trying to re-free mem.
5088 // Actually, we shouldn't do anything with an _abort CMND
5089 if (Exchanges->fcExchange[x_ID].Cmnd->result != (DID_ABORT << 16)) {
5091 call_scsi_done(Exchanges->fcExchange[x_ID].Cmnd);
5093 Exchanges->fcExchange[x_ID].Cmnd->SCp.sent_command = 0;
5094 // printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
5095 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5098 Exchanges->fcExchange[x_ID].Cmnd->SCp.sent_command = 0;
5099 printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID, Exchanges->fcExchange[x_ID].type, Exchanges->fcExchange[x_ID].Cmnd->cmnd[0]);
5100 printk(" cpqfcTS: Null scsi_done function pointer!\n");
5104 // Now, clean up non-Scsi_Cmnd items...
5105 CleanUpSestResources:
5107 if (!already_unmapped)
5108 cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, fcChip, x_ID); // undo DMA mappings.
5110 // Was an Extended Scatter/Gather page allocated? We know
5111 // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
5112 if (!(fcChip->SEST->u[x_ID].IWE.Buff_Off & 0x80000000)) {
5115 // extended S/G list was used -- Free the allocated ext. S/G pages
5116 for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
5120 fcChip->SEST->sgPages[x_ID] = NULL;
5123 Exchanges->fcExchange[x_ID].Cmnd = NULL;
5124 } // Done with FCP (SEST) exchanges
5127 // the remaining logic is common to ALL Exchanges:
5128 // FCP(SEST) and LinkServ.
5130 Exchanges->fcExchange[x_ID].type = 0; // there -- FREE!
5131 Exchanges->fcExchange[x_ID].status = 0;
5133 PCI_TRACEO(x_ID, 0xAC)
5134 } // (END of CompleteExchange function)
5139 // Unfortunately, we must snoop all command completions in
5140 // order to manipulate certain return fields, and take note of
5141 // device types, etc., to facilitate the Fibre-Channel to SCSI
5143 // (Watch for BIG Endian confusion on some payload fields)
5144 void cpqfcTSCheckandSnoopFCP(PTACHYON fcChip, u32 x_ID)
5146 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5147 Scsi_Cmnd *Cmnd = Exchanges->fcExchange[x_ID].Cmnd;
5148 FCP_STATUS_RESPONSE *pFcpStatus = (PFCP_STATUS_RESPONSE) & fcChip->SEST->RspHDR[x_ID].pl;
5151 ScsiStatus = pFcpStatus->fcp_status >> 24;
5153 #ifdef FCP_COMPLETION_DBG
5154 printk("ScsiStatus = 0x%X\n", ScsiStatus);
5157 // First, check FCP status
5158 if (pFcpStatus->fcp_status & FCP_RSP_LEN_VALID) {
5159 // check response code (RSP_CODE) -- most popular is bad len
5160 // 1st 4 bytes of rsp info -- only byte 3 interesting
5161 if (pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN) {
5163 // do we EVER get here?
5164 printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
5167 // for now, go by the ScsiStatus, and manipulate certain
5168 // commands when necessary...
5169 if (ScsiStatus == 0) // SCSI status byte "good"?
5171 Cmnd->result = 0; // everything's OK
5173 if ((Cmnd->cmnd[0] == INQUIRY)) {
5174 u8 *InquiryData = Cmnd->request_buffer;
5175 PFC_LOGGEDIN_PORT pLoggedInPort;
5177 // We need to manipulate INQUIRY
5178 // strings for COMPAQ RAID controllers to force
5179 // Linux to scan additional LUNs. Namely, set
5180 // the Inquiry string byte 2 (ANSI-approved version)
5183 if (!memcmp(&InquiryData[8], "COMPAQ", 6)) {
5184 InquiryData[2] = 0x2; // claim SCSI-2 compliance,
5185 // so multiple LUNs may be scanned.
5186 // (no SCSI-2 problems known in CPQ)
5188 // snoop the Inquiry to detect Disk, Tape, etc. type
5189 // (search linked list for the port_id we sent INQUIRY to)
5190 pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // DON'T search Scsi Nexus (we will set it)
5191 Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF, NULL, // DON'T search linked list for FC WWN
5192 NULL); // DON'T care about end of list
5194 if (pLoggedInPort) {
5195 pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
5197 printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n", Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF);
5202 // Scsi Status not good -- pass it back to caller
5205 Cmnd->result = ScsiStatus; // SCSI status byte is 1st
5207 // check for valid "sense" data
5209 if (pFcpStatus->fcp_status & FCP_SNS_LEN_VALID) { // limit Scsi Sense field length!
5210 int SenseLen = pFcpStatus->fcp_sns_len >> 24; // (BigEndian) lower byte
5212 SenseLen = SenseLen > sizeof(Cmnd->sense_buffer) ? sizeof(Cmnd->sense_buffer) : SenseLen;
5215 #ifdef FCP_COMPLETION_DBG
5216 printk("copy sense_buffer %p, len %d, result %Xh\n", Cmnd->sense_buffer, SenseLen, Cmnd->result);
5219 // NOTE: There is some dispute over the FCP response
5220 // format. Most FC devices assume that FCP_RSP_INFO
5221 // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
5222 // is (virtually) always 0 and the field is "invalid".
5223 // Some other devices assume that
5224 // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
5225 // when the FCP_RSP is invalid (this almost appears to be
5226 // one of those "religious" issues).
5227 // Consequently, we test the usual position of FCP_SNS_INFO
5228 // for 7Xh, since the SCSI sense format says the first
5229 // byte ("error code") should be 0x70 or 0x71. In practice,
5230 // we find that every device does in fact have 0x70 or 0x71
5231 // in the first byte position, so this test works for all
5233 // (This logic is especially effective for the CPQ/DEC HSG80
5234 // & HSG60 controllers).
5236 if ((pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70)
5237 memcpy(Cmnd->sense_buffer, &pFcpStatus->fcp_sns_info[0], SenseLen);
5239 unsigned char *sbPtr = (unsigned char *) &pFcpStatus->fcp_sns_info[0];
5240 sbPtr -= 8; // back up 8 bytes hoping to find the
5241 // start of the sense buffer
5242 memcpy(Cmnd->sense_buffer, sbPtr, SenseLen);
5245 // in the special case of Device Reset, tell upper layer
5246 // to immediately retry (with SOFT_ERROR status)
5247 // look for Sense Key Unit Attention (0x6) with ASC Device
5249 // printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
5250 // SenseLen, Cmnd->sense_buffer[2],
5251 // Cmnd->sense_buffer[12]);
5252 if (((Cmnd->sense_buffer[2] & 0xF) == 0x6) && (Cmnd->sense_buffer[12] == 0x29)) // Sense Code "reset"
5254 Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
5256 // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
5257 else if (((Cmnd->sense_buffer[2] & 0xF) == 0x4) && // "hardware error"
5258 (Cmnd->sense_buffer[12] == 0x44)) // Addtl. Sense Code
5260 // printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
5261 // Cmnd->channel, Cmnd->target, Cmnd->lun);
5262 Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
5265 } // (end of sense len valid)
5267 // there is no sense data to help out Linux's Scsi layers...
5268 // We'll just return the Scsi status and hope he will "do the
5271 // as far as we know, the Scsi status is sufficient
5272 Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
5279 //PPPPPPPPPPPPPPPPPPPPPPPPP PAYLOAD PPPPPPPPP
5280 // build data PAYLOAD; SCSI FCP_CMND I.U.
5281 // remember BIG ENDIAN payload - DWord values must be byte-reversed
5282 // (hence the affinity for byte pointer building).
5284 static int build_FCP_payload(Scsi_Cmnd * Cmnd, u8 * payload, u32 type, u32 fcp_dl)
5294 // Peripheral Device or Volume Set addressing, and LUN mapping
5295 // When the FC port was looked up, we copied address mode
5296 // and any LUN mask to the scratch pad SCp.phase & .mode
5298 *payload++ = (u8) Cmnd->SCp.phase;
5300 // Now, because of "lun masking"
5301 // (aka selective storage presentation),
5302 // the contiguous Linux Scsi lun number may not match the
5303 // device's lun number, so we may have to "map".
5305 *payload++ = (u8) Cmnd->SCp.have_data_in;
5307 // We don't know of anyone in the FC business using these
5308 // extra "levels" of addressing. In fact, confusion still exists
5309 // just using the FIRST level... ;-)
5311 *payload++ = 0; // 2nd level addressing
5313 *payload++ = 0; // 3rd level addressing
5315 *payload++ = 0; // 4th level addressing
5318 // 4 bytes Control Field FCP_CNTL
5319 *payload++ = 0; // byte 0: (MSB) reserved
5320 *payload++ = 0; // byte 1: task codes
5322 // byte 2: task management flags
5323 // another "use" of the spare field to accomplish TDR
5324 // note combination needed
5325 if ((Cmnd->cmnd[0] == RELEASE) && (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET)) {
5326 Cmnd->cmnd[0] = 0; // issue "Test Unit Ready" for TDR
5327 *payload++ = 0x20; // target device reset bit
5329 *payload++ = 0; // no TDR
5330 // byte 3: (LSB) execution management codes
5331 // bit 0 write, bit 1 read (don't set together)
5334 if (type == SCSI_IWE) // WRITE
5339 // On some devices, if RD or WR bits are set,
5340 // and fcp_dl is 0, they will generate an error on the command.
5341 // (i.e., if direction is specified, they insist on a length).
5342 *payload++ = 0; // no data (necessary for CPQ)
5346 // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
5347 // FCP_CDB allows 16 byte SCSI command descriptor blk;
5348 // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
5349 for (i = 0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
5350 *payload++ = Cmnd->cmnd[i];
5352 if (Cmnd->cmd_len == 16) {
5353 memcpy(payload, &Cmnd->SCp.buffers_residual, 4);
5355 payload += (16 - i);
5357 // FCP_DL is largest number of expected data bytes
5358 // per CDB (i.e. read/write command)
5359 *payload++ = (u8) (fcp_dl >> 24); // (MSB) 8 bytes data len FCP_DL
5360 *payload++ = (u8) (fcp_dl >> 16);
5361 *payload++ = (u8) (fcp_dl >> 8);
5362 *payload++ = (u8) fcp_dl; // (LSB)
5365 case SCSI_TWE: // need FCP_XFER_RDY
5366 *payload++ = 0; // (4 bytes) DATA_RO (MSB byte 0)
5369 *payload++ = 0; // LSB (byte 3)
5370 // (4 bytes) BURST_LEN
5371 // size of following FCP_DATA payload
5372 *payload++ = (u8) (fcp_dl >> 24); // (MSB) 8 bytes data len FCP_DL
5373 *payload++ = (u8) (fcp_dl >> 16);
5374 *payload++ = (u8) (fcp_dl >> 8);
5375 *payload++ = (u8) fcp_dl; // (LSB)