📄 buslogic.c
字号:
/* Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com> This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License Version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for complete details. The author respectfully requests that any modifications to this software be sent directly to him for evaluation and testing. Special thanks to Wayne Yen, Jin-Lon Hon, and Alex Win of BusLogic, whose advice has been invaluable, to David Gentzel, for writing the original Linux BusLogic driver, and to Paul Gortmaker, for being such a dedicated test site. Finally, special thanks to Mylex/BusLogic for making the FlashPoint SCCB Manager available as freely redistributable source code.*/#define BusLogic_DriverVersion "2.1.15"#define BusLogic_DriverDate "17 August 1998"#include <linux/version.h>#include <linux/module.h>#include <linux/config.h>#include <linux/init.h>#include <linux/types.h>#include <linux/blk.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/stat.h>#include <linux/pci.h>#include <linux/spinlock.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/system.h>#include "scsi.h"#include "hosts.h"#include "sd.h"#include "BusLogic.h"#include "FlashPoint.c"/* BusLogic_DriverOptionsCount is a count of the number of BusLogic Driver Options specifications provided via the Linux Kernel Command Line or via the Loadable Kernel Module Installation Facility.*/static int BusLogic_DriverOptionsCount;/* BusLogic_DriverOptions is an array of Driver Options structures representing BusLogic Driver Options specifications provided via the Linux Kernel Command Line or via the Loadable Kernel Module Installation Facility.*/static BusLogic_DriverOptions_T BusLogic_DriverOptions[BusLogic_MaxHostAdapters];/* BusLogic can be assigned a string by insmod.*/#ifdef MODULEstatic char *BusLogic;MODULE_PARM(BusLogic, "s");#endif/* BusLogic_ProbeOptions is a set of Probe Options to be applied across all BusLogic Host Adapters.*/static BusLogic_ProbeOptions_T BusLogic_ProbeOptions;/* BusLogic_GlobalOptions is a set of Global Options to be applied across all BusLogic Host Adapters.*/static BusLogic_GlobalOptions_T BusLogic_GlobalOptions;/* BusLogic_FirstRegisteredHostAdapter and BusLogic_LastRegisteredHostAdapter are pointers to the first and last registered BusLogic Host Adapters.*/static BusLogic_HostAdapter_T *BusLogic_FirstRegisteredHostAdapter, *BusLogic_LastRegisteredHostAdapter;/* BusLogic_ProbeInfoCount is the number of entries in BusLogic_ProbeInfoList.*/static int BusLogic_ProbeInfoCount;/* BusLogic_ProbeInfoList is the list of I/O Addresses and Bus Probe Information to be checked for potential BusLogic Host Adapters. It is initialized by interrogating the PCI Configuration Space on PCI machines as well as from the list of standard BusLogic I/O Addresses.*/static BusLogic_ProbeInfo_T *BusLogic_ProbeInfoList;/* BusLogic_CommandFailureReason holds a string identifying the reason why a call to BusLogic_Command failed. It is only non-NULL when BusLogic_Command returns a failure code.*/static char *BusLogic_CommandFailureReason;/* BusLogic_AnnounceDriver announces the Driver Version and Date, Author's Name, Copyright Notice, and Electronic Mail Address.*/static void BusLogic_AnnounceDriver(BusLogic_HostAdapter_T *HostAdapter){ BusLogic_Announce("***** BusLogic SCSI Driver Version " BusLogic_DriverVersion " of " BusLogic_DriverDate " *****\n", HostAdapter); BusLogic_Announce("Copyright 1995-1998 by Leonard N. Zubkoff " "<lnz@dandelion.com>\n", HostAdapter);}/* BusLogic_DriverInfo returns the Host Adapter Name to identify this SCSI Driver and Host Adapter.*/const char *BusLogic_DriverInfo(SCSI_Host_T *Host){ BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata; return HostAdapter->FullModelName;}/* BusLogic_RegisterHostAdapter adds Host Adapter to the list of registered BusLogic Host Adapters.*/static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter){ HostAdapter->Next = NULL; if (BusLogic_FirstRegisteredHostAdapter == NULL) { BusLogic_FirstRegisteredHostAdapter = HostAdapter; BusLogic_LastRegisteredHostAdapter = HostAdapter; } else { BusLogic_LastRegisteredHostAdapter->Next = HostAdapter; BusLogic_LastRegisteredHostAdapter = HostAdapter; }}/* BusLogic_UnregisterHostAdapter removes Host Adapter from the list of registered BusLogic Host Adapters.*/static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter){ if (HostAdapter == BusLogic_FirstRegisteredHostAdapter) { BusLogic_FirstRegisteredHostAdapter = BusLogic_FirstRegisteredHostAdapter->Next; if (HostAdapter == BusLogic_LastRegisteredHostAdapter) BusLogic_LastRegisteredHostAdapter = NULL; } else { BusLogic_HostAdapter_T *PreviousHostAdapter = BusLogic_FirstRegisteredHostAdapter; while (PreviousHostAdapter != NULL && PreviousHostAdapter->Next != HostAdapter) PreviousHostAdapter = PreviousHostAdapter->Next; if (PreviousHostAdapter != NULL) PreviousHostAdapter->Next = HostAdapter->Next; } HostAdapter->Next = NULL;}/* BusLogic_InitializeCCBs initializes a group of Command Control Blocks (CCBs) for Host Adapter from the BlockSize bytes located at BlockPointer. The newly created CCBs are added to Host Adapter's free list.*/static void BusLogic_InitializeCCBs(BusLogic_HostAdapter_T *HostAdapter, void *BlockPointer, int BlockSize){ BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) BlockPointer; memset(BlockPointer, 0, BlockSize); CCB->AllocationGroupHead = true; while ((BlockSize -= sizeof(BusLogic_CCB_T)) >= 0) { CCB->Status = BusLogic_CCB_Free; CCB->HostAdapter = HostAdapter; if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { CCB->CallbackFunction = BusLogic_QueueCompletedCCB; CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress; } CCB->Next = HostAdapter->Free_CCBs; CCB->NextAll = HostAdapter->All_CCBs; HostAdapter->Free_CCBs = CCB; HostAdapter->All_CCBs = CCB; HostAdapter->AllocatedCCBs++; CCB++; }}/* BusLogic_CreateInitialCCBs allocates the initial CCBs for Host Adapter.*/static boolean BusLogic_CreateInitialCCBs(BusLogic_HostAdapter_T *HostAdapter){ int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T); while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs) { void *BlockPointer = kmalloc(BlockSize, (HostAdapter->BounceBuffersRequired ? GFP_ATOMIC | GFP_DMA : GFP_ATOMIC)); if (BlockPointer == NULL) { BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", HostAdapter); return false; } BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize); } return true;}/* BusLogic_DestroyCCBs deallocates the CCBs for Host Adapter.*/static void BusLogic_DestroyCCBs(BusLogic_HostAdapter_T *HostAdapter){ BusLogic_CCB_T *NextCCB = HostAdapter->All_CCBs, *CCB; HostAdapter->All_CCBs = NULL; HostAdapter->Free_CCBs = NULL; while ((CCB = NextCCB) != NULL) { NextCCB = CCB->NextAll; if (CCB->AllocationGroupHead) kfree(CCB); }}/* BusLogic_CreateAdditionalCCBs allocates Additional CCBs for Host Adapter. If allocation fails and there are no remaining CCBs available, the Driver Queue Depth is decreased to a known safe value to avoid potential deadlocks when multiple host adapters share the same IRQ Channel.*/static void BusLogic_CreateAdditionalCCBs(BusLogic_HostAdapter_T *HostAdapter, int AdditionalCCBs, boolean SuccessMessageP){ int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T); int PreviouslyAllocated = HostAdapter->AllocatedCCBs; if (AdditionalCCBs <= 0) return; while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs) { void *BlockPointer = kmalloc(BlockSize, (HostAdapter->BounceBuffersRequired ? GFP_ATOMIC | GFP_DMA : GFP_ATOMIC)); if (BlockPointer == NULL) break; BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize); } if (HostAdapter->AllocatedCCBs > PreviouslyAllocated) { if (SuccessMessageP) BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n", HostAdapter, HostAdapter->AllocatedCCBs - PreviouslyAllocated, HostAdapter->AllocatedCCBs); return; } BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter); if (HostAdapter->DriverQueueDepth > HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount) { HostAdapter->DriverQueueDepth = HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount; HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth; }}/* BusLogic_AllocateCCB allocates a CCB from Host Adapter's free list, allocating more memory from the Kernel if necessary. The Host Adapter's Lock should already have been acquired by the caller.*/static BusLogic_CCB_T *BusLogic_AllocateCCB(BusLogic_HostAdapter_T *HostAdapter){ static unsigned long SerialNumber = 0; BusLogic_CCB_T *CCB; CCB = HostAdapter->Free_CCBs; if (CCB != NULL) { CCB->SerialNumber = ++SerialNumber; HostAdapter->Free_CCBs = CCB->Next; CCB->Next = NULL; if (HostAdapter->Free_CCBs == NULL) BusLogic_CreateAdditionalCCBs(HostAdapter, HostAdapter->IncrementalCCBs, true); return CCB; } BusLogic_CreateAdditionalCCBs(HostAdapter, HostAdapter->IncrementalCCBs,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -