⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpqfctscontrol.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
        // completes        {          pLoggedInPort = &fcChip->fcPorts;           while( pLoggedInPort ) // for all ports which are expecting                                 // PDISC after the next LIP, set the                                 // logoutTimer          {	    if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?            {              pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds                                              // but Timer granularity                                              // is 1 second            }                                // suspend any I/O in progress until                                // PDISC received...            pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands	                pLoggedInPort = pLoggedInPort->pNextPort;          }  // ... all Previously known ports checked        }        	// since any hot plugging device may NOT support LILP frames	// (such as early Tachyon chips), clear this flag indicating	// we shouldn't use (our copy of) a LILP map.	// If we receive an LILP frame, we'll set it again.	fcChip->Options.LILPin = 0; // our LILPmap is invalid        cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports!          // also, we want to invalidate (i.e. INITIATOR_ABORT) any          // open Login exchanges, in case the LinkDown happened in the          // middle of logins.  It's possible that some ports already          // ACCepted login commands which we have not processed before          // another LinkDown occured.  Any accepted Login exhanges are          // invalidated by LinkDown, even before they are acknowledged.          // It's also possible for a port to have a Queued Reply or Request          // for login which was interrupted by LinkDown; it may come later,          // but it will be unacceptable to us.          // we must scan the entire exchange space, find every Login type          // originated by us, and abort it. This is NOT an abort due to          // timeout, so we don't actually send abort to the other port -          // we just complete it to free up the fcExchange slot.        for( i=TACH_SEST_LEN; i< TACH_MAX_XID; i++)        {                     // looking for Extended Link Serv.Exchanges          if( Exchanges->fcExchange[i].type == ELS_PDISC ||              Exchanges->fcExchange[i].type == ELS_PLOGI ||              Exchanges->fcExchange[i].type == ELS_PRLI )           {              // ABORT the exchange!#ifdef IMQ_DEBUG            printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n",              i, Exchanges->fcExchange[i].type,            Exchanges->fcExchange[i].fchs.d_id);#endif            Exchanges->fcExchange[i].status |= INITIATOR_ABORT;            cpqfcTSCompleteExchange( fcChip, i); // abort on LDn          }        }      }             // ################   LINK UP   ##################      if( fcChip->Registers.FMstatus.value & 0x200L ) // Link Up bit      {                                 // AL_PA could have changed          // We need the following code, duplicated from LinkDn condition,          // because it's possible for the Tachyon to re-initialize (hard          // reset) without ever getting a LinkDn indication.        pLoggedInPort = &fcChip->fcPorts;         while( pLoggedInPort )   // for all ports which are expecting                                 // PDISC after the next LIP, set the                                 // logoutTimer        {          if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?          {            pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds                                              // but Timer granularity                                              // is 1 second                                               // suspend any I/O in progress until                                  // PDISC received...          }          pLoggedInPort = pLoggedInPort->pNextPort;        }  // ... all Previously known ports checked           // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)        fcChip->Registers.rcv_al_pa.value =           readl(fcChip->Registers.rcv_al_pa.address); 	// Now, if our acquired address is DIFFERENT from our        // previous one, we are not allow to do PDISC - we        // must go back to PLOGI, which will terminate I/O in        // progress for ALL logged in FC devices...	// (This is highly unlikely).	if( (fcChip->Registers.my_al_pa & 0xFF) != 	    ((fcChip->Registers.rcv_al_pa.value >> 16) &0xFF) )	{//	  printk(" #our HBA port_id changed!# "); // FC port_id changed!!		  pLoggedInPort = &fcChip->fcPorts;           while( pLoggedInPort ) // for all ports which are expecting                                 // PDISC after the next LIP, set the                                 // logoutTimer          {	    pLoggedInPort->pdisc  = FALSE;            pLoggedInPort->prli = FALSE;            pLoggedInPort = pLoggedInPort->pNextPort;          }  // ... all Previously known ports checked	  // when the port_id changes, we must terminate	  // all open exchanges.          cpqfcTSTerminateExchange( cpqfcHBAdata, NULL, PORTID_CHANGED);	}	               	// Replace the entire 24-bit port_id.  We only know the	// lower 8 bits (alpa) from Tachyon; if a FLOGI is done,	// we'll get the upper 16-bits from the FLOGI ACC frame.	// If someone plugs into Fabric switch, we'll do FLOGI and	// get full 24-bit port_id; someone could then remove and	// hot-plug us into a dumb hub.  If we send a 24-bit PLOGI	// to a "private" loop device, it might blow up.	// Consequently, we force the upper 16-bits of port_id to	// be re-set on every LinkUp transition        fcChip->Registers.my_al_pa =          (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;                            // copy frame manager status to unused ULONG slot        fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =          fcChip->Registers.my_al_pa; // (for debugging)              // for TachLite, we need to write the acquired al_pa              // back into the FMconfig register, because after              // first initialization, the AQ (prev. acq.) bit gets              // set, causing TL FM to use the AL_PA field in FMconfig.              // (In Tachyon, FM writes the acquired AL_PA for us.)        ulBuff = readl( fcChip->Registers.FMconfig.address);        ulBuff &= 0x00ffffffL;  // mask out current al_pa        ulBuff |= ( fcChip->Registers.my_al_pa << 24 ); // or in acq. al_pa        fcChip->Registers.FMconfig.value = ulBuff; // copy it back        writel( fcChip->Registers.FMconfig.value,  // put in TachLite          fcChip->Registers.FMconfig.address);            #ifdef IMQ_DEBUG        printk("#LUp %Xh, FMstat 0x%08X#", 		fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);#endif              // also set the WRITE-ONLY My_ID Register (for Fabric              // initialization)        writel( fcChip->Registers.my_al_pa,          fcChip->Registers.ReMapMemBase +TL_MEM_TACH_My_ID);                  fcChip->fcStats.linkUp++;                                     // reset TL statistics counters                                     // (we ignore these error counters                                     // while link is down)        ulBuff =                     // just reset TL's counter                 readl( fcChip->Registers.FMLinkStatus1.address);                  ulBuff =                     // just reset TL's counter                 readl( fcChip->Registers.FMLinkStatus2.address);          // for initiator, need to start verifying ports (e.g. PDISC)                     	CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachlite, if Link OK		// Tachyon creates an interesting problem for us on LILP frames.	// Instead of writing the incoming LILP frame into the SFQ before	// indicating LINK UP (the actual order of events), Tachyon tells	// us LINK UP, and later us the LILP.  So we delay, then examine the	// IMQ for an Inbound CM (x04); if found, we can set	// LINKACTIVE after processing the LILP.  Otherwise, just proceed.	// Since Tachyon imposes this time delay (and doesn't tell us	// what it is), we have to impose a delay before "Peeking" the IMQ	// for Tach hardware (DMA) delivery.	// Processing LILP is required by SANMark	udelay( 1000);  // microsec delay waiting for LILP (if it comes)        if( PeekIMQEntry( fcChip, ELS_LILP_FRAME) )	{  // found SFQ LILP, which will post LINKACTIVE	  //	  printk("skipping LINKACTIVE post\n");	}	else          cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, ulFibreFrame);        }      // ******* Set Fabric Login indication ********      if( fcChip->Registers.FMstatus.value & 0x2000 )      {	printk(" #Fabric# ");        fcChip->Options.fabric = 1;      }      else        fcChip->Options.fabric = 0;                                         // ******* LIP(F8,x) or BAD AL_PA? ********      if( fcChip->Registers.FMstatus.value & 0x30000L )      {                        // copy the error AL_PAs        fcChip->Registers.rcv_al_pa.value =           readl(fcChip->Registers.rcv_al_pa.address);                                    // Bad AL_PA?        if( fcChip->Registers.FMstatus.value & 0x10000L )        {          PFC_LOGGEDIN_PORT pLoggedInPort;                               // copy "BAD" al_pa field          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =              (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;	  pLoggedInPort = fcFindLoggedInPort( fcChip,            NULL,     // DON'T search Scsi Nexus            fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1], // port id            NULL,     // DON'T search linked list for FC WWN            NULL);    // DON'T care about end of list 	  if( pLoggedInPort )	  {            // Just in case we got this BAD_ALPA because a device	    // quietly disappeared (can happen on non-managed hubs such 	    // as the Vixel Rapport 1000),	    // do an Implicit Logout.  We never expect this on a Logged	    // in port (but do expect it on port discovery).	    // (As a reasonable alternative, this could be changed to 	    // simply start the implicit logout timer, giving the device	    // several seconds to "come back".)	    // 	    printk(" #BAD alpa %Xh# ",		   fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);            cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);	  }        }                        // LIP(f8,x)?        if( fcChip->Registers.FMstatus.value & 0x20000L )        {                        // for debugging, copy al_pa field          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] =              (fcChip->Registers.rcv_al_pa.value & 0xffL);                        // get the other port's al_pa                        // (one that sent LIP(F8,?) )        }      }                             // Elastic store err      if( fcChip->Registers.FMstatus.value & 0x400L )      {            // don't count e-s if loop is down!        if( !(USHORT)(fcChip->Registers.FMstatus.value & 0x80) )          fcChip->fcStats.e_stores++;                }    }    break;    case INBOUND_FCP_XCHG_COMPLETION:  // 0x0C    // Remarks:    // On Tachlite TL/TS, we get this message when the data phase    // of a SEST inbound transfer is complete.  For example, if a WRITE command    // was received with OX_ID 0, we might respond with XFER_RDY with    // RX_ID 8001.  This would start the SEST controlled data phases.  When    // all data frames are received, we get this inbound completion. This means    // we should send a status frame to complete the status phase of the     // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data    // frames.    // See Outbound CM discussion of x_IDs    // Psuedo Code    //   Get SEST index (x_ID)    //     x_ID out of range, return (err condition)    //   set status bits from 2nd dword    //   free transactionID & SEST entry    //   call fcComplete with transactionID & status      ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];      x_ID = ulBuff & 0x7fffL;  // lower 14 bits SEST_Index/Trans_ID                                // (mask out MSB "direction" bit)                                // Range check CM OX/RX_ID value...      if( x_ID < TACH_SEST_LEN )  // don't go beyond SEST array space      {//#define FCP_COMPLETION_DBG 1#ifdef FCP_COMPLETION_DBG        printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n",           x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);#endif        if( ulBuff & 0x08000000L ) // RPC -Response Phase Complete - or -                                   // time to send response frame?          RPCset = 1;             // (SEST transaction)        else          RPCset = 0;                // set the status for this Inbound SCSI transaction's ID        dwStatus = 0L;        if( ulBuff & 0x70000000L ) // any errs?        {                    if( ulBuff & 0x40000000L )            dwStatus |= LINKFAIL_RX;          	  if( ulBuff & 0x20000000L )            dwStatus |= COUNT_ERROR;                    if( ulBuff & 0x10000000L )            dwStatus |= OVERFLOW;        }      		  // FCP transaction done - copy status        Exchanges->fcExchange[ x_ID ].status = dwStatus;        // Did the exchange get an FCP-RSP response frame?        // (Note the little endian/big endian FC payload difference)        if( RPCset )             // SEST transaction Response frame rec'd        {    	  // complete the command in our driver...          cpqfcTSCompleteExchange( fcChip, x_ID);        }  // end "RPCset"	        else  // ("target" logic)        {            // Tachlite says all data frames have been received - now it's time            // to analyze data transfer (successful?), then send a response             // frame for this exchange          ulFibreFrame[0] = x_ID; // copy for later reference          // if this was a TWE, we have to send satus response          if( Exchanges->fcExchange[ x_ID].type == SCSI_TWE )	  {//            fcPutScsiQue( cpqfcHBAdata, //                NEED_FCP_RSP, ulFibreFrame);  // (ulFibreFrame not used here)	  }        }      }      else  // ERROR CONDITION!  bogus x_ID in completion message      {        printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);      }    break;    case INBOUND_SCSI_DATA_COMMAND:    case BAD_SCSI_FRAME:    case INB_SCSI_STATUS_COMPLETION:    case BUFFER_PROCESSED_COMPLETION:    break;    }					   // Tachyon is producing;					   // we are consuming    fcChip->IMQ->consumerIndex++;             // increment OUR consumerIndex    if( fcChip->IMQ->consumerIndex >= IMQ_LEN)// check for rollover      fcChip->IMQ->consumerIndex = 0L;        // reset it    if( fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex )    {                           // all Messages are processed -      iStatus = 0;              // no more messages to process    }    else      iStatus = 1;              // more messages to process    // update TachLite's ConsumerIndex... (clears INTA_L)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -