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

📄 cpqfctsworker.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
  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;  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;      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( cpqfcHBAdata->fcQueReady );  }//DoneWithPutQ:  LEAVE("cpqfcTSPutLinkQ");}// reset device ext FC link Qvoid 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.// (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){//  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;//  PTACHYON fcChip = &cpqfcHBAdata->fcChip;//  ULONG ndx;//  ULONG *pExchangeID;//  LONG ExchangeID;/*  KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);  ndx = pDevExt->fcScsiQue.producer + 1;  // test for Que full  if( ndx >= FC_SCSIQ_DEPTH ) // rollover test    ndx = 0;  if( ndx == pDevExt->fcScsiQue.consumer )   // QUE full test  {                       // QUE was full! lost LK command (fatal to logic)    fcChip->fcStats.ScsiQueFull++;#ifdef DBG    printk( "fcPutScsiQue - FULL!\n");#endif  }  else                        // QUE next element  {    pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].Type = Type;        if( Type == FCP_RSP )    {      // this TL inbound message type means that a TL SEST exchange has      // 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;            memcpy(	      pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,        &fcChip->SEST->RspHDR[ *pExchangeID ],	      sizeof(pDevExt->fcScsiQue.Qitem[0].ulBuff)); // (any element for size)          }    else    {      memcpy(	      pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,        QueContent, 	      sizeof(pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff));    }          pDevExt->fcScsiQue.producer = ndx;  // increment Que    KeSetEvent( &pDevExt->TYIBscsi,  // signal any waiting thread       0,                    // no priority boost		   FALSE );              // 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*);void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,		PFC_LOGGEDIN_PORT pFcPort){  PTACHYON fcChip = &cpqfcHBAdata->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}  // 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){  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;  }}// 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    }	  // 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// device changed it's port_id after Loop re-init, or when// the device sent us a logout.  In the case of changed port_id,// we want to complete the command and return SOFT_ERROR to// force a re-try.  In the case of LOGOut, we might return// BAD_TARGET if the device is really gone.// Since we must ensure that Tachyon is not operating on the// exchange, we have to freeze the chip// sterminateexvoid cpqfcTSTerminateExchange(   CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus){  PTACHYON fcChip = &cpqfcHBAdata->fcChip;  FC_EXCHANGES *Exchanges = fcChip->Exchanges;  ULONG 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( 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)      }     }  }}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??  // 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      

⌨️ 快捷键说明

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