patch-2.4.21 linux-2.4.21/drivers/scsi/cpqfcTSworker.c
Next file: linux-2.4.21/drivers/scsi/cyberstorm.c
Previous file: linux-2.4.21/drivers/scsi/cpqfcTStrigger.h
Back to the patch index
Back to the overall index
- Lines: 10705
- Date:
2003-06-13 07:51:36.000000000 -0700
- Orig file:
linux-2.4.20/drivers/scsi/cpqfcTSworker.c
- Orig date:
2002-11-28 15:53:14.000000000 -0800
diff -urN linux-2.4.20/drivers/scsi/cpqfcTSworker.c linux-2.4.21/drivers/scsi/cpqfcTSworker.c
@@ -44,7 +44,7 @@
#include "sd.h"
-#include "hosts.h" // struct Scsi_Host definition for T handler
+#include "hosts.h" // struct Scsi_Host definition for T handler
#include "cpqfcTSchip.h"
#include "cpqfcTSstructs.h"
#include "cpqfcTStrigger.h"
@@ -116,724 +116,579 @@
// local functions
-static void SetLoginFields(
- PFC_LOGGEDIN_PORT pLoggedInPort,
- TachFCHDR_GCMND* fchs,
- BOOLEAN PDisc,
- BOOLEAN Originator);
+static void SetLoginFields(PFC_LOGGEDIN_PORT pLoggedInPort, TachFCHDR_GCMND * fchs, u8 PDisc, u8 Originator);
-static void AnalyzeIncomingFrame(
- CPQFCHBA *cpqfcHBAdata,
- ULONG QNdx );
+static void AnalyzeIncomingFrame(CPQFCHBA * dev, u32 QNdx);
-static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
+static void SendLogins(CPQFCHBA * dev, __u32 * FabricPortIds);
-static int verify_PLOGI( PTACHYON fcChip,
- TachFCHDR_GCMND* fchs, ULONG* reject_explain);
-static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
+static int verify_PLOGI(PTACHYON fcChip, TachFCHDR_GCMND * fchs, u32 * reject_explain);
+static int verify_PRLI(TachFCHDR_GCMND * fchs, u32 * reject_explain);
-static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
-static void BuildLinkServicePayload(
- PTACHYON fcChip, ULONG type, void* payload);
+static void LoadWWN(PTACHYON fcChip, u8 * dest, u8 type);
+static void BuildLinkServicePayload(PTACHYON fcChip, u32 type, void *payload);
-static void UnblockScsiDevice( struct Scsi_Host *HostAdapter,
- PFC_LOGGEDIN_PORT pLoggedInPort);
+static void UnblockScsiDevice(struct Scsi_Host *HostAdapter, PFC_LOGGEDIN_PORT pLoggedInPort);
-static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
+static void cpqfcTSCheckandSnoopFCP(PTACHYON fcChip, u32 x_ID);
-static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
+static void CompleteBoardLockCmnd(CPQFCHBA * dev);
-static void RevalidateSEST( struct Scsi_Host *HostAdapter,
- PFC_LOGGEDIN_PORT pLoggedInPort);
+static void RevalidateSEST(struct Scsi_Host *HostAdapter, PFC_LOGGEDIN_PORT pLoggedInPort);
-static void IssueReportLunsCommand(
- CPQFCHBA* cpqfcHBAdata,
- TachFCHDR_GCMND* fchs);
+static void IssueReportLunsCommand(CPQFCHBA * dev, TachFCHDR_GCMND * fchs);
// (see scsi_error.c comments on kernel task creation)
-void cpqfcTSWorkerThread( void *host)
+void cpqfcTSWorkerThread(void *host)
{
- struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
- CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+ struct Scsi_Host *shpnt = (struct Scsi_Host *) host;
+ CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
#ifdef PCI_KERNEL_TRACE
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+ PTACHYON fcChip = &dev->fcChip;
#endif
- struct fs_struct *fs;
- DECLARE_MUTEX_LOCKED(fcQueReady);
- DECLARE_MUTEX_LOCKED(fcTYOBcomplete);
- DECLARE_MUTEX_LOCKED(TachFrozen);
- DECLARE_MUTEX_LOCKED(BoardLock);
+ struct fs_struct *fs;
+ DECLARE_MUTEX_LOCKED(fcQueReady);
+ DECLARE_MUTEX_LOCKED(fcTYOBcomplete);
+ DECLARE_MUTEX_LOCKED(TachFrozen);
+ DECLARE_MUTEX_LOCKED(BoardLock);
- ENTER("WorkerThread");
+ ENTER("WorkerThread");
- lock_kernel();
+ lock_kernel();
/*
* If we were started as result of loading a module, close all of the
* user space pages. We don't need them, and if we didn't close them
* they would be locked into memory.
+ *
+ * FIXME: should use daemonize!
*/
- exit_mm(current);
+ exit_mm(current);
- current->session = 1;
- current->pgrp = 1;
-
- /* Become as one with the init task */
-
- exit_fs(current); /* current->fs->count--; */
- fs = init_task.fs;
- // Some kernels compiled for SMP, while actually running
- // on a uniproc machine, will return NULL for this call
- if( !fs)
- {
- printk(" cpqfcTS FATAL: fs is NULL! Is this an SMP kernel on uniproc machine?\n ");
- }
-
- else
- {
- current->fs = fs;
- atomic_inc(&fs->count);
- }
+ current->session = 1;
+ current->pgrp = 1;
- siginitsetinv(¤t->blocked, SHUTDOWN_SIGS);
+ /* Become as one with the init task */
+ exit_fs(current); /* current->fs->count--; */
+ fs = init_task.fs;
+ current->fs = fs;
+ atomic_inc(&fs->count);
- /*
- * Set the name of this process.
- */
- sprintf(current->comm, "cpqfcTS_wt_%d", HostAdapter->host_no);
+ siginitsetinv(¤t->blocked, SHUTDOWN_SIGS);
- cpqfcHBAdata->fcQueReady = &fcQueReady; // primary wait point
- cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
- cpqfcHBAdata->TachFrozen = &TachFrozen;
-
-
- cpqfcHBAdata->worker_thread = current;
-
- unlock_kernel();
- if( cpqfcHBAdata->notify_wt != NULL )
- up( cpqfcHBAdata->notify_wt); // OK to continue
+ /*
+ * Set the name of this process.
+ */
+ sprintf(current->comm, "cpqfcTS_wt_%d", shpnt->host_no);
- while(1)
- {
- unsigned long flags;
+ dev->fcQueReady = &fcQueReady; // primary wait point
+ dev->TYOBcomplete = &fcTYOBcomplete;
+ dev->TachFrozen = &TachFrozen;
- down_interruptible( &fcQueReady); // wait for something to do
- if (signal_pending(current) )
- break;
-
- PCI_TRACE( 0x90)
- // first, take the IO lock so the SCSI upper layers can't call
- // into our _quecommand function (this also disables INTs)
- spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
- PCI_TRACE( 0x90)
-
- CPQ_SPINLOCK_HBA( cpqfcHBAdata)
- // next, set this pointer to indicate to the _quecommand function
- // that the board is in use, so it should que the command and
- // immediately return (we don't actually require the semaphore function
- // in this driver rev)
+ dev->worker_thread = current;
- cpqfcHBAdata->BoardLock = &BoardLock;
+ unlock_kernel();
- PCI_TRACE( 0x90)
+ if (dev->notify_wt != NULL)
+ up(dev->notify_wt); // OK to continue
- // release the IO lock (and re-enable interrupts)
- spin_unlock_irqrestore( &io_request_lock, flags);
+ while (1) {
+ unsigned long flags;
- // disable OUR HBA interrupt (keep them off as much as possible
- // during error recovery)
- disable_irq( cpqfcHBAdata->HostAdapter->irq);
+ down_interruptible(&fcQueReady); // wait for something to do
- // OK, let's process the Fibre Channel Link Q and do the work
- cpqfcTS_WorkTask( HostAdapter);
+ if (signal_pending(current))
+ break;
- // hopefully, no more "work" to do;
- // re-enable our INTs for "normal" completion processing
- enable_irq( cpqfcHBAdata->HostAdapter->irq);
-
+ PCI_TRACE(0x90)
+ // first, take the IO lock so the SCSI upper layers can't call
+ // into our _quecommand function (this also disables INTs)
+ spin_lock_irqsave(&io_request_lock, flags); // STOP _que function
+ PCI_TRACE(0x90)
- cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
- CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
+ CPQ_SPINLOCK_HBA(dev)
+ // next, set this pointer to indicate to the _quecommand function
+ // that the board is in use, so it should que the command and
+ // immediately return (we don't actually require the semaphore function
+ // in this driver rev)
+ dev->BoardLock = &BoardLock;
+ PCI_TRACE(0x90)
+ // release the IO lock (and re-enable interrupts)
+ spin_unlock_irqrestore(&io_request_lock, flags);
- // Now, complete any Cmnd we Q'd up while BoardLock was held
+ // disable OUR HBA interrupt (keep them off as much as possible
+ // during error recovery)
+ disable_irq(dev->HostAdapter->irq);
- CompleteBoardLockCmnd( cpqfcHBAdata);
-
+ // OK, let's process the Fibre Channel Link Q and do the work
+ cpqfcTS_WorkTask(shpnt);
- }
- // hopefully, the signal was for our module exit...
- if( cpqfcHBAdata->notify_wt != NULL )
- up( cpqfcHBAdata->notify_wt); // yep, we're outta here
+ // hopefully, no more "work" to do;
+ // re-enable our INTs for "normal" completion processing
+ enable_irq(dev->HostAdapter->irq);
+
+
+ dev->BoardLock = NULL; // allow commands to be queued
+ CPQ_SPINUNLOCK_HBA(dev)
+
+ // Now, complete any Cmnd we Q'd up while BoardLock was held
+ CompleteBoardLockCmnd(dev);
+
+
+ }
+ // hopefully, the signal was for our module exit...
+ if (dev->notify_wt != NULL)
+ up(dev->notify_wt); // yep, we're outta here
}
// Freeze Tachyon routine.
-// If Tachyon is already frozen, return FALSE
-// If Tachyon is not frozen, call freeze function, return TRUE
+// If Tachyon is already frozen, return 0
+// If Tachyon is not frozen, call freeze function, return 1
//
-static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
+static u8 FreezeTach(CPQFCHBA * dev)
{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- BOOLEAN FrozeTach = FALSE;
- // It's possible that the chip is already frozen; if so,
- // "Freezing" again will NOT! generate another Freeze
- // Completion Message.
-
- if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
- { // (need to freeze...)
- fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
-
- // 2. Get Tach freeze confirmation
- // (synchronize SEST manipulation with Freeze Completion Message)
- // we need INTs on so semaphore can be set.
- enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
- down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
- // can we TIMEOUT semaphore wait?? TBD
- disable_irq( cpqfcHBAdata->HostAdapter->irq);
-
- FrozeTach = TRUE;
- } // (else, already frozen)
-
- return FrozeTach;
-}
-
-
-
+ PTACHYON fcChip = &dev->fcChip;
+ u8 FrozeTach = 0;
+ // It's possible that the chip is already frozen; if so,
+ // "Freezing" again will NOT! generate another Freeze
+ // Completion Message.
+
+ if ((fcChip->Registers.TYstatus.value & 0x70000) != 0x70000) { // (need to freeze...)
+ fcChip->FreezeTachyon(fcChip, 2); // both ERQ and FCP assists
+ // 2. Get Tach freeze confirmation
+ // (synchronize SEST manipulation with Freeze Completion Message)
+ // we need INTs on so semaphore can be set.
+ enable_irq(dev->HostAdapter->irq); // only way to get Semaphore
+ down_interruptible(dev->TachFrozen); // wait for INT handler sem.
+ // can we TIMEOUT semaphore wait?? TBD
+ disable_irq(dev->HostAdapter->irq);
+ FrozeTach = 1;
+ } // (else, already frozen)
+ return FrozeTach;
+}
// This is the kernel worker thread task, which processes FC
// tasks which were queued by the Interrupt handler or by
// other WorkTask functions.
#define DBG 1
+
//#undef DBG
-void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
+void cpqfcTS_WorkTask(struct Scsi_Host *shpnt)
{
- CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- ULONG QconsumerNdx;
- LONG ExchangeID;
- ULONG ulStatus=0;
- TachFCHDR_GCMND fchs;
- PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-
- ENTER("WorkTask");
-
- // copy current index to work on
- QconsumerNdx = fcLQ->consumer;
-
- PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
-
-
- // NOTE: when this switch completes, we will "consume" the Que item
-// printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
- switch( fcLQ->Qitem[QconsumerNdx].Type )
- {
- // incoming frame - link service (ACC, UNSOL REQ, etc.)
- // or FCP-SCSI command
- case SFQ_UNKNOWN:
- AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
+ CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+ PTACHYON fcChip = &dev->fcChip;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ u32 QconsumerNdx;
+ s32 ExchangeID;
+ u32 ulStatus = 0;
+ TachFCHDR_GCMND fchs;
+ PFC_LINK_QUE fcLQ = dev->fcLQ;
+
+ ENTER("WorkTask");
+
+ // copy current index to work on
+ QconsumerNdx = fcLQ->consumer;
+
+ PCI_TRACEO(fcLQ->Qitem[QconsumerNdx].Type, 0x90)
+
+ // NOTE: when this switch completes, we will "consume" the Que item
+ // printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
+ switch (fcLQ->Qitem[QconsumerNdx].Type)
+ {
+ // incoming frame - link service (ACC, UNSOL REQ, etc.)
+ // or FCP-SCSI command
+ case SFQ_UNKNOWN:
+ AnalyzeIncomingFrame(dev, QconsumerNdx);
+ break;
- break;
-
-
-
- case EXCHANGE_QUEUED: // an Exchange (i.e. FCP-SCSI) was previously
- // Queued because the link was down. The
- // heartbeat timer detected it and Queued it here.
- // We attempt to start it again, and if
- // successful we clear the EXCHANGE_Q flag.
- // If the link doesn't come up, the Exchange
- // will eventually time-out.
-
- ExchangeID = (LONG) // x_ID copied from DPC timeout function
- fcLQ->Qitem[QconsumerNdx].ulBuff[0];
-
- // It's possible that a Q'd exchange could have already
- // been started by other logic (e.g. ABTS process)
- // Don't start if already started (Q'd flag clear)
-
- if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
- {
-// printk(" *Start Q'd x_ID %Xh: type %Xh ",
-// ExchangeID, Exchanges->fcExchange[ExchangeID].type);
-
- ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
- if( !ulStatus )
- {
-// printk("success* ");
- }
- else
- {
+ case EXCHANGE_QUEUED:
+ // an Exchange (i.e. FCP-SCSI) was previously
+ // Queued because the link was down. The
+ // heartbeat timer detected it and Queued it here.
+ // We attempt to start it again, and if
+ // successful we clear the EXCHANGE_Q flag.
+ // If the link doesn't come up, the Exchange
+ // will eventually time-out.
+
+ ExchangeID = (s32) fcLQ->Qitem[QconsumerNdx].ulBuff[0]; // x_ID copied from DPC timeout function
+
+ // It's possible that a Q'd exchange could have already
+ // been started by other logic (e.g. ABTS process)
+ // Don't start if already started (Q'd flag clear)
+
+ if (Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED) {
+// printk(" *Start Q'd x_ID %Xh: type %Xh ",
+// ExchangeID, Exchanges->fcExchange[ExchangeID].type);
+
+ ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+ if (!ulStatus) {
+// printk("success* ");
+ } else {
#ifdef DBG
-
- if( ulStatus == EXCHANGE_QUEUED)
- printk("Queued* ");
- else
- printk("failed* ");
-
+ if (ulStatus == EXCHANGE_QUEUED)
+ printk("Queued* ");
+ else
+ printk("failed* ");
#endif
- }
- }
- break;
+ }
+ }
+ break;
+ case LINKDOWN:
+ // (lots of things already done in INT handler) future here?
+ break;
- case LINKDOWN:
- // (lots of things already done in INT handler) future here?
- break;
-
-
- case LINKACTIVE: // Tachyon set the Lup bit in FM status
- // NOTE: some misbehaving FC ports (like Tach2.1)
- // can re-LIP immediately after a LIP completes.
-
- // if "initiator", need to verify LOGs with ports
-// printk("\n*LNKUP* ");
+ case LINKACTIVE: // Tachyon set the Lup bit in FM status
+ // NOTE: some misbehaving FC ports (like Tach2.1)
+ // can re-LIP immediately after a LIP completes.
+ // if "initiator", need to verify LOGs with ports
+// printk("\n*LNKUP* ");
+
+ if (fcChip->Options.initiator)
+ SendLogins(dev, NULL); // PLOGI or PDISC, based on fcPort data
+ // if SendLogins successfully completes, PortDiscDone
+ // will be set.
+ // If SendLogins was successful, then we expect to get incoming
+ // ACCepts or REJECTs, which are handled below.
+ break;
- if( fcChip->Options.initiator )
- SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
- // if SendLogins successfully completes, PortDiscDone
- // will be set.
-
-
- // If SendLogins was successful, then we expect to get incoming
- // ACCepts or REJECTs, which are handled below.
+ // LinkService and Fabric request/reply processing
+ case ELS_FDISC: // need to send Fabric Discovery (Login)
+ case ELS_FLOGI: // need to send Fabric Login
+ case ELS_SCR: // need to send State Change Registration
+ case FCS_NSR: // need to send Name Service Request
+ case ELS_PLOGI: // need to send PLOGI
+ case ELS_ACC: // send generic ACCept
+ case ELS_PLOGI_ACC: // need to send ELS ACCept frame to recv'd PLOGI
+ case ELS_PRLI_ACC: // need to send ELS ACCept frame to recv'd PRLI
+ case ELS_LOGO: // need to send ELS LOGO (logout)
+ case ELS_LOGO_ACC: // need to send ELS ACCept frame to recv'd PLOGI
+ case ELS_RJT: // ReJecT reply
+ case ELS_PRLI: // need to send ELS PRLI
+
+
+// printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
+ // if PortDiscDone is not set, it means the SendLogins routine
+ // failed to complete -- assume that LDn occurred, so login frames
+ // are invalid
+ if (!dev->PortDiscDone) // cleared by LDn
+ {
+ printk("Discard Q'd ELS login frame\n");
+ break;
+ }
- break;
+ ulStatus = cpqfcTSBuildExchange(dev, fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
+ (TachFCHDR_GCMND *)
+ fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
+ NULL, // no data (no scatter/gather list)
+ &ExchangeID); // fcController->fcExchanges index, -1 if failed
+
+ if (!ulStatus) // Exchange setup?
+ {
+ ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+ if (!ulStatus) {
+ // submitted to Tach's Outbound Que (ERQ PI incremented)
+ // waited for completion for ELS type (Login frames issued
+ // synchronously)
+ } else
+ // check reason for Exchange not being started - we might
+ // want to Queue and start later, or fail with error
+ {
- // LinkService and Fabric request/reply processing
- case ELS_FDISC: // need to send Fabric Discovery (Login)
- case ELS_FLOGI: // need to send Fabric Login
- case ELS_SCR: // need to send State Change Registration
- case FCS_NSR: // need to send Name Service Request
- case ELS_PLOGI: // need to send PLOGI
- case ELS_ACC: // send generic ACCept
- case ELS_PLOGI_ACC: // need to send ELS ACCept frame to recv'd PLOGI
- case ELS_PRLI_ACC: // need to send ELS ACCept frame to recv'd PRLI
- case ELS_LOGO: // need to send ELS LOGO (logout)
- case ELS_LOGO_ACC: // need to send ELS ACCept frame to recv'd PLOGI
- case ELS_RJT: // ReJecT reply
- case ELS_PRLI: // need to send ELS PRLI
-
-
-// printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
- // if PortDiscDone is not set, it means the SendLogins routine
- // failed to complete -- assume that LDn occurred, so login frames
- // are invalid
- if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
- {
- printk("Discard Q'd ELS login frame\n");
- break;
- }
-
- ulStatus = cpqfcTSBuildExchange(
- cpqfcHBAdata,
- fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
- (TachFCHDR_GCMND*)
- fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
- NULL, // no data (no scatter/gather list)
- &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
- if( !ulStatus ) // Exchange setup?
- {
- ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
- if( !ulStatus )
- {
- // submitted to Tach's Outbound Que (ERQ PI incremented)
- // waited for completion for ELS type (Login frames issued
- // synchronously)
- }
- else
- // check reason for Exchange not being started - we might
- // want to Queue and start later, or fail with error
- {
-
- }
- }
-
- else // Xchange setup failed...
- printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
-
- break;
-
- case SCSI_REPORT_LUNS:
- // pass the incoming frame (actually, it's a PRLI frame)
- // so we can send REPORT_LUNS, in order to determine VSA/PDU
- // FCP-SCSI Lun address mode
- IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
- fcLQ->Qitem[QconsumerNdx].ulBuff);
+ }
+ }
- break;
-
+ else // Xchange setup failed...
+ printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
+ break;
+ case SCSI_REPORT_LUNS:
+ // pass the incoming frame (actually, it's a PRLI frame)
+ // so we can send REPORT_LUNS, in order to determine VSA/PDU
+ // FCP-SCSI Lun address mode
+ IssueReportLunsCommand(dev, (TachFCHDR_GCMND *)
+ fcLQ->Qitem[QconsumerNdx].ulBuff);
- case BLS_ABTS: // need to ABORT one or more exchanges
- {
- LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
- BOOLEAN FrozeTach = FALSE;
-
- if( x_ID > TACH_SEST_LEN ) // (in)sanity check
- {
-// printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
- break;
- }
-
-
- if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
- {
-// printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
-
- break; // nothing to abort!
- }
+ break;
+ case BLS_ABTS: // need to ABORT one or more exchanges
+ {
+ s32 x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
+ u8 FrozeTach = 0;
+
+ if (x_ID > TACH_SEST_LEN) // (in)sanity check
+ {
+// printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
+ break;
+ }
+ if (Exchanges->fcExchange[x_ID].Cmnd == NULL) // should be RARE
+ {
+// printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
+ break; // nothing to abort!
+ }
//#define ABTS_DBG
#ifdef ABTS_DBG
- printk("INV SEST[%X] ", x_ID);
- if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
- {
- printk("FC2TO");
- }
- if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
- {
- printk("IA");
- }
- if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
- {
- printk("PORTID");
- }
- if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
- {
- printk("DEVRM");
- }
- if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
- {
- printk("LKF");
- }
- if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
- {
- printk("FRMTO");
- }
- if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
- {
- printk("ABSQ");
- }
- if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
- {
- printk("SFQFR");
- }
-
- if( Exchanges->fcExchange[ x_ID].type == 0x2000)
- printk(" WR");
- else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
- printk(" RD");
- else if( Exchanges->fcExchange[ x_ID].type == 0x10)
- printk(" ABTS");
- else
- printk(" %Xh", Exchanges->fcExchange[ x_ID].type);
-
- if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
- {
- printk(" Cmd %p, ",
- Exchanges->fcExchange[ x_ID].Cmnd);
-
- printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n",
- cpqfcHBAdata->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);
- }
- else // assume that Cmnd ptr is invalid on _abort()
- {
- printk(" Cmd ptr invalid\n");
- }
-
-#endif
-
-
- // Steps to ABORT a SEST exchange:
- // 1. Freeze TL SCSI assists & ERQ (everything)
- // 2. Receive FROZEN inbound CM (must succeed!)
- // 3. Invalidate x_ID SEST entry
- // 4. Resume TL SCSI assists & ERQ (everything)
- // 5. Build/start on exchange - change "type" to BLS_ABTS,
- // timeout to X sec (RA_TOV from PLDA is actually 0)
- // 6. Set Exchange Q'd status if ABTS cannot be started,
- // or simply complete Exchange in "Terminate" condition
-
- PCI_TRACEO( x_ID, 0xB4)
-
- // 1 & 2 . Freeze Tach & get confirmation of freeze
- FrozeTach = FreezeTach( cpqfcHBAdata);
-
- // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
- // FC2_TIMEOUT means we are originating the abort, while
- // TARGET_ABORT means we are ACCepting an abort.
- // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are
- // all from Tachyon:
- // Exchange was corrupted by LDn or other FC physical failure
- // INITIATOR_ABORT means the upper layer driver/application
- // requested the abort.
-
-
-
- // clear bit 31 (VALid), to invalidate & take control from TL
- fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
-
-
- // examine and Tach's "Linked List" for IWEs that
- // received (nearly) simultaneous transfer ready (XRDY)
- // repair linked list if necessary (TBD!)
- // (If we ignore the "Linked List", we will time out
- // WRITE commands where we received the FCP-SCSI XFRDY
- // frame (because Tachyon didn't processes it). Linked List
- // management should be done as an optimization.
-
-// readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
-
-
-
-
- // 4. Resume all Tachlite functions (for other open Exchanges)
- // as quickly as possible to allow other exchanges to other ports
- // to resume. Freezing Tachyon may cause cascading errors, because
- // any received SEST frame cannot be processed by the SEST.
- // Don't "unfreeze" unless Link is operational
- if( FrozeTach ) // did we just freeze it (above)?
- fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
-
-
- PCI_TRACEO( x_ID, 0xB4)
-
- // Note there is no confirmation that the chip is "unfrozen". Also,
- // if the Link is down when unfreeze is called, it has no effect.
- // Chip will unfreeze when the Link is back up.
-
- // 5. Now send out Abort commands if possible
- // Some Aborts can't be "sent" (Port_id changed or gone);
- // if the device is gone, there is no port_id to send the ABTS to.
-
- if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
- &&
- !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
- {
- Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
- fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
- ulStatus = cpqfcTSBuildExchange(
- cpqfcHBAdata,
- BLS_ABTS,
- &fchs, // (uses only s_id)
- NULL, // (no scatter/gather list for ABTS)
- &x_ID );// ABTS on this Exchange ID
-
- if( !ulStatus ) // Exchange setup build OK?
- {
-
- // ABTS may be needed because an Exchange was corrupted
- // by a Link disruption. If the Link is UP, we can
- // presume that this ABTS can start immediately; otherwise,
- // set Que'd status so the Login functions
- // can restart it when the FC physical Link is restored
- if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
- {
-// printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
- Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
- }
-
- else // what FC device (port_id) does the Cmd belong to?
- {
- PFC_LOGGEDIN_PORT pLoggedInPort =
- Exchanges->fcExchange[ x_ID].pLoggedInPort;
-
- // if Port is logged in, we might start the abort.
-
- if( (pLoggedInPort != NULL)
- &&
- (pLoggedInPort->prli == TRUE) )
- {
- // it's possible that an Exchange has already been Queued
- // to start after Login completes. Check and don't
- // start it (again) here if Q'd status set
-// printk(" ABTS xchg %Xh ", x_ID);
- if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
- {
-// printk("already Q'd ");
- }
- else
- {
-// printk("starting ");
-
- fcChip->fcStats.FC2aborted++;
- ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
- if( !ulStatus )
- {
- // OK
- // submitted to Tach's Outbound Que (ERQ PI incremented)
- }
- else
- {
-/* printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
- ulStatus, x_ID);
-*/
- }
- }
- }
- else
- {
-/* printk(" ABTS NOT starting xchg %Xh, %p ",
- x_ID, pLoggedInPort);
- if( pLoggedInPort )
- printk("prli %d ", pLoggedInPort->prli);
-*/
- }
- }
- }
- else // what the #@!
- { // how do we fail to build an Exchange for ABTS??
- printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
- ulStatus, x_ID);
- }
- }
- else // abort without ABTS -- just complete exchange/Cmnd to Linux
- {
-// printk(" *Terminating x_ID %Xh on %Xh* ",
-// x_ID, Exchanges->fcExchange[x_ID].status);
- cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, x_ID);
-
- }
- } // end of ABTS case
- break;
-
-
-
- case BLS_ABTS_ACC: // need to ACCept one ABTS
- // (NOTE! this code not updated for Linux yet..)
-
-
- printk(" *ABTS_ACC* ");
- // 1. Freeze TL
-
- fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
+ printk("INV SEST[%X] ", x_ID);
+ if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) {
+ printk("FC2TO");
+ }
+ if (Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT) {
+ printk("IA");
+ }
+ if (Exchanges->fcExchange[x_ID].status & PORTID_CHANGED) {
+ printk("PORTID");
+ }
+ if (Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) {
+ printk("DEVRM");
+ }
+ if (Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) {
+ printk("LKF");
+ }
+ if (Exchanges->fcExchange[x_ID].status & FRAME_TO) {
+ printk("FRMTO");
+ }
+ if (Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY) {
+ printk("ABSQ");
+ }
+ if (Exchanges->fcExchange[x_ID].status & SFQ_FRAME) {
+ printk("SFQFR");
+ }
- memcpy( // copy the incoming ABTS frame
- &fchs,
- fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
- sizeof( fchs));
-
- // 3. OK, Tachyon is frozen so we can invalidate SEST entry
- // (if necessary)
- // Status FC2_TIMEOUT means we are originating the abort, while
- // TARGET_ABORT means we are ACCepting an abort
-
- ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
-// printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
+ if (Exchanges->fcExchange[x_ID].type == 0x2000)
+ printk(" WR");
+ else if (Exchanges->fcExchange[x_ID].type == 0x3000)
+ printk(" RD");
+ else if (Exchanges->fcExchange[x_ID].type == 0x10)
+ printk(" ABTS");
+ else
+ printk(" %Xh", Exchanges->fcExchange[x_ID].type);
+
+ if (!(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)) {
+ printk(" Cmd %p, ", Exchanges->fcExchange[x_ID].Cmnd);
+
+ printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n",
+ 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);
+ } else // assume that Cmnd ptr is invalid on _abort()
+ {
+ printk(" Cmd ptr invalid\n");
+ }
+#endif
+ // Steps to ABORT a SEST exchange:
+ // 1. Freeze TL SCSI assists & ERQ (everything)
+ // 2. Receive FROZEN inbound CM (must succeed!)
+ // 3. Invalidate x_ID SEST entry
+ // 4. Resume TL SCSI assists & ERQ (everything)
+ // 5. Build/start on exchange - change "type" to BLS_ABTS,
+ // timeout to X sec (RA_TOV from PLDA is actually 0)
+ // 6. Set Exchange Q'd status if ABTS cannot be started,
+ // or simply complete Exchange in "Terminate" condition
+
+ PCI_TRACEO(x_ID, 0xB4)
+ // 1 & 2 . Freeze Tach & get confirmation of freeze
+ FrozeTach = FreezeTach(dev);
+
+ // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
+ // FC2_TIMEOUT means we are originating the abort, while
+ // TARGET_ABORT means we are ACCepting an abort.
+ // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are
+ // all from Tachyon:
+ // Exchange was corrupted by LDn or other FC physical failure
+ // INITIATOR_ABORT means the upper layer driver/application
+ // requested the abort.
+
+ // clear bit 31 (VALid), to invalidate & take control from TL
+ fcChip->SEST->u[x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
+
+ // examine and Tach's "Linked List" for IWEs that
+ // received (nearly) simultaneous transfer ready (XRDY)
+ // repair linked list if necessary (TBD!)
+ // (If we ignore the "Linked List", we will time out
+ // WRITE commands where we received the FCP-SCSI XFRDY
+ // frame (because Tachyon didn't processes it). Linked List
+ // management should be done as an optimization.
+
+// readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
+
+ // 4. Resume all Tachlite functions (for other open Exchanges)
+ // as quickly as possible to allow other exchanges to other ports
+ // to resume. Freezing Tachyon may cause cascading errors, because
+ // any received SEST frame cannot be processed by the SEST.
+ // Don't "unfreeze" unless Link is operational
+ if (FrozeTach) // did we just freeze it (above)?
+ fcChip->UnFreezeTachyon(fcChip, 2); // both ERQ and FCP assists
+
+ PCI_TRACEO(x_ID, 0xB4)
+ // Note there is no confirmation that the chip is "unfrozen". Also,
+ // if the Link is down when unfreeze is called, it has no effect.
+ // Chip will unfreeze when the Link is back up.
+ // 5. Now send out Abort commands if possible
+ // Some Aborts can't be "sent" (Port_id changed or gone);
+ // if the device is gone, there is no port_id to send the ABTS to.
+ if (!(Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
+ && !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)) {
+ Exchanges->fcExchange[x_ID].type = BLS_ABTS;
+ fchs.s_id = Exchanges->fcExchange[x_ID].fchs.d_id;
+ ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS, &fchs, // (uses only s_id)
+ NULL, // (no scatter/gather list for ABTS)
+ &x_ID); // ABTS on this Exchange ID
+
+ if (!ulStatus) // Exchange setup build OK?
+ {
+
+ // ABTS may be needed because an Exchange was corrupted
+ // by a Link disruption. If the Link is UP, we can
+ // presume that this ABTS can start immediately; otherwise,
+ // set Que'd status so the Login functions
+ // can restart it when the FC physical Link is restored
+ if (((fcChip->Registers.FMstatus.value & 0xF0) & 0x80)) // loop init?
+ {
+// printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
+ Exchanges->fcExchange[x_ID].status |= EXCHANGE_QUEUED;
+ }
+
+ else // what FC device (port_id) does the Cmd belong to?
+ {
+ PFC_LOGGEDIN_PORT pLoggedInPort = Exchanges->fcExchange[x_ID].pLoggedInPort;
+
+ // if Port is logged in, we might start the abort.
+
+ if ((pLoggedInPort != NULL)
+ && (pLoggedInPort->prli == 1)) {
+ // it's possible that an Exchange has already been Queued
+ // to start after Login completes. Check and don't
+ // start it (again) here if Q'd status set
+// printk(" ABTS xchg %Xh ", x_ID);
+ if (Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED) {
+// printk("already Q'd ");
+ } else {
+// printk("starting ");
+ fcChip->fcStats.FC2aborted++;
+ ulStatus = cpqfcTSStartExchange(dev, x_ID);
+ if (!ulStatus) {
+ // OK
+ // submitted to Tach's Outbound Que (ERQ PI incremented)
+ } else {
+// printk("ABTS exchange start failed -status %Xh, x_ID %Xh ", ulStatus, x_ID);
+ }
+ }
+ }
+ }
+ } else // what the #@!
+ { // how do we fail to build an Exchange for ABTS??
+ printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n", ulStatus, x_ID);
+ }
+ } else // abort without ABTS -- just complete exchange/Cmnd to Linux
+ {
+// printk(" *Terminating x_ID %Xh on %Xh* ",
+// x_ID, Exchanges->fcExchange[x_ID].status);
+ cpqfcTSCompleteExchange(dev->PciDev, fcChip, x_ID);
+ }
+ } // end of ABTS case
+ break;
- // sanity check on received ExchangeID
- if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
- {
- // clear bit 31 (VALid), to invalidate & take control from TL
-// printk("Invalidating SEST exchange %Xh\n", ExchangeID);
- fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
- }
-
-
- // 4. Resume all Tachlite functions (for other open Exchanges)
- // as quickly as possible to allow other exchanges to other ports
- // to resume. Freezing Tachyon for too long may royally screw
- // up everything!
- fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
-
- // Note there is no confirmation that the chip is "unfrozen". Also,
- // if the Link is down when unfreeze is called, it has no effect.
- // Chip will unfreeze when the Link is back up.
+ case BLS_ABTS_ACC: // need to ACCept one ABTS
+ // (NOTE! this code not updated for Linux yet..)
+ printk(" *ABTS_ACC* ");
+ // 1. Freeze TL
+
+ fcChip->FreezeTachyon(fcChip, 2); // both ERQ and FCP assists
+ memcpy( // copy the incoming ABTS frame
+ &fchs, fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
+ sizeof(fchs));
+
+ // 3. OK, Tachyon is frozen so we can invalidate SEST entry
+ // (if necessary)
+ // Status FC2_TIMEOUT means we are originating the abort, while
+ // TARGET_ABORT means we are ACCepting an abort
+
+ ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
+// printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
+
+ // sanity check on received ExchangeID
+ if (Exchanges->fcExchange[ExchangeID].status == TARGET_ABORT) {
+ // clear bit 31 (VALid), to invalidate & take control from TL
+// printk("Invalidating SEST exchange %Xh\n", ExchangeID);
+ fcChip->SEST->u[ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
+ }
- // 5. Now send out Abort ACC reply for this exchange
- Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
-
- fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
- ulStatus = cpqfcTSBuildExchange(
- cpqfcHBAdata,
- BLS_ABTS_ACC,
- &fchs,
- NULL, // no data (no scatter/gather list)
- &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
- if( !ulStatus ) // Exchange setup?
- {
- ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
- if( !ulStatus )
- {
- // submitted to Tach's Outbound Que (ERQ PI incremented)
- // waited for completion for ELS type (Login frames issued
- // synchronously)
- }
- else
- // check reason for Exchange not being started - we might
- // want to Queue and start later, or fail with error
- {
-
- }
- }
- break;
-
-
- case BLS_ABTS_RJT: // need to ReJecT one ABTS; reject implies the
- // exchange doesn't exist in the TARGET context.
- // ExchangeID has to come from LinkService space.
-
- printk(" *ABTS_RJT* ");
- ulStatus = cpqfcTSBuildExchange(
- cpqfcHBAdata,
- BLS_ABTS_RJT,
- (TachFCHDR_GCMND*)
- fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
- NULL, // no data (no scatter/gather list)
- &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
- if( !ulStatus ) // Exchange setup OK?
- {
- ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
- // If it fails, we aren't required to retry.
- }
- if( ulStatus )
- {
- printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
- }
- else
- {
- printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
-
- }
+ // 4. Resume all Tachlite functions (for other open Exchanges)
+ // as quickly as possible to allow other exchanges to other ports
+ // to resume. Freezing Tachyon for too long may royally screw
+ // up everything!
+ fcChip->UnFreezeTachyon(fcChip, 2); // both ERQ and FCP assists
+
+ // Note there is no confirmation that the chip is "unfrozen". Also,
+ // if the Link is down when unfreeze is called, it has no effect.
+ // Chip will unfreeze when the Link is back up.
+
+ // 5. Now send out Abort ACC reply for this exchange
+ Exchanges->fcExchange[ExchangeID].type = BLS_ABTS_ACC;
+
+ fchs.s_id = Exchanges->fcExchange[ExchangeID].fchs.d_id;
+ ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS_ACC, &fchs, NULL, // no data (no scatter/gather list)
+ &ExchangeID); // fcController->fcExchanges index, -1 if failed
+
+ if (!ulStatus) // Exchange setup?
+ {
+ ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+ if (!ulStatus) {
+ // submitted to Tach's Outbound Que (ERQ PI incremented)
+ // waited for completion for ELS type (Login frames issued
+ // synchronously)
+ } else
+ // check reason for Exchange not being started - we might
+ // want to Queue and start later, or fail with error
+ {
- break;
+ }
+ }
+ break;
+ case BLS_ABTS_RJT: // need to ReJecT one ABTS; reject implies the
+ // exchange doesn't exist in the TARGET context.
+ // ExchangeID has to come from LinkService space.
+
+ printk(" *ABTS_RJT* ");
+ ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS_RJT, (TachFCHDR_GCMND *)
+ fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
+ NULL, // no data (no scatter/gather list)
+ &ExchangeID); // fcController->fcExchanges index, -1 if failed
+
+ if (!ulStatus) // Exchange setup OK?
+ {
+ ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+ // If it fails, we aren't required to retry.
+ }
+ if (ulStatus) {
+ printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
+ } else {
+ printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
+ }
+ break;
- default:
- break;
- } // end switch
-//doNothing:
- // done with this item - now set the NEXT index
+ default:
+ break;
+ } // end switch
+ // done with this item - now set the NEXT index
- if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
- {
- fcLQ->consumer = 0;
- }
- else
- {
- fcLQ->consumer++;
- }
+ if (QconsumerNdx + 1 >= FC_LINKQ_DEPTH) // rollover test
+ fcLQ->consumer = 0;
+ else
+ fcLQ->consumer++;
- PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
+ PCI_TRACEO(fcLQ->Qitem[QconsumerNdx].Type, 0x94)
- LEAVE("WorkTask");
- return;
+ LEAVE("WorkTask");
+ return;
}
@@ -845,115 +700,89 @@
// This circular Q works like Tachyon's que - the producer points to the next
// (unused) entry. Called by Interrupt handler, WorkerThread, Timer
// sputlinkq
-void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
- int Type,
- void *QueContent)
-{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-// FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
- ULONG ndx;
-
- ENTER("cpqfcTSPutLinkQ");
-
- ndx = fcLQ->producer;
-
- ndx += 1; // test for Que full
-
-
-
- if( ndx >= FC_LINKQ_DEPTH ) // rollover test
- ndx = 0;
+void cpqfcTSPutLinkQue(CPQFCHBA * dev, int Type, void *QueContent)
+{
+ PTACHYON fcChip = &dev->fcChip;
+// FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ PFC_LINK_QUE fcLQ = dev->fcLQ;
+ u32 ndx;
- if( ndx == fcLQ->consumer ) // QUE full test
- {
- // QUE was full! lost LK command (fatal to logic)
- fcChip->fcStats.lnkQueFull++;
+ ENTER("cpqfcTSPutLinkQ");
- printk("*LinkQ Full!*");
- TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
-/*
- {
- int i;
- printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
- fcLQ->consumer);
-
- for( i=0; i< FC_LINKQ_DEPTH; )
- {
- printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
- if( (++i %8) == 0) printk("\n");
- }
-
- }
-*/
- printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
- }
- else // QUE next element
- {
- // Prevent certain multiple (back-to-back) requests.
- // This is important in that we don't want to issue multiple
- // ABTS for the same Exchange, or do multiple FM inits, etc.
- // We can never be sure of the timing of events reported to
- // us by Tach's IMQ, which can depend on system/bus speeds,
- // FC physical link circumstances, etc.
-
- if( (fcLQ->producer != fcLQ->consumer)
- &&
- (Type == FMINIT) )
- {
- LONG lastNdx; // compute previous producer index
- if( fcLQ->producer)
- lastNdx = fcLQ->producer- 1;
- else
- lastNdx = FC_LINKQ_DEPTH-1;
+ ndx = fcLQ->producer;
+ ndx += 1; // test for Que full
- if( fcLQ->Qitem[lastNdx].Type == FMINIT)
- {
-// printk(" *skip FMINIT Q post* ");
-// goto DoneWithPutQ;
- }
- }
- // OK, add the Q'd item...
-
- fcLQ->Qitem[fcLQ->producer].Type = Type;
-
- memcpy(
- fcLQ->Qitem[fcLQ->producer].ulBuff,
- QueContent,
- sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
+ if (ndx >= FC_LINKQ_DEPTH) // rollover test
+ ndx = 0;
- fcLQ->producer = ndx; // increment Que producer
+ if (ndx == fcLQ->consumer) // QUE full test
+ {
+ // QUE was full! lost LK command (fatal to logic)
+ fcChip->fcStats.lnkQueFull++;
- // set semaphore to wake up Kernel (worker) thread
- //
- up( cpqfcHBAdata->fcQueReady );
- }
+ printk("*LinkQ Full!*");
+ TriggerHBA(fcChip->Registers.ReMapMemBase, 1);
+/*
+ {
+ int i;
+ printk("LinkQ PI %d, CI %d\n", fcLQ->producer, fcLQ->consumer);
+
+ for( i=0; i< FC_LINKQ_DEPTH; )
+ {
+ printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
+ if( (++i %8) == 0)
+ printk("\n");
+ }
+ }
+*/
+ printk("cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
+ }
+ else // QUE next element
+ {
+ // Prevent certain multiple (back-to-back) requests.
+ // This is important in that we don't want to issue multiple
+ // ABTS for the same Exchange, or do multiple FM inits, etc.
+ // We can never be sure of the timing of events reported to
+ // us by Tach's IMQ, which can depend on system/bus speeds,
+ // FC physical link circumstances, etc.
+
+ if ((fcLQ->producer != fcLQ->consumer)
+ && (Type == FMINIT)) {
+ s32 lastNdx; // compute previous producer index
+ if (fcLQ->producer)
+ lastNdx = fcLQ->producer - 1;
+ else
+ lastNdx = FC_LINKQ_DEPTH - 1;
+
+
+ if (fcLQ->Qitem[lastNdx].Type == FMINIT) {
+// printk(" *skip FMINIT Q post* ");
+// goto DoneWithPutQ;
+ }
+ }
+ // OK, add the Q'd item...
+ fcLQ->Qitem[fcLQ->producer].Type = Type;
+ memcpy(fcLQ->Qitem[fcLQ->producer].ulBuff, QueContent, sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
+ fcLQ->producer = ndx; // increment Que producer
+ // set semaphore to wake up Kernel (worker) thread
+ up(dev->fcQueReady);
+ }
//DoneWithPutQ:
-
- LEAVE("cpqfcTSPutLinkQ");
+ LEAVE("cpqfcTSPutLinkQ");
}
-
-
-
// reset device ext FC link Q
-void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
-
+void cpqfcTSLinkQReset(CPQFCHBA * dev)
{
- PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
- fcLQ->producer = 0;
- fcLQ->consumer = 0;
-
+ PFC_LINK_QUE fcLQ = dev->fcLQ;
+ fcLQ->producer = 0;
+ fcLQ->consumer = 0;
}
-
-
-
-
// When Tachyon gets an unassisted FCP-SCSI frame, post here so
// an arbitrary context thread (e.g. IOCTL loopback test function)
// can process it.
@@ -961,17 +790,15 @@
// (NOTE: Not revised for Linux)
// This Q works like Tachyon's que - the producer points to the next
// (unused) entry.
-void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
- int Type,
- void *QueContent)
+void cpqfcTSPutScsiQue(CPQFCHBA * dev, int Type, void *QueContent)
{
-// CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-// PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+// CPQFCHBA *dev = (CPQFCHBA *)shpnt->hostdata;
+// PTACHYON fcChip = &dev->fcChip;
-// ULONG ndx;
+// u32 ndx;
-// ULONG *pExchangeID;
-// LONG ExchangeID;
+// u32 *pExchangeID;
+// s32 ExchangeID;
/*
KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
@@ -999,7 +826,7 @@
// copied an FCP response frame into a buffer pointed to by the SEST
// entry. That buffer is allocated in the SEST structure at ->RspHDR.
// Copy the RspHDR for use by the Que handler.
- pExchangeID = (ULONG *)QueContent;
+ pExchangeID = (u32 *)QueContent;
memcpy(
pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
@@ -1020,175 +847,127 @@
KeSetEvent( &pDevExt->TYIBscsi, // signal any waiting thread
0, // no priority boost
- FALSE ); // no waiting later for this event
+ 0 ); // no waiting later for this event
}
KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
*/
}
+static void ProcessELS_Request(CPQFCHBA *, TachFCHDR_GCMND *);
+static void ProcessELS_Reply(CPQFCHBA *, TachFCHDR_GCMND *);
+static void ProcessFCS_Reply(CPQFCHBA *, TachFCHDR_GCMND *);
-
-
-
-
-
-static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
-
-static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
-
-static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
-
-void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
- PFC_LOGGEDIN_PORT pFcPort)
+void cpqfcTSImplicitLogout(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pFcPort)
{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+ PTACHYON fcChip = &dev->fcChip;
- if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
- {
- fcChip->fcStats.logouts++;
- printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n",
- (ULONG)pFcPort->u.liWWN,
- (ULONG)(pFcPort->u.liWWN >>32),
- pFcPort->port_id);
-
- // Terminate I/O with this (Linux) Scsi target
- cpqfcTSTerminateExchange( cpqfcHBAdata,
- &pFcPort->ScsiNexus,
- DEVICE_REMOVED);
- }
-
- // Do an "implicit logout" - we can't really Logout the device
- // (i.e. with LOGOut Request) because of port_id confusion
- // (i.e. the Other port has no port_id).
- // A new login for that WWN will have to re-write port_id (0 invalid)
- pFcPort->port_id = 0; // invalid!
- pFcPort->pdisc = FALSE;
- pFcPort->prli = FALSE;
- pFcPort->plogi = FALSE;
- pFcPort->flogi = FALSE;
- pFcPort->LOGO_timer = 0;
- pFcPort->device_blocked = TRUE; // block Scsi Requests
- pFcPort->ScsiNexus.VolumeSetAddressing=0;
+ if (pFcPort->port_id != 0xFFFC01) // don't care about Fabric
+ {
+ fcChip->fcStats.logouts++;
+ printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", (u32) pFcPort->u.liWWN, (u32) (pFcPort->u.liWWN >> 32), pFcPort->port_id);
+
+ // Terminate I/O with this (Linux) Scsi target
+ cpqfcTSTerminateExchange(dev, &pFcPort->ScsiNexus, DEVICE_REMOVED);
+ }
+ // Do an "implicit logout" - we can't really Logout the device
+ // (i.e. with LOGOut Request) because of port_id confusion
+ // (i.e. the Other port has no port_id).
+ // A new login for that WWN will have to re-write port_id (0 invalid)
+ pFcPort->port_id = 0; // invalid!
+ pFcPort->pdisc = 0;
+ pFcPort->prli = 0;
+ pFcPort->plogi = 0;
+ pFcPort->flogi = 0;
+ pFcPort->LOGO_timer = 0;
+ pFcPort->device_blocked = 1; // block Scsi Requests
+ pFcPort->ScsiNexus.VolumeSetAddressing = 0;
}
-
+
// On FC-AL, there is a chance that a previously known device can
// be quietly removed (e.g. with non-managed hub),
// while a NEW device (with different WWN) took the same alpa or
// even 24-bit port_id. This chance is unlikely but we must always
// check for it.
-static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
- PFC_LOGGEDIN_PORT pLoggedInPort)
+
+static void TestDuplicatePortId(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pLoggedInPort)
{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- // set "other port" at beginning of fcPorts list
- PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
- while( pOtherPortWithPortId )
- {
- if( (pOtherPortWithPortId->port_id ==
- pLoggedInPort->port_id)
- &&
- (pOtherPortWithPortId != pLoggedInPort) )
- {
- // trouble! (Implicitly) Log the other guy out
- printk(" *port_id %Xh is duplicated!* ",
- pOtherPortWithPortId->port_id);
- cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId);
- }
- pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
- }
+ PTACHYON fcChip = &dev->fcChip;
+ // set "other port" at beginning of fcPorts list
+ PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
+ while (pOtherPortWithPortId) {
+ if ((pOtherPortWithPortId->port_id == pLoggedInPort->port_id)
+ && (pOtherPortWithPortId != pLoggedInPort)) {
+ // trouble! (Implicitly) Log the other guy out
+ printk(" *port_id %Xh is duplicated!* ", pOtherPortWithPortId->port_id);
+ cpqfcTSImplicitLogout(dev, pOtherPortWithPortId);
+ }
+ pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
+ }
}
-
-
-
-
-
// Dynamic Memory Allocation for newly discovered FC Ports.
// For simplicity, maintain fcPorts structs for ALL
// for discovered devices, including those we never do I/O with
// (e.g. Fabric addresses)
-static PFC_LOGGEDIN_PORT CreateFcPort(
- CPQFCHBA* cpqfcHBAdata,
- PFC_LOGGEDIN_PORT pLastLoggedInPort,
- TachFCHDR_GCMND* fchs,
- LOGIN_PAYLOAD* plogi)
-{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
- int i;
-
-
- printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
- for( i=3; i>=0; i--) // copy the LOGIN port's WWN
- printk("%02X", plogi->port_name[i]);
- for( i=7; i>3; i--) // copy the LOGIN port's WWN
- printk("%02X", plogi->port_name[i]);
-
-
- // allocate mem for new port
- // (these are small and rare allocations...)
- pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
-
-
- // allocation succeeded? Fill out NEW PORT
- if( pNextLoggedInPort )
- {
- // clear out any garbage (sometimes exists)
- memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
-
-
- // If we login to a Fabric, we don't want to treat it
- // as a SCSI device...
- if( (fchs->s_id & 0xFFF000) != 0xFFF000)
- {
- int i;
-
- // create a unique "virtual" SCSI Nexus (for now, just a
- // new target ID) -- we will update channel/target on REPORT_LUNS
- // special case for very first SCSI target...
- if( cpqfcHBAdata->HostAdapter->max_id == 0)
- {
- pNextLoggedInPort->ScsiNexus.target = 0;
- fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
- }
- else
- {
- pNextLoggedInPort->ScsiNexus.target =
- cpqfcHBAdata->HostAdapter->max_id;
- }
-
- // initialize the lun[] Nexus struct for lun masking
- for( i=0; i< CPQFCTS_MAX_LUN; i++)
- pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
-
- pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
-
- printk(" SCSI Chan/Trgt %d/%d",
- pNextLoggedInPort->ScsiNexus.channel,
- pNextLoggedInPort->ScsiNexus.target);
-
- // tell Scsi layers about the new target...
- cpqfcHBAdata->HostAdapter->max_id++;
-// printk("HostAdapter->max_id = %d\n",
-// cpqfcHBAdata->HostAdapter->max_id);
- }
- else
- {
- // device is NOT SCSI (in case of Fabric)
- pNextLoggedInPort->ScsiNexus.target = -1; // invalid
- }
+static PFC_LOGGEDIN_PORT CreateFcPort(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pLastLoggedInPort, TachFCHDR_GCMND * fchs, LOGIN_PAYLOAD * plogi)
+{
+ PTACHYON fcChip = &dev->fcChip;
+ PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
+ int i;
+
+ printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
+ for (i = 3; i >= 0; i--) // copy the LOGIN port's WWN
+ printk("%02X", plogi->port_name[i]);
+ for (i = 7; i > 3; i--) // copy the LOGIN port's WWN
+ printk("%02X", plogi->port_name[i]);
+
+ // allocate mem for new port
+ // (these are small and rare allocations...)
+ pNextLoggedInPort = kmalloc(sizeof(FC_LOGGEDIN_PORT), GFP_ATOMIC);
+
+ // allocation succeeded? Fill out NEW PORT
+ if (pNextLoggedInPort) {
+ // clear out any garbage (sometimes exists)
+ memset(pNextLoggedInPort, 0, sizeof(FC_LOGGEDIN_PORT));
+ // If we login to a Fabric, we don't want to treat it
+ // as a SCSI device...
+ if ((fchs->s_id & 0xFFF000) != 0xFFF000) {
+ int i;
+
+ // create a unique "virtual" SCSI Nexus (for now, just a
+ // new target ID) -- we will update channel/target on REPORT_LUNS
+ // special case for very first SCSI target...
+ if (dev->HostAdapter->max_id == 0) {
+ pNextLoggedInPort->ScsiNexus.target = 0;
+ fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
+ } else {
+ pNextLoggedInPort->ScsiNexus.target = dev->HostAdapter->max_id;
+ }
- // create forward link to new port
- pLastLoggedInPort->pNextPort = pNextLoggedInPort;
- printk("\n");
-
- }
- return pNextLoggedInPort; // NULL on allocation failure
-} // end NEW PORT (WWN) logic
+ // initialize the lun[] Nexus struct for lun masking
+ for (i = 0; i < CPQFCTS_MAX_LUN; i++)
+ pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
+
+ pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
+ printk(" SCSI Chan/Trgt %d/%d", pNextLoggedInPort->ScsiNexus.channel, pNextLoggedInPort->ScsiNexus.target);
+ // tell Scsi layers about the new target...
+ dev->HostAdapter->max_id++;
+// printk("HostAdapter->max_id = %d\n",
+// dev->HostAdapter->max_id);
+ } else {
+ // device is NOT SCSI (in case of Fabric)
+ pNextLoggedInPort->ScsiNexus.target = -1; // invalid
+ }
+ // create forward link to new port
+ pLastLoggedInPort->pNextPort = pNextLoggedInPort;
+ printk("\n");
+ }
+ return pNextLoggedInPort; // NULL on allocation failure
+} // end NEW PORT (WWN) logic
// For certain cases, we want to terminate exchanges without
// sending ABTS to the device. Examples include when an FC
@@ -1200,870 +979,620 @@
// Since we must ensure that Tachyon is not operating on the
// exchange, we have to freeze the chip
// sterminateex
-void cpqfcTSTerminateExchange(
- CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
+
+void cpqfcTSTerminateExchange(CPQFCHBA * dev, SCSI_NEXUS * ScsiNexus, int TerminateStatus)
{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- ULONG x_ID;
+ PTACHYON fcChip = &dev->fcChip;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ u32 x_ID;
+
+ if (ScsiNexus) {
+// printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
+// ScsiNexus->channel, ScsiNexus->target);
+ }
+ for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+ if (Exchanges->fcExchange[x_ID].type) // in use?
+ {
+ if (ScsiNexus == NULL) // our HBA changed - term. all
+ {
+ Exchanges->fcExchange[x_ID].status = TerminateStatus;
+ cpqfcTSPutLinkQue(dev, BLS_ABTS, &x_ID);
+ } else {
+ // If a device, according to WWN, has been removed, it's
+ // port_id may be used by another working device, so we
+ // have to terminate by SCSI target, NOT port_id.
+ if (Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
+ {
+ if ((Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
+ && (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel)) {
+ Exchanges->fcExchange[x_ID].status = TerminateStatus;
+ cpqfcTSPutLinkQue(dev, BLS_ABTS, &x_ID); // timed-out
+ }
+ }
+ // (in case we ever need it...)
+ // all SEST structures have a remote node ID at SEST DWORD 2
+ // if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
+ // == port_id)
+ }
+ }
+ }
+}
- if( ScsiNexus )
- {
-// printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
-// ScsiNexus->channel, ScsiNexus->target);
+static void ProcessELS_Request(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+ PTACHYON fcChip = &dev->fcChip;
+// FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+// u32 ox_id = (fchs->ox_rx_id >>16);
+ PFC_LOGGEDIN_PORT pLoggedInPort = NULL, pLastLoggedInPort;
+ u8 NeedReject = 0;
+ u32 ls_reject_code = 0; // default don'n know??
- }
-
- for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
- {
- if( Exchanges->fcExchange[x_ID].type ) // in use?
- {
- if( ScsiNexus == NULL ) // our HBA changed - term. all
- {
- Exchanges->fcExchange[x_ID].status = TerminateStatus;
- cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID );
- }
- else
- {
- // If a device, according to WWN, has been removed, it's
- // port_id may be used by another working device, so we
- // have to terminate by SCSI target, NOT port_id.
- if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
- {
- if( (Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
- &&
- (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel))
- {
- Exchanges->fcExchange[x_ID].status = TerminateStatus;
- cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
- }
- }
-
- // (in case we ever need it...)
- // all SEST structures have a remote node ID at SEST DWORD 2
- // if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
- // == port_id)
- }
- }
- }
-}
+ // Check the incoming frame for a supported ELS type
+ switch (fchs->pl[0] & 0xFFFF)
+ {
+ case 0x0050:
+ // PDISC?
+ // Payload for PLOGI and PDISC is identical (request & reply)
+ if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) // valid payload?
+ {
+ LOGIN_PAYLOAD logi; // FC-PH Port Login
+
+ // PDISC payload OK. If critical login fields
+ // (e.g. WWN) matches last login for this port_id,
+ // we may resume any prior exchanges
+ // with the other port
+
+ BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
+ 0, // don't search linked list for port_id
+ &logi.port_name[0], // search linked list for WWN
+ &pLastLoggedInPort); // must return non-NULL; when a port_id
+ // is not found, this pointer marks the
+ // end of the singly linked list
+
+ if (pLoggedInPort != NULL) // WWN found (prior login OK)
+ {
+ if ((fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) {
+ // Yes. We were expecting PDISC?
+ if (pLoggedInPort->pdisc) {
+ // Yes; set fields accordingly. (PDISC, not Originator)
+ SetLoginFields(pLoggedInPort, fchs, 1, 0);
+ // send 'ACC' reply
+ cpqfcTSPutLinkQue(dev, ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
+ fchs);
+ // OK to resume I/O...
+ } else {
+ printk("Not expecting PDISC (pdisc=0)\n");
+ NeedReject = 1;
+ // set reject reason code
+ ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+ }
+ } else {
+ if (pLoggedInPort->port_id != 0) {
+ printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id & 0xFFFFFF);
+ }
+ NeedReject = 1;
+ // set reject reason code
+ ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+ }
+ } else {
+ printk("PDISC Request from unknown WWN\n");
+ NeedReject = 1;
+ // set reject reason code
+ ls_reject_code = LS_RJT_REASON(LOGICAL_ERROR, INVALID_PORT_NAME);
+ }
-static void ProcessELS_Request(
- CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
-{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-// FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-// ULONG ox_id = (fchs->ox_rx_id >>16);
- PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
- BOOLEAN NeedReject = FALSE;
- ULONG ls_reject_code = 0; // default don'n know??
+ }
+ else // Payload unacceptable
+ {
+ printk("payload unacceptable\n");
+ NeedReject = 1; // reject code already set
+ }
+ if (NeedReject) {
+ u32 port_id;
+ // The PDISC failed. Set login struct flags accordingly,
+ // terminate any I/O to this port, and Q a PLOGI
+ if (pLoggedInPort) {
+ pLoggedInPort->pdisc = 0;
+ pLoggedInPort->prli = 0;
+ pLoggedInPort->plogi = 0;
+
+ cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+ port_id = pLoggedInPort->port_id;
+ } else {
+ port_id = fchs->s_id & 0xFFFFFF;
+ }
+ fchs->reserved = ls_reject_code; // borrow this (unused) field
+ cpqfcTSPutLinkQue(dev, ELS_RJT, fchs);
+ }
+ break;
- // Check the incoming frame for a supported ELS type
- switch( fchs->pl[0] & 0xFFFF)
- {
- case 0x0050: // PDISC?
+ case 0x0003:
+ // PLOGI?
+ // Payload for PLOGI and PDISC is identical (request & reply)
+ if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) // valid payload?
+ {
+ LOGIN_PAYLOAD logi; // FC-PH Port Login
+ u8 NeedReject = 0;
+
+ // PDISC payload OK. If critical login fields
+ // (e.g. WWN) matches last login for this port_id,
+ // we may resume any prior exchanges
+ // with the other port
+
+ BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
+ 0, // don't search linked list for port_id
+ &logi.port_name[0], // search linked list for WWN
+ &pLastLoggedInPort); // must return non-NULL; when a port_id
+ // is not found, this pointer marks the
+ // end of the singly linked list
+ if (pLoggedInPort == NULL) // WWN not found -New Port
+ {
+ pLoggedInPort = CreateFcPort(dev, pLastLoggedInPort, fchs, &logi);
+ if (pLoggedInPort == NULL) {
+ printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
+ // Now Q a LOGOut Request, since we won't be talking to that device
+ NeedReject = 1;
+ // set reject reason code
+ ls_reject_code = LS_RJT_REASON(LOGICAL_ERROR, NO_LOGIN_RESOURCES);
+ }
+ }
+ if (!NeedReject) {
+ // OK - we have valid fcPort ptr; set fields accordingly.
+ // (not PDISC, not Originator)
+ SetLoginFields(pLoggedInPort, fchs, 0, 0);
+ // send 'ACC' reply
+ cpqfcTSPutLinkQue(dev, ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
+ fchs);
+ }
+ }
+ else // Payload unacceptable
+ {
+ printk("payload unacceptable\n");
+ NeedReject = 1; // reject code already set
+ }
+ if (NeedReject) {
+ // The PDISC failed. Set login struct flags accordingly,
+ // terminate any I/O to this port, and Q a PLOGI
+ pLoggedInPort->pdisc = 0;
+ pLoggedInPort->prli = 0;
+ pLoggedInPort->plogi = 0;
- // Payload for PLOGI and PDISC is identical (request & reply)
- if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
- {
- LOGIN_PAYLOAD logi; // FC-PH Port Login
-
- // PDISC payload OK. If critical login fields
- // (e.g. WWN) matches last login for this port_id,
- // we may resume any prior exchanges
- // with the other port
+ fchs->reserved = ls_reject_code; // borrow this (unused) field
-
- BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-
- pLoggedInPort = fcFindLoggedInPort(
- fcChip,
- NULL, // don't search Scsi Nexus
- 0, // don't search linked list for port_id
- &logi.port_name[0], // search linked list for WWN
- &pLastLoggedInPort); // must return non-NULL; when a port_id
- // is not found, this pointer marks the
- // end of the singly linked list
-
- if( pLoggedInPort != NULL) // WWN found (prior login OK)
- {
-
- if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
- {
- // Yes. We were expecting PDISC?
- if( pLoggedInPort->pdisc )
- {
- // Yes; set fields accordingly. (PDISC, not Originator)
- SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
-
- // send 'ACC' reply
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
- fchs );
-
- // OK to resume I/O...
- }
- else
- {
- printk("Not expecting PDISC (pdisc=FALSE)\n");
- NeedReject = TRUE;
- // set reject reason code
- ls_reject_code =
- LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
- }
- }
- else
- {
- if( pLoggedInPort->port_id != 0)
- {
- printk("PDISC PortID change: old %Xh, new %Xh\n",
- pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
- }
- NeedReject = TRUE;
- // set reject reason code
- ls_reject_code =
- LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-
- }
- }
- else
- {
- printk("PDISC Request from unknown WWN\n");
- NeedReject = TRUE;
-
- // set reject reason code
- ls_reject_code =
- LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
- }
+ // send 'RJT' reply
+ cpqfcTSPutLinkQue(dev, ELS_RJT, fchs);
+ }
+ // terminate any exchanges with this device...
+ if (pLoggedInPort) {
+ cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+ }
+ break;
- }
- else // Payload unacceptable
- {
- printk("payload unacceptable\n");
- NeedReject = TRUE; // reject code already set
-
- }
+ case 0x1020: // PRLI?
+ {
+ u8 NeedReject = 1;
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
+ (fchs->s_id & 0xFFFFFF), // search linked list for port_id
+ NULL, // DON'T search linked list for WWN
+ NULL); // don't care
+
+ if (pLoggedInPort == NULL) {
+ // huh?
+ printk(" Unexpected PRLI Request -not logged in!\n");
+ // set reject reason code
+ ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+ // Q a LOGOut here?
+ } else {
+ // verify the PRLI ACC payload
+ if (!verify_PRLI(fchs, &ls_reject_code)) {
+ // PRLI Reply is acceptable; were we expecting it?
+ if (pLoggedInPort->plogi) {
+ // yes, we expected the PRLI ACC (not PDISC; not Originator)
+ SetLoginFields(pLoggedInPort, fchs, 0, 0);
+ // Q an ACCept Reply
+ cpqfcTSPutLinkQue(dev, ELS_PRLI_ACC, fchs);
+ NeedReject = 0;
+ } else {
+ // huh?
+ printk(" (unexpected) PRLI REQEST with plogi 0\n");
+ // set reject reason code
+ ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+ // Q a LOGOut here?
+ }
+ } else {
+ printk(" PRLI REQUEST payload failed verify\n");
+ // (reject code set by "verify")
+ // Q a LOGOut here?
+ }
+ }
- if( NeedReject)
- {
- ULONG port_id;
- // The PDISC failed. Set login struct flags accordingly,
- // terminate any I/O to this port, and Q a PLOGI
- if( pLoggedInPort )
- {
- pLoggedInPort->pdisc = FALSE;
- pLoggedInPort->prli = FALSE;
- pLoggedInPort->plogi = FALSE;
-
- cpqfcTSTerminateExchange( cpqfcHBAdata,
- &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
- port_id = pLoggedInPort->port_id;
- }
- else
- {
- port_id = fchs->s_id &0xFFFFFF;
- }
- fchs->reserved = ls_reject_code; // borrow this (unused) field
- cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
- }
-
- break;
+ if (NeedReject) {
+ // Q a ReJecT Reply with reason code
+ fchs->reserved = ls_reject_code;
+ cpqfcTSPutLinkQue(dev, ELS_RJT, // Q Type
+ fchs);
+ }
+ }
+ break;
+ case 0x0005: // LOGOut?
+ {
+ // was this LOGOUT because we sent a ELS_PDISC to an FC device
+ // with changed (or new) port_id, or does the port refuse
+ // to communicate to us?
+ // We maintain a logout counter - if we get 3 consecutive LOGOuts,
+ // give up!
+ LOGOUT_PAYLOAD logo;
+ u8 GiveUpOnDevice = 0;
+ u32 ls_reject_code = 0;
+
+ BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logo, sizeof(logo));
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
+ 0, // don't search linked list for port_id
+ &logo.port_name[0], // search linked list for WWN
+ NULL); // don't care about end of list
+
+ if (pLoggedInPort) // found the device?
+ {
+ // Q an ACC reply
+ cpqfcTSPutLinkQue(dev, ELS_LOGO_ACC, // Q Type
+ fchs); // device to respond to
+ // set login struct fields (LOGO_counter increment)
+ SetLoginFields(pLoggedInPort, fchs, 0, 0);
+ // are we an Initiator?
+ if (fcChip->Options.initiator) {
+ // we're an Initiator, so check if we should
+ // try (another?) login
+ // Fabrics routinely log out from us after
+ // getting device info - don't try to log them
+ // back in.
+ if ((fchs->s_id & 0xFFF000) == 0xFFF000) {
+ ; // do nothing
+ } else if (pLoggedInPort->LOGO_counter <= 3) {
+ // try (another) login (PLOGI request)
+ cpqfcTSPutLinkQue(dev, ELS_PLOGI, // Q Type
+ fchs);
+ // Terminate I/O with "retry" potential
+ cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+ } else {
+ printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n", fchs->s_id && 0xFFFFFF);
+ GiveUpOnDevice = 1;
+ }
+ } else {
+ GiveUpOnDevice = 1;
+ }
+
+ if (GiveUpOnDevice == 1) {
+ cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, DEVICE_REMOVED);
+ }
+ } else // we don't know this WWN!
+ {
+ // Q a ReJecT Reply with reason code
+ fchs->reserved = ls_reject_code;
+ cpqfcTSPutLinkQue(dev, ELS_RJT, // Q Type
+ fchs);
+ }
+ }
+ break;
+ // FABRIC only case
+ case 0x0461: // ELS RSCN (Registered State Change Notification)?
+ {
+ int Ports;
+ int i;
+ __u32 Buff;
+ // Typically, one or more devices have been added to or dropped
+ // from the Fabric.
+ // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
+ // The first 32-bit word has a 2-byte Payload Length, which
+ // includes the 4 bytes of the first word. Consequently,
+ // this PL len must never be less than 4, must be a multiple of 4,
+ // and has a specified max value 256.
+ // (Endianess!)
+ Ports = ((fchs->pl[0] >> 24) - 4) / 4;
+ Ports = Ports > 63 ? 63 : Ports;
+
+ printk(" RSCN ports: %d\n", Ports);
+ if (Ports <= 0) // huh?
+ {
+ // ReJecT the command
+ fchs->reserved = LS_RJT_REASON(UNABLE_TO_PERFORM, 0);
+
+ cpqfcTSPutLinkQue(dev, ELS_RJT, // Q Type
+ fchs);
+
+ break;
+ } else // Accept the command
+ {
+ cpqfcTSPutLinkQue(dev, ELS_ACC, // Q Type
+ fchs);
+ }
- case 0x0003: // PLOGI?
+ // Check the "address format" to determine action.
+ // We have 3 cases:
+ // 0 = Port Address; 24-bit address of affected device
+ // 1 = Area Address; MS 16 bits valid
+ // 2 = Domain Address; MS 8 bits valid
+ for (i = 0; i < Ports; i++) {
+ BigEndianSwap((u8 *) & fchs->pl[i + 1], (u8 *) & Buff, 4);
+ switch (Buff & 0xFF000000) {
+ case 0: // Port Address?
+ case 0x01000000: // Area Domain?
+ case 0x02000000: // Domain Address
+ // For example, "port_id" 0x201300
+ // OK, let's try a Name Service Request (Query)
+ fchs->s_id = 0xFFFFFC; // Name Server Address
+ cpqfcTSPutLinkQue(dev, FCS_NSR, fchs);
+ break;
+ default: // huh? new value on version change?
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ // don't support this request (yet)
+ // set reject reason code
+ fchs->reserved = LS_RJT_REASON(UNABLE_TO_PERFORM, REQUEST_NOT_SUPPORTED);
+ cpqfcTSPutLinkQue(dev, ELS_RJT, fchs); // Q Type
+ break;
+ }
+}
- // Payload for PLOGI and PDISC is identical (request & reply)
- if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
- {
- LOGIN_PAYLOAD logi; // FC-PH Port Login
- BOOLEAN NeedReject = FALSE;
-
- // PDISC payload OK. If critical login fields
- // (e.g. WWN) matches last login for this port_id,
- // we may resume any prior exchanges
- // with the other port
-
- BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-
- pLoggedInPort = fcFindLoggedInPort(
- fcChip,
- NULL, // don't search Scsi Nexus
- 0, // don't search linked list for port_id
- &logi.port_name[0], // search linked list for WWN
- &pLastLoggedInPort); // must return non-NULL; when a port_id
- // is not found, this pointer marks the
- // end of the singly linked list
-
- if( pLoggedInPort == NULL) // WWN not found -New Port
- {
- pLoggedInPort = CreateFcPort(
- cpqfcHBAdata,
- pLastLoggedInPort,
- fchs,
- &logi);
- if( pLoggedInPort == NULL )
- {
- printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
- // Now Q a LOGOut Request, since we won't be talking to that device
-
- NeedReject = TRUE;
-
- // set reject reason code
- ls_reject_code =
- LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
-
+static void ProcessELS_Reply(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+ PTACHYON fcChip = &dev->fcChip;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ u32 ox_id = (fchs->ox_rx_id >> 16);
+ u32 ls_reject_code;
+ PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
+
+ // If this is a valid reply, then we MUST have sent a request.
+ // Verify that we can find a valid request OX_ID corresponding to
+ // this reply
+
+ if (Exchanges->fcExchange[(fchs->ox_rx_id >> 16)].type == 0) {
+ printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+ goto Quit; // exit this routine
}
- }
- if( !NeedReject )
- {
-
- // OK - we have valid fcPort ptr; set fields accordingly.
- // (not PDISC, not Originator)
- SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
-
- // send 'ACC' reply
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
- fchs );
- }
- }
- else // Payload unacceptable
- {
- printk("payload unacceptable\n");
- NeedReject = TRUE; // reject code already set
- }
- if( NeedReject)
- {
- // The PDISC failed. Set login struct flags accordingly,
- // terminate any I/O to this port, and Q a PLOGI
- pLoggedInPort->pdisc = FALSE;
- pLoggedInPort->prli = FALSE;
- pLoggedInPort->plogi = FALSE;
-
- fchs->reserved = ls_reject_code; // borrow this (unused) field
+ // Is the reply a RJT (reject)?
+ if ((fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
+ {
+ // ****** REJECT REPLY ********
+ switch (Exchanges->fcExchange[ox_id].type) {
+ case ELS_FDISC: // we sent out Fabric Discovery
+ case ELS_FLOGI: // we sent out FLOGI
+ printk("RJT received on Fabric Login from %Xh, reason %Xh\n", fchs->s_id, fchs->pl[1]);
+ break;
+ default:
+ break;
+ }
+ goto Done;
+ }
+ // OK, we have an ACCept...
+ // What's the ACC type? (according to what we sent)
+ switch (Exchanges->fcExchange[ox_id].type) {
+ case ELS_PLOGI: // we sent out PLOGI
+ if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) {
+ LOGIN_PAYLOAD logi; // FC-PH Port Login
+ // login ACC payload acceptable; search for WWN in our list
+ // of fcPorts
+ BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
+ 0, // don't search linked list for port_id
+ &logi.port_name[0], // search linked list for WWN
+ &pLastLoggedInPort); // must return non-NULL; when a port_id
+ // is not found, this pointer marks the
+ // end of the singly linked list
+ if (pLoggedInPort == NULL) // WWN not found - new port
+ {
+ pLoggedInPort = CreateFcPort(dev, pLastLoggedInPort, fchs, &logi);
+ if (pLoggedInPort == NULL) {
+ printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
+ // Now Q a LOGOut Request, since we won't be talking to that device
+ goto Done; // exit with error! dropped login frame
+ }
+ } else // WWN was already known. Ensure that any open
+ // exchanges for this WWN are terminated.
+ // NOTE: It's possible that a device can change its
+ // 24-bit port_id after a Link init or Fabric change
+ // (e.g. LIP or Fabric RSCN). In that case, the old
+ // 24-bit port_id may be duplicated, or no longer exist.
+ {
+ cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+ }
- // send 'RJT' reply
- cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
- }
-
- // terminate any exchanges with this device...
- if( pLoggedInPort )
- {
- cpqfcTSTerminateExchange( cpqfcHBAdata,
- &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
- }
- break;
+ // We have an fcPort struct - set fields accordingly
+ // not PDISC, originator
+ SetLoginFields(pLoggedInPort, fchs, 0, 1);
+ // We just set a "port_id"; is it duplicated?
+ TestDuplicatePortId(dev, pLoggedInPort);
+ // For Fabric operation, we issued PLOGI to 0xFFFFFC
+ // so we can send SCR (State Change Registration)
+ // Check for this special case...
+ if (fchs->s_id == 0xFFFFFC) {
+ // PLOGI ACC was a Fabric response... issue SCR
+ fchs->s_id = 0xFFFFFD; // address for SCR
+ cpqfcTSPutLinkQue(dev, ELS_SCR, fchs);
+ }
+ else {
+ // Now we need a PRLI to enable FCP-SCSI operation
+ // set flags and Q up a ELS_PRLI
+ cpqfcTSPutLinkQue(dev, ELS_PRLI, fchs);
+ }
+ } else {
+ // login payload unacceptable - reason in ls_reject_code
+ // Q up a Logout Request
+ printk("Login Payload unacceptable\n");
+ }
+ break;
+ // PDISC logic very similar to PLOGI, except we never want
+ // to allocate mem for "new" port, and we set flags differently
+ // (might combine later with PLOGI logic for efficiency)
+ case ELS_PDISC: // we sent out PDISC
+ if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) {
+ LOGIN_PAYLOAD logi; // FC-PH Port Login
+ u8 NeedLogin = 0;
+
+ // login payload acceptable; search for WWN in our list
+ // of (previously seen) fcPorts
+ BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
+ 0, // don't search linked list for port_id
+ &logi.port_name[0], // search linked list for WWN
+ &pLastLoggedInPort); // must return non-NULL; when a port_id
+ // is not found, this pointer marks the
+ // end of the singly linked list
+ if (pLoggedInPort != NULL) // WWN found?
+ {
+ // WWN has same port_id as last login? (Of course, a properly
+ // working FC device should NEVER ACCept a PDISC if it's
+ // port_id changed, but check just in case...)
+ if ((fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) {
+ // Yes. We were expecting PDISC?
+ if (pLoggedInPort->pdisc) {
+ int i;
+
+
+ // PDISC expected -- set fields. (PDISC, Originator)
+ SetLoginFields(pLoggedInPort, fchs, 1, 1);
+
+ // We are ready to resume FCP-SCSI to this device...
+ // Do we need to start anything that was Queued?
+
+ for (i = 0; i < TACH_SEST_LEN; i++) {
+ // see if any exchange for this PDISC'd port was queued
+ if (((fchs->s_id & 0xFFFFFF) == (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
+ && (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED)) {
+ fchs->reserved = i; // copy ExchangeID
+// printk(" *Q x_ID %Xh after PDISC* ",i);
+
+ cpqfcTSPutLinkQue(dev, EXCHANGE_QUEUED, fchs);
+ }
+ }
+ // Complete commands Q'd while we were waiting for Login
+ UnblockScsiDevice(dev->HostAdapter, pLoggedInPort);
+ } else {
+ printk("Not expecting PDISC (pdisc=0)\n");
+ NeedLogin = 1;
+ }
+ } else {
+ printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id & 0xFFFFFF);
+ NeedLogin = 1;
+ }
+ } else {
+ printk("PDISC ACC from unknown WWN\n");
+ NeedLogin = 1;
+ }
+ if (NeedLogin) {
+ // The PDISC failed. Set login struct flags accordingly,
+ // terminate any I/O to this port, and Q a PLOGI
+ if (pLoggedInPort) // FC device previously known?
+ {
+ cpqfcTSPutLinkQue(dev, ELS_LOGO, fchs); // Qtype has port_id to send to
+ // There are a variety of error scenarios which can result
+ // in PDISC failure, so as a catchall, add the check for
+ // duplicate port_id.
+ TestDuplicatePortId(dev, pLoggedInPort);
+
+ // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+ pLoggedInPort->pdisc = 0;
+ pLoggedInPort->prli = 0;
+ pLoggedInPort->plogi = 0;
+
+ cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+ }
+ cpqfcTSPutLinkQue(dev, ELS_PLOGI, fchs);
+ }
+ } else {
+ // login payload unacceptable - reason in ls_reject_code
+ // Q up a Logout Request
+ printk("ERROR: Login Payload unacceptable!\n");
- case 0x1020: // PRLI?
- {
- BOOLEAN NeedReject = TRUE;
- pLoggedInPort = fcFindLoggedInPort(
- fcChip,
- NULL, // don't search Scsi Nexus
- (fchs->s_id & 0xFFFFFF), // search linked list for port_id
- NULL, // DON'T search linked list for WWN
- NULL); // don't care
-
- if( pLoggedInPort == NULL )
- {
- // huh?
- printk(" Unexpected PRLI Request -not logged in!\n");
-
- // set reject reason code
- ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-
- // Q a LOGOut here?
- }
- else
- {
- // verify the PRLI ACC payload
- if( !verify_PRLI( fchs, &ls_reject_code) )
- {
- // PRLI Reply is acceptable; were we expecting it?
- if( pLoggedInPort->plogi )
- {
- // yes, we expected the PRLI ACC (not PDISC; not Originator)
- SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
-
- // Q an ACCept Reply
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- ELS_PRLI_ACC,
- fchs );
-
- NeedReject = FALSE;
- }
- else
- {
- // huh?
- printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
-
- // set reject reason code
- ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-
- // Q a LOGOut here?
-
- }
- }
- else
- {
- printk(" PRLI REQUEST payload failed verify\n");
- // (reject code set by "verify")
-
- // Q a LOGOut here?
- }
- }
-
- if( NeedReject )
- {
- // Q a ReJecT Reply with reason code
- fchs->reserved = ls_reject_code;
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- ELS_RJT, // Q Type
- fchs );
- }
- }
- break;
-
-
-
-
- case 0x0005: // LOGOut?
- {
- // was this LOGOUT because we sent a ELS_PDISC to an FC device
- // with changed (or new) port_id, or does the port refuse
- // to communicate to us?
- // We maintain a logout counter - if we get 3 consecutive LOGOuts,
- // give up!
- LOGOUT_PAYLOAD logo;
- BOOLEAN GiveUpOnDevice = FALSE;
- ULONG ls_reject_code = 0;
-
- BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
-
- pLoggedInPort = fcFindLoggedInPort(
- fcChip,
- NULL, // don't search Scsi Nexus
- 0, // don't search linked list for port_id
- &logo.port_name[0], // search linked list for WWN
- NULL); // don't care about end of list
-
- if( pLoggedInPort ) // found the device?
- {
- // Q an ACC reply
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- ELS_LOGO_ACC, // Q Type
- fchs ); // device to respond to
-
- // set login struct fields (LOGO_counter increment)
- SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
-
- // are we an Initiator?
- if( fcChip->Options.initiator)
- {
- // we're an Initiator, so check if we should
- // try (another?) login
-
- // Fabrics routinely log out from us after
- // getting device info - don't try to log them
- // back in.
- if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
- {
- ; // do nothing
- }
- else if( pLoggedInPort->LOGO_counter <= 3)
- {
- // try (another) login (PLOGI request)
-
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- ELS_PLOGI, // Q Type
- fchs );
-
- // Terminate I/O with "retry" potential
- cpqfcTSTerminateExchange( cpqfcHBAdata,
- &pLoggedInPort->ScsiNexus,
- PORTID_CHANGED);
- }
- else
- {
- printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
- fchs->s_id &&0xFFFFFF);
- GiveUpOnDevice = TRUE;
- }
- }
- else
- {
- GiveUpOnDevice = TRUE;
- }
-
-
- if( GiveUpOnDevice == TRUE )
- {
- cpqfcTSTerminateExchange( cpqfcHBAdata,
- &pLoggedInPort->ScsiNexus,
- DEVICE_REMOVED);
- }
- }
- else // we don't know this WWN!
- {
- // Q a ReJecT Reply with reason code
- fchs->reserved = ls_reject_code;
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- ELS_RJT, // Q Type
- fchs );
- }
- }
- break;
-
-
-
-
- // FABRIC only case
- case 0x0461: // ELS RSCN (Registered State Change Notification)?
- {
- int Ports;
- int i;
- __u32 Buff;
- // Typically, one or more devices have been added to or dropped
- // from the Fabric.
- // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
- // The first 32-bit word has a 2-byte Payload Length, which
- // includes the 4 bytes of the first word. Consequently,
- // this PL len must never be less than 4, must be a multiple of 4,
- // and has a specified max value 256.
- // (Endianess!)
- Ports = ((fchs->pl[0] >>24) - 4) / 4;
- Ports = Ports > 63 ? 63 : Ports;
-
- printk(" RSCN ports: %d\n", Ports);
- if( Ports <= 0 ) // huh?
- {
- // ReJecT the command
- fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
-
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- ELS_RJT, // Q Type
- fchs );
-
- break;
- }
- else // Accept the command
- {
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- ELS_ACC, // Q Type
- fchs );
- }
-
- // Check the "address format" to determine action.
- // We have 3 cases:
- // 0 = Port Address; 24-bit address of affected device
- // 1 = Area Address; MS 16 bits valid
- // 2 = Domain Address; MS 8 bits valid
- for( i=0; i<Ports; i++)
- {
- BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
- switch( Buff & 0xFF000000)
- {
-
- case 0: // Port Address?
-
- case 0x01000000: // Area Domain?
- case 0x02000000: // Domain Address
- // For example, "port_id" 0x201300
- // OK, let's try a Name Service Request (Query)
- fchs->s_id = 0xFFFFFC; // Name Server Address
- cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
-
- break;
-
-
- default: // huh? new value on version change?
- break;
- }
- }
- }
- break;
-
-
-
-
- default: // don't support this request (yet)
- // set reject reason code
- fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM,
- REQUEST_NOT_SUPPORTED);
-
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- ELS_RJT, // Q Type
- fchs );
- break;
- }
-}
-
-
-static void ProcessELS_Reply(
- CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
-{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- ULONG ox_id = (fchs->ox_rx_id >>16);
- ULONG ls_reject_code;
- PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
-
- // If this is a valid reply, then we MUST have sent a request.
- // Verify that we can find a valid request OX_ID corresponding to
- // this reply
-
-
- if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
- {
- printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ",
- ox_id, fchs->ox_rx_id & 0xffff);
- goto Quit; // exit this routine
- }
-
-
- // Is the reply a RJT (reject)?
- if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
- {
-// ****** REJECT REPLY ********
- switch( Exchanges->fcExchange[ox_id].type )
- {
-
- case ELS_FDISC: // we sent out Fabric Discovery
- case ELS_FLOGI: // we sent out FLOGI
-
- printk("RJT received on Fabric Login from %Xh, reason %Xh\n",
- fchs->s_id, fchs->pl[1]);
-
- break;
-
- default:
- break;
- }
-
- goto Done;
- }
-
- // OK, we have an ACCept...
- // What's the ACC type? (according to what we sent)
- switch( Exchanges->fcExchange[ox_id].type )
- {
-
- case ELS_PLOGI: // we sent out PLOGI
- if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
- {
- LOGIN_PAYLOAD logi; // FC-PH Port Login
-
- // login ACC payload acceptable; search for WWN in our list
- // of fcPorts
-
- BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-
- pLoggedInPort = fcFindLoggedInPort(
- fcChip,
- NULL, // don't search Scsi Nexus
- 0, // don't search linked list for port_id
- &logi.port_name[0], // search linked list for WWN
- &pLastLoggedInPort); // must return non-NULL; when a port_id
- // is not found, this pointer marks the
- // end of the singly linked list
-
- if( pLoggedInPort == NULL) // WWN not found - new port
- {
+ }
+ break;
- pLoggedInPort = CreateFcPort(
- cpqfcHBAdata,
- pLastLoggedInPort,
- fchs,
- &logi);
-
- if( pLoggedInPort == NULL )
- {
- printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
- // Now Q a LOGOut Request, since we won't be talking to that device
-
- goto Done; // exit with error! dropped login frame
- }
- }
- else // WWN was already known. Ensure that any open
- // exchanges for this WWN are terminated.
- // NOTE: It's possible that a device can change its
- // 24-bit port_id after a Link init or Fabric change
- // (e.g. LIP or Fabric RSCN). In that case, the old
- // 24-bit port_id may be duplicated, or no longer exist.
- {
-
- cpqfcTSTerminateExchange( cpqfcHBAdata,
- &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
- }
-
- // We have an fcPort struct - set fields accordingly
- // not PDISC, originator
- SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
-
- // We just set a "port_id"; is it duplicated?
- TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
-
- // For Fabric operation, we issued PLOGI to 0xFFFFFC
- // so we can send SCR (State Change Registration)
- // Check for this special case...
- if( fchs->s_id == 0xFFFFFC )
- {
- // PLOGI ACC was a Fabric response... issue SCR
- fchs->s_id = 0xFFFFFD; // address for SCR
- cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
- }
-
- else
- {
- // Now we need a PRLI to enable FCP-SCSI operation
- // set flags and Q up a ELS_PRLI
- cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
- }
- }
- else
- {
- // login payload unacceptable - reason in ls_reject_code
- // Q up a Logout Request
- printk("Login Payload unacceptable\n");
+ case ELS_PRLI: // we sent out PRLI
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search Scsi Nexus
+ (fchs->s_id & 0xFFFFFF), // search linked list for port_id
+ NULL, // DON'T search linked list for WWN
+ NULL); // don't care
+
+ if (pLoggedInPort == NULL) {
+ // huh?
+ printk(" Unexpected PRLI ACCept frame!\n");
+ // Q a LOGOut here?
+ goto Done;
+ }
+ // verify the PRLI ACC payload
+ if (!verify_PRLI(fchs, &ls_reject_code)) {
+ // PRLI Reply is acceptable; were we expecting it?
+ if (pLoggedInPort->plogi) {
+ // yes, we expected the PRLI ACC (not PDISC; Originator)
+ SetLoginFields(pLoggedInPort, fchs, 0, 1);
+ // OK, let's send a REPORT_LUNS command to determine
+ // whether VSA or PDA FCP-LUN addressing is used.
+ cpqfcTSPutLinkQue(dev, SCSI_REPORT_LUNS, fchs);
+ // It's possible that a device we were talking to changed
+ // port_id, and has logged back in. This function ensures
+ // that I/O will resume.
+ UnblockScsiDevice(dev->HostAdapter, pLoggedInPort);
+ } else {
+ // huh?
+ printk(" (unexpected) PRLI ACCept with plogi 0\n");
+ // Q a LOGOut here?
+ goto Done;
+ }
+ } else {
+ printk(" PRLI ACCept payload failed verify\n");
+ // Q a LOGOut here?
+ }
+ break;
- }
- break;
+ case ELS_FLOGI: // we sent out FLOGI (Fabric Login)
+ // update the upper 16 bits of our port_id in Tachyon
+ // the switch adds those upper 16 bits when responding
+ // to us (i.e. we are the destination_id)
+ fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
+ writel(fcChip->Registers.my_al_pa, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+
+ // now send out a PLOGI to the well known port_id 0xFFFFFC
+ fchs->s_id = 0xFFFFFC;
+ cpqfcTSPutLinkQue(dev, ELS_PLOGI, fchs);
+ break;
- // PDISC logic very similar to PLOGI, except we never want
- // to allocate mem for "new" port, and we set flags differently
- // (might combine later with PLOGI logic for efficiency)
- case ELS_PDISC: // we sent out PDISC
- if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
- {
- LOGIN_PAYLOAD logi; // FC-PH Port Login
- BOOLEAN NeedLogin = FALSE;
-
- // login payload acceptable; search for WWN in our list
- // of (previously seen) fcPorts
-
- BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-
- pLoggedInPort = fcFindLoggedInPort(
- fcChip,
- NULL, // don't search Scsi Nexus
- 0, // don't search linked list for port_id
- &logi.port_name[0], // search linked list for WWN
- &pLastLoggedInPort); // must return non-NULL; when a port_id
- // is not found, this pointer marks the
- // end of the singly linked list
-
- if( pLoggedInPort != NULL) // WWN found?
- {
- // WWN has same port_id as last login? (Of course, a properly
- // working FC device should NEVER ACCept a PDISC if it's
- // port_id changed, but check just in case...)
- if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
- {
- // Yes. We were expecting PDISC?
- if( pLoggedInPort->pdisc )
- {
- int i;
-
-
- // PDISC expected -- set fields. (PDISC, Originator)
- SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
+ case ELS_FDISC: // we sent out FDISC (Fabric Discovery (Login))
+ printk(" ELS_FDISC success ");
+ break;
- // We are ready to resume FCP-SCSI to this device...
- // Do we need to start anything that was Queued?
+ case ELS_SCR: // we sent out State Change Registration
+ // now we can issue Name Service Request to find any
+ // Fabric-connected devices we might want to login to.
+ fchs->s_id = 0xFFFFFC; // Name Server Address
+ cpqfcTSPutLinkQue(dev, FCS_NSR, fchs);
+ break;
- for( i=0; i< TACH_SEST_LEN; i++)
- {
- // see if any exchange for this PDISC'd port was queued
- if( ((fchs->s_id &0xFFFFFF) ==
- (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
- &&
- (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
- {
- fchs->reserved = i; // copy ExchangeID
-// printk(" *Q x_ID %Xh after PDISC* ",i);
-
- cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
- }
- }
-
- // Complete commands Q'd while we were waiting for Login
-
- UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
- }
- else
- {
- printk("Not expecting PDISC (pdisc=FALSE)\n");
- NeedLogin = TRUE;
- }
+ default:
+ printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+ break;
}
- else
- {
- printk("PDISC PortID change: old %Xh, new %Xh\n",
- pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
- NeedLogin = TRUE;
-
- }
- }
- else
- {
- printk("PDISC ACC from unknown WWN\n");
- NeedLogin = TRUE;
- }
-
- if( NeedLogin)
- {
-
- // The PDISC failed. Set login struct flags accordingly,
- // terminate any I/O to this port, and Q a PLOGI
- if( pLoggedInPort ) // FC device previously known?
- {
-
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- ELS_LOGO, // Q Type
- fchs ); // has port_id to send to
-
- // There are a variety of error scenarios which can result
- // in PDISC failure, so as a catchall, add the check for
- // duplicate port_id.
- TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
-
-// TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
- pLoggedInPort->pdisc = FALSE;
- pLoggedInPort->prli = FALSE;
- pLoggedInPort->plogi = FALSE;
-
- cpqfcTSTerminateExchange( cpqfcHBAdata,
- &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
- }
- cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
- }
- }
- else
- {
- // login payload unacceptable - reason in ls_reject_code
- // Q up a Logout Request
- printk("ERROR: Login Payload unacceptable!\n");
-
- }
-
- break;
-
-
-
- case ELS_PRLI: // we sent out PRLI
-
-
- pLoggedInPort = fcFindLoggedInPort(
- fcChip,
- NULL, // don't search Scsi Nexus
- (fchs->s_id & 0xFFFFFF), // search linked list for port_id
- NULL, // DON'T search linked list for WWN
- NULL); // don't care
-
- if( pLoggedInPort == NULL )
- {
- // huh?
- printk(" Unexpected PRLI ACCept frame!\n");
-
- // Q a LOGOut here?
-
- goto Done;
- }
-
- // verify the PRLI ACC payload
- if( !verify_PRLI( fchs, &ls_reject_code) )
- {
- // PRLI Reply is acceptable; were we expecting it?
- if( pLoggedInPort->plogi )
- {
- // yes, we expected the PRLI ACC (not PDISC; Originator)
- SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
-
- // OK, let's send a REPORT_LUNS command to determine
- // whether VSA or PDA FCP-LUN addressing is used.
-
- cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
-
- // It's possible that a device we were talking to changed
- // port_id, and has logged back in. This function ensures
- // that I/O will resume.
- UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
-
- }
- else
- {
- // huh?
- printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
-
- // Q a LOGOut here?
- goto Done;
- }
- }
- else
- {
- printk(" PRLI ACCept payload failed verify\n");
-
- // Q a LOGOut here?
- }
-
- break;
-
- case ELS_FLOGI: // we sent out FLOGI (Fabric Login)
-
- // update the upper 16 bits of our port_id in Tachyon
- // the switch adds those upper 16 bits when responding
- // to us (i.e. we are the destination_id)
- fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
- writel( fcChip->Registers.my_al_pa,
- fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
-
- // now send out a PLOGI to the well known port_id 0xFFFFFC
- fchs->s_id = 0xFFFFFC;
- cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
-
- break;
-
-
- case ELS_FDISC: // we sent out FDISC (Fabric Discovery (Login))
-
- printk( " ELS_FDISC success ");
- break;
-
-
- case ELS_SCR: // we sent out State Change Registration
- // now we can issue Name Service Request to find any
- // Fabric-connected devices we might want to login to.
-
-
- fchs->s_id = 0xFFFFFC; // Name Server Address
- cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
-
-
- break;
-
-
- default:
- printk(" *Discarding unknown ACC frame, xID %04X/%04X* ",
- ox_id, fchs->ox_rx_id & 0xffff);
- break;
- }
-
-
Done:
- // Regardless of whether the Reply is valid or not, the
- // the exchange is done - complete
- cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
-
-Quit:
- return;
+ // Regardless of whether the Reply is valid or not, the
+ // the exchange is done - complete
+ cpqfcTSCompleteExchange(dev->PciDev, fcChip, (fchs->ox_rx_id >> 16));
+Quit:
+ return;
}
@@ -2075,352 +1604,263 @@
// This is where we process the Directory (Name) Service Reply
// to know which devices are on the Fabric
-static void ProcessFCS_Reply(
- CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
+static void ProcessFCS_Reply(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- ULONG ox_id = (fchs->ox_rx_id >>16);
-// ULONG ls_reject_code;
-// PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
-
- // If this is a valid reply, then we MUST have sent a request.
- // Verify that we can find a valid request OX_ID corresponding to
- // this reply
-
- if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
- {
- printk(" *Discarding Reply frame, xID %04X/%04X* ",
- ox_id, fchs->ox_rx_id & 0xffff);
- goto Quit; // exit this routine
- }
-
+ PTACHYON fcChip = &dev->fcChip;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ u32 ox_id = (fchs->ox_rx_id >> 16);
+// u32 ls_reject_code;
+// PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
+
+ // If this is a valid reply, then we MUST have sent a request.
+ // Verify that we can find a valid request OX_ID corresponding to
+ // this reply
+
+ if (Exchanges->fcExchange[(fchs->ox_rx_id >> 16)].type == 0) {
+ printk(" *Discarding Reply frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+ goto Quit; // exit this routine
+ }
- // OK, we were expecting it. Now check to see if it's a
- // "Name Service" Reply, and if so force a re-validation of
- // Fabric device logins (i.e. Start the login timeout and
- // send PDISC or PLOGI)
- // (Endianess Byte Swap?)
- if( fchs->pl[1] == 0x02FC ) // Name Service
- {
- // got a new (or NULL) list of Fabric attach devices...
- // Invalidate current logins
-
- PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
- while( pLoggedInPort ) // for all ports which are expecting
- // PDISC after the next LIP, set the
- // logoutTimer
- {
+ // OK, we were expecting it. Now check to see if it's a
+ // "Name Service" Reply, and if so force a re-validation of
+ // Fabric device logins (i.e. Start the login timeout and
+ // send PDISC or PLOGI)
+ // (Endianess Byte Swap?)
+ if (fchs->pl[1] == 0x02FC) // Name Service
+ {
+ // got a new (or NULL) list of Fabric attach devices...
+ // Invalidate current logins
- if( (pLoggedInPort->port_id & 0xFFFF00) // Fabric device?
- &&
- (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
- {
- pLoggedInPort->LOGO_timer = 6; // what's the Fabric timeout??
- // suspend any I/O in progress until
- // PDISC received...
- pLoggedInPort->prli = FALSE; // block FCP-SCSI commands
- }
-
- pLoggedInPort = pLoggedInPort->pNextPort;
- }
-
- if( fchs->pl[2] == 0x0280) // ACCept?
- {
- // Send PLOGI or PDISC to these Fabric devices
- SendLogins( cpqfcHBAdata, &fchs->pl[4] );
- }
+ PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+ while (pLoggedInPort) // for all ports which are expecting
+ // PDISC after the next LIP, set the
+ // logoutTimer
+ {
+
+ if ((pLoggedInPort->port_id & 0xFFFF00) // Fabric device?
+ && (pLoggedInPort->port_id != 0xFFFFFC)) // NOT the F_Port
+ {
+ pLoggedInPort->LOGO_timer = 6; // what's the Fabric timeout??
+ // suspend any I/O in progress until
+ // PDISC received...
+ pLoggedInPort->prli = 0; // block FCP-SCSI commands
+ }
+ pLoggedInPort = pLoggedInPort->pNextPort;
+ }
- // As of this writing, the only reason to reject is because NO
- // devices are left on the Fabric. We already started
- // "logged out" timers; if the device(s) don't come
- // back, we'll do the implicit logout in the heart beat
- // timer routine
- else // ReJecT
- {
- // this just means no Fabric device is visible at this instant
- }
- }
+ if (fchs->pl[2] == 0x0280) // ACCept?
+ {
+ // Send PLOGI or PDISC to these Fabric devices
+ SendLogins(dev, &fchs->pl[4]);
+ }
+ // As of this writing, the only reason to reject is because NO
+ // devices are left on the Fabric. We already started
+ // "logged out" timers; if the device(s) don't come
+ // back, we'll do the implicit logout in the heart beat
+ // timer routine
+ else // ReJecT
+ {
+ // this just means no Fabric device is visible at this instant
+ }
+ }
+ // Regardless of whether the Reply is valid or not, the
+ // the exchange is done - complete
+ cpqfcTSCompleteExchange(dev->PciDev, fcChip, (fchs->ox_rx_id >> 16));
- // Regardless of whether the Reply is valid or not, the
- // the exchange is done - complete
- cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
-
-Quit:
- return;
+Quit:
+ return;
}
-
-
-
-
-
-
-static void AnalyzeIncomingFrame(
- CPQFCHBA *cpqfcHBAdata,
- ULONG QNdx )
+static void AnalyzeIncomingFrame(CPQFCHBA * dev, u32 QNdx)
{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
- TachFCHDR_GCMND* fchs =
- (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
-// ULONG ls_reject_code; // reason for rejecting login
- LONG ExchangeID;
-// FC_LOGGEDIN_PORT *pLoggedInPort;
- BOOLEAN AbortAccept;
-
- ENTER("AnalyzeIncomingFrame");
-
-
-
- switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
- {
+ PTACHYON fcChip = &dev->fcChip;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ PFC_LINK_QUE fcLQ = dev->fcLQ;
+ TachFCHDR_GCMND *fchs = (TachFCHDR_GCMND *) fcLQ->Qitem[QNdx].ulBuff;
+// u32 ls_reject_code; // reason for rejecting login
+ s32 ExchangeID;
+// FC_LOGGEDIN_PORT *pLoggedInPort;
+ u8 AbortAccept;
- case SFQ_UNKNOWN: // unknown frame (e.g. LIP position frame, NOP, etc.)
-
+ ENTER("AnalyzeIncomingFrame");
- // ********* FC-4 Device Data/ Fibre Channel Service *************
- if( ((fchs->d_id &0xF0000000) == 0) // R_CTL (upper nibble) 0x0?
- &&
- (fchs->f_ctl & 0x20000000) ) // TYPE 20h is Fibre Channel Service
- {
-
- // ************** FCS Reply **********************
-
- if( (fchs->d_id & 0xff000000L) == 0x03000000L) // (31:23 R_CTL)
- {
- ProcessFCS_Reply( cpqfcHBAdata, fchs );
-
- } // end of FCS logic
-
- }
-
-
- // *********** Extended Link Service **************
-
- else if( fchs->d_id & 0x20000000 // R_CTL 0x2?
- &&
- (fchs->f_ctl & 0x01000000) ) // TYPE = 1
- {
-
- // these frames are either a response to
- // something we sent (0x23) or "unsolicited"
- // frames (0x22).
-
-
- // **************Extended Link REPLY **********************
- // R_CTL Solicited Control Reply
-
- if( (fchs->d_id & 0xff000000L) == 0x23000000L) // (31:23 R_CTL)
- {
-
- ProcessELS_Reply( cpqfcHBAdata, fchs );
-
- } // end of "R_CTL Solicited Control Reply"
-
-
-
-
- // **************Extended Link REQUEST **********************
- // (unsolicited commands from another port or task...)
-
- // R_CTL Ext Link REQUEST
- else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
- (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
- {
-
-
-
- ProcessELS_Request( cpqfcHBAdata, fchs );
-
- }
-
-
-
- // ************** LILP **********************
- else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
- (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
-
- {
- // SANMark specifies that when available, we must use
- // the LILP frame to determine which ALPAs to send Port Discovery
- // to...
-
- if( fchs->pl[0] == 0x0711L) // ELS_PLOGI?
+ switch (fcLQ->Qitem[QNdx].Type) // FCP or Unknown
{
-// UCHAR *ptr = (UCHAR*)&fchs->pl[1];
-// printk(" %d ALPAs found\n", *ptr);
- memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
- fcChip->Options.LILPin = 1; // our LILPmap is valid!
- // now post to make Port Discovery happen...
- cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);
- }
- }
- }
-
-
- // ***************** BASIC LINK SERVICE *****************
-
- else if( fchs->d_id & 0x80000000 // R_CTL:
- && // Basic Link Service Request
- !(fchs->f_ctl & 0xFF000000) ) // type=0 for BLS
- {
+ case SFQ_UNKNOWN: // unknown frame (e.g. LIP position frame, NOP, etc.)
+ // ********* FC-4 Device Data/ Fibre Channel Service *************
+ if (((fchs->d_id & 0xF0000000) == 0) // R_CTL (upper nibble) 0x0?
+ && (fchs->f_ctl & 0x20000000)) // TYPE 20h is Fibre Channel Service
+ {
+ // ************** FCS Reply **********************
+ if ((fchs->d_id & 0xff000000L) == 0x03000000L) // (31:23 R_CTL)
+ {
+ ProcessFCS_Reply(dev, fchs);
+ } // end of FCS logic
+ }
+ // *********** Extended Link Service **************
+ else if (fchs->d_id & 0x20000000 // R_CTL 0x2?
+ && (fchs->f_ctl & 0x01000000)) // TYPE = 1
+ {
+ // these frames are either a response to
+ // something we sent (0x23) or "unsolicited"
+ // frames (0x22).
+ // **************Extended Link REPLY **********************
+ // R_CTL Solicited Control Reply
+ if ((fchs->d_id & 0xff000000L) == 0x23000000L) // (31:23 R_CTL)
+ {
+ ProcessELS_Reply(dev, fchs);
+ } // end of "R_CTL Solicited Control Reply"
+ // **************Extended Link REQUEST **********************
+ // (unsolicited commands from another port or task...)
+ // R_CTL Ext Link REQUEST
+ else if ((fchs->d_id & 0xff000000L) == 0x22000000L && (fchs->ox_rx_id != 0xFFFFFFFFL)) // (ignore LIP frame)
+ {
+ ProcessELS_Request(dev, fchs);
+ }
+ // ************** LILP **********************
+ else if ((fchs->d_id & 0xff000000L) == 0x22000000L && (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
+ {
+ // SANMark specifies that when available, we must use
+ // the LILP frame to determine which ALPAs to send Port Discovery
+ // to...
+ if (fchs->pl[0] == 0x0711L) // ELS_PLOGI?
+ {
+// u8 *ptr = (u8*)&fchs->pl[1];
+// printk(" %d ALPAs found\n", *ptr);
+ memcpy(fcChip->LILPmap, &fchs->pl[1], 32 * 4); // 32 DWORDs
+ fcChip->Options.LILPin = 1; // our LILPmap is valid!
+ // now post to make Port Discovery happen...
+ cpqfcTSPutLinkQue(dev, LINKACTIVE, fchs);
+ }
+ }
+ }
+ // ***************** BASIC LINK SERVICE *****************
+ else if (fchs->d_id & 0x80000000 // R_CTL:
+ && // Basic Link Service Request
+ !(fchs->f_ctl & 0xFF000000)) // type=0 for BLS
+ {
+ // Check for ABTS (Abort Sequence)
+ if ((fchs->d_id & 0x8F000000) == 0x81000000) {
+ // look for OX_ID, S_ID pair that matches in our
+ // fcExchanges table; if found, reply with ACCept and complete
+ // the exchange
+
+ // Per PLDA, an ABTS is sent by an initiator; therefore
+ // assume that if we have an exhange open to the port who
+ // sent ABTS, it will be the d_id of what we sent.
+ for (ExchangeID = 0, AbortAccept = 0; ExchangeID < TACH_SEST_LEN; ExchangeID++) {
+ // Valid "target" exchange 24-bit port_id matches?
+ // NOTE: For the case of handling Intiator AND Target
+ // functions on the same chip, we can have TWO Exchanges
+ // with the same OX_ID -- OX_ID/FFFF for the CMND, and
+ // OX_ID/RX_ID for the XRDY or DATA frame(s). Ideally,
+ // we would like to support ABTS from Initiators or Targets,
+ // but it's not clear that can be supported on Tachyon for
+ // all cases (requires more investigation).
+
+ if ((Exchanges->fcExchange[ExchangeID].type == SCSI_TWE || Exchanges->fcExchange[ExchangeID].type == SCSI_TRE)
+ && ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+
+ // target xchnge port_id matches -- how about OX_ID?
+ if ((Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id & 0xFFFF0000)
+ == (fchs->ox_rx_id & 0xFFFF0000))
+ // yes! post ACCept response; will be completed by fcStart
+ {
+ Exchanges->fcExchange[ExchangeID].status = TARGET_ABORT;
+
+ // copy (add) rx_id field for simplified ACCept reply
+ fchs->ox_rx_id = Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id;
+
+ cpqfcTSPutLinkQue(dev, BLS_ABTS_ACC, // Q Type
+ fchs); // void QueContent
+ AbortAccept = 1;
+ printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", fchs->ox_rx_id, Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id);
+ break; // ABTS can affect only ONE exchange -exit loop
+ }
+ }
+ } // end of FOR loop
+ if (!AbortAccept) // can't ACCept ABTS - send Reject
+ {
+ printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", fchs->ox_rx_id);
+ if (Exchanges->fcExchange[ExchangeID].type && !(fcChip->SEST->u[ExchangeID].IWE.Hdr_Len & 0x80000000)) {
+ cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+ } else {
+ printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", ExchangeID, fcChip->SEST->u[ExchangeID].IWE.Hdr_Len);
+ }
+ }
+ }
+ // Check for BLS {ABTS? (Abort Sequence)} ACCept
+ else if ((fchs->d_id & 0x8F000000) == 0x84000000) {
+ // target has responded with ACC for our ABTS;
+ // complete the indicated exchange with ABORTED status
+ // Make no checks for correct RX_ID, since
+ // all we need to conform ABTS ACC is the OX_ID.
+ // Verify that the d_id matches!
- // Check for ABTS (Abort Sequence)
- if( (fchs->d_id & 0x8F000000) == 0x81000000)
- {
- // look for OX_ID, S_ID pair that matches in our
- // fcExchanges table; if found, reply with ACCept and complete
- // the exchange
-
- // Per PLDA, an ABTS is sent by an initiator; therefore
- // assume that if we have an exhange open to the port who
- // sent ABTS, it will be the d_id of what we sent.
- for( ExchangeID = 0, AbortAccept=FALSE;
- ExchangeID < TACH_SEST_LEN; ExchangeID++)
- {
- // Valid "target" exchange 24-bit port_id matches?
- // NOTE: For the case of handling Intiator AND Target
- // functions on the same chip, we can have TWO Exchanges
- // with the same OX_ID -- OX_ID/FFFF for the CMND, and
- // OX_ID/RX_ID for the XRDY or DATA frame(s). Ideally,
- // we would like to support ABTS from Initiators or Targets,
- // but it's not clear that can be supported on Tachyon for
- // all cases (requires more investigation).
-
- if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
- Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
- &&
- ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
- (fchs->s_id & 0xFFFFFF)) )
- {
-
- // target xchnge port_id matches -- how about OX_ID?
- if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
- == (fchs->ox_rx_id & 0xFFFF0000) )
- // yes! post ACCept response; will be completed by fcStart
- {
- Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
-
- // copy (add) rx_id field for simplified ACCept reply
- fchs->ox_rx_id =
- Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
-
- cpqfcTSPutLinkQue( cpqfcHBAdata,
- BLS_ABTS_ACC, // Q Type
- fchs ); // void QueContent
- AbortAccept = TRUE;
- printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n",
- fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
- break; // ABTS can affect only ONE exchange -exit loop
- }
- }
- } // end of FOR loop
- if( !AbortAccept ) // can't ACCept ABTS - send Reject
- {
- printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n",
- fchs->ox_rx_id);
- if( Exchanges->fcExchange[ ExchangeID].type
- &&
- !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
- & 0x80000000))
- {
- cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
- }
- else
- {
- printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n",
- ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
- }
- }
- }
-
- // Check for BLS {ABTS? (Abort Sequence)} ACCept
- else if( (fchs->d_id & 0x8F000000) == 0x84000000)
- {
- // target has responded with ACC for our ABTS;
- // complete the indicated exchange with ABORTED status
- // Make no checks for correct RX_ID, since
- // all we need to conform ABTS ACC is the OX_ID.
- // Verify that the d_id matches!
-
- ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
-// printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n",
+ ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
+// printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n",
// fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
// Exchanges->fcExchange[ExchangeID].status);
+ if (ExchangeID < TACH_SEST_LEN) // x_ID makes sense
+ {
+ // Does "target" exchange 24-bit port_id match?
+ // (See "NOTE" above for handling Intiator AND Target in
+ // the same device driver)
+ // First, if this is a target response, then we originated
+ // (initiated) it with BLS_ABTS:
+
+ if ((Exchanges->fcExchange[ExchangeID].type == BLS_ABTS) &&
+ // Second, does the source of this ACC match the destination
+ // of who we originally sent it to?
+ ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+ cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+ }
+ }
+ }
+ // Check for BLS {ABTS? (Abort Sequence)} ReJecT
+ else if ((fchs->d_id & 0x8F000000) == 0x85000000) {
+ // target has responded with RJT for our ABTS;
+ // complete the indicated exchange with ABORTED status
+ // Make no checks for correct RX_ID, since
+ // all we need to conform ABTS ACC is the OX_ID.
+ // Verify that the d_id matches!
+
+ ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
+// printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n",
+// fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
+
+ if (ExchangeID < TACH_SEST_LEN) // x_ID makes sense
+ {
+ // Does "target" exchange 24-bit port_id match?
+ // (See "NOTE" above for handling Intiator AND Target in
+ // the same device driver)
+ // First, if this is a target response, then we originated
+ // (initiated) it with BLS_ABTS:
+
+ if ((Exchanges->fcExchange[ExchangeID].type == BLS_ABTS)
+
+ &&
+ // Second, does the source of this ACC match the destination
+ // of who we originally sent it to?
+ ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+ // YES! NOTE: There is a bug in CPQ's RA-4000 box
+ // where the "reason code" isn't returned in the payload
+ // For now, simply presume the reject is because the target
+ // already completed the exchange...
+
+// printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
+ cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+ }
+ }
+ } // end of ABTS check
+ } // end of Basic Link Service Request
+ break;
-
-
- if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
- {
- // Does "target" exchange 24-bit port_id match?
- // (See "NOTE" above for handling Intiator AND Target in
- // the same device driver)
- // First, if this is a target response, then we originated
- // (initiated) it with BLS_ABTS:
-
- if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
-
- &&
- // Second, does the source of this ACC match the destination
- // of who we originally sent it to?
- ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
- (fchs->s_id & 0xFFFFFF)) )
- {
- cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
- }
- }
- }
- // Check for BLS {ABTS? (Abort Sequence)} ReJecT
- else if( (fchs->d_id & 0x8F000000) == 0x85000000)
- {
- // target has responded with RJT for our ABTS;
- // complete the indicated exchange with ABORTED status
- // Make no checks for correct RX_ID, since
- // all we need to conform ABTS ACC is the OX_ID.
- // Verify that the d_id matches!
-
- ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
-// printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n",
-// fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
-
- if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
- {
- // Does "target" exchange 24-bit port_id match?
- // (See "NOTE" above for handling Intiator AND Target in
- // the same device driver)
- // First, if this is a target response, then we originated
- // (initiated) it with BLS_ABTS:
-
- if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
-
- &&
- // Second, does the source of this ACC match the destination
- // of who we originally sent it to?
- ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
- (fchs->s_id & 0xFFFFFF)) )
- {
- // YES! NOTE: There is a bug in CPQ's RA-4000 box
- // where the "reason code" isn't returned in the payload
- // For now, simply presume the reject is because the target
- // already completed the exchange...
-
-// printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
- cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
- }
- }
- } // end of ABTS check
- } // end of Basic Link Service Request
- break;
-
- default:
- printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
- fcLQ->Qitem[QNdx].Type,
- fcLQ->Qitem[QNdx].Type);
- break;
- }
+ default:
+ printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n", fcLQ->Qitem[QNdx].Type, fcLQ->Qitem[QNdx].Type);
+ break;
+ }
}
@@ -2428,506 +1868,433 @@
// initialization (e.g. LIP).
// Also may be called if from Fabric Name Service logic.
-static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
+static void SendLogins(CPQFCHBA * dev, __u32 * FabricPortIds)
{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- ULONG ulStatus=0;
- TachFCHDR_GCMND fchs; // copy fields for transmission
- int i;
- ULONG loginType;
- LONG ExchangeID;
- PFC_LOGGEDIN_PORT pLoggedInPort;
- __u32 PortIds[ number_of_al_pa];
- int NumberOfPorts=0;
-
- // We're going to presume (for now) that our limit of Fabric devices
- // is the same as the number of alpa on a private loop (126 devices).
- // (Of course this could be changed to support however many we have
- // memory for).
- memset( &PortIds[0], 0, sizeof(PortIds));
-
- // First, check if this login is for our own Link Initialization
- // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
- // from a switch. If we are logging into Fabric devices, we'll
- // have a non-NULL FabricPortId pointer
-
- if( FabricPortIds != NULL) // may need logins
- {
- int LastPort=FALSE;
- i = 0;
- while( !LastPort)
- {
- // port IDs From NSR payload; byte swap needed?
- BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
-
-// printk("FPortId[%d] %Xh ", i, PortIds[i]);
- if( PortIds[i] & 0x80000000)
- LastPort = TRUE;
-
- PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
- // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
- // erroneously use ALPA 0.
- if( PortIds[i] ) // need non-zero port_id...
- i++;
-
- if( i >= number_of_al_pa ) // (in)sanity check
- break;
- FabricPortIds++; // next...
- }
-
- NumberOfPorts = i;
-// printk("NumberOf Fabric ports %d", NumberOfPorts);
- }
-
- else // need to send logins on our "local" link
- {
-
- // are we a loop port? If so, check for reception of LILP frame,
- // and if received use it (SANMark requirement)
- if( fcChip->Options.LILPin )
- {
- int j=0;
- // sanity check on number of ALPAs from LILP frame...
- // For format of LILP frame, see FC-AL specs or
- // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
- // First byte is number of ALPAs
- i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
- NumberOfPorts = i;
-// printk(" LILP alpa count %d ", i);
- while( i > 0)
- {
- PortIds[j] = fcChip->LILPmap[1+ j];
- j++; i--;
- }
- }
- else // have to send login to everybody
- {
- int j=0;
- i = number_of_al_pa;
- NumberOfPorts = i;
- while( i > 0)
- {
- PortIds[j] = valid_al_pa[j]; // all legal ALPAs
- j++; i--;
- }
- }
- }
-
-
- // Now we have a copy of the port_ids (and how many)...
- for( i = 0; i < NumberOfPorts; i++)
- {
- // 24-bit FC Port ID
- fchs.s_id = PortIds[i]; // note: only 8-bits used for ALPA
+ PTACHYON fcChip = &dev->fcChip;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ u32 ulStatus = 0;
+ TachFCHDR_GCMND fchs; // copy fields for transmission
+ int i;
+ u32 loginType;
+ s32 ExchangeID;
+ PFC_LOGGEDIN_PORT pLoggedInPort;
+ __u32 PortIds[number_of_al_pa];
+ int NumberOfPorts = 0;
+
+ // We're going to presume (for now) that our limit of Fabric devices
+ // is the same as the number of alpa on a private loop (126 devices).
+ // (Of course this could be changed to support however many we have
+ // memory for).
+ memset(&PortIds[0], 0, sizeof(PortIds));
+
+ // First, check if this login is for our own Link Initialization
+ // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
+ // from a switch. If we are logging into Fabric devices, we'll
+ // have a non-NULL FabricPortId pointer
-
- // don't log into ourselves (Linux Scsi disk scan will stop on
- // no TARGET support error on us, and quit trying for rest of devices)
- if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
- continue;
-
- // fabric login needed?
- if( (fchs.s_id == 0) ||
- (fcChip->Options.fabric == 1) )
- {
- fcChip->Options.flogi = 1; // fabric needs longer for login
- // Do we need FLOGI or FDISC?
- pLoggedInPort = fcFindLoggedInPort(
- fcChip,
- NULL, // don't search SCSI Nexus
- 0xFFFFFC, // search linked list for Fabric port_id
- NULL, // don't search WWN
- NULL); // (don't care about end of list)
-
- if( pLoggedInPort ) // If found, we have prior experience with
- // this port -- check whether PDISC is needed
- {
- if( pLoggedInPort->flogi )
+ if (FabricPortIds != NULL) // may need logins
{
- // does the switch support FDISC?? (FLOGI for now...)
- loginType = ELS_FLOGI; // prior FLOGI still valid
- }
- else
- loginType = ELS_FLOGI; // expired FLOGI
- }
- else // first FLOGI?
- loginType = ELS_FLOGI;
-
-
- fchs.s_id = 0xFFFFFE; // well known F_Port address
-
- // Fabrics are not required to support FDISC, and
- // it's not clear if that helps us anyway, since
- // we'll want a Name Service Request to re-verify
- // visible devices...
- // Consequently, we always want our upper 16 bit
- // port_id to be zero (we'll be rejected if we
- // use our prior port_id if we've been plugged into
- // a different switch port).
- // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
- // If our ALPA is 55h for instance, we want the FC frame
- // s_id to be 0x000055, while Tach's my_al_pa register
- // must be 0x000155, to force an OPN at ALPA 0
- // (the Fabric port)
- fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
- writel( fcChip->Registers.my_al_pa | 0x0100,
- fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
- }
+ int LastPort = 0;
+ i = 0;
+ while (!LastPort) {
+ // port IDs From NSR payload; byte swap needed?
+ BigEndianSwap((u8 *) FabricPortIds, (u8 *) & PortIds[i], 4);
+
+// printk("FPortId[%d] %Xh ", i, PortIds[i]);
+ if (PortIds[i] & 0x80000000)
+ LastPort = 1;
+
+ PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
+ // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
+ // erroneously use ALPA 0.
+ if (PortIds[i]) // need non-zero port_id...
+ i++;
+
+ if (i >= number_of_al_pa) // (in)sanity check
+ break;
+ FabricPortIds++; // next...
+ }
- else // not FLOGI...
- {
- // should we send PLOGI or PDISC? Check if any prior port_id
- // (e.g. alpa) completed a PLOGI/PRLI exchange by checking
- // the pdisc flag.
-
- pLoggedInPort = fcFindLoggedInPort(
- fcChip,
- NULL, // don't search SCSI Nexus
- fchs.s_id, // search linked list for al_pa
- NULL, // don't search WWN
- NULL); // (don't care about end of list)
-
-
-
- if( pLoggedInPort ) // If found, we have prior experience with
- // this port -- check whether PDISC is needed
- {
- if( pLoggedInPort->pdisc )
+ NumberOfPorts = i;
+// printk("NumberOf Fabric ports %d", NumberOfPorts);
+ }
+ else // need to send logins on our "local" link
{
- loginType = ELS_PDISC; // prior PLOGI and PRLI maybe still valid
-
+ // are we a loop port? If so, check for reception of LILP frame,
+ // and if received use it (SANMark requirement)
+ if (fcChip->Options.LILPin) {
+ int j = 0;
+ // sanity check on number of ALPAs from LILP frame...
+ // For format of LILP frame, see FC-AL specs or
+ // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
+ // First byte is number of ALPAs
+ i = fcChip->LILPmap[0] >= (32 * 4) ? 32 * 4 : fcChip->LILPmap[0];
+ NumberOfPorts = i;
+// printk(" LILP alpa count %d ", i);
+ while (i > 0) {
+ PortIds[j] = fcChip->LILPmap[1 + j];
+ j++;
+ i--;
+ }
+ }
+ else // have to send login to everybody
+ {
+ int j = 0;
+ i = number_of_al_pa;
+ NumberOfPorts = i;
+ while (i > 0) {
+ PortIds[j] = valid_al_pa[j]; // all legal ALPAs
+ j++;
+ i--;
+ }
+ }
}
- else
- loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
- }
- else // never talked to this port_id before
- loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
- }
-
-
-
- ulStatus = cpqfcTSBuildExchange(
- cpqfcHBAdata,
- loginType, // e.g. PLOGI
- &fchs, // no incoming frame (we are originator)
- NULL, // no data (no scatter/gather list)
- &ExchangeID );// fcController->fcExchanges index, -1 if failed
- if( !ulStatus ) // Exchange setup OK?
- {
- ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
- if( !ulStatus )
- {
- // submitted to Tach's Outbound Que (ERQ PI incremented)
- // waited for completion for ELS type (Login frames issued
- // synchronously)
+ // Now we have a copy of the port_ids (and how many)...
+ for (i = 0; i < NumberOfPorts; i++) {
+ // 24-bit FC Port ID
+ fchs.s_id = PortIds[i]; // note: only 8-bits used for ALPA
+ // don't log into ourselves (Linux Scsi disk scan will stop on
+ // no TARGET support error on us, and quit trying for rest of devices)
+ if ((fchs.s_id & 0xFF) == (fcChip->Registers.my_al_pa & 0xFF))
+ continue;
+ // fabric login needed?
+ if ((fchs.s_id == 0) || (fcChip->Options.fabric == 1)) {
+ fcChip->Options.flogi = 1; // fabric needs longer for login
+ // Do we need FLOGI or FDISC?
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search SCSI Nexus
+ 0xFFFFFC, // search linked list for Fabric port_id
+ NULL, // don't search WWN
+ NULL); // (don't care about end of list)
+
+ if (pLoggedInPort) // If found, we have prior experience with
+ // this port -- check whether PDISC is needed
+ {
+ if (pLoggedInPort->flogi) {
+ // does the switch support FDISC?? (FLOGI for now...)
+ loginType = ELS_FLOGI; // prior FLOGI still valid
+ } else
+ loginType = ELS_FLOGI; // expired FLOGI
+ } else // first FLOGI?
+ loginType = ELS_FLOGI;
+
+ fchs.s_id = 0xFFFFFE; // well known F_Port address
+
+ // Fabrics are not required to support FDISC, and
+ // it's not clear if that helps us anyway, since
+ // we'll want a Name Service Request to re-verify
+ // visible devices...
+ // Consequently, we always want our upper 16 bit
+ // port_id to be zero (we'll be rejected if we
+ // use our prior port_id if we've been plugged into
+ // a different switch port).
+ // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
+ // If our ALPA is 55h for instance, we want the FC frame
+ // s_id to be 0x000055, while Tach's my_al_pa register
+ // must be 0x000155, to force an OPN at ALPA 0
+ // (the Fabric port)
+ fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
+ writel(fcChip->Registers.my_al_pa | 0x0100, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+ }
+ else // not FLOGI...
+ {
+ // should we send PLOGI or PDISC? Check if any prior port_id
+ // (e.g. alpa) completed a PLOGI/PRLI exchange by checking
+ // the pdisc flag.
+
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // don't search SCSI Nexus
+ fchs.s_id, // search linked list for al_pa
+ NULL, // don't search WWN
+ NULL); // (don't care about end of list)
+
+ if (pLoggedInPort) // If found, we have prior experience with
+ // this port -- check whether PDISC is needed
+ {
+ if (pLoggedInPort->pdisc) {
+ loginType = ELS_PDISC; // prior PLOGI and PRLI maybe still valid
+ } else
+ loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
+ } else // never talked to this port_id before
+ loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
+ }
- if( loginType == ELS_PDISC )
- {
- // now, we really shouldn't Revalidate SEST exchanges until
- // we get an ACC reply from our target and verify that
- // the target address/WWN is unchanged. However, when a fast
- // target gets the PDISC, they can send SEST Exchange data
- // before we even get around to processing the PDISC ACC.
- // Consequently, we lose the I/O.
- // To avoid this, go ahead and Revalidate when the PDISC goes
- // out, anticipating that the ACC will be truly acceptable
- // (this happens 99.9999....% of the time).
- // If we revalidate a SEST write, and write data goes to a
- // target that is NOT the one we originated the WRITE to,
- // that target is required (FCP-SCSI specs, etc) to discard
- // our WRITE data.
-
- // Re-validate SEST entries (Tachyon hardware assists)
- RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort);
- //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
- }
- }
- else // give up immediately on error
- {
+ ulStatus = cpqfcTSBuildExchange(dev, loginType, // e.g. PLOGI
+ &fchs, // no incoming frame (we are originator)
+ NULL, // no data (no scatter/gather list)
+ &ExchangeID); // fcController->fcExchanges index, -1 if failed
+
+ if (!ulStatus) // Exchange setup OK?
+ {
+ ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+ if (!ulStatus) {
+ // submitted to Tach's Outbound Que (ERQ PI incremented)
+ // waited for completion for ELS type (Login frames issued
+ // synchronously)
+
+ if (loginType == ELS_PDISC) {
+ // now, we really shouldn't Revalidate SEST exchanges until
+ // we get an ACC reply from our target and verify that
+ // the target address/WWN is unchanged. However, when a fast
+ // target gets the PDISC, they can send SEST Exchange data
+ // before we even get around to processing the PDISC ACC.
+ // Consequently, we lose the I/O.
+ // To avoid this, go ahead and Revalidate when the PDISC goes
+ // out, anticipating that the ACC will be truly acceptable
+ // (this happens 99.9999....% of the time).
+ // If we revalidate a SEST write, and write data goes to a
+ // target that is NOT the one we originated the WRITE to,
+ // that target is required (FCP-SCSI specs, etc) to discard
+ // our WRITE data.
+
+ // Re-validate SEST entries (Tachyon hardware assists)
+ RevalidateSEST(dev->HostAdapter, pLoggedInPort);
+ //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
+ }
+ } else // give up immediately on error
+ {
#ifdef LOGIN_DBG
- printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
+ printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus);
#endif
- break;
- }
+ break;
+ }
+
-
- if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
- {
- ulStatus = LNKDWN_OSLS;
+ if (fcChip->Registers.FMstatus.value & 0x080) // LDn during Port Disc.
+ {
+ ulStatus = LNKDWN_OSLS;
#ifdef LOGIN_DBG
- printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
+ printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
#endif
- break;
- }
- // Check the exchange for bad status (i.e. FrameTimeOut),
- // and complete on bad status (most likely due to BAD_ALPA)
- // on LDn, DPC function may already complete (ABORT) a started
- // exchange, so check type first (type = 0 on complete).
- if( Exchanges->fcExchange[ExchangeID].status )
- {
-#ifdef LOGIN_DBG
- printk("completing x_ID %X on status %Xh\n",
- ExchangeID, Exchanges->fcExchange[ExchangeID].status);
+ break;
+ }
+ // Check the exchange for bad status (i.e. FrameTimeOut),
+ // and complete on bad status (most likely due to BAD_ALPA)
+ // on LDn, DPC function may already complete (ABORT) a started
+ // exchange, so check type first (type = 0 on complete).
+ if (Exchanges->fcExchange[ExchangeID].status) {
+#ifdef LOGIN_DBG
+ printk("completing x_ID %X on status %Xh\n", ExchangeID, Exchanges->fcExchange[ExchangeID].status);
#endif
- cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
- }
- }
- else // Xchange setup failed...
- {
+ cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+ }
+ } else // Xchange setup failed...
+ {
#ifdef LOGIN_DBG
- printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
+ printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
#endif
- break;
- }
- }
- if( !ulStatus )
- {
- // set the event signifying that all ALPAs were sent out.
+ break;
+ }
+ }
+ if (!ulStatus) {
+ // set the event signifying that all ALPAs were sent out.
#ifdef LOGIN_DBG
- printk("SendLogins: PortDiscDone\n");
+ printk("SendLogins: PortDiscDone\n");
#endif
- cpqfcHBAdata->PortDiscDone = 1;
-
-
- // TL/TS UG, pg. 184
- // 0x0065 = 100ms for RT_TOV
- // 0x01f5 = 500ms for ED_TOV
- fcChip->Registers.ed_tov.value = 0x006501f5L;
- writel( fcChip->Registers.ed_tov.value,
- (fcChip->Registers.ed_tov.address));
-
- // set the LP_TOV back to ED_TOV (i.e. 500 ms)
- writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
- }
- else
- {
- printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n",
- ExchangeID, fchs.s_id, ulStatus);
- }
- LEAVE("SendLogins");
+ dev->PortDiscDone = 1;
+ // TL/TS UG, pg. 184
+ // 0x0065 = 100ms for RT_TOV
+ // 0x01f5 = 500ms for ED_TOV
+ fcChip->Registers.ed_tov.value = 0x006501f5L;
+ writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
+
+ // set the LP_TOV back to ED_TOV (i.e. 500 ms)
+ writel(0x00000010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
+ } else {
+ printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", ExchangeID, fchs.s_id, ulStatus);
+ }
+ LEAVE("SendLogins");
}
-
// for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
// D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
-static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
+static void ScsiReportLunsDone(Scsi_Cmnd * Cmnd)
{
- struct Scsi_Host *HostAdapter = Cmnd->host;
- CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- PFC_LOGGEDIN_PORT pLoggedInPort;
- int LunListLen=0;
- int i;
- ULONG x_ID = 0xFFFFFFFF;
- UCHAR *ucBuff = Cmnd->request_buffer;
-
-// printk("cpqfcTS: ReportLunsDone \n");
- // first, we need to find the Exchange for this command,
- // so we can find the fcPort struct to make the indicated
- // changes.
- for( i=0; i< TACH_SEST_LEN; i++)
- {
- if( Exchanges->fcExchange[i].type // exchange defined?
- &&
- (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
-
- {
- x_ID = i; // found exchange!
- break;
- }
- }
- if( x_ID == 0xFFFFFFFF)
- {
-// printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
- goto Done; // Report Luns FC Exchange gone;
- // exchange probably Terminated by Implicit logout
- }
+ struct Scsi_Host *shpnt = Cmnd->host;
+ CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+ PTACHYON fcChip = &dev->fcChip;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ PFC_LOGGEDIN_PORT pLoggedInPort;
+ int LunListLen = 0;
+ int i;
+ u32 x_ID = 0xFFFFFFFF;
+ u8 *ucBuff = Cmnd->request_buffer;
+
+ // printk("cpqfcTS: ReportLunsDone \n");
+ // first, we need to find the Exchange for this command,
+ // so we can find the fcPort struct to make the indicated
+ // changes.
+ for (i = 0; i < TACH_SEST_LEN; i++) {
+ if (Exchanges->fcExchange[i].type // exchange defined?
+ && (Exchanges->fcExchange[i].Cmnd == Cmnd)) // matches?
+
+ {
+ x_ID = i; // found exchange!
+ break;
+ }
+ }
+ if (x_ID == 0xFFFFFFFF) {
+// printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
+ goto Done; // Report Luns FC Exchange gone;
+ // exchange probably Terminated by Implicit logout
+ }
+ // search linked list for the port_id we sent INQUIRY to
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // DON'T search Scsi Nexus (we will set it)
+ Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF, NULL, // DON'T search linked list for FC WWN
+ NULL); // DON'T care about end of list
+
+ if (!pLoggedInPort) {
+// printk("cpqfcTS: ReportLuns failed - device gone\n");
+ goto Done; // error! can't find logged in Port
+ }
+ LunListLen = ucBuff[3];
+ LunListLen += ucBuff[2] >> 8;
- // search linked list for the port_id we sent INQUIRY to
- pLoggedInPort = fcFindLoggedInPort( fcChip,
- NULL, // DON'T search Scsi Nexus (we will set it)
- Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,
- NULL, // DON'T search linked list for FC WWN
- NULL); // DON'T care about end of list
-
- if( !pLoggedInPort )
- {
-// printk("cpqfcTS: ReportLuns failed - device gone\n");
- goto Done; // error! can't find logged in Port
- }
- LunListLen = ucBuff[3];
- LunListLen += ucBuff[2]>>8;
+ if (!LunListLen) // failed
+ {
+ // generically speaking, a soft error means we should retry...
+ if ((Cmnd->result >> 16) == DID_SOFT_ERROR) {
+ if (((Cmnd->sense_buffer[2] & 0xF) == 0x6) && (Cmnd->sense_buffer[12] == 0x29)) // Sense Code "reset"
+ {
+ TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[x_ID].fchs;
+ // did we fail because of "check condition, device reset?"
+ // e.g. the device was reset (i.e., at every power up)
+ // retry the Report Luns
+
+ // who are we sending it to?
+ // we know this because we have a copy of the command
+ // frame from the original Report Lun command -
+ // switch the d_id/s_id fields, because the Exchange Build
+ // context is "reply to source".
- if( !LunListLen ) // failed
- {
- // generically speaking, a soft error means we should retry...
- if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
- {
- if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
- (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
- {
- TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
- // did we fail because of "check condition, device reset?"
- // e.g. the device was reset (i.e., at every power up)
- // retry the Report Luns
-
- // who are we sending it to?
- // we know this because we have a copy of the command
- // frame from the original Report Lun command -
- // switch the d_id/s_id fields, because the Exchange Build
- // context is "reply to source".
-
- fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
- cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
- }
- }
- else // probably, the device doesn't support Report Luns
- pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;
- }
- else // we have LUN info - check VSA mode
- {
- // for now, assume all LUNs will have same addr mode
- // for VSA, payload byte 8 will be 0x40; otherwise, 0
- pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];
-
- // Since we got a Report Luns answer, set lun masking flag
- pLoggedInPort->ScsiNexus.LunMasking = 1;
+ fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
+ cpqfcTSPutLinkQue(dev, SCSI_REPORT_LUNS, fchs);
+ }
+ } else // probably, the device doesn't support Report Luns
+ pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;
+ } else // we have LUN info - check VSA mode
+ {
+ // for now, assume all LUNs will have same addr mode
+ // for VSA, payload byte 8 will be 0x40; otherwise, 0
+ pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];
- if( LunListLen > 8*CPQFCTS_MAX_LUN) // We expect CPQFCTS_MAX_LUN max
- LunListLen = 8*CPQFCTS_MAX_LUN;
+ // Since we got a Report Luns answer, set lun masking flag
+ pLoggedInPort->ScsiNexus.LunMasking = 1;
+
+ if (LunListLen > 8 * CPQFCTS_MAX_LUN) // We expect CPQFCTS_MAX_LUN max
+ LunListLen = 8 * CPQFCTS_MAX_LUN;
/*
- printk("Device WWN %08X%08X Reports Luns @: ",
- (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
- (ULONG)(pLoggedInPort->u.liWWN>>32));
+ printk("Device WWN %08X%08X Reports Luns @: ",
+ (u32)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
+ (u32)(pLoggedInPort->u.liWWN>>32));
- for( i=8; i<LunListLen+8; i+=8)
- {
- printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
- }
- printk("\n");
+ for( i=8; i<LunListLen+8; i+=8)
+ {
+ printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
+ }
+ printk("\n");
*/
-
- // Since the device was kind enough to tell us where the
- // LUNs are, lets ensure they are contiguous for Linux's
- // SCSI driver scan, which expects them to start at 0.
- // Since Linux only supports 8 LUNs, only copy the first
- // eight from the report luns command
-
- // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
- // LUNs 4001, 4004, etc., because other LUNs are masked from
- // this HBA (owned by someone else). We'll make those appear as
- // LUN 0, 1... to Linux
- {
- int j;
- int AppendLunList = 0;
- // Walk through the LUN list. The 'j' array number is
- // Linux's lun #, while the value of .lun[j] is the target's
- // lun #.
- // Once we build a LUN list, it's possible for a known device
- // to go offline while volumes (LUNs) are added. Later,
- // the device will do another PLOGI ... Report Luns command,
- // and we must not alter the existing Linux Lun map.
- // (This will be very rare).
- for( j=0; j < CPQFCTS_MAX_LUN; j++)
- {
- if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
- {
- AppendLunList = 1;
- break;
- }
- }
- if( AppendLunList )
- {
- int k;
- int FreeLunIndex;
-// printk("cpqfcTS: AppendLunList\n");
-
- // If we get a new Report Luns, we cannot change
- // any existing LUN mapping! (Only additive entry)
- // For all LUNs in ReportLun list
- // if RL lun != ScsiNexus lun
- // if RL lun present in ScsiNexus lun[], continue
- // else find ScsiNexus lun[]==FF and add, continue
-
- for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
- {
- if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
- {
- // something changed from the last Report Luns
- printk(" cpqfcTS: Report Lun change!\n");
- for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN;
- k < CPQFCTS_MAX_LUN; k++)
- {
- if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
- {
- FreeLunIndex = k;
- break;
- }
- if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
- break; // we already masked this lun
- }
- if( k >= CPQFCTS_MAX_LUN )
- {
- printk(" no room for new LUN %d\n", ucBuff[i+1]);
- }
- else if( k == FreeLunIndex ) // need to add LUN
- {
- pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
-// printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
-
- }
- else
- {
- // lun already known
- }
- break;
- }
- }
- // print out the new list...
- for( j=0; j< CPQFCTS_MAX_LUN; j++)
- {
- if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
- break; // done
-// printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
- }
- }
- else
- {
-// printk("Linux SCSI LUNs[] -> Device LUNs: ");
- // first time - this is easy
- for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
- {
- pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
-// printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+
+ // Since the device was kind enough to tell us where the
+ // LUNs are, lets ensure they are contiguous for Linux's
+ // SCSI driver scan, which expects them to start at 0.
+ // Since Linux only supports 8 LUNs, only copy the first
+ // eight from the report luns command
+
+ // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
+ // LUNs 4001, 4004, etc., because other LUNs are masked from
+ // this HBA (owned by someone else). We'll make those appear as
+ // LUN 0, 1... to Linux
+ {
+ int j;
+ int AppendLunList = 0;
+ // Walk through the LUN list. The 'j' array number is
+ // Linux's lun #, while the value of .lun[j] is the target's
+ // lun #.
+ // Once we build a LUN list, it's possible for a known device
+ // to go offline while volumes (LUNs) are added. Later,
+ // the device will do another PLOGI ... Report Luns command,
+ // and we must not alter the existing Linux Lun map.
+ // (This will be very rare).
+ for (j = 0; j < CPQFCTS_MAX_LUN; j++) {
+ if (pLoggedInPort->ScsiNexus.lun[j] != 0xFF) {
+ AppendLunList = 1;
+ break;
+ }
+ }
+ if (AppendLunList) {
+ int k;
+ int FreeLunIndex;
+// printk("cpqfcTS: AppendLunList\n");
+
+ // If we get a new Report Luns, we cannot change
+ // any existing LUN mapping! (Only additive entry)
+ // For all LUNs in ReportLun list
+ // if RL lun != ScsiNexus lun
+ // if RL lun present in ScsiNexus lun[], continue
+ // else find ScsiNexus lun[]==FF and add, continue
+
+ for (i = 8, j = 0; i < LunListLen + 8 && j < CPQFCTS_MAX_LUN; i += 8, j++) {
+ if (pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i + 1]) {
+ // something changed from the last Report Luns
+ printk(" cpqfcTS: Report Lun change!\n");
+ for (k = 0, FreeLunIndex = CPQFCTS_MAX_LUN; k < CPQFCTS_MAX_LUN; k++) {
+ if (pLoggedInPort->ScsiNexus.lun[k] == 0xFF) {
+ FreeLunIndex = k;
+ break;
+ }
+ if (pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i + 1])
+ break; // we already masked this lun
+ }
+ if (k >= CPQFCTS_MAX_LUN) {
+ printk(" no room for new LUN %d\n", ucBuff[i + 1]);
+ } else if (k == FreeLunIndex) // need to add LUN
+ {
+ pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i + 1];
+// printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
+
+ } else {
+ // lun already known
+ }
+ break;
+ }
+ }
+ // print out the new list...
+ for (j = 0; j < CPQFCTS_MAX_LUN; j++) {
+ if (pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
+ break; // done
+// printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+ }
+ } else {
+// printk("Linux SCSI LUNs[] -> Device LUNs: ");
+ // first time - this is easy
+ for (i = 8, j = 0; i < LunListLen + 8 && j < CPQFCTS_MAX_LUN; i += 8, j++) {
+ pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i + 1];
+// printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+ }
+// printk("\n");
+ }
+ }
}
-// printk("\n");
- }
- }
- }
-Done: ;
+ Done:;
}
-static void
-call_scsi_done(Scsi_Cmnd *Cmnd)
+static void call_scsi_done(Scsi_Cmnd * Cmnd)
{
// We have to reinitialize sent_command here, so the scsi-mid
// layer won't re-use the scsi command leaving it set incorrectly.
// (incorrectly for our purposes...it's normally unused.)
- if (Cmnd->SCp.sent_command != 0) { // was it a passthru?
+ if (Cmnd->SCp.sent_command != 0) { // was it a passthru?
Cmnd->SCp.sent_command = 0;
Cmnd->result &= 0xff00ffff;
- Cmnd->result |= (DID_PASSTHROUGH << 16); // prevents retry
+ Cmnd->result |= (DID_PASSTHROUGH << 16); // prevents retry
}
if (Cmnd->scsi_done != NULL)
- (*Cmnd->scsi_done)(Cmnd);
+ (*Cmnd->scsi_done) (Cmnd);
}
// After successfully getting a "Process Login" (PRLI) from an
@@ -2939,361 +2306,301 @@
// driver model, which expects a contiguous LUNs starting at 0,
// will use the ReportLuns info to map from "device" to "Linux"
// LUNs.
-static void IssueReportLunsCommand(
- CPQFCHBA* cpqfcHBAdata,
- TachFCHDR_GCMND* fchs)
-{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- PFC_LOGGEDIN_PORT pLoggedInPort;
- Scsi_Cmnd *Cmnd;
- LONG x_ID;
- ULONG ulStatus;
- UCHAR *ucBuff;
-
- if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
- {
- printk("Discard Q'd ReportLun command\n");
- goto Done;
- }
-
- // find the device (from port_id) we're talking to
- pLoggedInPort = fcFindLoggedInPort( fcChip,
- NULL, // DON'T search Scsi Nexus
- fchs->s_id & 0xFFFFFF,
- NULL, // DON'T search linked list for FC WWN
- NULL); // DON'T care about end of list
- if( pLoggedInPort ) // we'd BETTER find it!
- {
-
-
- if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
- goto Done; // forget it - FC device not a "target"
-
- // now use the port's Scsi Command buffer for the
- // Report Luns Command
-
- Cmnd = &pLoggedInPort->ScsiCmnd;
- ucBuff = pLoggedInPort->ReportLunsPayload;
-
- memset( Cmnd, 0, sizeof(Scsi_Cmnd));
- memset( ucBuff, 0, REPORT_LUNS_PL);
-
- Cmnd->scsi_done = ScsiReportLunsDone;
- Cmnd->host = cpqfcHBAdata->HostAdapter;
-
- Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload;
- Cmnd->request_bufflen = REPORT_LUNS_PL;
-
- Cmnd->cmnd[0] = 0xA0;
- Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
- Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL;
- Cmnd->cmd_len = 12;
-
- Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
- Cmnd->target = pLoggedInPort->ScsiNexus.target;
+static void IssueReportLunsCommand(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+ PTACHYON fcChip = &dev->fcChip;
+ PFC_LOGGEDIN_PORT pLoggedInPort;
+ Scsi_Cmnd *Cmnd;
+ s32 x_ID;
+ u32 ulStatus;
+ u8 *ucBuff;
-
- ulStatus = cpqfcTSBuildExchange(
- cpqfcHBAdata,
- SCSI_IRE,
- fchs,
- Cmnd, // buffer for Report Lun data
- &x_ID );// fcController->fcExchanges index, -1 if failed
+ if (!dev->PortDiscDone) // cleared by LDn
+ {
+ printk("Discard Q'd ReportLun command\n");
+ goto Done;
+ }
+ // find the device (from port_id) we're talking to
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // DON'T search Scsi Nexus
+ fchs->s_id & 0xFFFFFF, NULL, // DON'T search linked list for FC WWN
+ NULL); // DON'T care about end of list
+ if (pLoggedInPort) // we'd BETTER find it!
+ {
- if( !ulStatus ) // Exchange setup?
- {
- ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
- if( !ulStatus )
- {
- // submitted to Tach's Outbound Que (ERQ PI incremented)
- // waited for completion for ELS type (Login frames issued
- // synchronously)
- }
- else
- // check reason for Exchange not being started - we might
- // want to Queue and start later, or fail with error
- {
-
- }
- }
- else // Xchange setup failed...
- printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
- }
- else // like, we just got a PRLI ACC, and now the port is gone?
- {
- printk(" can't send ReportLuns - no login for port_id %Xh\n",
- fchs->s_id & 0xFFFFFF);
- }
+ if (!(pLoggedInPort->fcp_info & TARGET_FUNCTION))
+ goto Done; // forget it - FC device not a "target"
+ // now use the port's Scsi Command buffer for the
+ // Report Luns Command
+ Cmnd = &pLoggedInPort->ScsiCmnd;
+ ucBuff = pLoggedInPort->ReportLunsPayload;
-Done: ;
+ memset(Cmnd, 0, sizeof(Scsi_Cmnd));
+ memset(ucBuff, 0, REPORT_LUNS_PL);
+
+ Cmnd->scsi_done = ScsiReportLunsDone;
+ Cmnd->host = dev->HostAdapter;
+
+ Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload;
+ Cmnd->request_bufflen = REPORT_LUNS_PL;
+
+ Cmnd->cmnd[0] = 0xA0;
+ Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
+ Cmnd->cmnd[9] = (u8) REPORT_LUNS_PL;
+ Cmnd->cmd_len = 12;
+
+ Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
+ Cmnd->target = pLoggedInPort->ScsiNexus.target;
+
+
+ ulStatus = cpqfcTSBuildExchange(dev, SCSI_IRE, fchs, Cmnd, // buffer for Report Lun data
+ &x_ID); // fcController->fcExchanges index, -1 if failed
+
+ if (!ulStatus) // Exchange setup?
+ {
+ ulStatus = cpqfcTSStartExchange(dev, x_ID);
+ if (!ulStatus) {
+ // submitted to Tach's Outbound Que (ERQ PI incremented)
+ // waited for completion for ELS type (Login frames issued
+ // synchronously)
+ } else
+ // check reason for Exchange not being started - we might
+ // want to Queue and start later, or fail with error
+ {
+ }
+ }
+ else // Xchange setup failed...
+ printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
+ } else // like, we just got a PRLI ACC, and now the port is gone?
+ {
+ printk(" can't send ReportLuns - no login for port_id %Xh\n", fchs->s_id & 0xFFFFFF);
+ }
+Done:;
}
-
-
-
-
-
-
-static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata)
+static void CompleteBoardLockCmnd(CPQFCHBA * dev)
{
- int i;
- for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--)
- {
- if( cpqfcHBAdata->BoardLockCmnd[i] != NULL )
- {
- Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i];
- cpqfcHBAdata->BoardLockCmnd[i] = NULL;
- Cmnd->result = (DID_SOFT_ERROR << 16); // ask for retry
-// printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
-// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
- call_scsi_done(Cmnd);
- }
- }
+ int i;
+ for (i = CPQFCTS_REQ_QUEUE_LEN - 1; i >= 0; i--) {
+ if (dev->BoardLockCmnd[i] != NULL) {
+ Scsi_Cmnd *Cmnd = dev->BoardLockCmnd[i];
+ dev->BoardLockCmnd[i] = NULL;
+ Cmnd->result = (DID_SOFT_ERROR << 16); // ask for retry
+// printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
+// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
+ call_scsi_done(Cmnd);
+ }
+ }
}
+// runs every 1 second for FC exchange timeouts and implicit FC device logouts
+void cpqfcTSheartbeat(unsigned long ptr)
+{
+ CPQFCHBA *dev = (CPQFCHBA *) ptr;
+ PTACHYON fcChip = &dev->fcChip;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+ u32 i;
+ unsigned long flags;
+ DECLARE_MUTEX_LOCKED(BoardLock);
+ PCI_TRACE(0xA8)
+ if (dev->BoardLock) // Worker Task Running?
+ goto Skip;
+ spin_lock_irqsave(&io_request_lock, flags); // STOP _que function
-// runs every 1 second for FC exchange timeouts and implicit FC device logouts
-
-void cpqfcTSheartbeat( unsigned long ptr )
-{
- CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr;
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
- ULONG i;
- unsigned long flags;
- DECLARE_MUTEX_LOCKED(BoardLock);
-
- PCI_TRACE( 0xA8)
-
- if( cpqfcHBAdata->BoardLock) // Worker Task Running?
- goto Skip;
-
- spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
-
- PCI_TRACE( 0xA8)
-
-
- cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
-
- // release the IO lock (and re-enable interrupts)
- spin_unlock_irqrestore( &io_request_lock, flags);
-
- // Ensure no contention from _quecommand or Worker process
- CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-
- PCI_TRACE( 0xA8)
-
-
- disable_irq( cpqfcHBAdata->HostAdapter->irq); // our IRQ
-
- // Complete the "bad target" commands (normally only used during
- // initialization, since we aren't supposed to call "scsi_done"
- // inside the queuecommand() function). (this is overly contorted,
- // scsi_done can be safely called from queuecommand for
- // this bad target case. May want to simplify this later)
+ PCI_TRACE(0xA8)
- for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
- {
- if( cpqfcHBAdata->BadTargetCmnd[i] )
- {
- Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
- cpqfcHBAdata->BadTargetCmnd[i] = NULL;
- Cmnd->result = (DID_BAD_TARGET << 16);
- call_scsi_done(Cmnd);
- }
- else
- break;
- }
+ dev->BoardLock = &BoardLock; // stop Linux SCSI command queuing
-
- // logged in ports -- re-login check (ports required to verify login with
- // PDISC after LIP within 2 secs)
-
- // prevent contention
- while( pLoggedInPort ) // for all ports which are expecting
- // PDISC after the next LIP, check to see if
- // time is up!
- {
- // Important: we only detect "timeout" condition on TRANSITION
- // from non-zero to zero
- if( pLoggedInPort->LOGO_timer ) // time-out "armed"?
- {
- if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0?
- {
- // LOGOUT time! Per PLDA, PDISC hasn't complete in 2 secs, so
- // issue LOGO request and destroy all I/O with other FC port(s).
-
-/*
- printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
- printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n",
- pLoggedInPort->ScsiNexus.channel,
- pLoggedInPort->ScsiNexus.target,
- pLoggedInPort->port_id,
- (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
- (ULONG)(pLoggedInPort->u.liWWN>>32));
+ // release the IO lock (and re-enable interrupts)
+ spin_unlock_irqrestore(&io_request_lock, flags);
-*/
- cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
+ // Ensure no contention from _quecommand or Worker process
+ CPQ_SPINLOCK_HBA(dev)
- }
- // else simply decremented - maybe next time...
- }
- pLoggedInPort = pLoggedInPort->pNextPort;
- }
+ PCI_TRACE(0xA8)
+ disable_irq(dev->HostAdapter->irq); // our IRQ
+ // Complete the "bad target" commands (normally only used during
+ // initialization, since we aren't supposed to call "scsi_done"
+ // inside the queuecommand() function). (this is overly contorted,
+ // scsi_done can be safely called from queuecommand for
+ // this bad target case. May want to simplify this later)
-
-
- // ************ FC EXCHANGE TIMEOUT CHECK **************
-
- for( i=0; i< TACH_MAX_XID; i++)
- {
- if( Exchanges->fcExchange[i].type ) // exchange defined?
- {
+ for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {
+ if (dev->BadTargetCmnd[i]) {
+ Scsi_Cmnd *Cmnd = dev->BadTargetCmnd[i];
+ dev->BadTargetCmnd[i] = NULL;
+ Cmnd->result = (DID_BAD_TARGET << 16);
+ call_scsi_done(Cmnd);
+ } else
+ break;
+ }
- if( !Exchanges->fcExchange[i].timeOut ) // time expired
- {
- // Set Exchange timeout status
- Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
-
- if( i >= TACH_SEST_LEN ) // Link Service Exchange
- {
- cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // Don't "abort" LinkService
- }
-
- else // SEST Exchange TO -- may post ABTS to Worker Thread Que
- {
- // (Make sure we don't keep timing it out; let other functions
- // complete it or set the timeOut as needed)
- Exchanges->fcExchange[i].timeOut = 30000; // seconds default
-
- if( Exchanges->fcExchange[i].type
- &
- (BLS_ABTS | BLS_ABTS_ACC ) )
- {
- // For BLS_ABTS*, an upper level might still have
- // an outstanding command waiting for low-level completion.
- // Also, in the case of a WRITE, we MUST get confirmation
- // of either ABTS ACC or RJT before re-using the Exchange.
- // It's possible that the RAID cache algorithm can hang
- // if we fail to complete a WRITE to a LBA, when a READ
- // comes later to that same LBA. Therefore, we must
- // ensure that the target verifies receipt of ABTS for
- // the exchange
-
- printk("~TO Q'd ABTS (x_ID %Xh)~ ", i);
-// TriggerHBA( fcChip->Registers.ReMapMemBase);
-
- // On timeout of a ABTS exchange, check to
- // see if the FC device has a current valid login.
- // If so, restart it.
- pLoggedInPort = fcFindLoggedInPort( fcChip,
- Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
- 0, // DON'T search linked list for FC port id
- NULL, // DON'T search linked list for FC WWN
- NULL); // DON'T care about end of list
-
- // device exists?
- if( pLoggedInPort ) // device exists?
- {
- if( pLoggedInPort->prli ) // logged in for FCP-SCSI?
- {
- // attempt to restart the ABTS
- printk(" ~restarting ABTS~ ");
- cpqfcTSStartExchange( cpqfcHBAdata, i );
-
- }
- }
- }
- else // not an ABTS
- {
-
- // We expect the WorkerThread to change the xchng type to
- // abort and set appropriate timeout.
- cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out
- }
- }
- }
- else // time not expired...
- {
- // decrement timeout: 1 or more seconds left
- --Exchanges->fcExchange[i].timeOut;
- }
- }
- }
+ // logged in ports -- re-login check (ports required to verify login with
+ // PDISC after LIP within 2 secs)
- enable_irq( cpqfcHBAdata->HostAdapter->irq);
-
+ // prevent contention
+ while (pLoggedInPort) // for all ports which are expecting
+ // PDISC after the next LIP, check to see if
+ // time is up!
+ {
+ // Important: we only detect "timeout" condition on TRANSITION
+ // from non-zero to zero
+ if (pLoggedInPort->LOGO_timer) // time-out "armed"?
+ {
+ if (!(--pLoggedInPort->LOGO_timer)) // DEC from 1 to 0?
+ {
+ // LOGOUT time! Per PLDA, PDISC hasn't complete in 2 secs, so
+ // issue LOGO request and destroy all I/O with other FC port(s).
- CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
+/*
+ printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
+ printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n",
+ pLoggedInPort->ScsiNexus.channel,
+ pLoggedInPort->ScsiNexus.target,
+ pLoggedInPort->port_id,
+ (u32)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
+ (u32)(pLoggedInPort->u.liWWN>>32));
+*/
+ cpqfcTSImplicitLogout(dev, pLoggedInPort);
- cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued
+ }
+ // else simply decremented - maybe next time...
+ }
+ pLoggedInPort = pLoggedInPort->pNextPort;
+ }
- // Now, complete any Cmnd we Q'd up while BoardLock was held
+ // ************ FC EXCHANGE TIMEOUT CHECK **************
- CompleteBoardLockCmnd( cpqfcHBAdata);
-
+ for (i = 0; i < TACH_MAX_XID; i++) {
+ if (Exchanges->fcExchange[i].type) // exchange defined?
+ {
+
+ if (!Exchanges->fcExchange[i].timeOut) // time expired
+ {
+ // Set Exchange timeout status
+ Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
+
+ if (i >= TACH_SEST_LEN) // Link Service Exchange
+ {
+ cpqfcTSCompleteExchange(dev->PciDev, fcChip, i); // Don't "abort" LinkService
+ }
+ else // SEST Exchange TO -- may post ABTS to Worker Thread Que
+ {
+ // (Make sure we don't keep timing it out; let other functions
+ // complete it or set the timeOut as needed)
+ Exchanges->fcExchange[i].timeOut = 30000; // seconds default
+
+ if (Exchanges->fcExchange[i].type & (BLS_ABTS | BLS_ABTS_ACC)) {
+ // For BLS_ABTS*, an upper level might still have
+ // an outstanding command waiting for low-level completion.
+ // Also, in the case of a WRITE, we MUST get confirmation
+ // of either ABTS ACC or RJT before re-using the Exchange.
+ // It's possible that the RAID cache algorithm can hang
+ // if we fail to complete a WRITE to a LBA, when a READ
+ // comes later to that same LBA. Therefore, we must
+ // ensure that the target verifies receipt of ABTS for
+ // the exchange
+
+ printk("~TO Q'd ABTS (x_ID %Xh)~ ", i);
+// TriggerHBA( fcChip->Registers.ReMapMemBase);
+
+ // On timeout of a ABTS exchange, check to
+ // see if the FC device has a current valid login.
+ // If so, restart it.
+ pLoggedInPort = fcFindLoggedInPort(fcChip, Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
+ 0, // DON'T search linked list for FC port id
+ NULL, // DON'T search linked list for FC WWN
+ NULL); // DON'T care about end of list
+ // device exists?
+ if (pLoggedInPort) // device exists?
+ {
+ if (pLoggedInPort->prli) // logged in for FCP-SCSI?
+ {
+ // attempt to restart the ABTS
+ printk(" ~restarting ABTS~ ");
+ cpqfcTSStartExchange(dev, i);
+
+ }
+ }
+ } else // not an ABTS
+ {
+
+ // We expect the WorkerThread to change the xchng type to
+ // abort and set appropriate timeout.
+ cpqfcTSPutLinkQue(dev, BLS_ABTS, &i); // timed-out
+ }
+ }
+ } else // time not expired...
+ {
+ // decrement timeout: 1 or more seconds left
+ --Exchanges->fcExchange[i].timeOut;
+ }
+ }
+ }
- // restart the timer to run again (1 sec later)
+ enable_irq(dev->HostAdapter->irq);
+ CPQ_SPINUNLOCK_HBA(dev)
+ dev->BoardLock = NULL; // Linux SCSI commands may be queued
+ // Now, complete any Cmnd we Q'd up while BoardLock was held
+ CompleteBoardLockCmnd(dev);
+ // restart the timer to run again (1 sec later)
Skip:
- mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ);
-
- PCI_TRACEO( i, 0xA8)
- return;
+ mod_timer(&dev->cpqfcTStimer, jiffies + HZ);
+ PCI_TRACEO(i, 0xA8)
+ return;
}
// put valid FC-AL physical address in spec order
-static const UCHAR valid_al_pa[]={
- 0xef, 0xe8, 0xe4, 0xe2,
- 0xe1, 0xE0, 0xDC, 0xDA,
- 0xD9, 0xD6, 0xD5, 0xD4,
- 0xD3, 0xD2, 0xD1, 0xCe,
- 0xCd, 0xCc, 0xCb, 0xCa,
- 0xC9, 0xC7, 0xC6, 0xC5,
- 0xC3, 0xBc, 0xBa, 0xB9,
- 0xB6, 0xB5, 0xB4, 0xB3,
- 0xB2, 0xB1, 0xae, 0xad,
- 0xAc, 0xAb, 0xAa, 0xA9,
-
- 0xA7, 0xA6, 0xA5, 0xA3,
- 0x9f, 0x9e, 0x9d, 0x9b,
- 0x98, 0x97, 0x90, 0x8f,
- 0x88, 0x84, 0x82, 0x81,
- 0x80, 0x7c, 0x7a, 0x79,
- 0x76, 0x75, 0x74, 0x73,
- 0x72, 0x71, 0x6e, 0x6d,
- 0x6c, 0x6b, 0x6a, 0x69,
- 0x67, 0x66, 0x65, 0x63,
- 0x5c, 0x5a, 0x59, 0x56,
-
- 0x55, 0x54, 0x53, 0x52,
- 0x51, 0x4e, 0x4d, 0x4c,
- 0x4b, 0x4a, 0x49, 0x47,
- 0x46, 0x45, 0x43, 0x3c,
- 0x3a, 0x39, 0x36, 0x35,
- 0x34, 0x33, 0x32, 0x31,
- 0x2e, 0x2d, 0x2c, 0x2b,
- 0x2a, 0x29, 0x27, 0x26,
- 0x25, 0x23, 0x1f, 0x1E,
- 0x1d, 0x1b, 0x18, 0x17,
-
- 0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case
-
-const int number_of_al_pa = (sizeof(valid_al_pa) );
+static const u8 valid_al_pa[] = {
+ 0xef, 0xe8, 0xe4, 0xe2,
+ 0xe1, 0xE0, 0xDC, 0xDA,
+ 0xD9, 0xD6, 0xD5, 0xD4,
+ 0xD3, 0xD2, 0xD1, 0xCe,
+ 0xCd, 0xCc, 0xCb, 0xCa,
+ 0xC9, 0xC7, 0xC6, 0xC5,
+ 0xC3, 0xBc, 0xBa, 0xB9,
+ 0xB6, 0xB5, 0xB4, 0xB3,
+ 0xB2, 0xB1, 0xae, 0xad,
+ 0xAc, 0xAb, 0xAa, 0xA9,
+
+ 0xA7, 0xA6, 0xA5, 0xA3,
+ 0x9f, 0x9e, 0x9d, 0x9b,
+ 0x98, 0x97, 0x90, 0x8f,
+ 0x88, 0x84, 0x82, 0x81,
+ 0x80, 0x7c, 0x7a, 0x79,
+ 0x76, 0x75, 0x74, 0x73,
+ 0x72, 0x71, 0x6e, 0x6d,
+ 0x6c, 0x6b, 0x6a, 0x69,
+ 0x67, 0x66, 0x65, 0x63,
+ 0x5c, 0x5a, 0x59, 0x56,
+
+ 0x55, 0x54, 0x53, 0x52,
+ 0x51, 0x4e, 0x4d, 0x4c,
+ 0x4b, 0x4a, 0x49, 0x47,
+ 0x46, 0x45, 0x43, 0x3c,
+ 0x3a, 0x39, 0x36, 0x35,
+ 0x34, 0x33, 0x32, 0x31,
+ 0x2e, 0x2d, 0x2c, 0x2b,
+ 0x2a, 0x29, 0x27, 0x26,
+ 0x25, 0x23, 0x1f, 0x1E,
+ 0x1d, 0x1b, 0x18, 0x17,
+ 0x10, 0x0f, 8, 4, 2, 1
+}; // ALPA 0 (Fabric) is special case
+const int number_of_al_pa = (sizeof(valid_al_pa));
// this function looks up an al_pa from the table of valid al_pa's
// we decrement from the last decimal loop ID, because soft al_pa
@@ -3306,16 +2613,16 @@
// -1 - invalid al_pa (not all 8 bit values are legal)
#if (0)
-static int GetLoopID( ULONG al_pa )
+static int GetLoopID(u32 al_pa)
{
- int i;
+ int i;
- for( i = number_of_al_pa -1; i >= 0; i--) // dec.
- {
- if( valid_al_pa[i] == (UCHAR)al_pa ) // take lowest 8 bits
- return i; // success - found valid al_pa; return decimal LoopID
- }
- return -1; // failed - not found
+ for (i = number_of_al_pa - 1; i >= 0; i--) // dec.
+ {
+ if (valid_al_pa[i] == (u8) al_pa) // take lowest 8 bits
+ return i; // success - found valid al_pa; return decimal LoopID
+ }
+ return -1; // failed - not found
}
#endif
@@ -3330,739 +2637,620 @@
// (NULL if not found)
// pLastLoggedInPort - ptr to last struct (for adding new ones)
//
-PFC_LOGGEDIN_PORT fcFindLoggedInPort(
- PTACHYON fcChip,
- Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
- ULONG port_id, // search linked list for al_pa, or
- UCHAR wwn[8], // search linked list for WWN, or...
- PFC_LOGGEDIN_PORT *pLastLoggedInPort )
-
-{
- PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
- BOOLEAN target_id_valid=FALSE;
- BOOLEAN port_id_valid=FALSE;
- BOOLEAN wwn_valid=FALSE;
- int i;
-
-
- if( Cmnd != NULL )
- target_id_valid = TRUE;
-
- else if( port_id ) // note! 24-bit NULL address is illegal
- port_id_valid = TRUE;
+PFC_LOGGEDIN_PORT fcFindLoggedInPort(PTACHYON fcChip, Scsi_Cmnd * Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
+ u32 port_id, // search linked list for al_pa, or
+ u8 wwn[8], // search linked list for WWN, or...
+ PFC_LOGGEDIN_PORT * pLastLoggedInPort)
+{
+ PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+ u8 target_id_valid = 0;
+ u8 port_id_valid = 0;
+ u8 wwn_valid = 0;
+ int i;
+
+
+ if (Cmnd != NULL)
+ target_id_valid = 1;
+
+ else if (port_id) // note! 24-bit NULL address is illegal
+ port_id_valid = 1;
+
+ else {
+ if (wwn) // non-null arg? (OK to pass NULL when not searching WWN)
+ {
+ for (i = 0; i < 8; i++) // valid WWN passed? NULL WWN invalid
+ {
+ if (wwn[i] != 0)
+ wwn_valid = 1; // any non-zero byte makes (presumably) valid
+ }
+ }
+ }
+ // check other options ...
- else
- {
- if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
- {
- for( i=0; i<8; i++) // valid WWN passed? NULL WWN invalid
- {
- if( wwn[i] != 0 )
- wwn_valid = TRUE; // any non-zero byte makes (presumably) valid
- }
- }
- }
- // check other options ...
+ // In case multiple search options are given, we use a priority
+ // scheme:
+ // While valid pLoggedIn Ptr
+ // If port_id is valid
+ // if port_id matches, return Ptr
+ // If wwn is valid
+ // if wwn matches, return Ptr
+ // Next Ptr in list
+ //
+ // Return NULL (not found)
- // In case multiple search options are given, we use a priority
- // scheme:
- // While valid pLoggedIn Ptr
- // If port_id is valid
- // if port_id matches, return Ptr
- // If wwn is valid
- // if wwn matches, return Ptr
- // Next Ptr in list
- //
- // Return NULL (not found)
-
-
- while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid)
- {
- if( pLastLoggedInPort ) // caller's pointer valid?
- *pLastLoggedInPort = pLoggedInPort; // end of linked list
-
- if( target_id_valid )
- {
- // check Linux Scsi Cmnd for channel/target Nexus match
- // (all luns are accessed through matching "pLoggedInPort")
- if( (pLoggedInPort->ScsiNexus.target == Cmnd->target)
- &&
- (pLoggedInPort->ScsiNexus.channel == Cmnd->channel))
- {
- // For "passthru" modes, the IOCTL caller is responsible
- // for setting the FCP-LUN addressing
- if( !Cmnd->SCp.sent_command ) // NOT passthru?
+
+ while (pLoggedInPort) // NULL marks end of list (1st ptr always valid)
{
-
- // set the FCP-LUN addressing type
- Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;
-
- // set the Device Type we got from the snooped INQUIRY string
- Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
-
- // handle LUN masking; if not "default" (illegal) lun value,
- // the use it. These lun values are set by a successful
- // Report Luns command
- if( pLoggedInPort->ScsiNexus.LunMasking == 1)
- {
- // we KNOW all the valid LUNs... 0xFF is invalid!
- Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
- if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
- return NULL;
- // printk("xlating lun %d to 0x%02x\n", Cmnd->lun,
- // pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
- }
- else
- Cmnd->SCp.have_data_in = Cmnd->lun; // Linux & target luns match
- }
- break; // found it!
- }
- }
-
- if( port_id_valid ) // look for alpa first
- {
- if( pLoggedInPort->port_id == port_id )
- break; // found it!
- }
- if( wwn_valid ) // look for wwn second
- {
+ if (pLastLoggedInPort) // caller's pointer valid?
+ *pLastLoggedInPort = pLoggedInPort; // end of linked list
- if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
- {
- // all 8 bytes of WWN match
- break; // found it!
- }
- }
-
- pLoggedInPort = pLoggedInPort->pNextPort; // try next port
- }
+ if (target_id_valid) {
+ // check Linux Scsi Cmnd for channel/target Nexus match
+ // (all luns are accessed through matching "pLoggedInPort")
+ if ((pLoggedInPort->ScsiNexus.target == Cmnd->target)
+ && (pLoggedInPort->ScsiNexus.channel == Cmnd->channel)) {
+ // For "passthru" modes, the IOCTL caller is responsible
+ // for setting the FCP-LUN addressing
+ if (!Cmnd->SCp.sent_command) // NOT passthru?
+ {
+
+ // set the FCP-LUN addressing type
+ Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;
+
+ // set the Device Type we got from the snooped INQUIRY string
+ Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
+
+ // handle LUN masking; if not "default" (illegal) lun value,
+ // the use it. These lun values are set by a successful
+ // Report Luns command
+ if (pLoggedInPort->ScsiNexus.LunMasking == 1) {
+ // we KNOW all the valid LUNs... 0xFF is invalid!
+ if (Cmnd->lun > sizeof(pLoggedInPort->ScsiNexus.lun)){
+ // printk("cpqfcTS FATAL: Invalid LUN index !!!!\n ");
+ return NULL;
+ }
+ Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
+ if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
+ return NULL;
+ // printk("xlating lun %d to 0x%02x\n", Cmnd->lun,
+ // pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
+ } else
+ Cmnd->SCp.have_data_in = Cmnd->lun; // Linux & target luns match
+ }
+ break; // found it!
+ }
+ }
- return pLoggedInPort;
-}
+ if (port_id_valid) // look for alpa first
+ {
+ if (pLoggedInPort->port_id == port_id)
+ break; // found it!
+ }
+ if (wwn_valid) // look for wwn second
+ {
+ if (!memcmp(&pLoggedInPort->u.ucWWN[0], &wwn[0], 8)) {
+ // all 8 bytes of WWN match
+ break; // found it!
+ }
+ }
+ pLoggedInPort = pLoggedInPort->pNextPort; // try next port
+ }
+ return pLoggedInPort;
+}
//
// We need to examine the SEST table and re-validate
// any open Exchanges for this LoggedInPort
// To make Tachyon pay attention, Freeze FCP assists,
// set VAL bits, Unfreeze FCP assists
-static void RevalidateSEST( struct Scsi_Host *HostAdapter,
- PFC_LOGGEDIN_PORT pLoggedInPort)
+static void RevalidateSEST(struct Scsi_Host *shpnt, PFC_LOGGEDIN_PORT pLoggedInPort)
{
- CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- ULONG x_ID;
- BOOLEAN TachFroze = FALSE;
-
-
- // re-validate any SEST exchanges that are permitted
- // to survive the link down (e.g., good PDISC performed)
- for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
- {
-
- // If the SEST entry port_id matches the pLoggedInPort,
- // we need to re-validate
- if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
- ||
- (Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
- {
-
- if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF) // (24-bit port ID)
- == pLoggedInPort->port_id)
- {
-// printk(" re-val xID %Xh ", x_ID);
- if( !TachFroze ) // freeze if not already frozen
- TachFroze |= FreezeTach( cpqfcHBAdata);
- fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
- }
- }
- }
-
- if( TachFroze)
- {
- fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
- }
-}
+ CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+ PTACHYON fcChip = &dev->fcChip;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ u32 x_ID;
+ u8 TachFroze = 0;
+
+
+ // re-validate any SEST exchanges that are permitted
+ // to survive the link down (e.g., good PDISC performed)
+ for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+
+ // If the SEST entry port_id matches the pLoggedInPort,
+ // we need to re-validate
+ if ((Exchanges->fcExchange[x_ID].type == SCSI_IRE)
+ || (Exchanges->fcExchange[x_ID].type == SCSI_IWE)) {
+ if ((Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) == pLoggedInPort->port_id) // (24-bit port ID)
+ {
+// printk(" re-val xID %Xh ", x_ID);
+ if (!TachFroze) // freeze if not already frozen
+ TachFroze |= FreezeTach(dev);
+ fcChip->SEST->u[x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
+ }
+ }
+ }
+ if (TachFroze) {
+ fcChip->UnFreezeTachyon(fcChip, 2); // both ERQ and FCP assists
+ }
+}
// Complete an Linux Cmnds that we Queued because
// our FC link was down (cause immediate retry)
-static void UnblockScsiDevice( struct Scsi_Host *HostAdapter,
- PFC_LOGGEDIN_PORT pLoggedInPort)
+static void UnblockScsiDevice(struct Scsi_Host *shpnt, PFC_LOGGEDIN_PORT pLoggedInPort)
{
-// Scsi_Device *sdev = HostAdapter->host_queue;
- CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
- Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
- Scsi_Cmnd *Cmnd;
- int indx;
-
-
-
- // if the device was previously "blocked", make sure
- // we unblock it so Linux SCSI will resume
-
- pLoggedInPort->device_blocked = FALSE; // clear our flag
-
- // check the Link Down command ptr buffer;
- // we can complete now causing immediate retry
- for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
- {
- if( *SCptr != NULL ) // scsi command to complete?
- {
+// Scsi_Device *sdev = shpnt->host_queue;
+ CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+ Scsi_Cmnd **SCptr = &dev->LinkDnCmnd[0];
+ Scsi_Cmnd *Cmnd;
+ int indx;
+
+ // if the device was previously "blocked", make sure
+ // we unblock it so Linux SCSI will resume
+
+ pLoggedInPort->device_blocked = 0; // clear our flag
+
+ // check the Link Down command ptr buffer;
+ // we can complete now causing immediate retry
+ for (indx = 0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++) {
+ if (*SCptr != NULL) // scsi command to complete?
+ {
#ifdef DUMMYCMND_DBG
- printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
+ printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr, indx);
#endif
- Cmnd = *SCptr;
-
+ Cmnd = *SCptr;
- // Are there any Q'd commands for this target?
- if( (Cmnd->target == pLoggedInPort->ScsiNexus.target)
- &&
- (Cmnd->channel == pLoggedInPort->ScsiNexus.channel) )
- {
- Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
- if( Cmnd->scsi_done == NULL)
- {
- printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
- pLoggedInPort->port_id);
- Cmnd->SCp.sent_command = 0;
+ // Are there any Q'd commands for this target?
+ if ((Cmnd->target == pLoggedInPort->ScsiNexus.target)
+ && (Cmnd->channel == pLoggedInPort->ScsiNexus.channel)) {
+ Cmnd->result = (DID_SOFT_ERROR << 16); // force retry
+ if (Cmnd->scsi_done == NULL) {
+ printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n", pLoggedInPort->port_id);
+ Cmnd->SCp.sent_command = 0;
+ } else
+ call_scsi_done(Cmnd);
+ *SCptr = NULL; // free this slot for next use
+ }
+ }
}
- else
- call_scsi_done(Cmnd);
- *SCptr = NULL; // free this slot for next use
- }
- }
- }
}
-
+
//#define WWN_DBG 1
-static void SetLoginFields(
- PFC_LOGGEDIN_PORT pLoggedInPort,
- TachFCHDR_GCMND* fchs,
- BOOLEAN PDisc,
- BOOLEAN Originator)
-{
- LOGIN_PAYLOAD logi; // FC-PH Port Login
- PRLI_REQUEST prli; // copy for BIG ENDIAN switch
- int i;
+static void SetLoginFields(PFC_LOGGEDIN_PORT pLoggedInPort, TachFCHDR_GCMND * fchs, u8 PDisc, u8 Originator)
+{
+ LOGIN_PAYLOAD logi; // FC-PH Port Login
+ PRLI_REQUEST prli; // copy for BIG ENDIAN switch
+ int i;
#ifdef WWN_DBG
- ULONG ulBuff;
+ u32 ulBuff;
#endif
- BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
+ BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
- pLoggedInPort->Originator = Originator;
- pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
-
- switch( fchs->pl[0] & 0xffff )
- {
- case 0x00000002: // PLOGI or PDISC ACCept?
- if( PDisc ) // PDISC accept
- goto PDISC_case;
-
- case 0x00000003: // ELS_PLOGI or ELS_PLOGI_ACC
-
- // Login BB_credit typically 0 for Tachyons
- pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
-
- // e.g. 128, 256, 1024, 2048 per FC-PH spec
- // We have to use this when setting up SEST Writes,
- // since that determines frame size we send.
- pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
- pLoggedInPort->plogi = TRUE;
- pLoggedInPort->pdisc = FALSE;
- pLoggedInPort->prli = FALSE; // ELS_PLOGI resets
- pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets
- pLoggedInPort->logo = FALSE; // ELS_PLOGI resets
- pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
- pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
-
- // was this PLOGI to a Fabric?
- if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
- pLoggedInPort->flogi = TRUE;
+ pLoggedInPort->Originator = Originator;
+ pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
+
+ switch (fchs->pl[0] & 0xffff) {
+ case 0x00000002: // PLOGI or PDISC ACCept?
+ if (PDisc) // PDISC accept
+ goto PDISC_case;
+
+ case 0x00000003: // ELS_PLOGI or ELS_PLOGI_ACC
+
+ // Login BB_credit typically 0 for Tachyons
+ pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
+
+ // e.g. 128, 256, 1024, 2048 per FC-PH spec
+ // We have to use this when setting up SEST Writes,
+ // since that determines frame size we send.
+ pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
+ pLoggedInPort->plogi = 1;
+ pLoggedInPort->pdisc = 0;
+ pLoggedInPort->prli = 0; // ELS_PLOGI resets
+ pLoggedInPort->flogi = 0; // ELS_PLOGI resets
+ pLoggedInPort->logo = 0; // ELS_PLOGI resets
+ pLoggedInPort->LOGO_counter = 0; // ELS_PLOGI resets
+ pLoggedInPort->LOGO_timer = 0; // ELS_PLOGI resets
+
+ // was this PLOGI to a Fabric?
+ if (pLoggedInPort->port_id == 0xFFFFFC) // well know address
+ pLoggedInPort->flogi = 1;
- for( i=0; i<8; i++) // copy the LOGIN port's WWN
- pLoggedInPort->u.ucWWN[i] = logi.port_name[i];
+ for (i = 0; i < 8; i++) // copy the LOGIN port's WWN
+ pLoggedInPort->u.ucWWN[i] = logi.port_name[i];
#ifdef WWN_DBG
- ulBuff = (ULONG)pLoggedInPort->u.liWWN;
- if( pLoggedInPort->Originator)
- printk("o");
- else
- printk("r");
- printk("PLOGI port_id %Xh, WWN %08X",
- pLoggedInPort->port_id, ulBuff);
+ ulBuff = (u32) pLoggedInPort->u.liWWN;
+ if (pLoggedInPort->Originator)
+ printk("o");
+ else
+ printk("r");
+ printk("PLOGI port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
- ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
- printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
+ ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+ printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
#endif
- break;
-
-
-
-
- case 0x00000005: // ELS_LOGO (logout)
-
+ break;
- pLoggedInPort->plogi = FALSE;
- pLoggedInPort->pdisc = FALSE;
- pLoggedInPort->prli = FALSE; // ELS_PLOGI resets
- pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets
- pLoggedInPort->logo = TRUE; // ELS_PLOGI resets
- pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
- pLoggedInPort->LOGO_timer = 0;
+ case 0x00000005: // ELS_LOGO (logout)
+ pLoggedInPort->plogi = 0;
+ pLoggedInPort->pdisc = 0;
+ pLoggedInPort->prli = 0; // ELS_PLOGI resets
+ pLoggedInPort->flogi = 0; // ELS_PLOGI resets
+ pLoggedInPort->logo = 1; // ELS_PLOGI resets
+ pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
+ pLoggedInPort->LOGO_timer = 0;
#ifdef WWN_DBG
- ulBuff = (ULONG)pLoggedInPort->u.liWWN;
- if( pLoggedInPort->Originator)
- printk("o");
- else
- printk("r");
- printk("LOGO port_id %Xh, WWN %08X",
- pLoggedInPort->port_id, ulBuff);
+ ulBuff = (u32) pLoggedInPort->u.liWWN;
+ if (pLoggedInPort->Originator)
+ printk("o");
+ else
+ printk("r");
+ printk("LOGO port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
- ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
- printk("%08Xh\n", ulBuff);
+ ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+ printk("%08Xh\n", ulBuff);
#endif
- break;
-
-
+ break;
-PDISC_case:
- case 0x00000050: // ELS_PDISC or ELS_PDISC_ACC
- pLoggedInPort->LOGO_timer = 0; // stop the time-out
-
- pLoggedInPort->prli = TRUE; // ready to accept FCP-SCSI I/O
-
+ PDISC_case:
+ case 0x00000050: // ELS_PDISC or ELS_PDISC_ACC
+ pLoggedInPort->LOGO_timer = 0; // stop the time-out
-
+ pLoggedInPort->prli = 1; // ready to accept FCP-SCSI I/O
#ifdef WWN_DBG
- ulBuff = (ULONG)pLoggedInPort->u.liWWN;
- if( pLoggedInPort->Originator)
- printk("o");
- else
- printk("r");
- printk("PDISC port_id %Xh, WWN %08X",
- pLoggedInPort->port_id, ulBuff);
+ ulBuff = (u32) pLoggedInPort->u.liWWN;
+ if (pLoggedInPort->Originator)
+ printk("o");
+ else
+ printk("r");
+ printk("PDISC port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
- ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
- printk("%08Xh\n", ulBuff);
+ ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+ printk("%08Xh\n", ulBuff);
#endif
+ break;
-
-
- break;
-
-
-
- case 0x1020L: // PRLI?
- case 0x1002L: // PRLI ACCept?
- BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
-
- pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
- pLoggedInPort->prli = TRUE; // PLOGI resets, PDISC doesn't
-
- pLoggedInPort->pdisc = TRUE; // expect to send (or receive) PDISC
- // next time
- pLoggedInPort->LOGO_timer = 0; // will be set next LinkDown
+ case 0x1020L: // PRLI?
+ case 0x1002L: // PRLI ACCept?
+ BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & prli, sizeof(prli));
+
+ pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
+ pLoggedInPort->prli = 1; // PLOGI resets, PDISC doesn't
+
+ pLoggedInPort->pdisc = 1; // expect to send (or receive) PDISC
+ // next time
+ pLoggedInPort->LOGO_timer = 0; // will be set next LinkDown
#ifdef WWN_DBG
- ulBuff = (ULONG)pLoggedInPort->u.liWWN;
- if( pLoggedInPort->Originator)
- printk("o");
- else
- printk("r");
- printk("PRLI port_id %Xh, WWN %08X",
- pLoggedInPort->port_id, ulBuff);
+ ulBuff = (u32) pLoggedInPort->u.liWWN;
+ if (pLoggedInPort->Originator)
+ printk("o");
+ else
+ printk("r");
+ printk("PRLI port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
- ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
- printk("%08Xh\n", ulBuff);
+ ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+ printk("%08Xh\n", ulBuff);
#endif
-
- break;
-
- }
-
- return;
+ break;
+ }
+ return;
}
-
-
-
-
-
-static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
+static void BuildLinkServicePayload(PTACHYON fcChip, u32 type, void *payload)
{
- LOGIN_PAYLOAD *plogi; // FC-PH Port Login
- LOGIN_PAYLOAD PlogiPayload; // copy for BIG ENDIAN switch
- PRLI_REQUEST *prli; // FCP-SCSI Process Login
- PRLI_REQUEST PrliPayload; // copy for BIG ENDIAN switch
- LOGOUT_PAYLOAD *logo;
- LOGOUT_PAYLOAD LogoutPayload;
-// PRLO_REQUEST *prlo;
-// PRLO_REQUEST PrloPayload;
- REJECT_MESSAGE rjt, *prjt;
-
- memset( &PlogiPayload, 0, sizeof( PlogiPayload));
- plogi = &PlogiPayload; // load into stack buffer,
- // then BIG-ENDIAN switch a copy to caller
-
-
- switch( type ) // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
- {
- case ELS_FDISC:
- case ELS_FLOGI:
- case ELS_PLOGI_ACC: // FC-PH PORT Login Accept
- case ELS_PLOGI: // FC-PH PORT Login
- case ELS_PDISC: // FC-PH2 Port Discovery - same payload as ELS_PLOGI
- plogi->login_cmd = LS_PLOGI;
- if( type == ELS_PDISC)
- plogi->login_cmd = LS_PDISC;
- else if( type == ELS_PLOGI_ACC )
- plogi->login_cmd = LS_ACC;
-
- plogi->cmn_services.bb_credit = 0x00;
- plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
- plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
- plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
- plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
- RANDOM_RELATIVE_OFFSET;
-
- // fill in with World Wide Name based Port Name - 8 UCHARs
- // get from Tach registers WWN hi & lo
- LoadWWN( fcChip, plogi->port_name, 0);
- // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
- // get from Tach registers WWN hi & lo
- LoadWWN( fcChip, plogi->node_name, 1);
-
- // For Seagate Drives.
- //
- plogi->cmn_services.common_features |= 0x800;
- plogi->cmn_services.rel_offset = 0xFE;
- plogi->cmn_services.concurrent_seq = 1;
- plogi->class1.service_options = 0x00;
- plogi->class2.service_options = 0x00;
- plogi->class3.service_options = CLASS_VALID;
- plogi->class3.initiator_control = 0x00;
- plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
- plogi->class3.recipient_control =
- ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
- plogi->class3.concurrent_sequences = 1;
- plogi->class3.open_sequences = 1;
- plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
- plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
- plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0';
- plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0';
-
-
- // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
- if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
- {
- if( type == ELS_FLOGI )
- plogi->login_cmd = LS_FLOGI;
- else
- plogi->login_cmd = LS_FDISC;
-
- plogi->cmn_services.lowest_ver = 0x20;
- plogi->cmn_services.common_features = 0x0800;
- plogi->cmn_services.rel_offset = 0;
- plogi->cmn_services.concurrent_seq = 0;
-
- plogi->class3.service_options = 0x8800;
- plogi->class3.rx_data_size = 0;
- plogi->class3.recipient_control = 0;
- plogi->class3.concurrent_sequences = 0;
- plogi->class3.open_sequences = 0;
- }
-
- // copy back to caller's buff, w/ BIG ENDIAN swap
- BigEndianSwap( (UCHAR*)&PlogiPayload, payload, sizeof(PlogiPayload));
- break;
-
-
- case ELS_ACC: // generic Extended Link Service ACCept
- plogi->login_cmd = LS_ACC;
- // copy back to caller's buff, w/ BIG ENDIAN swap
- BigEndianSwap( (UCHAR*)&PlogiPayload, payload, 4);
- break;
-
-
-
- case ELS_SCR: // Fabric State Change Registration
- {
- SCR_PL scr; // state change registration
-
- memset( &scr, 0, sizeof(scr));
-
- scr.command = LS_SCR; // 0x62000000
- // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
- scr.function = 3; // 1 = Events detected by Fabric
- // 2 = N_Port detected registration
- // 3 = Full registration
-
- // copy back to caller's buff, w/ BIG ENDIAN swap
- BigEndianSwap( (UCHAR*)&scr, payload, sizeof(SCR_PL));
- }
-
- break;
-
-
- case FCS_NSR: // Fabric Name Service Request
- {
- NSR_PL nsr; // Name Server Req. payload
-
- memset( &nsr, 0, sizeof(NSR_PL));
-
- // see Brocade Fabric Programming Guide,
- // Rev 1.3, pg 4-44
- nsr.CT_Rev = 0x01000000;
- nsr.FCS_Type = 0xFC020000;
- nsr.Command_code = 0x01710000;
- nsr.FCP = 8;
-
- // copy back to caller's buff, w/ BIG ENDIAN swap
- BigEndianSwap( (UCHAR*)&nsr, payload, sizeof(NSR_PL));
- }
-
- break;
-
-
-
-
- case ELS_LOGO: // FC-PH PORT LogOut
- logo = &LogoutPayload; // load into stack buffer,
- // then BIG-ENDIAN switch a copy to caller
- logo->cmd = LS_LOGO;
- // load the 3 UCHARs of the node name
- // (if private loop, upper two UCHARs 0)
- logo->reserved = 0;
-
- logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
- logo->n_port_identifier[1] =
- (UCHAR)(fcChip->Registers.my_al_pa>>8);
- logo->n_port_identifier[2] =
- (UCHAR)(fcChip->Registers.my_al_pa>>16);
- // fill in with World Wide Name based Port Name - 8 UCHARs
- // get from Tach registers WWN hi & lo
- LoadWWN( fcChip, logo->port_name, 0);
-
- BigEndianSwap( (UCHAR*)&LogoutPayload,
- payload, sizeof(LogoutPayload) ); // 16 UCHAR struct
- break;
-
-
- case ELS_LOGO_ACC: // Logout Accept (FH-PH pg 149, table 74)
- logo = &LogoutPayload; // load into stack buffer,
- // then BIG-ENDIAN switch a copy to caller
- logo->cmd = LS_ACC;
- BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 ); // 4 UCHAR cmnd
- break;
-
-
- case ELS_RJT: // ELS_RJT link service reject (FH-PH pg 155)
-
- prjt = (REJECT_MESSAGE*)payload; // pick up passed data
- rjt.command_code = ELS_RJT;
- // reverse fields, because of Swap that follows...
- rjt.vendor = prjt->reserved; // vendor specific
- rjt.explain = prjt->reason; //
- rjt.reason = prjt->explain; //
- rjt.reserved = prjt->vendor; //
- // BIG-ENDIAN switch a copy to caller
- BigEndianSwap( (UCHAR*)&rjt, payload, 8 ); // 8 UCHAR cmnd
- break;
+ LOGIN_PAYLOAD *plogi; // FC-PH Port Login
+ LOGIN_PAYLOAD PlogiPayload; // copy for BIG ENDIAN switch
+ PRLI_REQUEST *prli; // FCP-SCSI Process Login
+ PRLI_REQUEST PrliPayload; // copy for BIG ENDIAN switch
+ LOGOUT_PAYLOAD *logo;
+ LOGOUT_PAYLOAD LogoutPayload;
+// PRLO_REQUEST *prlo;
+// PRLO_REQUEST PrloPayload;
+ REJECT_MESSAGE rjt, *prjt;
+
+ memset(&PlogiPayload, 0, sizeof(PlogiPayload));
+ plogi = &PlogiPayload; // load into stack buffer,
+ // then BIG-ENDIAN switch a copy to caller
+ switch (type) // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
+ {
+ case ELS_FDISC:
+ case ELS_FLOGI:
+ case ELS_PLOGI_ACC: // FC-PH PORT Login Accept
+ case ELS_PLOGI: // FC-PH PORT Login
+ case ELS_PDISC: // FC-PH2 Port Discovery - same payload as ELS_PLOGI
+ plogi->login_cmd = LS_PLOGI;
+ if (type == ELS_PDISC)
+ plogi->login_cmd = LS_PDISC;
+ else if (type == ELS_PLOGI_ACC)
+ plogi->login_cmd = LS_ACC;
+
+ plogi->cmn_services.bb_credit = 0x00;
+ plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
+ plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
+ plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
+ plogi->cmn_services.common_features = CONTINUOSLY_INCREASING | RANDOM_RELATIVE_OFFSET;
+
+ // fill in with World Wide Name based Port Name - 8 u8s
+ // get from Tach registers WWN hi & lo
+ LoadWWN(fcChip, plogi->port_name, 0);
+ // fill in with World Wide Name based Node/Fabric Name - 8 u8s
+ // get from Tach registers WWN hi & lo
+ LoadWWN(fcChip, plogi->node_name, 1);
+
+ // For Seagate Drives.
+ //
+ plogi->cmn_services.common_features |= 0x800;
+ plogi->cmn_services.rel_offset = 0xFE;
+ plogi->cmn_services.concurrent_seq = 1;
+ plogi->class1.service_options = 0x00;
+ plogi->class2.service_options = 0x00;
+ plogi->class3.service_options = CLASS_VALID;
+ plogi->class3.initiator_control = 0x00;
+ plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
+ plogi->class3.recipient_control = ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
+ plogi->class3.concurrent_sequences = 1;
+ plogi->class3.open_sequences = 1;
+ plogi->vendor_id[0] = 'C';
+ plogi->vendor_id[1] = 'Q';
+ plogi->vendor_version[0] = 'C';
+ plogi->vendor_version[1] = 'Q';
+ plogi->vendor_version[2] = ' ';
+ plogi->vendor_version[3] = '0';
+ plogi->vendor_version[4] = '0';
+ plogi->vendor_version[5] = '0';
+
+ // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
+ if ((type == ELS_FLOGI) || (type == ELS_FDISC)) {
+ if (type == ELS_FLOGI)
+ plogi->login_cmd = LS_FLOGI;
+ else
+ plogi->login_cmd = LS_FDISC;
+
+ plogi->cmn_services.lowest_ver = 0x20;
+ plogi->cmn_services.common_features = 0x0800;
+ plogi->cmn_services.rel_offset = 0;
+ plogi->cmn_services.concurrent_seq = 0;
+
+ plogi->class3.service_options = 0x8800;
+ plogi->class3.rx_data_size = 0;
+ plogi->class3.recipient_control = 0;
+ plogi->class3.concurrent_sequences = 0;
+ plogi->class3.open_sequences = 0;
+ }
+ // copy back to caller's buff, w/ BIG ENDIAN swap
+ BigEndianSwap((u8 *) & PlogiPayload, payload, sizeof(PlogiPayload));
+ break;
+ case ELS_ACC: // generic Extended Link Service ACCept
+ plogi->login_cmd = LS_ACC;
+ // copy back to caller's buff, w/ BIG ENDIAN swap
+ BigEndianSwap((u8 *) & PlogiPayload, payload, 4);
+ break;
+ case ELS_SCR: // Fabric State Change Registration
+ {
+ SCR_PL scr; // state change registration
+
+ memset(&scr, 0, sizeof(scr));
+
+ scr.command = LS_SCR; // 0x62000000
+ // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
+ scr.function = 3; // 1 = Events detected by Fabric
+ // 2 = N_Port detected registration
+ // 3 = Full registration
+ // copy back to caller's buff, w/ BIG ENDIAN swap
+ BigEndianSwap((u8 *) & scr, payload, sizeof(SCR_PL));
+ }
+ break;
- case ELS_PRLI_ACC: // Process Login ACCept
- case ELS_PRLI: // Process Login
- case ELS_PRLO: // Process Logout
- memset( &PrliPayload, 0, sizeof( PrliPayload));
- prli = &PrliPayload; // load into stack buffer,
+ case FCS_NSR: // Fabric Name Service Request
+ {
+ NSR_PL nsr; // Name Server Req. payload
+
+ memset(&nsr, 0, sizeof(NSR_PL));
+
+ // see Brocade Fabric Programming Guide,
+ // Rev 1.3, pg 4-44
+ nsr.CT_Rev = 0x01000000;
+ nsr.FCS_Type = 0xFC020000;
+ nsr.Command_code = 0x01710000;
+ nsr.FCP = 8;
- if( type == ELS_PRLI )
- prli->cmd = 0x20; // Login
- else if( type == ELS_PRLO )
- prli->cmd = 0x21; // Logout
- else if( type == ELS_PRLI_ACC )
- {
- prli->cmd = 0x02; // Login ACCept
- prli->valid = REQUEST_EXECUTED;
- }
+ // copy back to caller's buff, w/ BIG ENDIAN swap
+ BigEndianSwap((u8 *) & nsr, payload, sizeof(NSR_PL));
+ }
+ break;
+ case ELS_LOGO: // FC-PH PORT LogOut
+ logo = &LogoutPayload; // load into stack buffer,
+ // then BIG-ENDIAN switch a copy to caller
+ logo->cmd = LS_LOGO;
+ // load the 3 u8s of the node name
+ // (if private loop, upper two u8s 0)
+ logo->reserved = 0;
+
+ logo->n_port_identifier[0] = (u8) (fcChip->Registers.my_al_pa);
+ logo->n_port_identifier[1] = (u8) (fcChip->Registers.my_al_pa >> 8);
+ logo->n_port_identifier[2] = (u8) (fcChip->Registers.my_al_pa >> 16);
+ // fill in with World Wide Name based Port Name - 8 u8s
+ // get from Tach registers WWN hi & lo
+ LoadWWN(fcChip, logo->port_name, 0);
- prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
- prli->fcp_info = READ_XFER_RDY;
- prli->page_length = 0x10;
- prli->payload_length = 20;
- // Can be initiator AND target
+ BigEndianSwap((u8 *) & LogoutPayload, payload, sizeof(LogoutPayload)); // 16 u8 struct
+ break;
- if( fcChip->Options.initiator )
- prli->fcp_info |= INITIATOR_FUNCTION;
- if( fcChip->Options.target )
- prli->fcp_info |= TARGET_FUNCTION;
+ case ELS_LOGO_ACC: // Logout Accept (FH-PH pg 149, table 74)
+ logo = &LogoutPayload; // load into stack buffer,
+ // then BIG-ENDIAN switch a copy to caller
+ logo->cmd = LS_ACC;
+ BigEndianSwap((u8 *) & LogoutPayload, payload, 4); // 4 u8 cmnd
+ break;
- BigEndianSwap( (UCHAR*)&PrliPayload, payload, prli->payload_length);
- break;
+ case ELS_RJT: // ELS_RJT link service reject (FH-PH pg 155)
+ prjt = (REJECT_MESSAGE *) payload; // pick up passed data
+ rjt.command_code = ELS_RJT;
+ // reverse fields, because of Swap that follows...
+ rjt.vendor = prjt->reserved; // vendor specific
+ rjt.explain = prjt->reason; //
+ rjt.reason = prjt->explain; //
+ rjt.reserved = prjt->vendor; //
+ // BIG-ENDIAN switch a copy to caller
+ BigEndianSwap((u8 *) & rjt, payload, 8); // 8 u8 cmnd
+ break;
+ case ELS_PRLI_ACC: // Process Login ACCept
+ case ELS_PRLI: // Process Login
+ case ELS_PRLO: // Process Logout
+ memset(&PrliPayload, 0, sizeof(PrliPayload));
+ prli = &PrliPayload; // load into stack buffer,
+
+ if (type == ELS_PRLI)
+ prli->cmd = 0x20; // Login
+ else if (type == ELS_PRLO)
+ prli->cmd = 0x21; // Logout
+ else if (type == ELS_PRLI_ACC) {
+ prli->cmd = 0x02; // Login ACCept
+ prli->valid = REQUEST_EXECUTED;
+ }
+ prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
+ prli->fcp_info = READ_XFER_RDY;
+ prli->page_length = 0x10;
+ prli->payload_length = 20;
+ // Can be initiator AND target
+
+ if (fcChip->Options.initiator)
+ prli->fcp_info |= INITIATOR_FUNCTION;
+ if (fcChip->Options.target)
+ prli->fcp_info |= TARGET_FUNCTION;
+ BigEndianSwap((u8 *) & PrliPayload, payload, prli->payload_length);
+ break;
- default: // no can do - programming error
- printk(" BuildLinkServicePayload unknown!\n");
- break;
- }
+ default: // no can do - programming error
+ printk(" BuildLinkServicePayload unknown!\n");
+ break;
+ }
}
-// loads 8 UCHARs for PORT name or NODE name base on
+// loads 8 u8s for PORT name or NODE name base on
// controller's WWN.
-void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
+void LoadWWN(PTACHYON fcChip, u8 * dest, u8 type)
{
- UCHAR* bPtr, i;
-
- switch( type )
- {
- case 0: // Port_Name
- bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
- for( i =0; i<4; i++)
- dest[i] = *bPtr++;
- bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
- for( i =4; i<8; i++)
- dest[i] = *bPtr++;
- break;
- case 1: // Node/Fabric _Name
- bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
- for( i =0; i<4; i++)
- dest[i] = *bPtr++;
- bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
- for( i =4; i<8; i++)
- dest[i] = *bPtr++;
- break;
- }
-
-}
+ u8 *bPtr, i;
+ switch (type) {
+ case 0: // Port_Name
+ bPtr = (u8 *) & fcChip->Registers.wwn_hi;
+ for (i = 0; i < 4; i++)
+ dest[i] = *bPtr++;
+ bPtr = (u8 *) & fcChip->Registers.wwn_lo;
+ for (i = 4; i < 8; i++)
+ dest[i] = *bPtr++;
+ break;
+ case 1: // Node/Fabric _Name
+ bPtr = (u8 *) & fcChip->Registers.wwn_hi;
+ for (i = 0; i < 4; i++)
+ dest[i] = *bPtr++;
+ bPtr = (u8 *) & fcChip->Registers.wwn_lo;
+ for (i = 4; i < 8; i++)
+ dest[i] = *bPtr++;
+ break;
+ }
+}
// We check the Port Login payload for required values. Note that
// ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
+int verify_PLOGI(PTACHYON fcChip, TachFCHDR_GCMND * fchs, u32 * reject_explain)
+{
+ LOGIN_PAYLOAD login;
-int verify_PLOGI( PTACHYON fcChip,
- TachFCHDR_GCMND* fchs,
- ULONG* reject_explain)
-{
- LOGIN_PAYLOAD login;
-
- // source, dest, len (should be mult. of 4)
- BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login, sizeof(login));
-
- // check FC version
- // if other port's highest supported version
- // is less than our lowest, and
- // if other port's lowest
- if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
- login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
- {
- *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
- return LOGICAL_ERROR;
- }
-
- // Receive Data Field Size must be >=128
- // per FC-PH
- if (login.cmn_services.bb_rx_size < 128)
- {
- *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
- return LOGICAL_ERROR;
- }
+ // source, dest, len (should be mult. of 4)
+ BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & login, sizeof(login));
- // Only check Class 3 params
- if( login.class3.service_options & CLASS_VALID)
- {
- if (login.class3.rx_data_size < 128)
- {
- *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
- return LOGICAL_ERROR;
- }
- if( login.class3.initiator_control & XID_REQUIRED)
- {
- *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
- return LOGICAL_ERROR;
- }
- }
- return 0; // success
+ // check FC version
+ // if other port's highest supported version
+ // is less than our lowest, and
+ // if other port's lowest
+ if (login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver || login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver) {
+ *reject_explain = LS_RJT_REASON(LOGICAL_ERROR, OPTIONS_ERROR);
+ return LOGICAL_ERROR;
+ }
+ // Receive Data Field Size must be >=128
+ // per FC-PH
+ if (login.cmn_services.bb_rx_size < 128) {
+ *reject_explain = LS_RJT_REASON(LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
+ return LOGICAL_ERROR;
+ }
+ // Only check Class 3 params
+ if (login.class3.service_options & CLASS_VALID) {
+ if (login.class3.rx_data_size < 128) {
+ *reject_explain = LS_RJT_REASON(LOGICAL_ERROR, INVALID_CSP);
+ return LOGICAL_ERROR;
+ }
+ if (login.class3.initiator_control & XID_REQUIRED) {
+ *reject_explain = LS_RJT_REASON(LOGICAL_ERROR, INITIATOR_CTL_ERROR);
+ return LOGICAL_ERROR;
+ }
+ }
+ return 0; // success
}
-
-
-
-int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
+int verify_PRLI(TachFCHDR_GCMND * fchs, u32 * reject_explain)
{
- PRLI_REQUEST prli; // buffer for BIG ENDIAN
+ PRLI_REQUEST prli; // buffer for BIG ENDIAN
- // source, dest, len (should be mult. of 4)
- BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
+ // source, dest, len (should be mult. of 4)
+ BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & prli, sizeof(prli));
- if( prli.fcp_info == 0 ) // i.e., not target or initiator?
- {
- *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
- return LOGICAL_ERROR;
- }
+ if (prli.fcp_info == 0) // i.e., not target or initiator?
+ {
+ *reject_explain = LS_RJT_REASON(LOGICAL_ERROR, OPTIONS_ERROR);
+ return LOGICAL_ERROR;
+ }
- return 0; // success
+ return 0; // success
}
-
-// SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
+// SWAP u8s as required by Fibre Channel (i.e. BIG ENDIAN)
// INPUTS:
-// source - ptr to LITTLE ENDIAN ULONGS
-// cnt - number of UCHARs to switch (should be mult. of ULONG)
+// source - ptr to LITTLE ENDIAN u32S
+// cnt - number of u8s to switch (should be mult. of u32)
// OUTPUTS:
// dest - ptr to BIG ENDIAN copy
// RETURN:
// none
//
-void BigEndianSwap( UCHAR *source, UCHAR *dest, USHORT cnt)
+void BigEndianSwap(u8 * source, u8 * dest, u16 cnt)
{
- int i,j;
+ int i, j;
- source+=3; // start at MSB of 1st ULONG
- for( j=0; j < cnt; j+=4, source+=4, dest+=4) // every ULONG
- {
- for( i=0; i<4; i++) // every UCHAR in ULONG
- *(dest+i) = *(source-i);
- }
+ source += 3; // start at MSB of 1st u32
+ for (j = 0; j < cnt; j += 4, source += 4, dest += 4) // every u32
+ {
+ for (i = 0; i < 4; i++) // every u8 in u32
+ *(dest + i) = *(source - i);
+ }
}
-
-
-
// Build FC Exchanges............
-static void buildFCPstatus(
- PTACHYON fcChip,
- ULONG ExchangeID);
-
-static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
-
-static ULONG build_SEST_sgList(
- struct pci_dev *pcidev,
- ULONG *SESTalPairStart,
- Scsi_Cmnd *Cmnd,
- ULONG *sgPairs,
- PSGPAGES *sgPages_head // link list of TL Ext. S/G pages from O/S Pool
-);
-
-static int build_FCP_payload( Scsi_Cmnd *Cmnd,
- UCHAR* payload, ULONG type, ULONG fcp_dl );
-
+static void buildFCPstatus(PTACHYON fcChip, u32 ExchangeID);
+static s32 FindFreeExchange(PTACHYON fcChip, u32 type);
+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
+static int build_FCP_payload(Scsi_Cmnd * Cmnd, u8 * payload, u32 type, u32 fcp_dl);
/*
IRB
@@ -4118,7 +3306,7 @@
// SEST entry, and several frame headers and data buffers all
// logically linked together.
// Inputs:
-// cpqfcHBAdata - controller struct
+// dev - controller struct
// type - PLOGI, SCSI_IWE, etc.
// InFCHS - Incoming Tachlite FCHS which prompted this exchange
// (only s_id set if we are originating)
@@ -4143,990 +3331,807 @@
// return success
//sbuildex
-ULONG cpqfcTSBuildExchange(
- CPQFCHBA *cpqfcHBAdata,
- ULONG type, // e.g. PLOGI
- TachFCHDR_GCMND* InFCHS, // incoming FCHS
- void *Data, // the CDB, scatter/gather, etc.
- LONG *fcExchangeIndex ) // points to allocated exchange,
-{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- ULONG ulStatus = 0; // assume OK
- USHORT ox_ID, rx_ID=0xFFFF;
- ULONG SfsLen=0L;
- TachLiteIRB* pIRB;
- IRBflags IRB_flags;
- UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
- TachFCHDR_GCMND* CMDfchs;
- TachFCHDR* dataHDR; // 32 byte HEADER ONLY FCP-DATA buffer
- TachFCHDR_RSP* rspHDR; // 32 byte header + RSP payload
- Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data; // Linux Scsi CDB, S/G, ...
- TachLiteIWE* pIWE;
- TachLiteIRE* pIRE;
- TachLiteTWE* pTWE;
- TachLiteTRE* pTRE;
- ULONG fcp_dl; // total byte length of DATA transferred
- ULONG fl; // frame length (FC frame size, 128, 256, 512, 1024)
- ULONG sgPairs; // number of valid scatter/gather pairs
- int FCP_SCSI_command;
- BA_ACC_PAYLOAD *ba_acc;
- BA_RJT_PAYLOAD *ba_rjt;
-
- // check passed ARGS
- if( !fcChip->ERQ ) // NULL ptr means uninitialized Tachlite chip
- return INVALID_ARGS;
-
-
- if( type == SCSI_IRE ||
- type == SCSI_TRE ||
- type == SCSI_IWE ||
- type == SCSI_TWE)
- FCP_SCSI_command = 1;
-
- else
- FCP_SCSI_command = 0;
-
-
- // for commands that pass payload data (e.g. SCSI write)
- // examine command struct - verify that the
- // length of s/g buffers is adequate for total payload
- // length (end of list is NULL address)
-
- if( FCP_SCSI_command )
- {
- if( Data ) // must have data descriptor (S/G list -- at least
- // one address with at least 1 byte of data)
- {
- // something to do (later)?
- }
-
- else
- return INVALID_ARGS; // invalid DATA ptr
- }
-
-
-
- // we can build an Exchange for later Queuing (on the TL chip)
- // if an empty slot is available in the DevExt for this controller
- // look for available Exchange slot...
-
- if( type != FCP_RESPONSE &&
- type != BLS_ABTS &&
- type != BLS_ABTS_ACC ) // already have Exchange slot!
- *fcExchangeIndex = FindFreeExchange( fcChip, type );
-
- if( *fcExchangeIndex != -1 ) // Exchange is available?
- {
- // assign tmp ptr (shorthand)
- CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs;
-
- if( Cmnd != NULL ) // (necessary for ABTS cases)
- {
- Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
- Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort =
- fcFindLoggedInPort( fcChip,
- Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
- 0, // DON'T search linked list for FC port id
- NULL, // DON'T search linked list for FC WWN
- NULL); // DON'T care about end of list
-
- }
-
-
- // Build the command frame header (& data) according
- // to command type
-
- // fields common for all SFS frame types
- CMDfchs->reserved = 0L; // must clear
- CMDfchs->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; LCr=0, no TS
-
- // get the destination port_id from incoming FCHS
- // (initialized before calling if we're Originator)
- // Frame goes to port it was from - the source_id
-
- CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
- CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+u32 cpqfcTSBuildExchange(CPQFCHBA * dev, u32 type, // e.g. PLOGI
+ TachFCHDR_GCMND * InFCHS, // incoming FCHS
+ void *Data, // the CDB, scatter/gather, etc.
+ s32 * fcExchangeIndex) // points to allocated exchange,
+{
+ PTACHYON fcChip = &dev->fcChip;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ u32 ulStatus = 0; // assume OK
+ u16 ox_ID, rx_ID = 0xFFFF;
+ u32 SfsLen = 0L;
+ TachLiteIRB *pIRB;
+ IRBflags IRB_flags;
+ u8 *pIRB_flags = (u8 *) & IRB_flags;
+ TachFCHDR_GCMND *CMDfchs;
+ TachFCHDR *dataHDR; // 32 byte HEADER ONLY FCP-DATA buffer
+ TachFCHDR_RSP *rspHDR; // 32 byte header + RSP payload
+ Scsi_Cmnd *Cmnd = (Scsi_Cmnd *) Data; // Linux Scsi CDB, S/G, ...
+ TachLiteIWE *pIWE;
+ TachLiteIRE *pIRE;
+ TachLiteTWE *pTWE;
+ TachLiteTRE *pTRE;
+ u32 fcp_dl; // total byte length of DATA transferred
+ u32 fl; // frame length (FC frame size, 128, 256, 512, 1024)
+ u32 sgPairs; // number of valid scatter/gather pairs
+ int FCP_SCSI_command;
+ BA_ACC_PAYLOAD *ba_acc;
+ BA_RJT_PAYLOAD *ba_rjt;
+
+ // check passed ARGS
+ if (!fcChip->ERQ) // NULL ptr means uninitialized Tachlite chip
+ return INVALID_ARGS;
-
- // now enter command-specific fields
- switch( type )
- {
-
- case BLS_NOP: // FC defined basic link service command NO-OP
- // ensure unique X_IDs! (use tracking function)
-
- *pIRB_flags = 0; // clear IRB flags
- IRB_flags.SFA = 1; // send SFS (not SEST index)
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- SfsLen += 32L; // add len to LSB (header only - no payload)
-
- // TYPE[31-24] 00 Basic Link Service
- // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
- CMDfchs->d_id |= 0x80000000L; // R_CTL = 80 for NOP (Basic Link Ser.)
- CMDfchs->f_ctl = 0x00310000L; // xchng originator, 1st seq,....
- CMDfchs->seq_cnt = 0x0L;
- CMDfchs->ox_rx_id = 0xFFFF; // RX_ID for now; OX_ID on start
- CMDfchs->ro = 0x0L; // relative offset (n/a)
- CMDfchs->pl[0] = 0xaabbccddL; // words 8-15 frame data payload (n/a)
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
- // (NOP should complete ~instantly)
- break;
-
-
-
-
- case BLS_ABTS_ACC: // Abort Sequence ACCept
- *pIRB_flags = 0; // clear IRB flags
- IRB_flags.SFA = 1; // send SFS (not SEST index)
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
-
- CMDfchs->d_id |= 0x84000000L; // R_CTL = 84 for BASIC ACCept
- // TYPE[31-24] 00 Basic Link Service
- // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
- CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
- // CMDfchs->seq_id & count might be set from DataHdr?
- CMDfchs->ro = 0x0L; // relative offset (n/a)
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
- // (Timeout in case of weird error)
-
- // now set the ACCept payload...
- ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
- memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
- // Since PLDA requires (only) entire Exchange aborts, we don't need
- // to worry about what the last sequence was.
-
- // We expect that a "target" task is accepting the abort, so we
- // can use the OX/RX ID pair
- ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
-
- // source, dest, #bytes
- BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
-
- ba_acc->low_seq_cnt = 0;
- ba_acc->high_seq_cnt = 0xFFFF;
-
-
- break;
-
-
- case BLS_ABTS_RJT: // Abort Sequence ACCept
- *pIRB_flags = 0; // clear IRB flags
- IRB_flags.SFA = 1; // send SFS (not SEST index)
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
-
- CMDfchs->d_id |= 0x85000000L; // R_CTL = 85 for BASIC ReJecT
- // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
- // TYPE[31-24] 00 Basic Link Service
- CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
- // CMDfchs->seq_id & count might be set from DataHdr?
- CMDfchs->ro = 0x0L; // relative offset (n/a)
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
- // (Timeout in case of weird error)
-
- CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
-
- // now set the ReJecT payload...
- ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
- memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
-
- // We expect that a "target" task couldn't find the Exhange in the
- // array of active exchanges, so we use a new LinkService X_ID.
- // See Reject payload description in FC-PH (Rev 4.3), pg. 140
- ba_rjt->reason_code = 0x09; // "unable to perform command request"
- ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
-
-
- break;
-
-
- case BLS_ABTS: // FC defined basic link service command ABTS
- // Abort Sequence
-
-
- *pIRB_flags = 0; // clear IRB flags
- IRB_flags.SFA = 1; // send SFS (not SEST index)
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- SfsLen += 32L; // add len to LSB (header only - no payload)
-
- // TYPE[31-24] 00 Basic Link Service
- // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
- CMDfchs->d_id |= 0x81000000L; // R_CTL = 81 for ABTS
- CMDfchs->f_ctl = 0x00110000L; // xchnge originator, last seq, xfer SI
- // CMDfchs->seq_id & count might be set from DataHdr?
- CMDfchs->ro = 0x0L; // relative offset (n/a)
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
- // (ABTS must timeout when responder is gone)
- break;
-
-
-
- case FCS_NSR: // Fabric Name Service Request
- Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
-
-
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
- // OX_ID, linked to Driver Transaction ID
- // (fix-up at Queing time)
- CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
- // OX_ID set at ERQueing time
- *pIRB_flags = 0; // clear IRB flags
- IRB_flags.SFA = 1; // send SFS (not SEST index)
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
-
- CMDfchs->d_id |= 0x02000000L; // R_CTL = 02 for -
- // Name Service Request: Unsolicited
- // TYPE[31-24] 01 Extended Link Service
- // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
- CMDfchs->f_ctl = 0x20210000L;
- // OX_ID will be fixed-up at Tachyon enqueing time
- CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
- CMDfchs->ro = 0x0L; // relative offset (n/a)
-
- BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-
-
-
-
-
- break;
-
-
-
-
- case ELS_PLOGI: // FC-PH extended link service command Port Login
- // (May, 2000)
- // NOTE! This special case facilitates SANMark testing. The SANMark
- // test script for initialization-timeout.fcal.SANMark-1.fc
- // "eats" the OPN() primitive without issuing an R_RDY, causing
- // Tachyon to report LST (loop state timeout), which causes a
- // LIP. To avoid this, simply send out the frame (i.e. assuming a
- // buffer credit of 1) without waiting for R_RDY. Many FC devices
- // (other than Tachyon) have been doing this for years. We don't
- // ever want to do this for non-Link Service frames unless the
- // other device really did report non-zero login BB credit (i.e.
- // in the PLOGI ACCept frame).
-// CMDfchs->sof_eof |= 0x00000400L; // LCr=1
-
- case ELS_FDISC: // Fabric Discovery (Login)
- case ELS_FLOGI: // Fabric Login
- case ELS_SCR: // Fabric State Change Registration
- case ELS_LOGO: // FC-PH extended link service command Port Logout
- case ELS_PDISC: // FC-PH extended link service cmnd Port Discovery
- case ELS_PRLI: // FC-PH extended link service cmnd Process Login
-
- Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
-
-
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
- // OX_ID, linked to Driver Transaction ID
- // (fix-up at Queing time)
- CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
- // OX_ID set at ERQueing time
- *pIRB_flags = 0; // clear IRB flags
- IRB_flags.SFA = 1; // send SFS (not SEST index)
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- if( type == ELS_LOGO )
- SfsLen += (32L + 16L); // add len (header & PLOGI payload)
- else if( type == ELS_PRLI )
- SfsLen += (32L + 20L); // add len (header & PRLI payload)
- else if( type == ELS_SCR )
- SfsLen += (32L + sizeof(SCR_PL)); // add len (header & SCR payload)
- else
- SfsLen += (32L + 116L); // add len (header & PLOGI payload)
-
- CMDfchs->d_id |= 0x22000000L; // R_CTL = 22 for -
- // Extended Link_Data: Unsolicited Control
- // TYPE[31-24] 01 Extended Link Service
- // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
- CMDfchs->f_ctl = 0x01210000L;
- // OX_ID will be fixed-up at Tachyon enqueing time
- CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
- CMDfchs->ro = 0x0L; // relative offset (n/a)
-
- BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
- break;
-
-
-
- case ELS_LOGO_ACC: // FC-PH extended link service logout accept
- case ELS_RJT: // extended link service reject (add reason)
- case ELS_ACC: // ext. link service generic accept
- case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
- case ELS_PRLI_ACC: // ext. link service process login accept
-
-
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
- // ensure unique X_IDs! (use tracking function)
- // OX_ID from initiator cmd
- ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16);
- rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
-
- *pIRB_flags = 0; // clear IRB flags
- IRB_flags.SFA = 1; // send SFS (not SEST index)
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- if( type == ELS_RJT )
- {
- SfsLen += (32L + 8L); // add len (header + payload)
-
- // ELS_RJT reason codes (utilize unused "reserved" field)
- CMDfchs->pl[0] = 1;
- CMDfchs->pl[1] = InFCHS->reserved;
-
- }
- else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC) )
- SfsLen += (32L + 4L); // add len (header + payload)
- else if( type == ELS_PLOGI_ACC )
- SfsLen += (32L + 116L); // add len (header + payload)
- else if( type == ELS_PRLI_ACC )
- SfsLen += (32L + 20L); // add len (header + payload)
-
- CMDfchs->d_id |= 0x23000000L; // R_CTL = 23 for -
- // Extended Link_Data: Control Reply
- // TYPE[31-24] 01 Extended Link Service
- // f_ctl[23:0] exchg responder, last seq, e_s, tsi
- CMDfchs->f_ctl = 0x01990000L;
- CMDfchs->seq_cnt = 0x0L;
- CMDfchs->ox_rx_id = 0L; // clear
- CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
- CMDfchs->ox_rx_id <<= 16; // shift them
-
- CMDfchs->ro = 0x0L; // relative offset (n/a)
-
- BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
- break;
-
-
- // Fibre Channel SCSI 'originator' sequences...
- // (originator means 'initiator' in FCP-SCSI)
-
- case SCSI_IWE: // TachLite Initiator Write Entry
- {
- PFC_LOGGEDIN_PORT pLoggedInPort =
- Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
-
- Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
-
- // first, build FCP_CMND
- // unique X_ID fix-ups in StartExchange
-
- *pIRB_flags = 0; // clear IRB flags
- IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
-
- // NOTE: unlike FC LinkService login frames, normal
- // SCSI commands are sent without outgoing verification
- IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- SfsLen += 64L; // add len to LSB (header & CMND payload)
-
- CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
-
- // TYPE[31-24] 8 for FCP SCSI
- // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
- // valid RO
- CMDfchs->f_ctl = 0x08210008L;
- CMDfchs->seq_cnt = 0x0L;
- CMDfchs->ox_rx_id = 0L; // clear for now (-or- in later)
- CMDfchs->ro = 0x0L; // relative offset (n/a)
-
- // now, fill out FCP-DATA header
- // (use buffer inside SEST object)
- dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
- dataHDR->reserved = 0L; // must clear
- dataHDR->sof_eof = 0x75002000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
- dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
- dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
- // TYPE[31-24] 8 for FCP SCSI
- // f_ctl[23:0] xfer S.I.| valid RO
- dataHDR->f_ctl = 0x08010008L;
- dataHDR->seq_cnt = 0x02000000L; // sequence ID: df_ctl : seqence count
- dataHDR->ox_rx_id = 0L; // clear; fix-up dataHDR fields later
- dataHDR->ro = 0x0L; // relative offset (n/a)
-
- // Now setup the SEST entry
- pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
-
- // fill out the IWE:
-
- // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
- pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
-
-
- // from login parameters with other port, what's the largest frame
- // we can send?
- if( pLoggedInPort == NULL)
- {
- ulStatus = INVALID_ARGS; // failed! give up
- break;
- }
- if( pLoggedInPort->rx_data_size >= 2048)
- fl = 0x00020000; // 2048 code (only support 1024!)
- else if( pLoggedInPort->rx_data_size >= 1024)
- fl = 0x00020000; // 1024 code
- else if( pLoggedInPort->rx_data_size >= 512)
- fl = 0x00010000; // 512 code
- else
- fl = 0; // 128 bytes -- should never happen
-
-
- pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
- pIWE->Hdr_Addr = fcChip->SEST->base +
- ((unsigned long)&fcChip->SEST->DataHDR[*fcExchangeIndex] -
- (unsigned long)fcChip->SEST);
-
- pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
- pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-
- memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0,
- sizeof( FCP_STATUS_RESPONSE) ); // clear out previous status
-
- pIWE->RSP_Addr = fcChip->SEST->base +
- ((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] -
- (unsigned long)fcChip->SEST);
-
- // Do we need local or extended gather list?
- // depends on size - we can handle 3 len/addr pairs
- // locally.
-
- fcp_dl = build_SEST_sgList(
- cpqfcHBAdata->PciDev,
- &pIWE->GLen1,
- Cmnd, // S/G list
- &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
- &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-
- if( !fcp_dl ) // error building S/G list?
- {
- ulStatus = MEMPOOL_FAIL;
- break; // give up
- }
-
- // Now that we know total data length in
- // the passed S/G buffer, set FCP CMND frame
- build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-
-
- if( sgPairs > 3 ) // need extended s/g list
- pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
- else // local data pointers (in SEST)
- pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
-
- // ULONG 5
- pIWE->Link = 0x0000ffffL; // Buff_Index | Link
-
- pIWE->RX_ID = 0x0L; // DWord 6: RX_ID set by target XFER_RDY
-
- // DWord 7
- pIWE->Data_Len = 0L; // TL enters rcv'd XFER_RDY BURST_LEN
- pIWE->Exp_RO = 0L; // DWord 8
- // DWord 9
- pIWE->Exp_Byte_Cnt = fcp_dl; // sum of gather buffers
- }
- break;
-
-
-
-
-
- case SCSI_IRE: // TachLite Initiator Read Entry
-
- if( Cmnd->timeout != 0)
- {
-// printk("Cmnd->timeout %d\n", Cmnd->timeout);
- // per Linux Scsi
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
- }
- else // use our best guess, based on FC & device
- {
-
- if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)
- {
- // turn off our timeouts (for now...)
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF;
- }
+ if (type == SCSI_IRE || type == SCSI_TRE || type == SCSI_IWE || type == SCSI_TWE)
+ FCP_SCSI_command = 1;
else
- {
- Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
- }
- }
-
-
- // first, build FCP_CMND
-
-
- *pIRB_flags = 0; // clear IRB flags
- IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
- // NOTE: unlike FC LinkService login frames,
- // normal SCSI commands are sent "open loop"
- IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- SfsLen += 64L; // add len to LSB (header & CMND payload)
-
- CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
-
- // TYPE[31-24] 8 for FCP SCSI
- // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
- // valid RO
- CMDfchs->f_ctl = 0x08210008L;
- CMDfchs->seq_cnt = 0x0L;
- // x_ID & data direction bit set later
- CMDfchs->ox_rx_id = 0xFFFF; // clear
- CMDfchs->ro = 0x0L; // relative offset (n/a)
-
-
-
- // Now setup the SEST entry
- pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
-
- // fill out the IRE:
- // VALid entry:Dir outbound:enable CM:enal INT:
- pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
-
- pIRE->reserved = 0L;
- pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
- pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-
- pIRE->RSP_Addr = fcChip->SEST->base +
- ((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] -
- (unsigned long)fcChip->SEST);
-
- // Do we need local or extended gather list?
- // depends on size - we can handle 3 len/addr pairs
- // locally.
-
- fcp_dl = build_SEST_sgList(
- cpqfcHBAdata->PciDev,
- &pIRE->SLen1,
- Cmnd, // SCSI command Data desc. with S/G list
- &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
- &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-
-
- if( !fcp_dl ) // error building S/G list?
- {
- // It is permissible to have a ZERO LENGTH Read command.
- // If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
- // to 0 and continue.
- if( Cmnd->request_bufflen == 0 )
- {
- fcp_dl = 0; // no FC DATA frames expected
+ FCP_SCSI_command = 0;
+ // for commands that pass payload data (e.g. SCSI write)
+ // examine command struct - verify that the
+ // length of s/g buffers is adequate for total payload
+ // length (end of list is NULL address)
+
+ if (FCP_SCSI_command) {
+ if (Data) // must have data descriptor (S/G list -- at least
+ // one address with at least 1 byte of data)
+ {
+ // something to do (later)?
+ }
+ else
+ return INVALID_ARGS; // invalid DATA ptr
}
- else
- {
- ulStatus = MEMPOOL_FAIL;
- break; // give up
- }
- }
-
- // now that we know the S/G length, build CMND payload
- build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-
- if( sgPairs > 3 ) // need extended s/g list
- pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
- else
- pIRE->Buff_Off = 0x80000000; // local data, no offset
-
- pIRE->Buff_Index = 0x0L; // DWord 5: Buff_Index | Reserved
-
- pIRE->Exp_RO = 0x0L; // DWord 6: Expected Rel. Offset
-
- pIRE->Byte_Count = 0; // DWord 7: filled in by TL on err
- pIRE->reserved_ = 0; // DWord 8: reserved
- // NOTE: 0 length READ is OK.
- pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
-
- break;
-
-
-
-
- // Fibre Channel SCSI 'responder' sequences...
- // (originator means 'target' in FCP-SCSI)
- case SCSI_TWE: // TachLite Target Write Entry
-
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
-
- // first, build FCP_CMND
-
- *pIRB_flags = 0; // clear IRB flags
- IRB_flags.SFA = 1; // send SFS (XFER_RDY)
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
-
- CMDfchs->d_id |= (0x05000000L); // R_CTL = 5 for XFER_RDY
-
- // TYPE[31-24] 8 for FCP SCSI
- // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
- // valid RO
- CMDfchs->f_ctl = 0x08810008L;
- CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
- // use originator (other port's) OX_ID
- CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // we want upper 16 bits
- CMDfchs->ro = 0x0L; // relative offset (n/a)
-
- // now, fill out FCP-RSP header
- // (use buffer inside SEST object)
-
- rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
- rspHDR->reserved = 0L; // must clear
- rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
- rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
- rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
- // TYPE[31-24] 8 for FCP SCSI
- // f_ctl[23:0] responder|last seq| xfer S.I.
- rspHDR->f_ctl = 0x08910000L;
- rspHDR->seq_cnt = 0x03000000; // sequence ID
- rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
- rspHDR->ro = 0x0L; // relative offset (n/a)
-
-
- // Now setup the SEST entry
-
- pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
-
- // fill out the TWE:
-
- // VALid entry:Dir outbound:enable CM:enal INT:
- pTWE->Seq_Accum = 0xC4000000L; // upper word flags
- pTWE->reserved = 0L;
- pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
- pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-
-
- // Do we need local or extended gather list?
- // depends on size - we can handle 3 len/addr pairs
- // locally.
-
- fcp_dl = build_SEST_sgList(
- cpqfcHBAdata->PciDev,
- &pTWE->SLen1,
- Cmnd, // S/G list
- &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
- &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-
-
- if( !fcp_dl ) // error building S/G list?
- {
- ulStatus = MEMPOOL_FAIL;
- break; // give up
- }
-
- // now that we know the S/G length, build CMND payload
- build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-
- if( sgPairs > 3 ) // need extended s/g list
- pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
- else
- pTWE->Buff_Off = 0x80000000; // local data, no offset
-
- pTWE->Buff_Index = 0; // Buff_Index | Link
- pTWE->Exp_RO = 0;
- pTWE->Byte_Count = 0; // filled in by TL on err
- pTWE->reserved_ = 0;
- pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
-
- break;
-
-
-
-
-
-
- case SCSI_TRE: // TachLite Target Read Entry
-
- // It doesn't make much sense for us to "time-out" a READ,
- // but we'll use it for design consistency and internal error recovery.
- Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
-
- // I/O request block settings...
- *pIRB_flags = 0; // clear IRB flags
- // check PRLI (process login) info
- // to see if Initiator Requires XFER_RDY
- // if not, don't send one!
- // { PRLI check...}
- IRB_flags.SFA = 0; // don't send XFER_RDY - start data
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
-
-
- // now, fill out FCP-DATA header
- // (use buffer inside SEST object)
- dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
-
- dataHDR->reserved = 0L; // must clear
- dataHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
- dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
- dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-
-
- // TYPE[31-24] 8 for FCP SCSI
- // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
- // valid RO
- dataHDR->f_ctl = 0x08810008L;
- dataHDR->seq_cnt = 0x01000000; // sequence ID (no XRDY)
- dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
- dataHDR->ro = 0x0L; // relative offset (n/a)
-
- // now, fill out FCP-RSP header
- // (use buffer inside SEST object)
- rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
-
- rspHDR->reserved = 0L; // must clear
- rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
- rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
- rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
- // TYPE[31-24] 8 for FCP SCSI
- // f_ctl[23:0] responder|last seq| xfer S.I.
- rspHDR->f_ctl = 0x08910000L;
- rspHDR->seq_cnt = 0x02000000; // sequence ID: df_ctl: sequence count
-
- rspHDR->ro = 0x0L; // relative offset (n/a)
-
-
- // Now setup the SEST entry
- pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
-
-
- // VALid entry:Dir outbound:enable CM:enal INT:
- pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
- pTRE->Hdr_Addr = // bus address of dataHDR;
- fcChip->SEST->base +
- ((unsigned long)&fcChip->SEST->DataHDR[ *fcExchangeIndex ] -
- (unsigned long)fcChip->SEST);
-
- pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
- pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
- pTRE->RSP_Addr = // bus address of rspHDR
- fcChip->SEST->base +
- ((unsigned long)&fcChip->SEST->RspHDR[ *fcExchangeIndex ] -
- (unsigned long)fcChip->SEST);
-
- // Do we need local or extended gather list?
- // depends on size - we can handle 3 len/addr pairs
- // locally.
-
- fcp_dl = build_SEST_sgList(
- cpqfcHBAdata->PciDev,
- &pTRE->GLen1,
- Cmnd, // S/G list
- &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
- &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-
-
- if( !fcp_dl ) // error building S/G list?
- {
- ulStatus = MEMPOOL_FAIL;
- break; // give up
- }
-
- // no payload or command to build -- READ doesn't need XRDY
-
-
- if( sgPairs > 3 ) // need extended s/g list
- pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
- else // local data pointers (in SEST)
- pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
-
- // ULONG 5
- pTRE->Buff_Index = 0L; // Buff_Index | reserved
- pTRE->reserved = 0x0L; // DWord 6
-
- // DWord 7: NOTE: zero length will
- // hang TachLite!
- pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
-
- pTRE->reserved_ = 0L; // DWord 8
- pTRE->reserved__ = 0L; // DWord 9
-
- break;
+ // we can build an Exchange for later Queuing (on the TL chip)
+ // if an empty slot is available in the DevExt for this controller
+ // look for available Exchange slot...
+ if (type != FCP_RESPONSE && type != BLS_ABTS && type != BLS_ABTS_ACC) // already have Exchange slot!
+ *fcExchangeIndex = FindFreeExchange(fcChip, type);
+ if (*fcExchangeIndex != -1) // Exchange is available?
+ {
+ // assign tmp ptr (shorthand)
+ CMDfchs = &Exchanges->fcExchange[*fcExchangeIndex].fchs;
+ if (Cmnd != NULL) // (necessary for ABTS cases)
+ {
+ Exchanges->fcExchange[*fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
+ Exchanges->fcExchange[*fcExchangeIndex].pLoggedInPort = fcFindLoggedInPort(fcChip, Exchanges->fcExchange[*fcExchangeIndex].Cmnd, // find Scsi Nexus
+ 0, // DON'T search linked list for FC port id
+ NULL, // DON'T search linked list for FC WWN
+ NULL); // DON'T care about end of list
+ }
+ // Build the command frame header (& data) according
+ // to command type
-
-
- case FCP_RESPONSE:
- // Target response frame: this sequence uses an OX/RX ID
- // pair from a completed SEST exchange. We built most
- // of the response frame when we created the TWE/TRE.
-
- *pIRB_flags = 0; // clear IRB flags
- IRB_flags.SFA = 1; // send SFS (RSP)
- SfsLen = *pIRB_flags;
-
- SfsLen <<= 24; // shift flags to MSB
- SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
-
-
- Exchanges->fcExchange[ *fcExchangeIndex].type =
- FCP_RESPONSE; // change Exchange type to "response" phase
-
- // take advantage of prior knowledge of OX/RX_ID pair from
- // previous XFER outbound frame (still in fchs of exchange)
- fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id =
- CMDfchs->ox_rx_id;
-
- // Check the status of the DATA phase of the exchange so we can report
- // status to the initiator
- buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
-
- memcpy(
- CMDfchs, // re-use same XFER fchs for Response frame
- &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
- sizeof( TachFCHDR_RSP ));
-
-
- break;
+ // fields common for all SFS frame types
+ CMDfchs->reserved = 0L; // must clear
+ CMDfchs->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; LCr=0, no TS
+
+ // get the destination port_id from incoming FCHS
+ // (initialized before calling if we're Originator)
+ // Frame goes to port it was from - the source_id
+
+ CMDfchs->d_id = InFCHS->s_id & 0xFFFFFF; // destination (add R_CTL later)
+ CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+
+ // now enter command-specific fields
+ switch (type) {
+ case BLS_NOP: // FC defined basic link service command NO-OP
+ // ensure unique X_IDs! (use tracking function)
+ *pIRB_flags = 0; // clear IRB flags
+ IRB_flags.SFA = 1; // send SFS (not SEST index)
+ SfsLen = *pIRB_flags;
+
+ SfsLen <<= 24; // shift flags to MSB
+ SfsLen += 32L; // add len to LSB (header only - no payload)
+
+ // TYPE[31-24] 00 Basic Link Service
+ // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+ CMDfchs->d_id |= 0x80000000L; // R_CTL = 80 for NOP (Basic Link Ser.)
+ CMDfchs->f_ctl = 0x00310000L; // xchng originator, 1st seq,....
+ CMDfchs->seq_cnt = 0x0L;
+ CMDfchs->ox_rx_id = 0xFFFF; // RX_ID for now; OX_ID on start
+ CMDfchs->ro = 0x0L; // relative offset (n/a)
+ CMDfchs->pl[0] = 0xaabbccddL; // words 8-15 frame data payload (n/a)
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 1; // seconds
+ // (NOP should complete ~instantly)
+ break;
+
+ case BLS_ABTS_ACC: // Abort Sequence ACCept
+ *pIRB_flags = 0; // clear IRB flags
+ IRB_flags.SFA = 1; // send SFS (not SEST index)
+ SfsLen = *pIRB_flags;
+
+ SfsLen <<= 24; // shift flags to MSB
+ SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
+
+ CMDfchs->d_id |= 0x84000000L; // R_CTL = 84 for BASIC ACCept
+ // TYPE[31-24] 00 Basic Link Service
+ // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+ CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
+ // CMDfchs->seq_id & count might be set from DataHdr?
+ CMDfchs->ro = 0x0L; // relative offset (n/a)
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 5; // seconds
+ // (Timeout in case of weird error)
+
+ // now set the ACCept payload...
+ ba_acc = (BA_ACC_PAYLOAD *) & CMDfchs->pl[0];
+ memset(ba_acc, 0, sizeof(BA_ACC_PAYLOAD));
+ // Since PLDA requires (only) entire Exchange aborts, we don't need
+ // to worry about what the last sequence was.
+
+ // We expect that a "target" task is accepting the abort, so we
+ // can use the OX/RX ID pair
+ ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
+
+ // source, dest, #bytes
+ BigEndianSwap((u8 *) & CMDfchs->ox_rx_id, (u8 *) & ba_acc->ox_rx_id, 4);
+
+ ba_acc->low_seq_cnt = 0;
+ ba_acc->high_seq_cnt = 0xFFFF;
+ break;
+
+ case BLS_ABTS_RJT: // Abort Sequence ACCept
+ *pIRB_flags = 0; // clear IRB flags
+ IRB_flags.SFA = 1; // send SFS (not SEST index)
+ SfsLen = *pIRB_flags;
+
+ SfsLen <<= 24; // shift flags to MSB
+ SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
+
+ CMDfchs->d_id |= 0x85000000L; // R_CTL = 85 for BASIC ReJecT
+ // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+ // TYPE[31-24] 00 Basic Link Service
+ CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
+ // CMDfchs->seq_id & count might be set from DataHdr?
+ CMDfchs->ro = 0x0L; // relative offset (n/a)
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 5; // seconds
+ // (Timeout in case of weird error)
+
+ CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
+
+ // now set the ReJecT payload...
+ ba_rjt = (BA_RJT_PAYLOAD *) & CMDfchs->pl[0];
+ memset(ba_rjt, 0, sizeof(BA_RJT_PAYLOAD));
+
+ // We expect that a "target" task couldn't find the Exhange in the
+ // array of active exchanges, so we use a new LinkService X_ID.
+ // See Reject payload description in FC-PH (Rev 4.3), pg. 140
+ ba_rjt->reason_code = 0x09; // "unable to perform command request"
+ ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
+ break;
+
+ case BLS_ABTS: // FC defined basic link service command ABTS
+ // Abort Sequence
+ *pIRB_flags = 0; // clear IRB flags
+ IRB_flags.SFA = 1; // send SFS (not SEST index)
+ SfsLen = *pIRB_flags;
+
+ SfsLen <<= 24; // shift flags to MSB
+ SfsLen += 32L; // add len to LSB (header only - no payload)
+
+ // TYPE[31-24] 00 Basic Link Service
+ // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+ CMDfchs->d_id |= 0x81000000L; // R_CTL = 81 for ABTS
+ CMDfchs->f_ctl = 0x00110000L; // xchnge originator, last seq, xfer SI
+ // CMDfchs->seq_id & count might be set from DataHdr?
+ CMDfchs->ro = 0x0L; // relative offset (n/a)
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2; // seconds
+ // (ABTS must timeout when responder is gone)
+ break;
+
+ case FCS_NSR: // Fabric Name Service Request
+ Exchanges->fcExchange[*fcExchangeIndex].reTries = 2;
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2; // seconds
+ // OX_ID, linked to Driver Transaction ID
+ // (fix-up at Queing time)
+ CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
+ // OX_ID set at ERQueing time
+ *pIRB_flags = 0; // clear IRB flags
+ IRB_flags.SFA = 1; // send SFS (not SEST index)
+ SfsLen = *pIRB_flags;
+ SfsLen <<= 24; // shift flags to MSB
+ SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
+ CMDfchs->d_id |= 0x02000000L; // R_CTL = 02 for -
+ // Name Service Request: Unsolicited
+ // TYPE[31-24] 01 Extended Link Service
+ // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+ CMDfchs->f_ctl = 0x20210000L;
+ // OX_ID will be fixed-up at Tachyon enqueing time
+ CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
+ CMDfchs->ro = 0x0L; // relative offset (n/a)
+ BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+ break;
+
+ case ELS_PLOGI: // FC-PH extended link service command Port Login
+ // (May, 2000)
+ // NOTE! This special case facilitates SANMark testing. The SANMark
+ // test script for initialization-timeout.fcal.SANMark-1.fc
+ // "eats" the OPN() primitive without issuing an R_RDY, causing
+ // Tachyon to report LST (loop state timeout), which causes a
+ // LIP. To avoid this, simply send out the frame (i.e. assuming a
+ // buffer credit of 1) without waiting for R_RDY. Many FC devices
+ // (other than Tachyon) have been doing this for years. We don't
+ // ever want to do this for non-Link Service frames unless the
+ // other device really did report non-zero login BB credit (i.e.
+ // in the PLOGI ACCept frame).
+// CMDfchs->sof_eof |= 0x00000400L; // LCr=1
+
+ case ELS_FDISC: // Fabric Discovery (Login)
+ case ELS_FLOGI: // Fabric Login
+ case ELS_SCR: // Fabric State Change Registration
+ case ELS_LOGO: // FC-PH extended link service command Port Logout
+ case ELS_PDISC: // FC-PH extended link service cmnd Port Discovery
+ case ELS_PRLI: // FC-PH extended link service cmnd Process Login
+ Exchanges->fcExchange[*fcExchangeIndex].reTries = 2;
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2; // seconds
+ // OX_ID, linked to Driver Transaction ID
+ // (fix-up at Queing time)
+ CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
+ // OX_ID set at ERQueing time
+ *pIRB_flags = 0; // clear IRB flags
+ IRB_flags.SFA = 1; // send SFS (not SEST index)
+ SfsLen = *pIRB_flags;
+ SfsLen <<= 24; // shift flags to MSB
+ if (type == ELS_LOGO)
+ SfsLen += (32L + 16L); // add len (header & PLOGI payload)
+ else if (type == ELS_PRLI)
+ SfsLen += (32L + 20L); // add len (header & PRLI payload)
+ else if (type == ELS_SCR)
+ SfsLen += (32L + sizeof(SCR_PL)); // add len (header & SCR payload)
+ else
+ SfsLen += (32L + 116L); // add len (header & PLOGI payload)
+
+ CMDfchs->d_id |= 0x22000000L; // R_CTL = 22 for -
+ // Extended Link_Data: Unsolicited Control
+ // TYPE[31-24] 01 Extended Link Service
+ // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+ CMDfchs->f_ctl = 0x01210000L;
+ // OX_ID will be fixed-up at Tachyon enqueing time
+ CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
+ CMDfchs->ro = 0x0L; // relative offset (n/a)
+
+ BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+ break;
+
+ case ELS_LOGO_ACC: // FC-PH extended link service logout accept
+ case ELS_RJT: // extended link service reject (add reason)
+ case ELS_ACC: // ext. link service generic accept
+ case ELS_PLOGI_ACC: // ext. link service login accept (PLOGI or PDISC)
+ case ELS_PRLI_ACC: // ext. link service process login accept
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 1; // assume done
+ // ensure unique X_IDs! (use tracking function)
+ // OX_ID from initiator cmd
+ ox_ID = (u16) (InFCHS->ox_rx_id >> 16);
+ rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
+
+ *pIRB_flags = 0; // clear IRB flags
+ IRB_flags.SFA = 1; // send SFS (not SEST index)
+ SfsLen = *pIRB_flags;
+
+ SfsLen <<= 24; // shift flags to MSB
+ if (type == ELS_RJT) {
+ SfsLen += (32L + 8L); // add len (header + payload)
+
+ // ELS_RJT reason codes (utilize unused "reserved" field)
+ CMDfchs->pl[0] = 1;
+ CMDfchs->pl[1] = InFCHS->reserved;
+
+ } else if ((type == ELS_LOGO_ACC) || (type == ELS_ACC))
+ SfsLen += (32L + 4L); // add len (header + payload)
+ else if (type == ELS_PLOGI_ACC)
+ SfsLen += (32L + 116L); // add len (header + payload)
+ else if (type == ELS_PRLI_ACC)
+ SfsLen += (32L + 20L); // add len (header + payload)
+
+ CMDfchs->d_id |= 0x23000000L; // R_CTL = 23 for -
+ // Extended Link_Data: Control Reply
+ // TYPE[31-24] 01 Extended Link Service
+ // f_ctl[23:0] exchg responder, last seq, e_s, tsi
+ CMDfchs->f_ctl = 0x01990000L;
+ CMDfchs->seq_cnt = 0x0L;
+ CMDfchs->ox_rx_id = 0L; // clear
+ CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
+ CMDfchs->ox_rx_id <<= 16; // shift them
+
+ CMDfchs->ro = 0x0L; // relative offset (n/a)
+
+ BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+ break;
+
+ // Fibre Channel SCSI 'originator' sequences...
+ // (originator means 'initiator' in FCP-SCSI)
+ case SCSI_IWE: // TachLite Initiator Write Entry
+ {
+ PFC_LOGGEDIN_PORT pLoggedInPort = Exchanges->fcExchange[*fcExchangeIndex].pLoggedInPort;
+
+ Exchanges->fcExchange[*fcExchangeIndex].reTries = 1;
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 7; // FC2 timeout
+
+ // first, build FCP_CMND
+ // unique X_ID fix-ups in StartExchange
+
+ *pIRB_flags = 0; // clear IRB flags
+ IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
+
+ // NOTE: unlike FC LinkService login frames, normal
+ // SCSI commands are sent without outgoing verification
+ IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
+ SfsLen = *pIRB_flags;
+
+ SfsLen <<= 24; // shift flags to MSB
+ SfsLen += 64L; // add len to LSB (header & CMND payload)
+
+ CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
+
+ // TYPE[31-24] 8 for FCP SCSI
+ // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+ // valid RO
+ CMDfchs->f_ctl = 0x08210008L;
+ CMDfchs->seq_cnt = 0x0L;
+ CMDfchs->ox_rx_id = 0L; // clear for now (-or- in later)
+ CMDfchs->ro = 0x0L; // relative offset (n/a)
+
+ // now, fill out FCP-DATA header
+ // (use buffer inside SEST object)
+ dataHDR = &fcChip->SEST->DataHDR[*fcExchangeIndex];
+ dataHDR->reserved = 0L; // must clear
+ dataHDR->sof_eof = 0x75002000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
+ dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
+ dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+ // TYPE[31-24] 8 for FCP SCSI
+ // f_ctl[23:0] xfer S.I.| valid RO
+ dataHDR->f_ctl = 0x08010008L;
+ dataHDR->seq_cnt = 0x02000000L; // sequence ID: df_ctl : seqence count
+ dataHDR->ox_rx_id = 0L; // clear; fix-up dataHDR fields later
+ dataHDR->ro = 0x0L; // relative offset (n/a)
+
+ // Now setup the SEST entry
+ pIWE = &fcChip->SEST->u[*fcExchangeIndex].IWE;
+
+ // fill out the IWE:
+
+ // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
+ pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
+
+
+ // from login parameters with other port, what's the largest frame
+ // we can send?
+ if (pLoggedInPort == NULL) {
+ ulStatus = INVALID_ARGS; // failed! give up
+ break;
+ }
+ if (pLoggedInPort->rx_data_size >= 2048)
+ fl = 0x00020000; // 2048 code (only support 1024!)
+ else if (pLoggedInPort->rx_data_size >= 1024)
+ fl = 0x00020000; // 1024 code
+ else if (pLoggedInPort->rx_data_size >= 512)
+ fl = 0x00010000; // 512 code
+ else
+ fl = 0; // 128 bytes -- should never happen
+
+
+ pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
+ pIWE->Hdr_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->DataHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+ pIWE->RSP_Len = sizeof(TachFCHDR_RSP); // hdr+data (recv'd RSP frame)
+ pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
+
+ memset(&fcChip->SEST->RspHDR[*fcExchangeIndex].pl, 0, sizeof(FCP_STATUS_RESPONSE)); // clear out previous status
+
+ pIWE->RSP_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+ // Do we need local or extended gather list?
+ // depends on size - we can handle 3 len/addr pairs
+ // locally.
+
+ fcp_dl = build_SEST_sgList(dev->PciDev, &pIWE->GLen1, Cmnd, // S/G list
+ &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
+ &fcChip->SEST->sgPages[*fcExchangeIndex]); // (for Freeing later)
+
+ if (!fcp_dl) // error building S/G list?
+ {
+ ulStatus = MEMPOOL_FAIL;
+ break; // give up
+ }
+ // Now that we know total data length in
+ // the passed S/G buffer, set FCP CMND frame
+ build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
+
+
+
+ if (sgPairs > 3) // need extended s/g list
+ pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
+ else // local data pointers (in SEST)
+ pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
+
+ // u32 5
+ pIWE->Link = 0x0000ffffL; // Buff_Index | Link
+
+ pIWE->RX_ID = 0x0L; // DWord 6: RX_ID set by target XFER_RDY
+
+ // DWord 7
+ pIWE->Data_Len = 0L; // TL enters rcv'd XFER_RDY BURST_LEN
+ pIWE->Exp_RO = 0L; // DWord 8
+ // DWord 9
+ pIWE->Exp_Byte_Cnt = fcp_dl; // sum of gather buffers
+ }
+ break;
- default:
- printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
- break;
+ case SCSI_IRE: // TachLite Initiator Read Entry
+ if (Cmnd->timeout != 0) {
+// printk("Cmnd->timeout %d\n", Cmnd->timeout);
+ // per Linux Scsi
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = Cmnd->timeout;
+ } else // use our best guess, based on FC & device
+ {
+
+ if (Cmnd->SCp.Message == 1) // Tape device? (from INQUIRY)
+ {
+ // turn off our timeouts (for now...)
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 0xFFFFFFFF;
+ } else {
+ Exchanges->fcExchange[*fcExchangeIndex].reTries = 1;
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 7; // per SCSI req.
+ }
+ }
+ // first, build FCP_CMND
+ *pIRB_flags = 0; // clear IRB flags
+ IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
+ // NOTE: unlike FC LinkService login frames,
+ // normal SCSI commands are sent "open loop"
+ IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
+ SfsLen = *pIRB_flags;
+
+ SfsLen <<= 24; // shift flags to MSB
+ SfsLen += 64L; // add len to LSB (header & CMND payload)
+
+ CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
+
+ // TYPE[31-24] 8 for FCP SCSI
+ // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+ // valid RO
+ CMDfchs->f_ctl = 0x08210008L;
+ CMDfchs->seq_cnt = 0x0L;
+ // x_ID & data direction bit set later
+ CMDfchs->ox_rx_id = 0xFFFF; // clear
+ CMDfchs->ro = 0x0L; // relative offset (n/a)
+ // Now setup the SEST entry
+ pIRE = &fcChip->SEST->u[*fcExchangeIndex].IRE;
+ // fill out the IRE:
+ // VALid entry:Dir outbound:enable CM:enal INT:
+ pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
+
+ pIRE->reserved = 0L;
+ pIRE->RSP_Len = sizeof(TachFCHDR_RSP); // hdr+data (recv'd RSP frame)
+ pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
+
+ pIRE->RSP_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+ // Do we need local or extended gather list?
+ // depends on size - we can handle 3 len/addr pairs
+ // locally.
+
+ fcp_dl = build_SEST_sgList(dev->PciDev, &pIRE->SLen1, Cmnd, // SCSI command Data desc. with S/G list
+ &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
+ &fcChip->SEST->sgPages[*fcExchangeIndex]); // (for Freeing later)
+
+
+ if (!fcp_dl) // error building S/G list?
+ {
+ // It is permissible to have a ZERO LENGTH Read command.
+ // If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
+ // to 0 and continue.
+ if (Cmnd->request_bufflen == 0) {
+ fcp_dl = 0; // no FC DATA frames expected
+
+ } else {
+ ulStatus = MEMPOOL_FAIL;
+ break; // give up
+ }
+ }
+ // now that we know the S/G length, build CMND payload
+ build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
- }
-
-
- if( !ulStatus) // no errors above?
- {
- // FCHS is built; now build IRB
+ if (sgPairs > 3) // need extended s/g list
+ pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
+ else
+ pIRE->Buff_Off = 0x80000000; // local data, no offset
+
+ pIRE->Buff_Index = 0x0L; // DWord 5: Buff_Index | Reserved
+
+ pIRE->Exp_RO = 0x0L; // DWord 6: Expected Rel. Offset
+
+ pIRE->Byte_Count = 0; // DWord 7: filled in by TL on err
+ pIRE->reserved_ = 0; // DWord 8: reserved
+ // NOTE: 0 length READ is OK.
+ pIRE->Exp_Byte_Cnt = fcp_dl; // DWord 9: sum of scatter buffers
+ break;
+
+ // Fibre Channel SCSI 'responder' sequences...
+ // (originator means 'target' in FCP-SCSI)
+ case SCSI_TWE: // TachLite Target Write Entry
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 10; // per SCSI req.
+ // first, build FCP_CMND
+ *pIRB_flags = 0; // clear IRB flags
+ IRB_flags.SFA = 1; // send SFS (XFER_RDY)
+ SfsLen = *pIRB_flags;
+ SfsLen <<= 24; // shift flags to MSB
+ SfsLen += (32L + 12L); // add SFS len (header & XFER_RDY payload)
+
+ CMDfchs->d_id |= (0x05000000L); // R_CTL = 5 for XFER_RDY
+
+ // TYPE[31-24] 8 for FCP SCSI
+ // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
+ // valid RO
+ CMDfchs->f_ctl = 0x08810008L;
+ CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
+ // use originator (other port's) OX_ID
+ CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // we want upper 16 bits
+ CMDfchs->ro = 0x0L; // relative offset (n/a)
+
+ // now, fill out FCP-RSP header
+ // (use buffer inside SEST object)
+
+ rspHDR = &fcChip->SEST->RspHDR[*fcExchangeIndex];
+ rspHDR->reserved = 0L; // must clear
+ rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
+ rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
+ rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+ // TYPE[31-24] 8 for FCP SCSI
+ // f_ctl[23:0] responder|last seq| xfer S.I.
+ rspHDR->f_ctl = 0x08910000L;
+ rspHDR->seq_cnt = 0x03000000; // sequence ID
+ rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
+ rspHDR->ro = 0x0L; // relative offset (n/a)
+ // Now setup the SEST entry
+
+ pTWE = &fcChip->SEST->u[*fcExchangeIndex].TWE;
+ // fill out the TWE:
+
+ // VALid entry:Dir outbound:enable CM:enal INT:
+ pTWE->Seq_Accum = 0xC4000000L; // upper word flags
+ pTWE->reserved = 0L;
+ pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
+ pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
+
+ // Do we need local or extended gather list?
+ // depends on size - we can handle 3 len/addr pairs
+ // locally.
+
+ fcp_dl = build_SEST_sgList(dev->PciDev, &pTWE->SLen1, Cmnd, // S/G list
+ &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
+ &fcChip->SEST->sgPages[*fcExchangeIndex]); // (for Freeing later)
+
+ if (!fcp_dl) // error building S/G list?
+ {
+ ulStatus = MEMPOOL_FAIL;
+ break; // give up
+ }
+ // now that we know the S/G length, build CMND payload
+ build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
- // link the just built FCHS (the "command") to the IRB entry
- // for this Exchange.
- pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB;
-
- // len & flags according to command type above
- pIRB->Req_A_SFS_Len = SfsLen; // includes IRB flags & len
- pIRB->Req_A_SFS_Addr = // TL needs physical addr of frame to send
- fcChip->exch_dma_handle + (unsigned long)CMDfchs -
- (unsigned long)Exchanges;
-
- pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
-
- // Exchange is complete except for "fix-up" fields to be set
- // at Tachyon Queuing time:
- // IRB->Req_A_Trans_ID (OX_ID/ RX_ID):
- // for SEST entry, lower bits correspond to actual FC Exchange ID
- // fchs->OX_ID or RX_ID
- }
- else
- {
-#ifdef DBG
- printk( "FC Error: SEST build Pool Allocation failed\n");
+ if (sgPairs > 3) // need extended s/g list
+ pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
+ else
+ pTWE->Buff_Off = 0x80000000; // local data, no offset
+
+ pTWE->Buff_Index = 0; // Buff_Index | Link
+ pTWE->Exp_RO = 0;
+ pTWE->Byte_Count = 0; // filled in by TL on err
+ pTWE->reserved_ = 0;
+ pTWE->Exp_Byte_Cnt = fcp_dl; // sum of scatter buffers
+ break;
+
+ case SCSI_TRE: // TachLite Target Read Entry
+ // It doesn't make much sense for us to "time-out" a READ,
+ // but we'll use it for design consistency and internal error recovery.
+ Exchanges->fcExchange[*fcExchangeIndex].timeOut = 10; // per SCSI req.
+ // I/O request block settings...
+ *pIRB_flags = 0; // clear IRB flags
+ // check PRLI (process login) info
+ // to see if Initiator Requires XFER_RDY
+ // if not, don't send one!
+ // { PRLI check...}
+ IRB_flags.SFA = 0; // don't send XFER_RDY - start data
+ SfsLen = *pIRB_flags;
+ SfsLen <<= 24; // shift flags to MSB
+ SfsLen += (32L + 12L); // add SFS len (header & XFER_RDY payload)
+
+ // now, fill out FCP-DATA header
+ // (use buffer inside SEST object)
+ dataHDR = &fcChip->SEST->DataHDR[*fcExchangeIndex];
+
+ dataHDR->reserved = 0L; // must clear
+ dataHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
+ dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
+ dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+
+ // TYPE[31-24] 8 for FCP SCSI
+ // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
+ // valid RO
+ dataHDR->f_ctl = 0x08810008L;
+ dataHDR->seq_cnt = 0x01000000; // sequence ID (no XRDY)
+ dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
+ dataHDR->ro = 0x0L; // relative offset (n/a)
+
+ // now, fill out FCP-RSP header
+ // (use buffer inside SEST object)
+ rspHDR = &fcChip->SEST->RspHDR[*fcExchangeIndex];
+
+ rspHDR->reserved = 0L; // must clear
+ rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
+ rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
+ rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+ // TYPE[31-24] 8 for FCP SCSI
+ // f_ctl[23:0] responder|last seq| xfer S.I.
+ rspHDR->f_ctl = 0x08910000L;
+ rspHDR->seq_cnt = 0x02000000; // sequence ID: df_ctl: sequence count
+ rspHDR->ro = 0x0L; // relative offset (n/a)
+
+ // Now setup the SEST entry
+ pTRE = &fcChip->SEST->u[*fcExchangeIndex].TRE;
+
+ // VALid entry:Dir outbound:enable CM:enal INT:
+ pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
+ pTRE->Hdr_Addr = // bus address of dataHDR;
+ fcChip->SEST->base + ((unsigned long) &fcChip->SEST->DataHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+ pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
+ pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
+ pTRE->RSP_Addr = // bus address of rspHDR
+ fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+ // Do we need local or extended gather list?
+ // depends on size - we can handle 3 len/addr pairs
+ // locally.
+
+ fcp_dl = build_SEST_sgList(dev->PciDev, &pTRE->GLen1, Cmnd, // S/G list
+ &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
+ &fcChip->SEST->sgPages[*fcExchangeIndex]); // (for Freeing later)
+
+ if (!fcp_dl) // error building S/G list?
+ {
+ ulStatus = MEMPOOL_FAIL;
+ break; // give up
+ }
+ // no payload or command to build -- READ doesn't need XRDY
+ if (sgPairs > 3) // need extended s/g list
+ pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
+ else // local data pointers (in SEST)
+ pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
+
+ // u32 5
+ pTRE->Buff_Index = 0L; // Buff_Index | reserved
+ pTRE->reserved = 0x0L; // DWord 6
+
+ // DWord 7: NOTE: zero length will
+ // hang TachLite!
+ pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
+
+ pTRE->reserved_ = 0L; // DWord 8
+ pTRE->reserved__ = 0L; // DWord 9
+
+ break;
+
+ case FCP_RESPONSE:
+ // Target response frame: this sequence uses an OX/RX ID
+ // pair from a completed SEST exchange. We built most
+ // of the response frame when we created the TWE/TRE.
+
+ *pIRB_flags = 0; // clear IRB flags
+ IRB_flags.SFA = 1; // send SFS (RSP)
+ SfsLen = *pIRB_flags;
+
+ SfsLen <<= 24; // shift flags to MSB
+ SfsLen += sizeof(TachFCHDR_RSP); // add SFS len (header & RSP payload)
+ Exchanges->fcExchange[*fcExchangeIndex].type = FCP_RESPONSE; // change Exchange type to "response" phase
+
+ // take advantage of prior knowledge of OX/RX_ID pair from
+ // previous XFER outbound frame (still in fchs of exchange)
+ fcChip->SEST->RspHDR[*fcExchangeIndex].ox_rx_id = CMDfchs->ox_rx_id;
+
+ // Check the status of the DATA phase of the exchange so we can report
+ // status to the initiator
+ buildFCPstatus(fcChip, *fcExchangeIndex); // set RSP payload fields
+
+ memcpy(CMDfchs, // re-use same XFER fchs for Response frame
+ &fcChip->SEST->RspHDR[*fcExchangeIndex], sizeof(TachFCHDR_RSP));
+ break;
+
+ default:
+ printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type, type);
+ break;
+ }
+ if (!ulStatus) // no errors above?
+ {
+ // FCHS is built; now build IRB
+
+ // link the just built FCHS (the "command") to the IRB entry
+ // for this Exchange.
+ pIRB = &Exchanges->fcExchange[*fcExchangeIndex].IRB;
+
+ // len & flags according to command type above
+ pIRB->Req_A_SFS_Len = SfsLen; // includes IRB flags & len
+ pIRB->Req_A_SFS_Addr = // TL needs physical addr of frame to send
+ fcChip->exch_dma_handle + (unsigned long) CMDfchs - (unsigned long) Exchanges;
+
+ pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
+
+ // Exchange is complete except for "fix-up" fields to be set
+ // at Tachyon Queuing time:
+ // IRB->Req_A_Trans_ID (OX_ID/ RX_ID):
+ // for SEST entry, lower bits correspond to actual FC Exchange ID
+ // fchs->OX_ID or RX_ID
+ } else {
+#ifdef DBG
+ printk("FC Error: SEST build Pool Allocation failed\n");
#endif
- // return resources...
- cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, *fcExchangeIndex); // SEST build failed
- }
- }
- else // no Exchanges available
- {
- ulStatus = SEST_FULL;
- printk( "FC Error: no fcExchanges available\n");
- }
- return ulStatus;
+ // return resources...
+ cpqfcTSCompleteExchange(dev->PciDev, fcChip, *fcExchangeIndex); // SEST build failed
+ }
+ } else // no Exchanges available
+ {
+ ulStatus = SEST_FULL;
+ printk("FC Error: no fcExchanges available\n");
+ }
+ return ulStatus;
}
-
-
-
-
-
// set RSP payload fields
-static void buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID)
+static void buildFCPstatus(PTACHYON fcChip, u32 ExchangeID)
{
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID]; // shorthand
- PFCP_STATUS_RESPONSE pFcpStatus;
-
- memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
- sizeof( FCP_STATUS_RESPONSE) );
- if( pExchange->status ) // something wrong?
- {
- pFcpStatus = (PFCP_STATUS_RESPONSE) // cast RSP buffer for this xchng
- &fcChip->SEST->RspHDR[ ExchangeID ].pl;
- if( pExchange->status & COUNT_ERROR )
- {
-
- // set FCP response len valid (so we can report count error)
- pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
- pFcpStatus->fcp_rsp_len = 0x04000000; // 4 byte len (BIG Endian)
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID]; // shorthand
+ PFCP_STATUS_RESPONSE pFcpStatus;
- pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
- }
- }
+ memset(&fcChip->SEST->RspHDR[ExchangeID].pl, 0, sizeof(FCP_STATUS_RESPONSE));
+ if (pExchange->status) // something wrong?
+ {
+ pFcpStatus = (PFCP_STATUS_RESPONSE) // cast RSP buffer for this xchng
+ & fcChip->SEST->RspHDR[ExchangeID].pl;
+ if (pExchange->status & COUNT_ERROR) {
+
+ // set FCP response len valid (so we can report count error)
+ pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
+ pFcpStatus->fcp_rsp_len = 0x04000000; // 4 byte len (BIG Endian)
+
+ pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
+ }
+ }
}
-static dma_addr_t
-cpqfc_pci_map_sg_page(
- struct pci_dev *pcidev,
- ULONG *hw_paddr, // where to put phys addr for HW use
- void *sgp_vaddr, // the virtual address of the sg page
- dma_addr_t *umap_paddr, // where to put phys addr for unmap
- unsigned int *maplen, // where to store sg entry length
- int PairCount) // number of sg pairs used in the page.
+static dma_addr_t cpqfc_pci_map_sg_page(struct pci_dev *pcidev, u32 * hw_paddr, // where to put phys addr for HW use
+ void *sgp_vaddr, // the virtual address of the sg page
+ dma_addr_t * umap_paddr, // where to put phys addr for unmap
+ unsigned int *maplen, // where to store sg entry length
+ int PairCount) // number of sg pairs used in the page.
{
unsigned long aligned_addr = (unsigned long) sgp_vaddr;
*maplen = PairCount * 8;
- aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
- aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
-
- *umap_paddr = pci_map_single(pcidev, (void *) aligned_addr,
- *maplen, PCI_DMA_TODEVICE);
- *hw_paddr = (ULONG) *umap_paddr;
+ aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
+ aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN - 1);
+
+ *umap_paddr = pci_map_single(pcidev, (void *) aligned_addr, *maplen, PCI_DMA_TODEVICE);
+ *hw_paddr = (u32) * umap_paddr;
# if BITS_PER_LONG > 32
- if( *umap_paddr >>32 ) {
- printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n",
- (void*)umap_paddr);
- return 0;
- }
+ if (*umap_paddr >> 32) {
+ printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n", (void *) umap_paddr);
+ return 0;
+ }
# endif
return *umap_paddr;
}
-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)
+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)
{
PSGPAGES i, next;
@@ -5136,14 +4141,12 @@
if (sgl != NULL)
pci_unmap_sg(pcidev, sgl, use_sg, dir);
- for (i=*sgPages_head; i != NULL ;i = next)
- {
- pci_unmap_single(pcidev, i->busaddr, i->maplen,
- scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
- i->busaddr = (dma_addr_t) NULL;
- i->maplen = 0L;
+ for (i = *sgPages_head; i != NULL; i = next) {
+ pci_unmap_single(pcidev, i->busaddr, i->maplen, scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+ i->busaddr = (dma_addr_t) NULL;
+ i->maplen = 0L;
next = i->next;
- kfree(i);
+ kfree(i);
}
*sgPages_head = NULL;
}
@@ -5166,380 +4169,331 @@
static int ap_hi_water = TL_DANGER_SGPAGES;
-static ULONG build_SEST_sgList(
- struct pci_dev *pcidev,
- ULONG *SESTalPairStart, // the 3 len/address buffers in SEST
- Scsi_Cmnd *Cmnd,
- ULONG *sgPairs,
- PSGPAGES *sgPages_head) // link list of TL Ext. S/G pages from O/S Pool
-
+static u32 build_SEST_sgList(struct pci_dev *pcidev, u32 * SESTalPairStart, // the 3 len/address buffers in SEST
+ Scsi_Cmnd * Cmnd, u32 * sgPairs, PSGPAGES * sgPages_head) // link list of TL Ext. S/G pages from O/S Pool
{
- ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
- ULONG* alPair = SESTalPairStart;
- ULONG* ext_sg_page_phys_addr_place = NULL;
- int PairCount;
- unsigned long ulBuff, contigaddr;
- ULONG total_data_len=0; // (in bytes)
- ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
- ULONG thisMappingLen;
- struct scatterlist *sgl = NULL; // S/G list (Linux format)
- int sg_count, totalsgs;
- dma_addr_t busaddr;
- unsigned long thislen, offset;
- PSGPAGES *sgpage = sgPages_head;
- PSGPAGES prev_page = NULL;
-
-# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
- contigaddr = (unsigned long) NULL;
-
- if( !Cmnd->use_sg ) // no S/G list?
- {
- if (bytes_to_go <= TL_MAX_SG_ELEM_LEN)
- {
- *sgPairs = 1; // use "local" S/G pair in SEST entry
- // (for now, ignore address bits above #31)
+ u32 i, AllocatedPages = 0; // Tach Ext. S/G page allocations
+ u32 *alPair = SESTalPairStart;
+ u32 *ext_sg_page_phys_addr_place = NULL;
+ int PairCount;
+ unsigned long ulBuff, contigaddr;
+ u32 total_data_len = 0; // (in bytes)
+ u32 bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
+ u32 thisMappingLen;
+ struct scatterlist *sgl = NULL; // S/G list (Linux format)
+ int sg_count, totalsgs;
+ dma_addr_t busaddr;
+ unsigned long thislen, offset;
+ PSGPAGES *sgpage = sgPages_head;
+ PSGPAGES prev_page = NULL;
- *alPair++ = bytes_to_go; // bits 18-0, length
+# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
+ contigaddr = (unsigned long) NULL;
- if (bytes_to_go != 0) {
- contigaddr = ulBuff = pci_map_single(pcidev,
- Cmnd->request_buffer,
- Cmnd->request_bufflen,
- scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
- // printk("ms %p ", ulBuff);
- }
- else {
- // No data transfer, (e.g.: Test Unit Ready)
- // printk("btg=0 ");
- *sgPairs = 0;
- memset(alPair, 0, sizeof(*alPair));
- return 0;
- }
+ if (!Cmnd->use_sg) // no S/G list?
+ {
+ if (bytes_to_go <= TL_MAX_SG_ELEM_LEN) {
+ *sgPairs = 1; // use "local" S/G pair in SEST entry
+ // (for now, ignore address bits above #31)
+
+ *alPair++ = bytes_to_go; // bits 18-0, length
+
+ if (bytes_to_go != 0) {
+ contigaddr = ulBuff = pci_map_single(pcidev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+ // printk("ms %p ", ulBuff);
+ } else {
+ // No data transfer, (e.g.: Test Unit Ready)
+ // printk("btg=0 ");
+ *sgPairs = 0;
+ memset(alPair, 0, sizeof(*alPair));
+ return 0;
+ }
# if BITS_PER_LONG > 32
- if( ulBuff >>32 ) {
- printk("FATAL! Tachyon DMA address %p "
- "exceeds 32 bits\n", (void*)ulBuff );
- return 0;
- }
+ if (ulBuff >> 32) {
+ printk("FATAL! Tachyon DMA address %p " "exceeds 32 bits\n", (void *) ulBuff);
+ return 0;
+ }
# endif
- *alPair = (ULONG)ulBuff;
- return bytes_to_go;
- }
- else // We have a single large (too big) contiguous buffer.
- { // We will have to break it up. We'll use the scatter
- // gather code way below, but use contigaddr instead
- // of sg_dma_addr(). (this is a very rare case).
-
- unsigned long btg;
- contigaddr = pci_map_single(pcidev, Cmnd->request_buffer,
- Cmnd->request_bufflen,
- scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
-
- // printk("contigaddr = %p, len = %d\n",
- // (void *) contigaddr, bytes_to_go);
- totalsgs = 0;
- for (btg = bytes_to_go; btg > 0; ) {
- btg -= ( btg > TL_MAX_SG_ELEM_LEN ?
- TL_MAX_SG_ELEM_LEN : btg );
- totalsgs++;
- }
- sgl = NULL;
- *sgPairs = totalsgs;
- }
- }
- else // we do have a scatter gather list
- {
- // [TBD - update for Linux to support > 32 bits addressing]
- // since the format for local & extended S/G lists is different,
- // check if S/G pairs exceeds 3.
- // *sgPairs = Cmnd->use_sg; Nope, that's wrong.
-
- sgl = (struct scatterlist*)Cmnd->request_buffer;
- sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg,
- scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
- // printk("sgl = %p, sg_count = %d\n", (void *) sgl, sg_count);
- if( sg_count <= 3 ) {
-
- // we need to be careful here that no individual mapping
- // is too large, and if any is, that breaking it up
- // doesn't push us over 3 sgs, or, if it does, that we
- // handle that case. Tachyon can take 0x7FFFF bits for length,
- // but sg structure uses "unsigned int", on the face of it,
- // up to 0xFFFFFFFF or even more.
-
- int i;
- unsigned long thislen;
-
- totalsgs = 0;
- for (i=0;i<sg_count;i++) {
- thislen = sg_dma_len(&sgl[i]);
- while (thislen >= TL_MAX_SG_ELEM_LEN) {
+ *alPair = (u32) ulBuff;
+ return bytes_to_go;
+ } else // We have a single large (too big) contiguous buffer.
+ { // We will have to break it up. We'll use the scatter
+ // gather code way below, but use contigaddr instead
+ // of sg_dma_addr(). (this is a very rare case).
+
+ unsigned long btg;
+ contigaddr = pci_map_single(pcidev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
+ // printk("contigaddr = %p, len = %d\n",
+ // (void *) contigaddr, bytes_to_go);
+ totalsgs = 0;
+ for (btg = bytes_to_go; btg > 0;) {
+ btg -= (btg > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : btg);
totalsgs++;
- thislen -= TL_MAX_SG_ELEM_LEN;
}
- if (thislen > 0) totalsgs++;
+ sgl = NULL;
+ *sgPairs = totalsgs;
}
- *sgPairs = totalsgs;
- } else totalsgs = 999; // as a first estimate, definitely >3,
-
- // if (totalsgs != sg_count)
- // printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
- }
+ } else // we do have a scatter gather list
+ {
+ // [TBD - update for Linux to support > 32 bits addressing]
+ // since the format for local & extended S/G lists is different,
+ // check if S/G pairs exceeds 3.
+ // *sgPairs = Cmnd->use_sg; Nope, that's wrong.
+
+ sgl = (struct scatterlist *) Cmnd->request_buffer;
+ sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+ // printk("sgl = %p, sg_count = %d\n", (void *) sgl, sg_count);
+ if (sg_count <= 3) {
+
+ // we need to be careful here that no individual mapping
+ // is too large, and if any is, that breaking it up
+ // doesn't push us over 3 sgs, or, if it does, that we
+ // handle that case. Tachyon can take 0x7FFFF bits for length,
+ // but sg structure uses "unsigned int", on the face of it,
+ // up to 0xFFFFFFFF or even more.
+
+ int i;
+ unsigned long thislen;
+
+ totalsgs = 0;
+ for (i = 0; i < sg_count; i++) {
+ thislen = sg_dma_len(&sgl[i]);
+ while (thislen >= TL_MAX_SG_ELEM_LEN) {
+ totalsgs++;
+ thislen -= TL_MAX_SG_ELEM_LEN;
+ }
+ if (thislen > 0)
+ totalsgs++;
+ }
+ *sgPairs = totalsgs;
+ } else
+ totalsgs = 999; // as a first estimate, definitely >3,
- // printk("totalsgs = %d, sgcount=%d\n", totalsgs, sg_count);
- if( totalsgs <= 3 ) // can (must) use "local" SEST list
- {
- while( bytes_to_go)
- {
- offset = 0L;
+ // if (totalsgs != sg_count)
+ // printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
+ }
- if ( WE_HAVE_SG_LIST )
- thisMappingLen = sg_dma_len(sgl);
- else // or contiguous buffer?
- thisMappingLen = bytes_to_go;
+ // printk("totalsgs = %d, sgcount=%d\n", totalsgs, sg_count);
+ if (totalsgs <= 3) // can (must) use "local" SEST list
+ {
+ while (bytes_to_go) {
+ offset = 0L;
- while (thisMappingLen > 0)
- {
- thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ?
- TL_MAX_SG_ELEM_LEN : thisMappingLen;
- bytes_to_go = bytes_to_go - thislen;
+ if (WE_HAVE_SG_LIST)
+ thisMappingLen = sg_dma_len(sgl);
+ else // or contiguous buffer?
+ thisMappingLen = bytes_to_go;
- // we have L/A pair; L = thislen, A = physicalAddress
- // load into SEST...
+ while (thisMappingLen > 0) {
+ thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : thisMappingLen;
+ bytes_to_go = bytes_to_go - thislen;
- total_data_len += thislen;
- *alPair = thislen; // bits 18-0, length
+ // we have L/A pair; L = thislen, A = physicalAddress
+ // load into SEST...
- alPair++;
+ total_data_len += thislen;
+ *alPair = thislen; // bits 18-0, length
- if ( WE_HAVE_SG_LIST )
- ulBuff = sg_dma_address(sgl) + offset;
- else
- ulBuff = contigaddr + offset;
+ alPair++;
- offset += thislen;
+ if (WE_HAVE_SG_LIST)
+ ulBuff = sg_dma_address(sgl) + offset;
+ else
+ ulBuff = contigaddr + offset;
+
+ offset += thislen;
# if BITS_PER_LONG > 32
- if( ulBuff >>32 ) {
- printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n",
- (void*)ulBuff );
- printk("%s = %p, offset = %ld\n",
- WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
- WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
- offset);
- return 0;
- }
+ if (ulBuff >> 32) {
+ printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n", (void *) ulBuff);
+ printk("%s = %p, offset = %ld\n", WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr", WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr, offset);
+ return 0;
+ }
# endif
- *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
- thisMappingLen -= thislen;
- }
+ *alPair++ = (u32) ulBuff; // lower 32 bits (31-0)
+ thisMappingLen -= thislen;
+ }
- if ( WE_HAVE_SG_LIST ) ++sgl; // next S/G pair
- else if (bytes_to_go != 0) printk("BTG not zero!\n");
+ if (WE_HAVE_SG_LIST)
+ ++sgl; // next S/G pair
+ else if (bytes_to_go != 0)
+ printk("BTG not zero!\n");
# ifdef DBG_SEST_SGLIST
- printk("L=%d ", thisMappingLen);
- printk("btg=%d ", bytes_to_go);
+ printk("L=%d ", thisMappingLen);
+ printk("btg=%d ", bytes_to_go);
# endif
- }
- // printk("i:%d\n", *sgPairs);
- }
- else // more than 3 pairs requires Extended S/G page (Pool Allocation)
- {
- // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
- for( i=2; i<6; i++)
- alPair[i] = 0;
-
- PairCount = TL_EXT_SG_PAGE_COUNT; // forces initial page allocation
- totalsgs = 0;
- while( bytes_to_go )
- {
- // Per SEST format, we can support 524287 byte lengths per
- // S/G pair. Typical user buffers are 4k, and very rarely
- // exceed 12k due to fragmentation of physical memory pages.
- // However, on certain O/S system (not "user") buffers (on platforms
- // with huge memories), it's possible to exceed this
- // length in a single S/G address/len mapping, so we have to handle
- // that.
-
- offset = 0L;
- if ( WE_HAVE_SG_LIST )
- thisMappingLen = sg_dma_len(sgl);
- else
- thisMappingLen = bytes_to_go;
-
- while (thisMappingLen > 0)
- {
- thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ?
- TL_MAX_SG_ELEM_LEN : thisMappingLen;
- // printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
-
- // should we load into "this" extended S/G page, or allocate
- // new page?
-
- if( PairCount >= TL_EXT_SG_PAGE_COUNT )
+ }
+ // printk("i:%d\n", *sgPairs);
+ } else // more than 3 pairs requires Extended S/G page (Pool Allocation)
{
- // Now, we have to map the previous page, (triggering buffer bounce)
- // The first time thru the loop, there won't be a previous page.
- if (prev_page != NULL) // is there a prev page?
- {
- // this code is normally kind of hard to trigger,
- // you have to use up more than 256 scatter gather
- // elements to get here. Cranking down TL_MAX_SG_ELEM_LEN
- // to an absurdly low value (128 bytes or so) to artificially
- // break i/o's into a zillion pieces is how I tested it.
- busaddr = cpqfc_pci_map_sg_page(pcidev,
- ext_sg_page_phys_addr_place,
- prev_page->page,
- &prev_page->busaddr,
- &prev_page->maplen,
- PairCount);
- }
- // Allocate the TL Extended S/G list page. We have
- // to allocate twice what we want to ensure required TL alignment
- // (Tachlite TL/TS User Man. Rev 6.0, p 168)
- // We store the original allocated PVOID so we can free later
- *sgpage = kmalloc( sizeof(SGPAGES), GFP_ATOMIC);
- if ( ! *sgpage )
- {
- printk("cpqfc: Allocation failed @ %d S/G page allocations\n",
- AllocatedPages);
- total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
-
- // unmap the previous mappings, if any.
-
- 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);
-
- // FIXME: testing shows that if we get here,
- // it's bad news. (this has been this way for a long
- // time though, AFAIK. Not that that excuses it.)
-
- return 0; // give up (and probably hang the system)
- }
- // clear out memory we just allocated
- memset( (*sgpage)->page,0,TL_EXT_SG_PAGE_BYTELEN*2);
- (*sgpage)->next = NULL;
- (*sgpage)->busaddr = (dma_addr_t) NULL;
- (*sgpage)->maplen = 0L;
-
- // align the memory - TL requires sizeof() Ext. S/G page alignment.
- // We doubled the actual required size so we could mask off LSBs
- // to get desired offset
-
- ulBuff = (unsigned long) (*sgpage)->page;
- ulBuff += TL_EXT_SG_PAGE_BYTELEN;
- ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
-
- // set pointer, in SEST if first Ext. S/G page, or in last pair
- // of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just
- // load lower 32 bits)
- // NOTE: the Len field must be '0' if this is the first Ext. S/G
- // pointer in SEST, and not 0 otherwise (we know thislen != 0).
+ // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
+ for (i = 2; i < 6; i++)
+ alPair[i] = 0;
- *alPair = (alPair != SESTalPairStart) ? thislen : 0;
+ PairCount = TL_EXT_SG_PAGE_COUNT; // forces initial page allocation
+ totalsgs = 0;
+ while (bytes_to_go) {
+ // Per SEST format, we can support 524287 byte lengths per
+ // S/G pair. Typical user buffers are 4k, and very rarely
+ // exceed 12k due to fragmentation of physical memory pages.
+ // However, on certain O/S system (not "user") buffers (on platforms
+ // with huge memories), it's possible to exceed this
+ // length in a single S/G address/len mapping, so we have to handle
+ // that.
+
+ offset = 0L;
+ if (WE_HAVE_SG_LIST)
+ thisMappingLen = sg_dma_len(sgl);
+ else
+ thisMappingLen = bytes_to_go;
+
+ while (thisMappingLen > 0) {
+ thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : thisMappingLen;
+ // printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
+
+ // should we load into "this" extended S/G page, or allocate
+ // new page?
+
+ if (PairCount >= TL_EXT_SG_PAGE_COUNT) {
+ // Now, we have to map the previous page, (triggering buffer bounce)
+ // The first time thru the loop, there won't be a previous page.
+ if (prev_page != NULL) // is there a prev page?
+ {
+ // this code is normally kind of hard to trigger,
+ // you have to use up more than 256 scatter gather
+ // elements to get here. Cranking down TL_MAX_SG_ELEM_LEN
+ // to an absurdly low value (128 bytes or so) to artificially
+ // break i/o's into a zillion pieces is how I tested it.
+ busaddr = cpqfc_pci_map_sg_page(pcidev, ext_sg_page_phys_addr_place, prev_page->page, &prev_page->busaddr, &prev_page->maplen, PairCount);
+ }
+ // Allocate the TL Extended S/G list page. We have
+ // to allocate twice what we want to ensure required TL alignment
+ // (Tachlite TL/TS User Man. Rev 6.0, p 168)
+ // We store the original allocated PVOID so we can free later
+ *sgpage = kmalloc(sizeof(SGPAGES), GFP_ATOMIC);
+ if (!*sgpage) {
+ printk("cpqfc: Allocation failed @ %d S/G page allocations\n", AllocatedPages);
+ total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
+
+ // unmap the previous mappings, if any.
+
+ 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);
+
+ // FIXME: testing shows that if we get here,
+ // it's bad news. (this has been this way for a long
+ // time though, AFAIK. Not that that excuses it.)
+
+ return 0; // give up (and probably hang the system)
+ }
+ // clear out memory we just allocated
+ memset((*sgpage)->page, 0, TL_EXT_SG_PAGE_BYTELEN * 2);
+ (*sgpage)->next = NULL;
+ (*sgpage)->busaddr = (dma_addr_t) NULL;
+ (*sgpage)->maplen = 0L;
+
+ // align the memory - TL requires sizeof() Ext. S/G page alignment.
+ // We doubled the actual required size so we could mask off LSBs
+ // to get desired offset
+
+ ulBuff = (unsigned long) (*sgpage)->page;
+ ulBuff += TL_EXT_SG_PAGE_BYTELEN;
+ ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN - 1);
+
+ // set pointer, in SEST if first Ext. S/G page, or in last pair
+ // of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just
+ // load lower 32 bits)
+ // NOTE: the Len field must be '0' if this is the first Ext. S/G
+ // pointer in SEST, and not 0 otherwise (we know thislen != 0).
+
+ *alPair = (alPair != SESTalPairStart) ? thislen : 0;
# ifdef DBG_SEST_SGLIST
- printk("PairCount %d @%p even %Xh, ",
- PairCount, alPair, *alPair);
+ printk("PairCount %d @%p even %Xh, ", PairCount, alPair, *alPair);
# endif
- // Save the place where we need to store the physical
- // address of this scatter gather page which we get when we map it
- // (and mapping we can do only after we fill it in.)
- alPair++; // next DWORD, will contain phys addr of the ext page
- ext_sg_page_phys_addr_place = alPair;
-
- // Now, set alPair = the virtual addr of the (Extended) S/G page
- // which will accept the Len/ PhysicalAddress pairs
- alPair = (ULONG *) ulBuff;
-
- AllocatedPages++;
- if (AllocatedPages >= ap_hi_water)
- {
- // This message should rarely, if ever, come out.
- // Previously (cpqfc version <= 2.0.5) the driver would
- // just puke if more than 4 SG pages were used, and nobody
- // ever complained about that. This only comes out if
- // more than 8 pages are used.
-
- printk(KERN_WARNING
- "cpqfc: Possible danger. %d scatter gather pages used.\n"
- "cpqfc: detected seemingly extreme memory "
- "fragmentation or huge data transfers.\n",
- AllocatedPages);
- ap_hi_water = AllocatedPages+1;
- }
-
- PairCount = 1; // starting new Ext. S/G page
- prev_page = (*sgpage); // remember this page, for next time thru
- sgpage = &((*sgpage)->next);
- } // end of new TL Ext. S/G page allocation
+ // Save the place where we need to store the physical
+ // address of this scatter gather page which we get when we map it
+ // (and mapping we can do only after we fill it in.)
+ alPair++; // next DWORD, will contain phys addr of the ext page
+ ext_sg_page_phys_addr_place = alPair;
+
+ // Now, set alPair = the virtual addr of the (Extended) S/G page
+ // which will accept the Len/ PhysicalAddress pairs
+ alPair = (u32 *) ulBuff;
+
+ AllocatedPages++;
+ if (AllocatedPages >= ap_hi_water) {
+ // This message should rarely, if ever, come out.
+ // Previously (cpqfc version <= 2.0.5) the driver would
+ // just puke if more than 4 SG pages were used, and nobody
+ // ever complained about that. This only comes out if
+ // more than 8 pages are used.
+
+ printk(KERN_WARNING "cpqfc: Possible danger. %d scatter gather pages used.\n" "cpqfc: detected seemingly extreme memory " "fragmentation or huge data transfers.\n", AllocatedPages);
+ ap_hi_water = AllocatedPages + 1;
+ }
+
+ PairCount = 1; // starting new Ext. S/G page
+ prev_page = (*sgpage); // remember this page, for next time thru
+ sgpage = &((*sgpage)->next);
+ } // end of new TL Ext. S/G page allocation
+
+ *alPair = thislen; // bits 18-0, length (range check above)
- *alPair = thislen; // bits 18-0, length (range check above)
-
# ifdef DBG_SEST_SGLIST
- printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
+ printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
# endif
- alPair++; // next DWORD, physical address
+ alPair++; // next DWORD, physical address
- if ( WE_HAVE_SG_LIST )
- ulBuff = sg_dma_address(sgl) + offset;
- else
- ulBuff = contigaddr + offset;
- offset += thislen;
+ if (WE_HAVE_SG_LIST)
+ ulBuff = sg_dma_address(sgl) + offset;
+ else
+ ulBuff = contigaddr + offset;
+ offset += thislen;
# if BITS_PER_LONG > 32
- if( ulBuff >>32 )
- {
- printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void*)ulBuff );
- printk("%s = %p, offset = %ld\n",
- WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
- WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
- offset);
- return 0;
- }
+ if (ulBuff >> 32) {
+ printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void *) ulBuff);
+ printk("%s = %p, offset = %ld\n", WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr", WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr, offset);
+ return 0;
+ }
# endif
- *alPair = (ULONG) ulBuff; // lower 32 bits (31-0)
+ *alPair = (u32) ulBuff; // lower 32 bits (31-0)
# ifdef DBG_SEST_SGLIST
- printk("odd %Xh\n", *alPair);
+ printk("odd %Xh\n", *alPair);
# endif
- alPair++; // next DWORD, next address/length pair
-
- PairCount++; // next Length/Address pair
-
- // if (PairCount > pc_hi_water)
- // {
- // printk("pc hi = %d ", PairCount);
- // pc_hi_water = PairCount;
- // }
- bytes_to_go -= thislen;
- total_data_len += thislen;
- thisMappingLen -= thislen;
- totalsgs++;
- } // while (thisMappingLen > 0)
- if ( WE_HAVE_SG_LIST ) sgl++; // next S/G pair
- } // while (bytes_to_go)
-
- // printk("Totalsgs=%d\n", totalsgs);
- *sgPairs = totalsgs;
-
- // PCI map (and bounce) the last (and usually only) extended SG page
- busaddr = cpqfc_pci_map_sg_page(pcidev,
- ext_sg_page_phys_addr_place,
- prev_page->page,
- &prev_page->busaddr,
- &prev_page->maplen,
- PairCount);
- }
- return total_data_len;
+ alPair++; // next DWORD, next address/length pair
+
+ PairCount++; // next Length/Address pair
+
+ // if (PairCount > pc_hi_water)
+ // {
+ // printk("pc hi = %d ", PairCount);
+ // pc_hi_water = PairCount;
+ // }
+ bytes_to_go -= thislen;
+ total_data_len += thislen;
+ thisMappingLen -= thislen;
+ totalsgs++;
+ } // while (thisMappingLen > 0)
+ if (WE_HAVE_SG_LIST)
+ sgl++; // next S/G pair
+ } // while (bytes_to_go)
+
+ // printk("Totalsgs=%d\n", totalsgs);
+ *sgPairs = totalsgs;
+
+ // PCI map (and bounce) the last (and usually only) extended SG page
+ busaddr = cpqfc_pci_map_sg_page(pcidev, ext_sg_page_phys_addr_place, prev_page->page, &prev_page->busaddr, &prev_page->maplen, PairCount);
+ }
+ return total_data_len;
}
@@ -5554,268 +4508,249 @@
// 0 if successful
// non-zero on error
//sstartex
-ULONG cpqfcTSStartExchange(
- CPQFCHBA *cpqfcHBAdata,
- LONG ExchangeID )
-{
- PTACHYON fcChip = &cpqfcHBAdata->fcChip;
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
- USHORT producer, consumer;
- ULONG ulStatus=0;
- short int ErqIndex;
- BOOLEAN CompleteExchange = FALSE; // e.g. ACC replies are complete
- BOOLEAN SestType=FALSE;
- ULONG InboundData=0;
- // We will manipulate Tachlite chip registers here to successfully
- // start exchanges.
+u32 cpqfcTSStartExchange(CPQFCHBA * dev, s32 ExchangeID)
+{
+ PTACHYON fcChip = &dev->fcChip;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID]; // shorthand
+ u16 producer, consumer;
+ u32 ulStatus = 0;
+ short int ErqIndex;
+ u8 CompleteExchange = 0; // e.g. ACC replies are complete
+ u8 SestType = 0;
+ u32 InboundData = 0;
- // Check that link is not down -- we can't start an exchange on a
- // down link!
+ // We will manipulate Tachlite chip registers here to successfully
+ // start exchanges.
- if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
- {
-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);
+ // Check that link is not down -- we can't start an exchange on a
+ // down link!
- if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame?
- {
- // Our most popular LinkService commands are port discovery types
- // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
- // events, so it makes no sense to Que them. However, ABTS should
- // be queued, since exchange sequences are likely destroyed by
- // Link Down events, and we want to notify other ports of broken
- // sequences by aborting the corresponding exchanges.
- if( pExchange->type != BLS_ABTS )
- {
- ulStatus = LNKDWN_OSLS;
- goto Done;
- // don't Que most LinkServ exchanges on LINK DOWN
- }
- }
+ if (fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
+ {
+ 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);
- printk("fcStartExchange: Que x_ID %Xh, type %Xh\n",
- ExchangeID, pExchange->type);
- pExchange->status |= EXCHANGE_QUEUED;
- ulStatus = EXCHANGE_QUEUED;
- goto Done;
- }
+ if (ExchangeID >= TACH_SEST_LEN) // Link Service Outbound frame?
+ {
+ // Our most popular LinkService commands are port discovery types
+ // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
+ // events, so it makes no sense to Que them. However, ABTS should
+ // be queued, since exchange sequences are likely destroyed by
+ // Link Down events, and we want to notify other ports of broken
+ // sequences by aborting the corresponding exchanges.
+ if (pExchange->type != BLS_ABTS) {
+ ulStatus = LNKDWN_OSLS;
+ goto Done;
+ // don't Que most LinkServ exchanges on LINK DOWN
+ }
+ }
- // Make sure ERQ has available space.
-
- producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
- consumer = (USHORT)fcChip->ERQ->consumerIndex;
- producer++; // We are testing for full que by incrementing
-
- if( producer >= ERQ_LEN ) // rollover condition?
- producer = 0;
- if( consumer != producer ) // ERQ not full?
- {
- // ****************** Need Atomic access to chip registers!!********
-
- // remember ERQ PI for copying IRB
- ErqIndex = (USHORT)fcChip->ERQ->producerIndex;
- fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
- // we have an ERQ slot! If SCSI command, need SEST slot
- // otherwise we are done.
-
- // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
- // set according to direction of data to/from Tachyon for SEST assists.
- // For consistency, enforce this rule for Link Service (non-SEST)
- // exchanges as well.
-
- // fix-up the X_ID field in IRB
- pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
-
- // fix-up the X_ID field in fchs -- depends on Originator or Responder,
- // outgoing or incoming data?
- switch( pExchange->type )
- {
- // ORIGINATOR types... we're setting our OX_ID and
- // defaulting the responder's RX_ID to 0xFFFF
-
- case SCSI_IRE:
- // Requirement: set MSB of x_ID for Incoming TL data
- // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
- InboundData = 0x8000;
-
- case SCSI_IWE:
- SestType = TRUE;
- pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
- pExchange->fchs.ox_rx_id <<= 16; // MSW shift
- pExchange->fchs.ox_rx_id |= 0xffff; // add default RX_ID
-
- // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
- // (not necessary for IRE -- data buffer unused)
- if( pExchange->type == SCSI_IWE)
- {
- fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id =
- pExchange->fchs.ox_rx_id;
-
- }
-
- break;
-
-
- case FCS_NSR: // ext. link service Name Service Request
- case ELS_SCR: // ext. link service State Change Registration
- case ELS_FDISC:// ext. link service login
- case ELS_FLOGI:// ext. link service login
- case ELS_LOGO: // FC-PH extended link service logout
- case BLS_NOP: // Basic link service No OPeration
- case ELS_PLOGI:// ext. link service login (PLOGI)
- case ELS_PDISC:// ext. link service login (PDISC)
- case ELS_PRLI: // ext. link service process login
-
- pExchange->fchs.ox_rx_id = ExchangeID;
- pExchange->fchs.ox_rx_id <<= 16; // MSW shift
- pExchange->fchs.ox_rx_id |= 0xffff; // and RX_ID
+ printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", ExchangeID, pExchange->type);
+ pExchange->status |= EXCHANGE_QUEUED;
+ ulStatus = EXCHANGE_QUEUED;
+ goto Done;
+ }
+ // Make sure ERQ has available space.
- break;
-
+ producer = (u16) fcChip->ERQ->producerIndex; // copies for logical arith.
+ consumer = (u16) fcChip->ERQ->consumerIndex;
+ producer++; // We are testing for full que by incrementing
+
+ if (producer >= ERQ_LEN) // rollover condition?
+ producer = 0;
+ if (consumer != producer) // ERQ not full?
+ {
+ // ****************** Need Atomic access to chip registers!!********
+ // remember ERQ PI for copying IRB
+ ErqIndex = (u16) fcChip->ERQ->producerIndex;
+ fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
+ // we have an ERQ slot! If SCSI command, need SEST slot
+ // otherwise we are done.
+
+ // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
+ // set according to direction of data to/from Tachyon for SEST assists.
+ // For consistency, enforce this rule for Link Service (non-SEST)
+ // exchanges as well.
+
+ // fix-up the X_ID field in IRB
+ pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
+
+ // fix-up the X_ID field in fchs -- depends on Originator or Responder,
+ // outgoing or incoming data?
+ switch (pExchange->type) {
+ // ORIGINATOR types... we're setting our OX_ID and
+ // defaulting the responder's RX_ID to 0xFFFF
+
+ case SCSI_IRE:
+ // Requirement: set MSB of x_ID for Incoming TL data
+ // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
+ InboundData = 0x8000;
+
+ case SCSI_IWE:
+ SestType = 1;
+ pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
+ pExchange->fchs.ox_rx_id <<= 16; // MSW shift
+ pExchange->fchs.ox_rx_id |= 0xffff; // add default RX_ID
+
+ // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
+ // (not necessary for IRE -- data buffer unused)
+ if (pExchange->type == SCSI_IWE) {
+ fcChip->SEST->DataHDR[ExchangeID].ox_rx_id = pExchange->fchs.ox_rx_id;
+ }
- // RESPONDER types... we must set our RX_ID while preserving
- // sender's OX_ID
- // outgoing (or no) data
- case ELS_RJT: // extended link service reject
- case ELS_LOGO_ACC: // FC-PH extended link service logout accept
- case ELS_ACC: // ext. generic link service accept
- case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
- case ELS_PRLI_ACC: // ext. link service process login accept
-
- CompleteExchange = TRUE; // Reply (ACC or RJT) is end of exchange
- pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
-
- break;
-
-
- // since we are a Responder, OX_ID should already be set by
- // cpqfcTSBuildExchange(). We need to -OR- in RX_ID
- case SCSI_TWE:
- SestType = TRUE;
- // Requirement: set MSB of x_ID for Incoming TL data
- // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-
- pExchange->fchs.ox_rx_id &= 0xFFFF0000; // clear RX_ID
- // Requirement: set MSB of RX_ID for Incoming TL data
- // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
- pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
- break;
-
-
- case SCSI_TRE:
- SestType = TRUE;
-
- // there is no XRDY for SEST target read; the data
- // header needs to be updated. Also update the RSP
- // exchange IDs for the status frame, in case it is sent automatically
- fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
- fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id =
- fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
-
- // for easier FCP response logic (works for TWE and TRE),
- // copy exchange IDs. (Not needed if TRE 'RSP' bit set)
- pExchange->fchs.ox_rx_id =
- fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
-
- break;
+ break;
- case FCP_RESPONSE: // using existing OX_ID/ RX_ID pair,
- // start SFS FCP-RESPONSE frame
- // OX/RX_ID should already be set! (See "fcBuild" above)
- CompleteExchange = TRUE; // RSP is end of FCP-SCSI exchange
+ case FCS_NSR: // ext. link service Name Service Request
+ case ELS_SCR: // ext. link service State Change Registration
+ case ELS_FDISC: // ext. link service login
+ case ELS_FLOGI: // ext. link service login
+ case ELS_LOGO: // FC-PH extended link service logout
+ case BLS_NOP: // Basic link service No OPeration
+ case ELS_PLOGI: // ext. link service login (PLOGI)
+ case ELS_PDISC: // ext. link service login (PDISC)
+ case ELS_PRLI: // ext. link service process login
-
- break;
+ pExchange->fchs.ox_rx_id = ExchangeID;
+ pExchange->fchs.ox_rx_id <<= 16; // MSW shift
+ pExchange->fchs.ox_rx_id |= 0xffff; // and RX_ID
+ break;
- case BLS_ABTS_RJT: // uses new RX_ID, since SEST x_ID non-existent
- case BLS_ABTS_ACC: // using existing OX_ID/ RX_ID pair from SEST entry
- CompleteExchange = TRUE; // ACC or RJT marks end of FCP-SCSI exchange
- case BLS_ABTS: // using existing OX_ID/ RX_ID pair from SEST entry
- break;
+ // RESPONDER types... we must set our RX_ID while preserving
+ // sender's OX_ID
+ // outgoing (or no) data
+ case ELS_RJT: // extended link service reject
+ case ELS_LOGO_ACC: // FC-PH extended link service logout accept
+ case ELS_ACC: // ext. generic link service accept
+ case ELS_PLOGI_ACC: // ext. link service login accept (PLOGI or PDISC)
+ case ELS_PRLI_ACC: // ext. link service process login accept
- default:
- printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
- pExchange->type, pExchange->type);
- return INVALID_ARGS;
- }
-
-
- // X_ID fields are entered -- copy IRB to Tachyon's ERQ
-
+ CompleteExchange = 1; // Reply (ACC or RJT) is end of exchange
+ pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
- memcpy(
- &fcChip->ERQ->QEntry[ ErqIndex ], // dest.
- &pExchange->IRB,
- 32); // fixed (hardware) length!
-
- PCI_TRACEO( ExchangeID, 0xA0)
-
- // ACTION! May generate INT and IMQ entry
- writel( fcChip->ERQ->producerIndex,
- fcChip->Registers.ERQproducerIndex.address);
+ break;
-
- if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame?
- {
-
- // wait for completion! (TDB -- timeout and chip reset)
-
- PCI_TRACEO( ExchangeID, 0xA4)
-
- enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
-
- down_interruptible( cpqfcHBAdata->TYOBcomplete);
-
- disable_irq( cpqfcHBAdata->HostAdapter->irq);
- PCI_TRACE( 0xA4)
-
- // On login exchanges, BAD_ALPA (non-existent port_id) results in
- // FTO (Frame Time Out) on the Outbound Completion message.
- // If we got an FTO status, complete the exchange (free up slot)
- if( CompleteExchange || // flag from Reply frames
- pExchange->status ) // typically, can get FRAME_TO
- {
- cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
- }
- }
+ // since we are a Responder, OX_ID should already be set by
+ // cpqfcTSBuildExchange(). We need to -OR- in RX_ID
+ case SCSI_TWE:
+ SestType = 1;
+ // Requirement: set MSB of x_ID for Incoming TL data
+ // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
- else // SEST Exchange
- {
- ulStatus = 0; // ship & pray success (e.g. FCP-SCSI)
-
- if( CompleteExchange ) // by Type of exchange (e.g. end-of-xchng)
- {
- cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
- }
-
- else
- pExchange->status &= ~EXCHANGE_QUEUED; // clear ExchangeQueued flag
+ pExchange->fchs.ox_rx_id &= 0xFFFF0000; // clear RX_ID
+ // Requirement: set MSB of RX_ID for Incoming TL data
+ // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
+ pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
+ break;
- }
- }
-
- else // ERQ 'producer' = 'consumer' and QUE is full
- {
- ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
- }
-
-Done:
- PCI_TRACE( 0xA0)
- return ulStatus;
+ case SCSI_TRE:
+ SestType = 1;
+
+ // there is no XRDY for SEST target read; the data
+ // header needs to be updated. Also update the RSP
+ // exchange IDs for the status frame, in case it is sent automatically
+ fcChip->SEST->DataHDR[ExchangeID].ox_rx_id |= ExchangeID;
+ fcChip->SEST->RspHDR[ExchangeID].ox_rx_id = fcChip->SEST->DataHDR[ExchangeID].ox_rx_id;
+
+ // for easier FCP response logic (works for TWE and TRE),
+ // copy exchange IDs. (Not needed if TRE 'RSP' bit set)
+ pExchange->fchs.ox_rx_id = fcChip->SEST->DataHDR[ExchangeID].ox_rx_id;
+
+ break;
+
+
+ case FCP_RESPONSE: // using existing OX_ID/ RX_ID pair,
+ // start SFS FCP-RESPONSE frame
+ // OX/RX_ID should already be set! (See "fcBuild" above)
+ CompleteExchange = 1; // RSP is end of FCP-SCSI exchange
+
+
+ break;
+
+
+ case BLS_ABTS_RJT: // uses new RX_ID, since SEST x_ID non-existent
+ case BLS_ABTS_ACC: // using existing OX_ID/ RX_ID pair from SEST entry
+ CompleteExchange = 1; // ACC or RJT marks end of FCP-SCSI exchange
+ case BLS_ABTS: // using existing OX_ID/ RX_ID pair from SEST entry
+
+
+ break;
+
+
+ default:
+ printk("Error on fcStartExchange: undefined type %Xh(%d)\n", pExchange->type, pExchange->type);
+ return INVALID_ARGS;
+ }
+
+
+ // X_ID fields are entered -- copy IRB to Tachyon's ERQ
+
+
+ memcpy(&fcChip->ERQ->QEntry[ErqIndex], // dest.
+ &pExchange->IRB, 32); // fixed (hardware) length!
+
+ PCI_TRACEO(ExchangeID, 0xA0)
+ // ACTION! May generate INT and IMQ entry
+ writel(fcChip->ERQ->producerIndex, fcChip->Registers.ERQproducerIndex.address);
+
+
+ if (ExchangeID >= TACH_SEST_LEN) // Link Service Outbound frame?
+ {
+
+ // wait for completion! (TDB -- timeout and chip reset)
+
+
+ PCI_TRACEO(ExchangeID, 0xA4)
+
+ enable_irq(dev->HostAdapter->irq); // only way to get Sem.
+
+ down_interruptible(dev->TYOBcomplete);
+
+ disable_irq(dev->HostAdapter->irq);
+ PCI_TRACE(0xA4)
+ // On login exchanges, BAD_ALPA (non-existent port_id) results in
+ // FTO (Frame Time Out) on the Outbound Completion message.
+ // If we got an FTO status, complete the exchange (free up slot)
+ if (CompleteExchange || // flag from Reply frames
+ pExchange->status) // typically, can get FRAME_TO
+ {
+ cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+ }
+ }
+
+ else // SEST Exchange
+ {
+ ulStatus = 0; // ship & pray success (e.g. FCP-SCSI)
+
+ if (CompleteExchange) // by Type of exchange (e.g. end-of-xchng)
+ {
+ cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+ }
+
+ else
+ pExchange->status &= ~EXCHANGE_QUEUED; // clear ExchangeQueued flag
+
+ }
+ }
+
+
+ else // ERQ 'producer' = 'consumer' and QUE is full
+ {
+ ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
+ }
+
+ Done:
+ PCI_TRACE(0xA0)
+ return ulStatus;
}
@@ -5839,408 +4774,364 @@
// (Least Recently Used) scheme.
-static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
+static s32 FindFreeExchange(PTACHYON fcChip, u32 type)
{
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- ULONG i;
- ULONG ulStatus=-1; // assume failure
-
-
- if( type == SCSI_IRE ||
- type == SCSI_TRE ||
- type == SCSI_IWE ||
- type == SCSI_TWE)
- {
- // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
- if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
- fcChip->fcSestExchangeLRU = 0;
- i = fcChip->fcSestExchangeLRU; // typically it's already free!
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ u32 i;
+ u32 ulStatus = -1; // assume failure
+
+
+ if (type == SCSI_IRE || type == SCSI_TRE || type == SCSI_IWE || type == SCSI_TWE) {
+ // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
+ if (fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
+ fcChip->fcSestExchangeLRU = 0;
+ i = fcChip->fcSestExchangeLRU; // typically it's already free!
+
+ if (Exchanges->fcExchange[i].type == 0) // check for "free" element
+ {
+ ulStatus = 0; // success!
+ }
- if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
- {
- ulStatus = 0; // success!
- }
-
- else
- { // YUK! we need to do a linear search for free element.
- // Fragmentation of the fcExchange array is due to excessively
- // long completions or timeouts.
-
- while( TRUE )
- {
- if( ++i >= TACH_SEST_LEN ) // rollover check
- i = 0; // beginning of SEST X_IDs
-
-// printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n",
-// i, Exchanges->fcExchange[i].type);
-
- if( Exchanges->fcExchange[i].type == 0 ) // "free"?
- {
- ulStatus = 0; // success!
- break;
- }
- if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
- {
- printk( "SEST X_ID space full\n");
- break; // failed - prevent inf. loop
- }
- }
- }
- fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
- }
+ else { // YUK! we need to do a linear search for free element.
+ // Fragmentation of the fcExchange array is due to excessively
+ // long completions or timeouts.
+
+ while (1) {
+ if (++i >= TACH_SEST_LEN) // rollover check
+ i = 0; // beginning of SEST X_IDs
+
+// printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n",
+// i, Exchanges->fcExchange[i].type);
+
+ if (Exchanges->fcExchange[i].type == 0) // "free"?
+ {
+ ulStatus = 0; // success!
+ break;
+ }
+ if (i == fcChip->fcSestExchangeLRU) // wrapped-around array?
+ {
+ printk("SEST X_ID space full\n");
+ break; // failed - prevent inf. loop
+ }
+ }
+ }
+ fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
+ }
+ else // Link Service type - X_IDs should be from TACH_SEST_LEN
+ // to TACH_MAX_XID
+ {
+ if (fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
+ fcChip->fcLsExchangeLRU < TACH_SEST_LEN) // (e.g. startup)
+ fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
+
+ i = fcChip->fcLsExchangeLRU; // typically it's already free!
+ if (Exchanges->fcExchange[i].type == 0) // check for "free" element
+ {
+ ulStatus = 0; // success!
+ }
-
-
- else // Link Service type - X_IDs should be from TACH_SEST_LEN
- // to TACH_MAX_XID
- {
- if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
- fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
- fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
+ else { // YUK! we need to do a linear search for free element
+ // Fragmentation of the fcExchange array is due to excessively
+ // long completions or timeouts.
+
+ while (1) {
+ if (++i >= TACH_MAX_XID) // rollover check
+ i = TACH_SEST_LEN; // beginning of Link Service X_IDs
+
+// printk( "looping for xchng ID: i=%d, type=%Xh\n",
+// i, Exchanges->fcExchange[i].type);
+
+ if (Exchanges->fcExchange[i].type == 0) // "free"?
+ {
+ ulStatus = 0; // success!
+ break;
+ }
+ if (i == fcChip->fcLsExchangeLRU) // wrapped-around array?
+ {
+ printk("LinkService X_ID space full\n");
+ break; // failed - prevent inf. loop
+ }
+ }
+ }
+ fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
- i = fcChip->fcLsExchangeLRU; // typically it's already free!
- if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
- {
- ulStatus = 0; // success!
- }
-
- else
- { // YUK! we need to do a linear search for free element
- // Fragmentation of the fcExchange array is due to excessively
- // long completions or timeouts.
-
- while( TRUE )
- {
- if( ++i >= TACH_MAX_XID ) // rollover check
- i = TACH_SEST_LEN;// beginning of Link Service X_IDs
-
-// printk( "looping for xchng ID: i=%d, type=%Xh\n",
-// i, Exchanges->fcExchange[i].type);
-
- if( Exchanges->fcExchange[i].type == 0 ) // "free"?
- {
- ulStatus = 0; // success!
- break;
- }
- if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
- {
- printk( "LinkService X_ID space full\n");
- break; // failed - prevent inf. loop
- }
- }
- }
- fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
+ }
- }
+ if (!ulStatus) // success?
+ Exchanges->fcExchange[i].type = type; // allocate it.
- if( !ulStatus ) // success?
- Exchanges->fcExchange[i].type = type; // allocate it.
-
- else
- i = -1; // error - all exchanges "open"
+ else
+ i = -1; // error - all exchanges "open"
- return i;
+ return i;
}
-static void
-cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev,
- PTACHYON fcChip,
- ULONG x_ID)
+static void cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev, PTACHYON fcChip, u32 x_ID)
{
// Unmaps the memory regions used to hold the scatter gather lists
PSGPAGES i;
// Were there any such regions needing unmapping?
- if (! USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
- return; // No such regions, we're outta here.
+ if (!USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
+ return; // No such regions, we're outta here.
// for each extended scatter gather region needing unmapping...
- for (i=fcChip->SEST->sgPages[x_ID] ; i != NULL ; i = i->next)
- pci_unmap_single(pcidev, i->busaddr, i->maplen,
- scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+ for (i = fcChip->SEST->sgPages[x_ID]; i != NULL; i = i->next)
+ pci_unmap_single(pcidev, i->busaddr, i->maplen, scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
}
// Called also from cpqfcTScontrol.o, so can't be static
-void
-cpqfc_pci_unmap(struct pci_dev *pcidev,
- Scsi_Cmnd *cmd,
- PTACHYON fcChip,
- ULONG x_ID)
+void cpqfc_pci_unmap(struct pci_dev *pcidev, Scsi_Cmnd * cmd, PTACHYON fcChip, u32 x_ID)
{
// Undo the DMA mappings
if (cmd->use_sg) { // Used scatter gather list for data buffer?
cpqfc_pci_unmap_extended_sg(pcidev, fcChip, x_ID);
- pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg,
- scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
// printk("umsg %d\n", cmd->use_sg);
- }
- else if (cmd->request_bufflen) {
+ } else if (cmd->request_bufflen) {
// printk("ums %p ", fcChip->SEST->u[ x_ID ].IWE.GAddr1);
- pci_unmap_single(pcidev, fcChip->SEST->u[ x_ID ].IWE.GAddr1,
- cmd->request_bufflen,
- scsi_to_pci_dma_dir(cmd->sc_data_direction));
- }
+ pci_unmap_single(pcidev, fcChip->SEST->u[x_ID].IWE.GAddr1, cmd->request_bufflen, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ }
}
// We call this routine to free an Exchange for any reason:
// completed successfully, completed with error, aborted, etc.
-// returns FALSE if Exchange failed and "retry" is acceptable
-// returns TRUE if Exchange was successful, or retry is impossible
+// returns 0 if Exchange failed and "retry" is acceptable
+// returns 1 if Exchange was successful, or retry is impossible
// (e.g. port/device gone).
//scompleteexchange
-void cpqfcTSCompleteExchange(
- struct pci_dev *pcidev,
- PTACHYON fcChip,
- ULONG x_ID)
-{
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- int already_unmapped = 0;
-
- if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
- {
- if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
- {
-// TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
- printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
- Exchanges->fcExchange[ x_ID ].type);
+void cpqfcTSCompleteExchange(struct pci_dev *pcidev, PTACHYON fcChip, u32 x_ID)
+{
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ int already_unmapped = 0;
- goto CleanUpSestResources; // this path should be very rare.
- }
+ if (x_ID < TACH_SEST_LEN) // SEST-based (or LinkServ for FCP exchange)
+ {
+ if (Exchanges->fcExchange[x_ID].Cmnd == NULL) // what#@!
+ {
+// TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+ printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID, Exchanges->fcExchange[x_ID].type);
- // we have Linux Scsi Cmnd ptr..., now check our Exchange status
- // to decide how to complete this SEST FCP exchange
+ goto CleanUpSestResources; // this path should be very rare.
+ }
+ // we have Linux Scsi Cmnd ptr..., now check our Exchange status
+ // to decide how to complete this SEST FCP exchange
- if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
- // or abnormal exchange completion
- {
- // set FCP Link statistics
-
- if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
- fcChip->fcStats.timeouts++;
- if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
- fcChip->fcStats.FC4aborted++;
- if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
- fcChip->fcStats.CntErrors++;
- if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
- fcChip->fcStats.linkFailTX++;
- if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
- fcChip->fcStats.linkFailRX++;
- if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
- fcChip->fcStats.CntErrors++;
-
- // First, see if the Scsi upper level initiated an ABORT on this
- // exchange...
- if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
- {
- printk(" DID_ABORT, x_ID %Xh, Cmnd %p ",
- x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
- goto CleanUpSestResources; // (we don't expect Linux _aborts)
- }
-
- // Did our driver timeout the Exchange, or did Tachyon indicate
- // a failure during transmission? Ask for retry with "SOFT_ERROR"
- else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
- {
-// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
-// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
- Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
- }
-
- // Did frame(s) for an open exchange arrive in the SFQ,
- // meaning the SEST was unable to process them?
- else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME)
- {
-// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
-// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
- Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
- }
-
- // Did our driver timeout the Exchange, or did Tachyon indicate
- // a failure during transmission? Ask for retry with "SOFT_ERROR"
- else if(
- (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
- (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) )
-
-
- {
-// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
-// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
- Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-
-
- }
-
- // e.g., a LOGOut happened, or device never logged back in.
- else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED)
- {
-// printk(" *LOGOut or timeout on login!* ");
- // trigger?
-// TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-
- Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
- }
-
-
- // Did Tachyon indicate a CNT error? We need further analysis
- // to determine if the exchange is acceptable
- else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
- {
- UCHAR ScsiStatus;
- FCP_STATUS_RESPONSE *pFcpStatus =
- (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
-
- ScsiStatus = pFcpStatus->fcp_status >>24;
-
- // If the command is a SCSI Read/Write type, we don't tolerate
- // count errors of any kind; assume the count error is due to
- // a dropped frame and ask for retry...
-
- 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) )
- &&
- ScsiStatus == 0 )
- {
- // ask for retry
-/* printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n",
- x_ID, Exchanges->fcExchange[ x_ID ].status,
- Exchanges->fcExchange[ x_ID ].Cmnd);*/
- Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
- }
-
- else // need more analysis
- {
- cpqfcTSCheckandSnoopFCP(fcChip, x_ID); // (will set ->result)
- }
- }
-
- // default: NOTE! We don't ever want to get here. Getting here
- // implies something new is happening that we've never had a test
- // case for. Need code maintenance! Return "ERROR"
- else
- {
- unsigned int stat = Exchanges->fcExchange[ x_ID ].status;
- printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p",
- Exchanges->fcExchange[ x_ID ].status, x_ID,
- Exchanges->fcExchange[ x_ID ].Cmnd);
-
- if (stat & INVALID_ARGS) printk(" INVALID_ARGS ");
- if (stat & LNKDWN_OSLS) printk(" LNKDWN_OSLS ");
- if (stat & LNKDWN_LASER) printk(" LNKDWN_LASER ");
- if (stat & OUTQUE_FULL) printk(" OUTQUE_FULL ");
- if (stat & DRIVERQ_FULL) printk(" DRIVERQ_FULL ");
- if (stat & SEST_FULL) printk(" SEST_FULL ");
- if (stat & BAD_ALPA) printk(" BAD_ALPA ");
- if (stat & OVERFLOW) printk(" OVERFLOW ");
- if (stat & COUNT_ERROR) printk(" COUNT_ERROR ");
- if (stat & LINKFAIL_RX) printk(" LINKFAIL_RX ");
- if (stat & ABORTSEQ_NOTIFY) printk(" ABORTSEQ_NOTIFY ");
- if (stat & LINKFAIL_TX) printk(" LINKFAIL_TX ");
- if (stat & HOSTPROG_ERR) printk(" HOSTPROG_ERR ");
- if (stat & FRAME_TO) printk(" FRAME_TO ");
- if (stat & INV_ENTRY) printk(" INV_ENTRY ");
- if (stat & SESTPROG_ERR) printk(" SESTPROG_ERR ");
- if (stat & OUTBOUND_TIMEOUT) printk(" OUTBOUND_TIMEOUT ");
- if (stat & INITIATOR_ABORT) printk(" INITIATOR_ABORT ");
- if (stat & MEMPOOL_FAIL) printk(" MEMPOOL_FAIL ");
- if (stat & FC2_TIMEOUT) printk(" FC2_TIMEOUT ");
- if (stat & TARGET_ABORT) printk(" TARGET_ABORT ");
- if (stat & EXCHANGE_QUEUED) printk(" EXCHANGE_QUEUED ");
- if (stat & PORTID_CHANGED) printk(" PORTID_CHANGED ");
- if (stat & DEVICE_REMOVED) printk(" DEVICE_REMOVED ");
- if (stat & SFQ_FRAME) printk(" SFQ_FRAME ");
- printk("\n");
+ if (Exchanges->fcExchange[x_ID].status) // perhaps a Tach indicated problem,
+ // or abnormal exchange completion
+ {
+ // set FCP Link statistics
+
+ if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
+ fcChip->fcStats.timeouts++;
+ if (Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
+ fcChip->fcStats.FC4aborted++;
+ if (Exchanges->fcExchange[x_ID].status & COUNT_ERROR)
+ fcChip->fcStats.CntErrors++;
+ if (Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
+ fcChip->fcStats.linkFailTX++;
+ if (Exchanges->fcExchange[x_ID].status & LINKFAIL_RX)
+ fcChip->fcStats.linkFailRX++;
+ if (Exchanges->fcExchange[x_ID].status & OVERFLOW)
+ fcChip->fcStats.CntErrors++;
+
+ // First, see if the Scsi upper level initiated an ABORT on this
+ // exchange...
+ if (Exchanges->fcExchange[x_ID].status == INITIATOR_ABORT) {
+ printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", x_ID, Exchanges->fcExchange[x_ID].Cmnd);
+ goto CleanUpSestResources; // (we don't expect Linux _aborts)
+ }
+ // Did our driver timeout the Exchange, or did Tachyon indicate
+ // a failure during transmission? Ask for retry with "SOFT_ERROR"
+ else if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) {
+// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
+// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+ Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+ }
+ // Did frame(s) for an open exchange arrive in the SFQ,
+ // meaning the SEST was unable to process them?
+ else if (Exchanges->fcExchange[x_ID].status & SFQ_FRAME) {
+// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
+// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+ Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+ }
+ // Did our driver timeout the Exchange, or did Tachyon indicate
+ // a failure during transmission? Ask for retry with "SOFT_ERROR"
+ else if ((Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) ||
+ (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))
+
+ {
+// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
+// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+ Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
- Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
- }
- }
- else // definitely no Tach problem, but perhaps an FCP problem
- {
- // set FCP Link statistic
- fcChip->fcStats.ok++;
- cpqfcTSCheckandSnoopFCP( fcChip, x_ID); // (will set ->result)
- }
- cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd,
- fcChip, x_ID); // undo DMA mappings.
- already_unmapped = 1;
-
- // OK, we've set the Scsi "->result" field, so proceed with calling
- // Linux Scsi "done" (if not NULL), and free any kernel memory we
- // may have allocated for the exchange.
-
- PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
- // complete the command back to upper Scsi drivers
- if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
- {
- // Calling "done" on an Linux _abort() aborted
- // Cmnd causes a kernel panic trying to re-free mem.
- // Actually, we shouldn't do anything with an _abort CMND
- if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
- {
- PCI_TRACE(0xAC)
- call_scsi_done(Exchanges->fcExchange[ x_ID ].Cmnd);
- }
- else
- {
- Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
-// printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
-// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
- }
- }
- else{
- Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
- printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
- Exchanges->fcExchange[ x_ID ].type,
- Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);
- printk(" cpqfcTS: Null scsi_done function pointer!\n");
- }
+ }
+ // e.g., a LOGOut happened, or device never logged back in.
+ else if (Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) {
+// printk(" *LOGOut or timeout on login!* ");
+// trigger?
+// TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+ Exchanges->fcExchange[x_ID].Cmnd->result = (DID_BAD_TARGET << 16);
+ }
+
+ // Did Tachyon indicate a CNT error? We need further analysis
+ // to determine if the exchange is acceptable
+ else if (Exchanges->fcExchange[x_ID].status == COUNT_ERROR) {
+ u8 ScsiStatus;
+ FCP_STATUS_RESPONSE *pFcpStatus = (PFCP_STATUS_RESPONSE) & fcChip->SEST->RspHDR[x_ID].pl;
+
+ ScsiStatus = pFcpStatus->fcp_status >> 24;
+
+ // If the command is a SCSI Read/Write type, we don't tolerate
+ // count errors of any kind; assume the count error is due to
+ // a dropped frame and ask for retry...
+
+ 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))
+ && ScsiStatus == 0) {
+ // ask for retry
+// printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n",
+// x_ID, Exchanges->fcExchange[ x_ID ].status,
+// Exchanges->fcExchange[ x_ID ].Cmnd);
+ Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+ }
+
+ else // need more analysis
+ {
+ cpqfcTSCheckandSnoopFCP(fcChip, x_ID); // (will set ->result)
+ }
+ }
+ // default: NOTE! We don't ever want to get here. Getting here
+ // implies something new is happening that we've never had a test
+ // case for. Need code maintenance! Return "ERROR"
+ else {
+ unsigned int stat = Exchanges->fcExchange[x_ID].status;
+ printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p", Exchanges->fcExchange[x_ID].status, x_ID, Exchanges->fcExchange[x_ID].Cmnd);
+
+ if (stat & INVALID_ARGS)
+ printk(" INVALID_ARGS ");
+ if (stat & LNKDWN_OSLS)
+ printk(" LNKDWN_OSLS ");
+ if (stat & LNKDWN_LASER)
+ printk(" LNKDWN_LASER ");
+ if (stat & OUTQUE_FULL)
+ printk(" OUTQUE_FULL ");
+ if (stat & DRIVERQ_FULL)
+ printk(" DRIVERQ_FULL ");
+ if (stat & SEST_FULL)
+ printk(" SEST_FULL ");
+ if (stat & BAD_ALPA)
+ printk(" BAD_ALPA ");
+ if (stat & OVERFLOW)
+ printk(" OVERFLOW ");
+ if (stat & COUNT_ERROR)
+ printk(" COUNT_ERROR ");
+ if (stat & LINKFAIL_RX)
+ printk(" LINKFAIL_RX ");
+ if (stat & ABORTSEQ_NOTIFY)
+ printk(" ABORTSEQ_NOTIFY ");
+ if (stat & LINKFAIL_TX)
+ printk(" LINKFAIL_TX ");
+ if (stat & HOSTPROG_ERR)
+ printk(" HOSTPROG_ERR ");
+ if (stat & FRAME_TO)
+ printk(" FRAME_TO ");
+ if (stat & INV_ENTRY)
+ printk(" INV_ENTRY ");
+ if (stat & SESTPROG_ERR)
+ printk(" SESTPROG_ERR ");
+ if (stat & OUTBOUND_TIMEOUT)
+ printk(" OUTBOUND_TIMEOUT ");
+ if (stat & INITIATOR_ABORT)
+ printk(" INITIATOR_ABORT ");
+ if (stat & MEMPOOL_FAIL)
+ printk(" MEMPOOL_FAIL ");
+ if (stat & FC2_TIMEOUT)
+ printk(" FC2_TIMEOUT ");
+ if (stat & TARGET_ABORT)
+ printk(" TARGET_ABORT ");
+ if (stat & EXCHANGE_QUEUED)
+ printk(" EXCHANGE_QUEUED ");
+ if (stat & PORTID_CHANGED)
+ printk(" PORTID_CHANGED ");
+ if (stat & DEVICE_REMOVED)
+ printk(" DEVICE_REMOVED ");
+ if (stat & SFQ_FRAME)
+ printk(" SFQ_FRAME ");
+ printk("\n");
+
+ Exchanges->fcExchange[x_ID].Cmnd->result = (DID_ERROR << 16);
+ }
+ } else // definitely no Tach problem, but perhaps an FCP problem
+ {
+ // set FCP Link statistic
+ fcChip->fcStats.ok++;
+ cpqfcTSCheckandSnoopFCP(fcChip, x_ID); // (will set ->result)
+ }
+
+ cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, fcChip, x_ID); // undo DMA mappings.
+ already_unmapped = 1;
+
+ // OK, we've set the Scsi "->result" field, so proceed with calling
+ // Linux Scsi "done" (if not NULL), and free any kernel memory we
+ // may have allocated for the exchange.
+
+ PCI_TRACEO((u32) Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
+ // complete the command back to upper Scsi drivers
+ if (Exchanges->fcExchange[x_ID].Cmnd->scsi_done != NULL) {
+ // Calling "done" on an Linux _abort() aborted
+ // Cmnd causes a kernel panic trying to re-free mem.
+ // Actually, we shouldn't do anything with an _abort CMND
+ if (Exchanges->fcExchange[x_ID].Cmnd->result != (DID_ABORT << 16)) {
+ PCI_TRACE(0xAC)
+ call_scsi_done(Exchanges->fcExchange[x_ID].Cmnd);
+ } else {
+ Exchanges->fcExchange[x_ID].Cmnd->SCp.sent_command = 0;
+// printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
+// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+ }
+ } else {
+ Exchanges->fcExchange[x_ID].Cmnd->SCp.sent_command = 0;
+ printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID, Exchanges->fcExchange[x_ID].type, Exchanges->fcExchange[x_ID].Cmnd->cmnd[0]);
+ printk(" cpqfcTS: Null scsi_done function pointer!\n");
+ }
- // Now, clean up non-Scsi_Cmnd items...
+ // Now, clean up non-Scsi_Cmnd items...
CleanUpSestResources:
-
- if (!already_unmapped)
- cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd,
- fcChip, x_ID); // undo DMA mappings.
-
- // Was an Extended Scatter/Gather page allocated? We know
- // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
- if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
- {
- PSGPAGES p, next;
- // extended S/G list was used -- Free the allocated ext. S/G pages
- for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
- next = p->next;
- kfree(p);
- }
- fcChip->SEST->sgPages[x_ID] = NULL;
- }
-
- Exchanges->fcExchange[ x_ID ].Cmnd = NULL;
- } // Done with FCP (SEST) exchanges
-
-
- // the remaining logic is common to ALL Exchanges:
- // FCP(SEST) and LinkServ.
-
- Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!
- Exchanges->fcExchange[ x_ID ].status = 0;
-
- PCI_TRACEO( x_ID, 0xAC)
-
-
- return;
-} // (END of CompleteExchange function)
-
+ if (!already_unmapped)
+ cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, fcChip, x_ID); // undo DMA mappings.
+
+ // Was an Extended Scatter/Gather page allocated? We know
+ // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
+ if (!(fcChip->SEST->u[x_ID].IWE.Buff_Off & 0x80000000)) {
+ PSGPAGES p, next;
+
+ // extended S/G list was used -- Free the allocated ext. S/G pages
+ for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
+ next = p->next;
+ kfree(p);
+ }
+ fcChip->SEST->sgPages[x_ID] = NULL;
+ }
+
+ Exchanges->fcExchange[x_ID].Cmnd = NULL;
+ } // Done with FCP (SEST) exchanges
+
+
+ // the remaining logic is common to ALL Exchanges:
+ // FCP(SEST) and LinkServ.
+
+ Exchanges->fcExchange[x_ID].type = 0; // there -- FREE!
+ Exchanges->fcExchange[x_ID].status = 0;
+
+ PCI_TRACEO(x_ID, 0xAC)
+} // (END of CompleteExchange function)
+
@@ -6249,161 +5140,137 @@
// device types, etc., to facilitate the Fibre-Channel to SCSI
// "mapping".
// (Watch for BIG Endian confusion on some payload fields)
-void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
+void cpqfcTSCheckandSnoopFCP(PTACHYON fcChip, u32 x_ID)
{
- FC_EXCHANGES *Exchanges = fcChip->Exchanges;
- Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
- FCP_STATUS_RESPONSE *pFcpStatus =
- (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
- UCHAR ScsiStatus;
+ FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ Scsi_Cmnd *Cmnd = Exchanges->fcExchange[x_ID].Cmnd;
+ FCP_STATUS_RESPONSE *pFcpStatus = (PFCP_STATUS_RESPONSE) & fcChip->SEST->RspHDR[x_ID].pl;
+ u8 ScsiStatus;
- ScsiStatus = pFcpStatus->fcp_status >>24;
+ ScsiStatus = pFcpStatus->fcp_status >> 24;
#ifdef FCP_COMPLETION_DBG
- printk("ScsiStatus = 0x%X\n", ScsiStatus);
-#endif
+ printk("ScsiStatus = 0x%X\n", ScsiStatus);
+#endif
- // First, check FCP status
- if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
- {
- // check response code (RSP_CODE) -- most popular is bad len
- // 1st 4 bytes of rsp info -- only byte 3 interesting
- if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
- {
+ // First, check FCP status
+ if (pFcpStatus->fcp_status & FCP_RSP_LEN_VALID) {
+ // check response code (RSP_CODE) -- most popular is bad len
+ // 1st 4 bytes of rsp info -- only byte 3 interesting
+ if (pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN) {
- // do we EVER get here?
- printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
- }
- }
+ // do we EVER get here?
+ printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
+ }
+ }
+ // for now, go by the ScsiStatus, and manipulate certain
+ // commands when necessary...
+ if (ScsiStatus == 0) // SCSI status byte "good"?
+ {
+ Cmnd->result = 0; // everything's OK
- // for now, go by the ScsiStatus, and manipulate certain
- // commands when necessary...
- if( ScsiStatus == 0) // SCSI status byte "good"?
- {
- Cmnd->result = 0; // everything's OK
+ if ((Cmnd->cmnd[0] == INQUIRY)) {
+ u8 *InquiryData = Cmnd->request_buffer;
+ PFC_LOGGEDIN_PORT pLoggedInPort;
+
+ // We need to manipulate INQUIRY
+ // strings for COMPAQ RAID controllers to force
+ // Linux to scan additional LUNs. Namely, set
+ // the Inquiry string byte 2 (ANSI-approved version)
+ // to 2.
+
+ if (!memcmp(&InquiryData[8], "COMPAQ", 6)) {
+ InquiryData[2] = 0x2; // claim SCSI-2 compliance,
+ // so multiple LUNs may be scanned.
+ // (no SCSI-2 problems known in CPQ)
+ }
+ // snoop the Inquiry to detect Disk, Tape, etc. type
+ // (search linked list for the port_id we sent INQUIRY to)
+ pLoggedInPort = fcFindLoggedInPort(fcChip, NULL, // DON'T search Scsi Nexus (we will set it)
+ Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF, NULL, // DON'T search linked list for FC WWN
+ NULL); // DON'T care about end of list
+
+ if (pLoggedInPort) {
+ pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
+ } else {
+ printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n", Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF);
+ }
+ }
+ }
- if( (Cmnd->cmnd[0] == INQUIRY))
- {
- UCHAR *InquiryData = Cmnd->request_buffer;
- PFC_LOGGEDIN_PORT pLoggedInPort;
+ // Scsi Status not good -- pass it back to caller
- // We need to manipulate INQUIRY
- // strings for COMPAQ RAID controllers to force
- // Linux to scan additional LUNs. Namely, set
- // the Inquiry string byte 2 (ANSI-approved version)
- // to 2.
-
- if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
- {
- InquiryData[2] = 0x2; // claim SCSI-2 compliance,
- // so multiple LUNs may be scanned.
- // (no SCSI-2 problems known in CPQ)
- }
-
- // snoop the Inquiry to detect Disk, Tape, etc. type
- // (search linked list for the port_id we sent INQUIRY to)
- pLoggedInPort = fcFindLoggedInPort( fcChip,
- NULL, // DON'T search Scsi Nexus (we will set it)
- Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,
- NULL, // DON'T search linked list for FC WWN
- NULL); // DON'T care about end of list
-
- if( pLoggedInPort )
- {
- pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
- }
- else
- {
- printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
- Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
- }
- }
- }
+ else {
+ Cmnd->result = ScsiStatus; // SCSI status byte is 1st
+ // check for valid "sense" data
- // Scsi Status not good -- pass it back to caller
+ if (pFcpStatus->fcp_status & FCP_SNS_LEN_VALID) { // limit Scsi Sense field length!
+ int SenseLen = pFcpStatus->fcp_sns_len >> 24; // (BigEndian) lower byte
- else
- {
- Cmnd->result = ScsiStatus; // SCSI status byte is 1st
-
- // check for valid "sense" data
+ SenseLen = SenseLen > sizeof(Cmnd->sense_buffer) ? sizeof(Cmnd->sense_buffer) : SenseLen;
- if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID )
- { // limit Scsi Sense field length!
- int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
-
- SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ?
- sizeof( Cmnd->sense_buffer) : SenseLen;
-
-
-#ifdef FCP_COMPLETION_DBG
- printk("copy sense_buffer %p, len %d, result %Xh\n",
- Cmnd->sense_buffer, SenseLen, Cmnd->result);
-#endif
-
- // NOTE: There is some dispute over the FCP response
- // format. Most FC devices assume that FCP_RSP_INFO
- // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
- // is (virtually) always 0 and the field is "invalid".
- // Some other devices assume that
- // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
- // when the FCP_RSP is invalid (this almost appears to be
- // one of those "religious" issues).
- // Consequently, we test the usual position of FCP_SNS_INFO
- // for 7Xh, since the SCSI sense format says the first
- // byte ("error code") should be 0x70 or 0x71. In practice,
- // we find that every device does in fact have 0x70 or 0x71
- // in the first byte position, so this test works for all
- // FC devices.
- // (This logic is especially effective for the CPQ/DEC HSG80
- // & HSG60 controllers).
-
- if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
- memcpy( Cmnd->sense_buffer,
- &pFcpStatus->fcp_sns_info[0], SenseLen);
- else
- {
- unsigned char *sbPtr =
- (unsigned char *)&pFcpStatus->fcp_sns_info[0];
- sbPtr -= 8; // back up 8 bytes hoping to find the
- // start of the sense buffer
- memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
- }
-
- // in the special case of Device Reset, tell upper layer
- // to immediately retry (with SOFT_ERROR status)
- // look for Sense Key Unit Attention (0x6) with ASC Device
- // Reset (0x29)
- // printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
- // SenseLen, Cmnd->sense_buffer[2],
- // Cmnd->sense_buffer[12]);
- if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
- (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
- {
- Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
- }
-
- // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
- else if( ((Cmnd->sense_buffer[2] & 0xF) == 0x4) && // "hardware error"
- (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code
- {
+
+#ifdef FCP_COMPLETION_DBG
+ printk("copy sense_buffer %p, len %d, result %Xh\n", Cmnd->sense_buffer, SenseLen, Cmnd->result);
+#endif
+
+ // NOTE: There is some dispute over the FCP response
+ // format. Most FC devices assume that FCP_RSP_INFO
+ // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
+ // is (virtually) always 0 and the field is "invalid".
+ // Some other devices assume that
+ // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
+ // when the FCP_RSP is invalid (this almost appears to be
+ // one of those "religious" issues).
+ // Consequently, we test the usual position of FCP_SNS_INFO
+ // for 7Xh, since the SCSI sense format says the first
+ // byte ("error code") should be 0x70 or 0x71. In practice,
+ // we find that every device does in fact have 0x70 or 0x71
+ // in the first byte position, so this test works for all
+ // FC devices.
+ // (This logic is especially effective for the CPQ/DEC HSG80
+ // & HSG60 controllers).
+
+ if ((pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70)
+ memcpy(Cmnd->sense_buffer, &pFcpStatus->fcp_sns_info[0], SenseLen);
+ else {
+ unsigned char *sbPtr = (unsigned char *) &pFcpStatus->fcp_sns_info[0];
+ sbPtr -= 8; // back up 8 bytes hoping to find the
+ // start of the sense buffer
+ memcpy(Cmnd->sense_buffer, sbPtr, SenseLen);
+ }
+
+ // in the special case of Device Reset, tell upper layer
+ // to immediately retry (with SOFT_ERROR status)
+ // look for Sense Key Unit Attention (0x6) with ASC Device
+ // Reset (0x29)
+ // printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
+ // SenseLen, Cmnd->sense_buffer[2],
+ // Cmnd->sense_buffer[12]);
+ if (((Cmnd->sense_buffer[2] & 0xF) == 0x6) && (Cmnd->sense_buffer[12] == 0x29)) // Sense Code "reset"
+ {
+ Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
+ }
+ // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
+ else if (((Cmnd->sense_buffer[2] & 0xF) == 0x4) && // "hardware error"
+ (Cmnd->sense_buffer[12] == 0x44)) // Addtl. Sense Code
+ {
// printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
-// Cmnd->channel, Cmnd->target, Cmnd->lun);
- Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
- }
-
- } // (end of sense len valid)
+// Cmnd->channel, Cmnd->target, Cmnd->lun);
+ Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
+ }
- // there is no sense data to help out Linux's Scsi layers...
- // We'll just return the Scsi status and hope he will "do the
- // right thing"
- else
- {
- // as far as we know, the Scsi status is sufficient
- Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
- }
- }
+ } // (end of sense len valid)
+
+ // there is no sense data to help out Linux's Scsi layers...
+ // We'll just return the Scsi status and hope he will "do the
+ // right thing"
+ else {
+ // as far as we know, the Scsi status is sufficient
+ Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
+ }
+ }
}
@@ -6413,118 +5280,108 @@
// remember BIG ENDIAN payload - DWord values must be byte-reversed
// (hence the affinity for byte pointer building).
-static int build_FCP_payload( Scsi_Cmnd *Cmnd,
- UCHAR* payload, ULONG type, ULONG fcp_dl )
+static int build_FCP_payload(Scsi_Cmnd * Cmnd, u8 * payload, u32 type, u32 fcp_dl)
{
- int i;
+ int i;
-
- switch( type)
- {
-
- case SCSI_IWE:
- case SCSI_IRE:
- // 8 bytes FCP_LUN
- // Peripheral Device or Volume Set addressing, and LUN mapping
- // When the FC port was looked up, we copied address mode
- // and any LUN mask to the scratch pad SCp.phase & .mode
-
- *payload++ = (UCHAR)Cmnd->SCp.phase;
-
- // Now, because of "lun masking"
- // (aka selective storage presentation),
- // the contiguous Linux Scsi lun number may not match the
- // device's lun number, so we may have to "map".
-
- *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
-
- // We don't know of anyone in the FC business using these
- // extra "levels" of addressing. In fact, confusion still exists
- // just using the FIRST level... ;-)
-
- *payload++ = 0; // 2nd level addressing
- *payload++ = 0;
- *payload++ = 0; // 3rd level addressing
- *payload++ = 0;
- *payload++ = 0; // 4th level addressing
- *payload++ = 0;
-
- // 4 bytes Control Field FCP_CNTL
- *payload++ = 0; // byte 0: (MSB) reserved
- *payload++ = 0; // byte 1: task codes
-
- // byte 2: task management flags
- // another "use" of the spare field to accomplish TDR
- // note combination needed
- if( (Cmnd->cmnd[0] == RELEASE) &&
- (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
- {
- Cmnd->cmnd[0] = 0; // issue "Test Unit Ready" for TDR
- *payload++ = 0x20; // target device reset bit
- }
- else
- *payload++ = 0; // no TDR
- // byte 3: (LSB) execution management codes
- // bit 0 write, bit 1 read (don't set together)
-
- if( fcp_dl != 0 )
- {
- if( type == SCSI_IWE ) // WRITE
- *payload++ = 1;
- else // READ
- *payload++ = 2;
- }
- else
- {
- // On some devices, if RD or WR bits are set,
- // and fcp_dl is 0, they will generate an error on the command.
- // (i.e., if direction is specified, they insist on a length).
- *payload++ = 0; // no data (necessary for CPQ)
- }
-
-
- // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
- // FCP_CDB allows 16 byte SCSI command descriptor blk;
- // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
- for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
- *payload++ = Cmnd->cmnd[i];
-
- if( Cmnd->cmd_len == 16 )
- {
- memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
- }
- payload+= (16 - i);
-
- // FCP_DL is largest number of expected data bytes
- // per CDB (i.e. read/write command)
- *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL
- *payload++ = (UCHAR)(fcp_dl >>16);
- *payload++ = (UCHAR)(fcp_dl >>8);
- *payload++ = (UCHAR)fcp_dl; // (LSB)
- break;
-
- case SCSI_TWE: // need FCP_XFER_RDY
- *payload++ = 0; // (4 bytes) DATA_RO (MSB byte 0)
- *payload++ = 0;
- *payload++ = 0;
- *payload++ = 0; // LSB (byte 3)
- // (4 bytes) BURST_LEN
- // size of following FCP_DATA payload
- *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL
- *payload++ = (UCHAR)(fcp_dl >>16);
- *payload++ = (UCHAR)(fcp_dl >>8);
- *payload++ = (UCHAR)fcp_dl; // (LSB)
- // 4 bytes RESERVED
- *payload++ = 0;
- *payload++ = 0;
- *payload++ = 0;
- *payload++ = 0;
- break;
- default:
- break;
- }
+ switch (type) {
- return 0;
-}
+ case SCSI_IWE:
+ case SCSI_IRE:
+ // 8 bytes FCP_LUN
+ // Peripheral Device or Volume Set addressing, and LUN mapping
+ // When the FC port was looked up, we copied address mode
+ // and any LUN mask to the scratch pad SCp.phase & .mode
+
+ *payload++ = (u8) Cmnd->SCp.phase;
+
+ // Now, because of "lun masking"
+ // (aka selective storage presentation),
+ // the contiguous Linux Scsi lun number may not match the
+ // device's lun number, so we may have to "map".
+
+ *payload++ = (u8) Cmnd->SCp.have_data_in;
+
+ // We don't know of anyone in the FC business using these
+ // extra "levels" of addressing. In fact, confusion still exists
+ // just using the FIRST level... ;-)
+
+ *payload++ = 0; // 2nd level addressing
+ *payload++ = 0;
+ *payload++ = 0; // 3rd level addressing
+ *payload++ = 0;
+ *payload++ = 0; // 4th level addressing
+ *payload++ = 0;
+
+ // 4 bytes Control Field FCP_CNTL
+ *payload++ = 0; // byte 0: (MSB) reserved
+ *payload++ = 0; // byte 1: task codes
+
+ // byte 2: task management flags
+ // another "use" of the spare field to accomplish TDR
+ // note combination needed
+ if ((Cmnd->cmnd[0] == RELEASE) && (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET)) {
+ Cmnd->cmnd[0] = 0; // issue "Test Unit Ready" for TDR
+ *payload++ = 0x20; // target device reset bit
+ } else
+ *payload++ = 0; // no TDR
+ // byte 3: (LSB) execution management codes
+ // bit 0 write, bit 1 read (don't set together)
+
+ if (fcp_dl != 0) {
+ if (type == SCSI_IWE) // WRITE
+ *payload++ = 1;
+ else // READ
+ *payload++ = 2;
+ } else {
+ // On some devices, if RD or WR bits are set,
+ // and fcp_dl is 0, they will generate an error on the command.
+ // (i.e., if direction is specified, they insist on a length).
+ *payload++ = 0; // no data (necessary for CPQ)
+ }
+
+
+ // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
+ // FCP_CDB allows 16 byte SCSI command descriptor blk;
+ // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
+ for (i = 0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
+ *payload++ = Cmnd->cmnd[i];
+
+ if (Cmnd->cmd_len == 16) {
+ memcpy(payload, &Cmnd->SCp.buffers_residual, 4);
+ }
+ payload += (16 - i);
+ // FCP_DL is largest number of expected data bytes
+ // per CDB (i.e. read/write command)
+ *payload++ = (u8) (fcp_dl >> 24); // (MSB) 8 bytes data len FCP_DL
+ *payload++ = (u8) (fcp_dl >> 16);
+ *payload++ = (u8) (fcp_dl >> 8);
+ *payload++ = (u8) fcp_dl; // (LSB)
+ break;
+
+ case SCSI_TWE: // need FCP_XFER_RDY
+ *payload++ = 0; // (4 bytes) DATA_RO (MSB byte 0)
+ *payload++ = 0;
+ *payload++ = 0;
+ *payload++ = 0; // LSB (byte 3)
+ // (4 bytes) BURST_LEN
+ // size of following FCP_DATA payload
+ *payload++ = (u8) (fcp_dl >> 24); // (MSB) 8 bytes data len FCP_DL
+ *payload++ = (u8) (fcp_dl >> 16);
+ *payload++ = (u8) (fcp_dl >> 8);
+ *payload++ = (u8) fcp_dl; // (LSB)
+ // 4 bytes RESERVED
+ *payload++ = 0;
+ *payload++ = 0;
+ *payload++ = 0;
+ *payload++ = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)