diff -aurp linux-2.6.13/drivers/cpq/cpqfcTScontrol.c linux-2.6.13-e/drivers/scsi/cpqfcTScontrol.c --- linux-2.6.13/drivers/cpq/cpqfcTScontrol.c 2005-09-03 10:13:57.000000000 +0200 +++ linux-2.6.13-e/drivers/scsi/cpqfcTScontrol.c 2005-09-03 10:33:45.000000000 +0200 @@ -41,6 +41,7 @@ #include // struct pt_regs for IRQ handler & Port I/O #include #include +#include #include "scsi.h" #include // Scsi_Host definition for INT handler @@ -51,6 +52,7 @@ static void fcParseLinkStatusCounters(TACHYON * fcChip); static void CpqTsGetSFQEntry(TACHYON *, ULONG, TachFCHDR_GCMND*, int); +static int CpqTsDestroyTachLiteQues(CPQFCHBA*, int); static void cpqfc_free_dma_consistent(CPQFCHBA *cpqfcHBAdata) @@ -62,10 +64,14 @@ cpqfc_free_dma_consistent(CPQFCHBA *cpqf pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES), fcChip->Exchanges, fcChip->exch_dma_handle); fcChip->Exchanges = NULL; - if (cpqfcHBAdata->fcLQ != NULL) - pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE), - cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle); - cpqfcHBAdata->fcLQ = NULL; + while (!list_empty(&cpqfcHBAdata->work_list)) { + struct cpqfc_work_evt *evtp = NULL; + + evtp = list_entry((&cpqfcHBAdata->work_list)->next, typeof(*evtp), evt_listp); + list_del(&evtp->evt_listp); + + kfree(evtp); + } } // Note special requirements for Q alignment! (TL/TS UG pg. 190) @@ -73,9 +79,8 @@ cpqfc_free_dma_consistent(CPQFCHBA *cpqf // in non-symbolic (i.e. memory dump) debugging // opcode defines placement of Queues (e.g. local/external RAM) -int CpqTsCreateTachLiteQues( void* pHBA, int opcode) +static int CpqTsCreateTachLiteQues(CPQFCHBA *cpqfcHBAdata, int opcode) { - CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA; PTACHYON fcChip = &cpqfcHBAdata->fcChip; int iStatus=0; @@ -91,7 +96,6 @@ int CpqTsCreateTachLiteQues( void* pHBA, // Allocate primary EXCHANGES array... fcChip->Exchanges = NULL; - cpqfcHBAdata->fcLQ = NULL; /* printk("Allocating %u for %u Exchanges ", (ULONG)sizeof(FC_EXCHANGES), TACH_MAX_XID); */ @@ -106,18 +110,7 @@ int CpqTsCreateTachLiteQues( void* pHBA, } memset(fcChip->Exchanges, 0, sizeof(FC_EXCHANGES)); - /* printk("Allocating %u for LinkQ ", (ULONG)sizeof(FC_LINK_QUE)); */ - cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev, - sizeof(FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle); - /* printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH); */ - - if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!! - { - cpqfc_free_dma_consistent(cpqfcHBAdata); - printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n"); - return -1; - } - memset(cpqfcHBAdata->fcLQ, 0, sizeof(FC_LINK_QUE)); + INIT_LIST_HEAD(&cpqfcHBAdata->work_list); // Verify that basic Tach I/O registers are not NULL if( !fcChip->Registers.ReMapMemBase ) @@ -1623,9 +1616,8 @@ int CpqTsInitializeTachLite( void *pHBA, // it's probably best to free memory in opposite order as it was allocated. // Order of allocation: see other function -int CpqTsDestroyTachLiteQues( void *pHBA, int opcode) +static int CpqTsDestroyTachLiteQues(CPQFCHBA *cpqfcHBAdata, int opcode) { - CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA; PTACHYON fcChip = &cpqfcHBAdata->fcChip; USHORT i, iStatus=0; void* vPtr; // mem Align manager sets this to the freed address on success diff -aurp linux-2.6.13/drivers/cpq/cpqfcTSinit.c linux-2.6.13-e/drivers/scsi/cpqfcTSinit.c --- linux-2.6.13/drivers/cpq/cpqfcTSinit.c 2005-09-03 10:13:57.000000000 +0200 +++ linux-2.6.13-e/drivers/scsi/cpqfcTSinit.c 2005-09-03 10:18:17.000000000 +0200 @@ -190,8 +190,6 @@ static void Cpqfc_initHBAdata(CPQFCHBA * cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite; cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite; cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite; - cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues; - cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues; cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite; cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl; cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry; diff -aurp linux-2.6.13/drivers/cpq/cpqfcTSstructs.h linux-2.6.13-e/drivers/scsi/cpqfcTSstructs.h --- linux-2.6.13/drivers/cpq/cpqfcTSstructs.h 2005-09-03 10:13:57.000000000 +0200 +++ linux-2.6.13-e/drivers/scsi/cpqfcTSstructs.h 2005-09-03 10:41:03.000000000 +0200 @@ -22,6 +22,7 @@ #include // timer declaration in our host data #include +#include #include #include "cpqfcTSioctl.h" @@ -798,8 +799,6 @@ typedef struct // these function pointers are for "generic" functions, which are // replaced with Host Bus Adapter types at // runtime. - int (*CreateTachyonQues)( void* , int); - int (*DestroyTachyonQues)( void* , int); int (*LaserControl)(void*, int ); // e.g. On/Off int (*ResetTachyon)(void*, int ); void (*FreezeTachyon)(void*, int ); @@ -815,8 +814,6 @@ typedef struct void cpqfcTSClearLinkStatusCounters(TACHYON * fcChip); -int CpqTsCreateTachLiteQues( void* pHBA, int opcode); -int CpqTsDestroyTachLiteQues( void* , int); int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2); int CpqTsProcessIMQEntry(void* pHBA); @@ -862,23 +859,12 @@ void cpqfcTSheartbeat( unsigned long ptr // The biggest Q element we deal with is Aborts - we // need 4 bytes for x_ID, and a Scsi_Cmnd (~284 bytes) //#define LINKQ_ITEM_SIZE ((4+sizeof(Scsi_Cmnd)+3)/4) -#define LINKQ_ITEM_SIZE (3*16) -typedef struct -{ - ULONG Type; // e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ... - ULONG ulBuff[ LINKQ_ITEM_SIZE ]; -} LINKQ_ITEM; - -#define FC_LINKQ_DEPTH TACH_MAX_XID -typedef struct -{ - ULONG producer; - ULONG consumer; // when producer equals consumer, Q empty - - LINKQ_ITEM Qitem[ FC_LINKQ_DEPTH ]; - -} FC_LINK_QUE, *PFC_LINK_QUE; - +/*#define LINKQ_ITEM_SIZE (3*16) */ +struct cpqfc_work_evt { + struct list_head evt_listp; + ULONG type; + TachFCHDR_GCMND buff; +}; // DPC routines post to here on Inbound SCSI frames // User thread processes @@ -942,11 +928,11 @@ typedef struct struct semaphore *TachFrozen; struct semaphore *TYOBcomplete; // handshake for Tach outbound frames - struct semaphore *fcQueReady; // FibreChannel work for our kernel thread struct semaphore *notify_wt; // synchronizes kernel thread kill struct semaphore *BoardLock; - - PFC_LINK_QUE fcLQ; // the WorkerThread operates on this + + struct list_head work_list; + wait_queue_head_t *work_wait; spinlock_t hba_spinlock; // held/released by WorkerThread cpqfc_passthru_private_t *private_data_pool; @@ -1000,7 +986,7 @@ PFC_LOGGEDIN_PORT fcFindLoggedInPort( PFC_LOGGEDIN_PORT *pLastLoggedInPort ); -void cpqfcTSPutLinkQue(CPQFCHBA *, int, TachFCHDR_GCMND*, ULONG); +int cpqfcTSPutLinkQue(CPQFCHBA *, int, TachFCHDR_GCMND*, ULONG); void fcPutScsiQue( CPQFCHBA *cpqfcHBAdata, diff -aurp linux-2.6.13/drivers/cpq/cpqfcTSworker.c linux-2.6.13-e/drivers/scsi/cpqfcTSworker.c --- linux-2.6.13/drivers/cpq/cpqfcTSworker.c 2005-09-03 10:13:57.000000000 +0200 +++ linux-2.6.13-e/drivers/scsi/cpqfcTSworker.c 2005-09-03 10:52:23.000000000 +0200 @@ -116,9 +116,7 @@ static void SetLoginFields( BOOLEAN PDisc, BOOLEAN Originator); -static void AnalyzeIncomingFrame( - CPQFCHBA *cpqfcHBAdata, - ULONG QNdx ); +static void AnalyzeIncomingFrame(CPQFCHBA *, struct cpqfc_work_evt *); static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds ); @@ -144,6 +141,21 @@ static void IssueReportLunsCommand( CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs); +static int +check_work_wait_done(CPQFCHBA *hba) +{ + spin_lock_irq(hba->HostAdapter->host_lock); + if (!list_empty(&hba->work_list) || + kthread_should_stop()) { + spin_unlock_irq(hba->HostAdapter->host_lock); + return 1; + } else { + spin_unlock_irq(hba->HostAdapter->host_lock); + return 0; + } +} + int cpqfcTSWorkerThread(void *host) { @@ -152,27 +166,30 @@ cpqfcTSWorkerThread(void *host) #ifdef PCI_KERNEL_TRACE PTACHYON fcChip = &cpqfcHBAdata->fcChip; #endif - DECLARE_MUTEX_LOCKED(fcQueReady); DECLARE_MUTEX_LOCKED(fcTYOBcomplete); DECLARE_MUTEX_LOCKED(TachFrozen); DECLARE_MUTEX_LOCKED(BoardLock); + DECLARE_WAIT_QUEUE_HEAD(work_waitq); ENTER(__FUNCTION__); - cpqfcHBAdata->fcQueReady = &fcQueReady; // primary wait point + cpqfcHBAdata->work_wait = &work_waitq; cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete; cpqfcHBAdata->TachFrozen = &TachFrozen; while(1) { unsigned long flags; + int rc; - down_interruptible( &fcQueReady); // wait for something to do + rc = wait_event_interruptible(work_waitq, + check_work_wait_done(cpqfcHBAdata)); + BUG_ON(rc); - if (signal_pending(current)) - flush_signals(current); - if (kthread_should_stop()) + if (kthread_should_stop()) { + cpqfcHBAdata->work_wait = NULL; return 0; + } PCI_TRACE( 0x90) // first, take the IO lock so the SCSI upper layers can't call @@ -259,28 +274,24 @@ void cpqfcTS_WorkTask( struct Scsi_Host 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; + struct cpqfc_work_evt *evtp; - ENTER("WorkTask"); + ENTER(__FUNCTION__); - // copy current index to work on - QconsumerNdx = fcLQ->consumer; + evtp = list_entry((&cpqfcHBAdata->work_list)->next, typeof(*evtp), evt_listp); + list_del(&evtp->evt_listp); - PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90) - + PCI_TRACEO(evtp->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 ) - { + switch (evtp->type) { // incoming frame - link service (ACC, UNSOL REQ, etc.) // or FCP-SCSI command case SFQ_UNKNOWN: - AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx ); + AnalyzeIncomingFrame(cpqfcHBAdata, evtp); break; @@ -294,8 +305,7 @@ void cpqfcTS_WorkTask( struct Scsi_Host // 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]; + ExchangeID = evtp->buff.reserved; // 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) @@ -376,9 +386,8 @@ void cpqfcTS_WorkTask( struct Scsi_Host ulStatus = cpqfcTSBuildExchange( cpqfcHBAdata, - fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI - (TachFCHDR_GCMND*) - fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs + evtp->type, // e.g. PLOGI + &evtp->buff, // incoming fchs NULL, // no data (no scatter/gather list) &ExchangeID );// fcController->fcExchanges index, -1 if failed @@ -408,8 +417,7 @@ void cpqfcTS_WorkTask( struct Scsi_Host // 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); + IssueReportLunsCommand(cpqfcHBAdata, &evtp->buff); break; @@ -418,7 +426,7 @@ void cpqfcTS_WorkTask( struct Scsi_Host case BLS_ABTS: // need to ABORT one or more exchanges { - LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0]; + LONG x_ID = evtp->buff.reserved; BOOLEAN FrozeTach = FALSE; if ( x_ID >= TACH_SEST_LEN ) // (in)sanity check @@ -664,10 +672,8 @@ void cpqfcTS_WorkTask( struct Scsi_Host fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists - memcpy( // copy the incoming ABTS frame - &fchs, - fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs - sizeof( fchs)); + /* copy the incoming ABTS frame */ + memcpy(&fchs, &evtp->buff, sizeof(fchs)); // 3. OK, Tachyon is frozen so we can invalidate SEST entry // (if necessary) @@ -735,8 +741,7 @@ void cpqfcTS_WorkTask( struct Scsi_Host ulStatus = cpqfcTSBuildExchange( cpqfcHBAdata, BLS_ABTS_RJT, - (TachFCHDR_GCMND*) - fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs + &evtp->buff, // incoming fchs NULL, // no data (no scatter/gather list) &ExchangeID );// fcController->fcExchanges index, -1 if failed @@ -765,16 +770,7 @@ void cpqfcTS_WorkTask( struct Scsi_Host //doNothing: // done with this item - now set the NEXT index - if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test - { - fcLQ->consumer = 0; - } - else - { - fcLQ->consumer++; - } - - PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94) + PCI_TRACEO(evtp->type, 0x94) LEAVE("WorkTask"); return; @@ -783,119 +779,41 @@ void cpqfcTS_WorkTask( struct Scsi_Host -// When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login) -// commands come in, post to the LinkQ so that action can be taken outside the -// interrupt handler. -// 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, - TachFCHDR_GCMND *content, ULONG err) +/* When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login) + * commands come in, post to the LinkQ so that action can be taken outside the + * interrupt handler. + * Called by Interrupt handler, WorkerThread, Timer sputlinkq + */ +int +cpqfcTSPutLinkQue(CPQFCHBA *hba, int type, TachFCHDR_GCMND *content, ULONG err) { - PTACHYON fcChip = &cpqfcHBAdata->fcChip; -// FC_EXCHANGES *Exchanges = fcChip->Exchanges; - PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ; - ULONG ndx; - - ENTER("cpqfcTSPutLinkQ"); - - ndx = fcLQ->producer + 1; /* test for Que full */ - - if( ndx >= FC_LINKQ_DEPTH ) // rollover test - ndx = 0; - - if( ndx == fcLQ->consumer ) // QUE full test - { - // QUE was full! lost LK command (fatal to logic) - fcChip->fcStats.lnkQueFull++; - - 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; + struct cpqfc_work_evt *evtp; + ENTER(__FUNCTION__); - 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; + evtp = kmalloc(sizeof(*evtp), GFP_KERNEL); + if (!evtp) + return -ENOMEM; + + evtp->type = type; if (content) { - memcpy(fcLQ->Qitem[fcLQ->producer].ulBuff, content, - sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff)); + memcpy(&evtp->buff, content, + sizeof(evtp->buff)); } else { - fcLQ->Qitem[fcLQ->producer].ulBuff[0] = err; + evtp->buff.reserved = err; } - fcLQ->producer = ndx; // increment Que producer - - // set semaphore to wake up Kernel (worker) thread - // - up( cpqfcHBAdata->fcQueReady ); - } + list_add_tail(&evtp->evt_listp, &hba->work_list); + spin_lock_irq(hba->HostAdapter->host_lock); + if (hba->work_wait) + wake_up(hba->work_wait); + spin_unlock_irq(hba->HostAdapter->host_lock); -//DoneWithPutQ: - - LEAVE("cpqfcTSPutLinkQ"); + LEAVE(__FUNCTION__); + return 0; } - - - -// reset device ext FC link Q -void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata) - -{ - PFC_LINK_QUE fcLQ = cpqfcHBAdata->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. @@ -2059,21 +1978,12 @@ Quit: return; } - - - - - - -static void AnalyzeIncomingFrame( - CPQFCHBA *cpqfcHBAdata, - ULONG QNdx ) +static void +AnalyzeIncomingFrame(CPQFCHBA *cpqfcHBAdata, struct cpqfc_work_evt *evtp) { PTACHYON fcChip = &cpqfcHBAdata->fcChip; FC_EXCHANGES *Exchanges = fcChip->Exchanges; - PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ; - TachFCHDR_GCMND* fchs = - (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff; + TachFCHDR_GCMND* fchs = &evtp->buff; // ULONG ls_reject_code; // reason for rejecting login LONG ExchangeID; // FC_LOGGEDIN_PORT *pLoggedInPort; @@ -2081,14 +1991,6 @@ static void AnalyzeIncomingFrame( ENTER("AnalyzeIncomingFrame"); - - - switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown - { - - 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? && @@ -2319,17 +2221,8 @@ static void AnalyzeIncomingFrame( } } // 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; - } } - // Function for Port Discovery necessary after every FC // initialization (e.g. LIP). // Also may be called if from Fabric Name Service logic.