📄 cpqfctsinit.c
字号:
// from Linux Scsi (e.g. ceated a SEST entry) and it // got lost somehow. If we can't find any reference // to the passed pointer, we can only presume it // got completed as far as our driver is concerned. // If we found it, we will try to abort it through // common mechanism. If FC ABTS is successful (ACC) // or is rejected (RJT) by target, we will call // Scsi "done" quickly. Otherwise, the ABTS will timeout // and we'll call "done" later. // Search the SEST exchanges for a matching Cmnd ptr. for( i=0; i< TACH_SEST_LEN; i++) { if( Exchanges->fcExchange[i].Cmnd == Cmnd ) { // found it! printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type); Exchanges->fcExchange[i].status = INITIATOR_ABORT; // seconds default Exchanges->fcExchange[i].timeOut = 10; // seconds default (changed later) // Since we need to immediately return the aborted Cmnd to Scsi // upper layers, we can't make future reference to any of it's // fields (e.g the Nexus). cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i); break; } } if( i >= TACH_SEST_LEN ) // didn't find Cmnd ptr in chip's SEST? { // now search our non-SEST buffers (i.e. Cmnd waiting to // start on the HBA or waiting to complete with error for retry). // first check BadTargetCmnd for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++) { if( cpqfcHBAdata->BadTargetCmnd[i] == Cmnd ) { cpqfcHBAdata->BadTargetCmnd[i] = NULL; printk("in BadTargetCmnd Q\n"); goto Done; // exit } } // if not found above... for( i=0; i < CPQFCTS_REQ_QUEUE_LEN; i++) { if( cpqfcHBAdata->LinkDnCmnd[i] == Cmnd ) { cpqfcHBAdata->LinkDnCmnd[i] = NULL; printk("in LinkDnCmnd Q\n"); goto Done; } } for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++) { // find spare slot if( cpqfcHBAdata->BoardLockCmnd[i] == Cmnd ) { cpqfcHBAdata->BoardLockCmnd[i] = NULL; printk("in BoardLockCmnd Q\n"); goto Done; } } Cmnd->result = DID_ERROR <<16; // Hmmm... printk("Not found! ");// panic("_abort"); } Done: // panic("_abort"); LEAVE("cpqfcTS_abort"); return 0; // (see scsi.h)} // To be done... int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags){ int return_status = SUCCESS; ENTER("cpqfcTS_reset"); LEAVE("cpqfcTS_reset"); return return_status;} /* This function determines the bios parameters for a given harddisk. These tend to be numbers that are made up by the host adapter. Parameters: size, device number, list (heads, sectors,cylinders). (from hosts.h)*/int cpqfcTS_biosparam(Disk *disk, kdev_t n, int ip[]){ int size = disk->capacity; ENTER("cpqfcTS_biosparam"); ip[0] = 64; ip[1] = 32; ip[2] = size >> 11; if( ip[2] > 1024 ) { ip[0] = 255; ip[1] = 63; ip[2] = size / (ip[0] * ip[1]); } LEAVE("cpqfcTS_biosparam"); return 0;} void cpqfcTS_intr_handler( int irq, void *dev_id, struct pt_regs *regs){ unsigned long flags, InfLoopBrk=0; struct Scsi_Host *HostAdapter = dev_id; CPQFCHBA *cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata; int MoreMessages = 1; // assume we have something to do UCHAR IntPending; ENTER("intr_handler"); spin_lock_irqsave( &io_request_lock, flags); // is this our INT? IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address); // broken boards can generate messages forever, so // prevent the infinite loop#define INFINITE_IMQ_BREAK 10000 if( IntPending ) { // mask our HBA interrupts until we handle it... writeb( 0, cpqfcHBA->fcChip.Registers.INTEN.address); if( IntPending & 0x4) // "INT" - Tach wrote to IMQ { while( (++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages ==1) ) { MoreMessages = CpqTsProcessIMQEntry( HostAdapter); // ret 0 when done } if( InfLoopBrk >= INFINITE_IMQ_BREAK ) { printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n"); printk("or investigate alternate causes (e.g. physical FC layer)\n"); } else // working normally - re-enable INTs and continue writeb( 0x1F, cpqfcHBA->fcChip.Registers.INTEN.address); } // (...ProcessIMQEntry() clears INT by writing IMQ consumer) else // indications of errors or problems... // these usually indicate critical system hardware problems. { if( IntPending & 0x10 ) printk(" cpqfcTS adapter external memory parity error detected\n"); if( IntPending & 0x8 ) printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n"); if( IntPending & 0x2 ) printk(" cpqfcTS adapter DMA error detected\n"); if( IntPending & 0x1 ) printk(" cpqfcTS adapter PCI error detected\n"); } } spin_unlock_irqrestore( &io_request_lock, flags); LEAVE("intr_handler");}int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[]){ // Verify GBIC type (if any) and correct Tachyon Port State Machine // (GBIC) module definition is: // GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0. The input states appear // to be inverted -- i.e., a setting of 111 is read when there is NO // GBIC present. The Module Def (MD) spec says 000 is "no GBIC" // Hard code the bit states to detect Copper, // Long wave (single mode), Short wave (multi-mode), and absent GBIC ULONG ulBuff; sprintf( cErrorString, "\nGBIC detected: "); ulBuff = fcChip->Registers.TYstatus.value & 0x13; switch( ulBuff ) { case 0x13: // GPIO4, GPIO1, GPIO0 = 111; no GBIC! sprintf( &cErrorString[ strlen( cErrorString)], "NONE! "); return FALSE; case 0x11: // Copper GBIC detected sprintf( &cErrorString[ strlen( cErrorString)], "Copper. "); break; case 0x10: // Long-wave (single mode) GBIC detected sprintf( &cErrorString[ strlen( cErrorString)], "Long-wave. "); break; case 0x1: // Short-wave (multi mode) GBIC detected sprintf( &cErrorString[ strlen( cErrorString)], "Short-wave. "); break; default: // unknown GBIC - presumably it will work (?) sprintf( &cErrorString[ strlen( cErrorString)], "Unknown. "); break; } // end switch GBIC detection return TRUE;}int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[]){ // Tachyon's Frame Manager LPSM in LinkDown state? // (For non-loop port, check PSM instead.) // return string with state and FALSE is Link Down int LinkUp; if( fcChip->Registers.FMstatus.value & 0x80 ) LinkUp = FALSE; else LinkUp = TRUE; sprintf( &cErrorString[ strlen( cErrorString)], " LPSM %Xh ", (fcChip->Registers.FMstatus.value >>4) & 0xf ); switch( fcChip->Registers.FMstatus.value & 0xF0) { // bits set in LPSM case 0x10: sprintf( &cErrorString[ strlen( cErrorString)], "ARB"); break; case 0x20: sprintf( &cErrorString[ strlen( cErrorString)], "ARBwon"); break; case 0x30: sprintf( &cErrorString[ strlen( cErrorString)], "OPEN"); break; case 0x40: sprintf( &cErrorString[ strlen( cErrorString)], "OPENed"); break; case 0x50: sprintf( &cErrorString[ strlen( cErrorString)], "XmitCLS"); break; case 0x60: sprintf( &cErrorString[ strlen( cErrorString)], "RxCLS"); break; case 0x70: sprintf( &cErrorString[ strlen( cErrorString)], "Xfer"); break; case 0x80: sprintf( &cErrorString[ strlen( cErrorString)], "Init"); break; case 0x90: sprintf( &cErrorString[ strlen( cErrorString)], "O-IInitFin"); break; case 0xa0: sprintf( &cErrorString[ strlen( cErrorString)], "O-IProtocol"); break; case 0xb0: sprintf( &cErrorString[ strlen( cErrorString)], "O-ILipRcvd"); break; case 0xc0: sprintf( &cErrorString[ strlen( cErrorString)], "HostControl"); break; case 0xd0: sprintf( &cErrorString[ strlen( cErrorString)], "LoopFail"); break; case 0xe0: sprintf( &cErrorString[ strlen( cErrorString)], "Offline"); break; case 0xf0: sprintf( &cErrorString[ strlen( cErrorString)], "OldPort"); break; case 0: default: sprintf( &cErrorString[ strlen( cErrorString)], "Monitor"); break; } return LinkUp;}#include "linux/malloc.h"// Dynamic memory allocation alignment routines// HP's Tachyon Fibre Channel Controller chips require// certain memory queues and register pointers to be aligned// on various boundaries, usually the size of the Queue in question.// Alignment might be on 2, 4, 8, ... or even 512 byte boundaries.// Since most O/Ss don't allow this (usually only Cache aligned -// 32-byte boundary), these routines provide generic alignment (after// O/S allocation) at any boundary, and store the original allocated// pointer for deletion (O/S free function). Typically, we expect// these functions to only be called at HBA initialization and// removal time (load and unload times)// ALGORITHM notes:// Memory allocation varies by compiler and platform. In the worst case,// we are only assured BYTE allignment, but in the best case, we can// request allocation on any desired boundary. Our strategy: pad the// allocation request size (i.e. waste memory) so that we are assured// of passing desired boundary near beginning of contiguous space, then// mask out lower address bits.// We define the following algorithm:// allocBoundary - compiler/platform specific address alignment// in number of bytes (default is single byte; i.e. 1)// n_alloc - number of bytes application wants @ aligned address// ab - alignment boundary, in bytes (e.g. 4, 32, ...)// t_alloc - total allocation needed to ensure desired boundary// mask - to clear least significant address bits for boundary// Compute:// t_alloc = n_alloc + (ab - allocBoundary)// allocate t_alloc bytes @ alloc_address// mask = NOT (ab - 1)// (e.g. if ab=32 _0001 1111 -> _1110 0000// aligned_address = alloc_address & mask// set n_alloc bytes to 0// return aligned_address (NULL if failed)//// If u32_AlignedAddress is non-zero, then search for BaseAddress (stored// from previous allocation). If found, invoke call to FREE the memory.// Return NULL if BaseAddress not found// we need about 8 allocations per HBA. Figuring at most 10 HBAs per server// size the dynamic_mem array at 80.void* fcMemManager( ALIGNED_MEM *dynamic_mem, ULONG n_alloc, ULONG ab, ULONG u32_AlignedAddress){ USHORT allocBoundary=1; // compiler specific - worst case 1 // best case - replace malloc() call // with function that allocates exactly // at desired boundary unsigned long ulAddress; ULONG t_alloc, i; void *alloc_address = 0; // def. error code / address not found LONG mask; // must be 32-bits wide! ENTER("fcMemManager"); if( u32_AlignedAddress ) // are we freeing existing memory? {// printk(" freeing AlignedAddress %Xh\n", u32_AlignedAddress); for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for the base address {// printk("dynamic_mem[%u].AlignedAddress %lX\n", i, dynamic_mem[i].AlignedAddress); if( dynamic_mem[i].AlignedAddress == u32_AlignedAddress ) { alloc_address = dynamic_mem[i].BaseAllocated; // 'success' status kfree( dynamic_mem[i].BaseAllocated); // return pages to kernel dynamic_mem[i].BaseAllocated = 0; // clear for next use dynamic_mem[i].AlignedAddress = 0; break; // quit for loop; done } } } else if( n_alloc ) // want new memory? { t_alloc = n_alloc + (ab - allocBoundary); // pad bytes for alignment// printk("kmalloc() for Tach alignment: %ld bytes\n", t_alloc); alloc_address = // total bytes (NumberOfBytes) kmalloc( t_alloc, GFP_KERNEL); // allow thread block to free pages // now mask off least sig. bits of address if( alloc_address ) // (only if non-NULL) { // find place to store ptr, so we // can free it later... for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for free slot { if( dynamic_mem[i].BaseAllocated == 0) // take 1st available { dynamic_mem[i].BaseAllocated = alloc_address;// address from O/S break; } } mask = (LONG)(ab - 1); // mask all low-order bits mask = ~mask; // invert bits ulAddress = (unsigned long)alloc_address; ulAddress += (ab - allocBoundary); // add the alignment bytes- // then truncate address... alloc_address = (void*)(ulAddress & mask); dynamic_mem[i].AlignedAddress = (ULONG)(ulAddress & mask); // 32bit Tach address memset( alloc_address, 0, n_alloc ); // clear new memory } else // O/S dynamic mem alloc failed! alloc_address = 0; // (for debugging breakpt) } LEAVE("fcMemManager"); return alloc_address; // good (or NULL) address}#ifdef MODULEScsi_Host_Template driver_template = CPQFCTS;#include "scsi_module.c"#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -