diff -Naurp linux-2.6.13/drivers/scsi/cpqfcTScontrol.c linux-2.6.13-eike/drivers/scsi/cpqfcTScontrol.c --- linux-2.6.13/drivers/scsi/cpqfcTScontrol.c 2005-09-13 16:46:47.000000000 +0200 +++ linux-2.6.13-eike/drivers/scsi/cpqfcTScontrol.c 2005-09-13 16:48:26.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 @@ -66,10 +67,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) @@ -94,7 +99,6 @@ int CpqTsCreateTachLiteQues(CPQFCHBA *cp // Allocate primary EXCHANGES array... fcChip->Exchanges = NULL; - cpqfcHBAdata->fcLQ = NULL; /* printk("Allocating %u for %u Exchanges ", (ULONG)sizeof(FC_EXCHANGES), TACH_MAX_XID); */ @@ -109,19 +113,6 @@ int CpqTsCreateTachLiteQues(CPQFCHBA *cp } 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)); - // Verify that basic Tach I/O registers are not NULL if( !fcChip->Registers.ReMapMemBase ) { diff -Naurp linux-2.6.13/drivers/scsi/cpqfcTSinit.c linux-2.6.13-eike/drivers/scsi/cpqfcTSinit.c --- linux-2.6.13/drivers/scsi/cpqfcTSinit.c 2005-09-13 16:46:47.000000000 +0200 +++ linux-2.6.13-eike/drivers/scsi/cpqfcTSinit.c 2005-09-13 16:48:26.000000000 +0200 @@ -191,6 +191,8 @@ static void Cpqfc_initHBAdata(CPQFCHBA * "cpqfc: unable to allocate pool for passthru ioctls. " "Passthru ioctls disabled.\n"); } + + INIT_LIST_HEAD(&cpqfcHBAdata->work_list); } static int launch_FCworker_thread(struct Scsi_Host *HostAdapter) diff -Naurp linux-2.6.13/drivers/scsi/cpqfcTSstructs.h linux-2.6.13-eike/drivers/scsi/cpqfcTSstructs.h --- linux-2.6.13/drivers/scsi/cpqfcTSstructs.h 2005-09-13 16:46:47.000000000 +0200 +++ linux-2.6.13-eike/drivers/scsi/cpqfcTSstructs.h 2005-09-13 16:48:26.000000000 +0200 @@ -22,6 +22,7 @@ #include // timer declaration in our host data #include +#include #include #include "cpqfcTSioctl.h" @@ -765,23 +766,13 @@ 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) -struct cpqfc_linkque_item -{ - ULONG Type; // e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ... - ULONG ulBuff[ LINKQ_ITEM_SIZE ]; +/*#define LINKQ_ITEM_SIZE (3*16)*/ +struct cpqfc_work_evt { + struct list_head evt_listp; + ULONG type; + TachFCHDR_GCMND buff; }; -#define FC_LINKQ_DEPTH TACH_MAX_XID -typedef struct -{ - ULONG producer; - ULONG consumer; // when producer equals consumer, Q empty - - struct cpqfc_linkque_item Qitem[ FC_LINKQ_DEPTH ]; - -} FC_LINK_QUE, *PFC_LINK_QUE; - // DPC routines post to here on Inbound SCSI frames // User thread processes #define FC_SCSIQ_DEPTH 32 @@ -828,11 +819,11 @@ typedef struct cpqfc_hba 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; @@ -879,7 +870,7 @@ PFC_LOGGEDIN_PORT fcFindLoggedInPort( PFC_LOGGEDIN_PORT *pLastLoggedInPort ); -void cpqfcTSPutLinkQue(CPQFCHBA *, int, TachFCHDR_GCMND*, ULONG); +int __must_check cpqfcTSPutLinkQue(CPQFCHBA *, int, TachFCHDR_GCMND*, ULONG); void fcLinkQReset(CPQFCHBA *); void fcScsiQReset(CPQFCHBA *); diff -Naurp linux-2.6.13/drivers/scsi/cpqfcTSworker.c linux-2.6.13-eike/drivers/scsi/cpqfcTSworker.c --- linux-2.6.13/drivers/scsi/cpqfcTSworker.c 2005-09-13 16:46:47.000000000 +0200 +++ linux-2.6.13-eike/drivers/scsi/cpqfcTSworker.c 2005-09-13 16:48:27.000000000 +0200 @@ -115,9 +115,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 ); @@ -145,6 +143,20 @@ static void IssueReportLunsCommand( static void BigEndianSwap(UCHAR *, UCHAR *, USHORT); +static int +check_work_wait_done(CPQFCHBA *hba) +{ + int rc; + + spin_lock_irq(hba->HostAdapter->host_lock); + rc = !list_empty(&hba->work_list) || + kthread_should_stop(); + + spin_unlock_irq(hba->HostAdapter->host_lock); + + return rc; +} + int cpqfcTSWorkerThread(void *host) { @@ -153,27 +165,32 @@ 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) - { + while(!kthread_should_stop()) { unsigned long flags; + int rc; - down_interruptible( &fcQueReady); // wait for something to do + rc = wait_event_interruptible(work_waitq, + check_work_wait_done(cpqfcHBAdata)); - if (kthread_should_stop()) - break; + if (kthread_should_stop()) + break; + + if (rc) { + BUG(); + continue; + } - 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( HostAdapter->host_lock, flags); // STOP _que function @@ -212,6 +229,7 @@ cpqfcTSWorkerThread(void *host) CompleteBoardLockCmnd( cpqfcHBAdata); } + cpqfcHBAdata->work_wait = NULL; return 0; } @@ -256,27 +274,22 @@ 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; - - ENTER("WorkTask"); + struct cpqfc_work_evt *evtp; - // copy current index to work on - QconsumerNdx = fcLQ->consumer; + ENTER(__FUNCTION__); - PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90) + evtp = list_entry((&cpqfcHBAdata->work_list)->next, typeof(*evtp), evt_listp); + list_del(&evtp->evt_listp); // 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; @@ -288,8 +301,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) @@ -367,9 +379,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 @@ -399,14 +410,12 @@ 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; 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 @@ -638,11 +647,8 @@ void cpqfcTS_WorkTask( struct Scsi_Host // 1. Freeze TL CpqTsFreezeTachlite(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) @@ -677,7 +683,7 @@ void cpqfcTS_WorkTask( struct Scsi_Host ulStatus = cpqfcTSBuildExchange( cpqfcHBAdata, BLS_ABTS_ACC, - &fchs, + &evtp->buff, // incoming fchs NULL, // no data (no scatter/gather list) &ExchangeID );// fcController->fcExchanges index, -1 if failed @@ -707,8 +713,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 @@ -735,122 +740,41 @@ 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) - - LEAVE("WorkTask"); - return; + LEAVE(__FUNCTION__); } -// 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 */ + struct cpqfc_work_evt *evtp; - if( ndx >= FC_LINKQ_DEPTH ) // rollover test - ndx = 0; + ENTER(__FUNCTION__); - if( ndx == fcLQ->consumer ) // QUE full test - { - // QUE was full! lost LK command (fatal to logic) - fcChip->fcStats.lnkQueFull++; - - printk("*LinkQ Full!*"); -/* - { - int i; - printk("LinkQ PI %d, CI %d\n", fcLQ->producer, - fcLQ->consumer); + evtp = kmalloc(sizeof(*evtp), GFP_KERNEL); + if (!evtp) + return -ENOMEM; - 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; - - - 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->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 ); - } - -//DoneWithPutQ: - - LEAVE("cpqfcTSPutLinkQ"); -} + 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); -// reset device ext FC link Q -void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata) -{ - PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ; - fcLQ->producer = 0; - fcLQ->consumer = 0; + LEAVE(__FUNCTION__); + return 0; } static void ProcessELS_Request(CPQFCHBA*, TachFCHDR_GCMND*); @@ -1882,15 +1806,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;