📄 cpqfctsinit.c
字号:
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_eh_abort"); return 0; // (see scsi.h)} // FCP-SCSI Target Device Reset// See dpANS Fibre Channel Protocol for SCSI// X3.269-199X revision 12, pg 25int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags){ int timeout = 10*HZ; int retries = 1; char scsi_cdb[12]; int result; Scsi_Cmnd * SCpnt; Scsi_Device * SDpnt; // printk(" ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags); if (ScsiDev->host->eh_active) return FAILED; memset( scsi_cdb, 0, sizeof( scsi_cdb)); scsi_cdb[0] = RELEASE; // allocate with wait = true, interruptible = false SCpnt = scsi_allocate_device(ScsiDev, 1, 0); { CPQFC_DECLARE_COMPLETION(wait); SCpnt->SCp.buffers_residual = FCP_TARGET_RESET; SCpnt->request.CPQFC_WAITING = &wait; scsi_do_cmd(SCpnt, scsi_cdb, NULL, 0, my_ioctl_done, timeout, retries); CPQFC_WAIT_FOR_COMPLETION(&wait); SCpnt->request.CPQFC_WAITING = NULL; } /* if(driver_byte(SCpnt->result) != 0) switch(SCpnt->sense_buffer[2] & 0xf) { case ILLEGAL_REQUEST: if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0; else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); break; case NOT_READY: // This happens if there is no disc in drive if(dev->removable && (cmd[0] != TEST_UNIT_READY)){ printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); break; } case UNIT_ATTENTION: if (dev->removable){ dev->changed = 1; SCpnt->result = 0; // This is no longer considered an error // gag this error, VFS will log it anyway /axboe // printk(KERN_INFO "Disc change detected.\n"); break; }; default: // Fall through for non-removable media printk("SCSI error: host %d id %d lun %d return code = %x\n", dev->host->host_no, dev->id, dev->lun, SCpnt->result); printk("\tSense class %x, sense error %x, extended sense %x\n", sense_class(SCpnt->sense_buffer[0]), sense_error(SCpnt->sense_buffer[0]), SCpnt->sense_buffer[2] & 0xf); };*/ result = SCpnt->result; SDpnt = SCpnt->device; scsi_release_command(SCpnt); SCpnt = NULL; // if (!SDpnt->was_reset && SDpnt->scsi_request_fn) // (*SDpnt->scsi_request_fn)(); wake_up(&SDpnt->scpnt_wait); // printk(" LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n"); return SUCCESS;}int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd){ int retval; Scsi_Device *SDpnt = Cmnd->device; // printk(" ENTERING cpqfcTS_eh_device_reset() \n"); spin_unlock_irq(&io_request_lock); retval = cpqfcTS_TargetDeviceReset( SDpnt, 0); spin_lock_irq(&io_request_lock); return retval;} int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags){ ENTER("cpqfcTS_reset"); LEAVE("cpqfcTS_reset"); return SCSI_RESET_ERROR; /* Bus Reset Not supported */}/* 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 ) { UCHAR IntStat; printk(" cpqfcTS adapter PCI error detected\n"); IntStat = readb( cpqfcHBA->fcChip.Registers.INTSTAT.address); if (IntStat & 0x4) printk("(INT)\n"); if (IntStat & 0x8) printk("CRS: PCI master address crossed 46 bit bouandary\n"); if (IntStat & 0x10) printk("MRE: external memory parity error.\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/slab.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 alignment, 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( struct pci_dev *pdev, ALIGNED_MEM *dynamic_mem, ULONG n_alloc, ULONG ab, ULONG u32_AlignedAddress, dma_addr_t *dma_handle){ 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 pci_free_consistent(pdev,dynamic_mem[i].size, alloc_address, dynamic_mem[i].dma_handle); dynamic_mem[i].BaseAllocated = 0; // clear for next use dynamic_mem[i].AlignedAddress = 0; dynamic_mem[i].size = 0; break; // quit for loop; done } } } else if( n_alloc ) // want new memory? { dma_addr_t handle; t_alloc = n_alloc + (ab - allocBoundary); // pad bytes for alignment// printk("pci_alloc_consistent() for Tach alignment: %ld bytes\n", t_alloc);// (would like to) allow thread block to free pages alloc_address = // total bytes (NumberOfBytes) pci_alloc_consistent(pdev, t_alloc, &handle); // 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... mask = (LONG)(ab - 1); // mask all low-order bits mask = ~mask; // invert bits 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 dynamic_mem[i].dma_handle = handle; if (dma_handle != NULL) {// printk("handle = %p, ab=%d, boundary = %d, mask=0x%08x\n", // handle, ab, allocBoundary, mask); *dma_handle = (dma_addr_t) ((((ULONG)handle) + (ab - allocBoundary)) & mask); } dynamic_mem[i].size = t_alloc; break; } } 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}static Scsi_Host_Template driver_template = CPQFCTS;#include "scsi_module.c"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -