📄 cpqfctsworker.c
字号:
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 + -