mptsas驱动阅读笔记

mptsas驱动阅读笔记
mptsas驱动阅读笔记

1. MPTSAS概述

本文主要对1000系列软RAID产品中所涉及的LSISAS1068E SAS控制器驱动部分作了分析。限于项目需求与时间,本文重点分析了MPTSAS驱动的结构、SAS 控制器初始化过程、以及磁盘热插拔事件的响应过程。

LSISAS1068E是一个基于Fusion-MPT架构的SAS控制器。Fusion-MPT技术由LSI Logic开发,旨在为客户提供更为容易的实现SCSI和Fibre Channel的解决方案。这种开放式的Fusion-MPT架构具有高I/O性能,同时还能降低产品验证的时间和推向市场的时间。LSI Fusion-MPT基于行业标准的ARM处理器技术,支持Ultra320 SCSI,Fibre Channel,SAS接口,并可以对将来出现的其他接口扩展。

Fusion-MPT技术主要包括Fusion-MPT固件,SAS、U320 SCSI、Fibre Channel 硬核,和操作系统级的驱动程序等部分。如图1.1所示,Fusion-MPT架构中使用统一的固件及驱动来支持所有基于Fusion-MPT技术的I/O控制器。

图1.1 Fusion-MPT 架构

如图1.2所示,Fusion-MPT架构可分为操作系统层和硬件层两部分,而从驱动程序设计的角度,又可进一步将其分为驱动、固件和硬件三个功能层次。

图1.2 Fusion-MPT架构框图

Fusion-MPT在硬件层之上构建独有的固件层,不同的固件为上层驱动程序

提供对SCSI或FC的支持,以及高级的集成RAID等功能。固件层有效地将驱动程序同硬件隔离,对上层驱动程序提供统一的MPI ( Message Passing Interface )接口,使同一驱动程序可以应用于不同的底层硬件系统,有助于加速应用开发。

驱动层对上层操作系统提供功能函数接口,通过MPI访问固件层,实现操作系统对硬件的访问,并且按照通信协议实现相关的帧封装和拆解。消息传递接口MPI提供了一个消息传递传输架构,它定义了主机与LSI Fusion-MPT芯片组通信的接口。

Fusion-MPT技术在硬件上采用了GigaBlaze收发器、先进的I/O焊盘、高性能ARM处理器,在固件上简化架构、优化高效的信息传递,从而实现了业界领先的性能。

图1.3 LSISAS1068E SAS控制器功能框图及其在系统中的位置

图1.4 LSISAS1068E SAS控制器应用示例

LSISAS1068E是一个基于Fusion-MPT架构的SAS控制器,它具有8个3.0Gb/s SAS端口,并提供8通道PCI Express接口。该LSI SAS控制器支持1.5和3.0Gb/s SAS和SATA端口,被广泛应用于服务器、工作站、刀片存储和外部存储系统。

图1.5 LSISAS1068E SAS控制器硬件框图

MPTSAS驱动的源码在文件drivers\message\fusion 中。

查看Kconfig文件:

menuconfig FUSION

bool "Fusion MPT device support"

depends on PCI

……

config FUSION_SAS

tristate "Fusion MPT ScsiHost drivers for SAS"

depends on PCI && SCSI

select SCSI_SAS_ATTRS

---help---

SCSI HOST support for a SAS host adapters.

List of supported controllers:

LSISAS1064

LSISAS1068

LSISAS1064E

LSISAS1068E

LSISAS1078

……

可见内核配置时应选择FUSION_SAS支持LSISAS1068E设备,其依赖PCI和SCSI模块。

查看MakeFile:

……

obj-$(CONFIG_FUSION_SAS) += mptbase.o mptscsih.o mptsas.o

……

可见编译内核时,选中CONFIG_FUSION_SAS,将会把mptbase.o、mptscsih.o、mptsas.o加入到内核中。其中:

mptbase是LSI Fusion-MPT驱动的通用函数集合,包含基础管理用到的函数;

mptsas是SAS控制器的函数集合,用来实现各种SAS命令的处理;

mptscsih 是LSI Fusion-MPT驱动和Linux SCSI层衔接用的函数集合。

2. 模块初始化

2.1 Mptbase模块初始化

Mptbase模块在加载时调用fusion_init做初始化。

fusion_init主要做了以下工作:

1、初始化函数指针数组

for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { MptCallbacks[cb_idx] = NULL;

MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;

MptEvHandlers[cb_idx] = NULL;

MptResetHandlers[cb_idx] = NULL;

}

MPT_MAX_PROTOCOL_DRIVERS为16,MptCallbacks[]为Callback lookup table,MptDriverClass[]为Protocol driver class lookup table,MptEvHandlers[]为Event handler lookup table,MptResetHandlers[]为Reset handler lookup table。

2、注册mpt_base_reply

mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);

将mpt_base_reply注册到MptCallbacks[],设置对应MptDriverClass []为MPTBASE_DRIVER。mpt_base_reply是MPT基本的驱动程序回调例程,所有的基本驱动程序“内部”请求/应答处理经过这里,用于EventNotification和EventAck 处理。

3、注册mpt_ioc_reset

mpt_reset_register(mpt_base_index, mpt_ioc_reset);

将mpt_ioc_reset注册到mpt_base_index对应的MptResetHandlers[]。mpt_ioc_reset对硬重置做基本清理,以内部产生的命令释放资源。

2.2 Mptsas模块初始化

Mptsas模块在加载时调用mptsas_init做初始化。

mptsas_init主要做了以下工作:

1、设置scsi_transport_template模版

mptsas_transport_template =

sas_attach_transport(&mptsas_transport_functions);

mptsas_transport_functions的定义为:

static struct sas_function_template mptsas_transport_functions = {

.get_linkerrors = mptsas_get_linkerrors,

.get_enclosure_identifier = mptsas_get_enclosure_identifier,

.get_bay_identifier = mptsas_get_bay_identifier,

.phy_reset = mptsas_phy_reset,

.smp_handler = mptsas_smp_handler,

};

scsi_transport_template描述了Scsi_Host的scsi host transport模版。

2、注册mptscsih_io_done、mptsas_taskmgmt_complete、mptscsih_scandv_complete、mptsas_mgmt_done

mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);

mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);

mptsasInternalCtx =

mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);

mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);

将mptscsih_io_done注册到MptCallbacks[],设置对应MptDriverClass []为MPTBASE_DRIVER,mptscsih_io_done是主要的SCSI IO回调例程,在完成SCSI IO后由mpt_interrupt调用。

将mptsas_taskmgmt_complete注册到MptCallbacks[],设置对应MptDriverClass []为MPTBASE_DRIVER,mptsas_taskmgmt_complete是SCSI task management request回调例程,完成管理任务后由mpt_interrupt调用。

将mptscsih_scandv_complete注册到MptCallbacks[],设置对应MptDriverClass []为MPTBASE_DRIVER,mptscsih_scandv_complete是扫描和域验证回调例程,仅用于DV和其他内部命令。

将mptsas_mgmt_done注册到MptCallbacks[],设置对应MptDriverClass []为MPTBASE_DRIVER。mptsas_mgmt_done是SAS management回调例程。

3、注册mpt_event_register、mpt_reset_register

mpt_event_register(mptsasDoneCtx, mptsas_event_process);

mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);

将mptsas_event_process注册到mptscsih_io_done对应的MptEvHandlers[]。将mptsas_ioc_reset注册到mptscsih_io_done对应的MptResetHandlers[]。

4、注册为PCI设备

error = pci_register_driver(&mptsas_driver);

mptsas_driver定义为:

static struct pci_driver mptsas_driver = {

.name = "mptsas",

.id_table = mptsas_pci_table,

.probe = mptsas_probe,

.remove = __devexit_p(mptsas_remove),

.shutdown = mptscsih_shutdown,

#ifdef CONFIG_PM

.suspend = mptscsih_suspend,

.resume = mptscsih_resume,

#endif

};

其中id_table成员变量,记录了当前这个驱动所能够进行驱动的那些设备的ID值,

static struct pci_device_id mptsas_pci_table[] = {

{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,

PCI_ANY_ID, PCI_ANY_ID },

{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,

PCI_ANY_ID, PCI_ANY_ID },

{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,

PCI_ANY_ID, PCI_ANY_ID },

{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,

PCI_ANY_ID, PCI_ANY_ID },

{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,

PCI_ANY_ID, PCI_ANY_ID },

{0} /* Terminating entry */

};

MODULE_DEVICE_TABLE(pci, mptsas_pci_table);

PCI的注册就是将PCI驱动程序挂载到其所在的总线的drivers链,同时扫描PCI设备,将它能够进行驱动的设备挂载到driver上的devices链表上来。图2.1为mptsas在PCI层的注册的函数调用流程图,能够更直观地展现Mptsas 从注册到调用其自身的mptsas_probe初始化的这一个函数调用过程。

pci.h

Mptsas设备驱动的初始化函数

在初始化函数中调用pci_register_driver函

数来注册该PCI设备

pci_driver.c pci_register_driver函数调用_pci_register_driver

driver.c__pci_register_driver函数调用driver_register,

将当前设备注册到其对应的总线上

driver register函数调用bus_add_driver,获

得当前设备所在的总线

bus.c

dd.c 遍历PCI总线上的每个设备,如果某设备能被当前驱动所支持则在设备与驱动之间

建立联系

dd.c driver_attach调用__driver_attach,对总线上的设备与当前驱动之间调用函数

driver_probe_device

dd.c将设备与驱动联系起来

pci_driver.c 获得pci_driver,pci_dev结构体的地址,并调用函数pci_match_device

pci_driver.c

根据pci_driver中所支持的PCI设备的标识与当前设备进行比较,以检测该PCI驱动是否支

持这个设备

dd.c

从pci_bus_match返回后继续在函数

driver_probe_device中

该函数最终会执行这个PCI驱动程序所对应的probe函数,为该设备进行相应的初始化

dd.c

获得当前PCI设备的pci_dev地址以及PCI驱动

的pci_driver地址

pci_driver.c

pci_driver.c

最后再检查当前PCI驱动与PCI设备是否相匹配,如果匹配就调用最后的pci_call_probe函数

pci_driver.c 在该函数中会调用当前PCI驱动中的probe函

数,即mptsas_probe

Mptsas.c

为Mptsas设备进行初始化等操作,PCI层的注册

到此结束

图2.1 MPTSAS PCI注册流程

3. Mptsas_probe探测

LSISAS1068E SAS控制器作为PCI设备,由PCI总线驱动层加载Mptsas_probe 来探测。

在Mptsas具体的probe函数中会建立MPT_ADAPTER、注册中断处理函数,完成其作为MPTSAS设备的初始化;

并调用scsi_host_alloc函数建立一个SCSI_HOST,调用scsi_add_host添加到scsi middle level,最后调用mptsas_scan_sas_topology函数扫描它所管理的所有scsi总线,完成其作为SCSI设备的初始化。

3.1 将MPT adapter设置为可操作状态

调用mpt_attach

r = mpt_attach(pdev,id);

mpt_attach执行所有必要的步骤,将MPT adapter设置为可操作状态,这个过程包括注册内存区域、注册中断、分配请求/答复内存池。

(1)建立MPT_ADAPTER结构体

ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);

pci_dev结构体负责描述MPT adapter的PCI规范,而MPT_ADAPTER结构体描述了其负责MPT adapter设备的职责。MPT_ADAPTER的定义在Mptbase.h 中:

typedef struct _MPT_ADAPTER

{

int id; /* Unique adapter id N {0,1,2,...} */

int pci_irq; /* This irq */

char name[MPT_NAME_LENGTH]; /* "iocN" */

char prod_name[MPT_NAME_LENGTH]; /* "LSIFC9x9" */ char board_name[16];

char board_assembly[16];

char board_tracer[16];

u16 nvdata_version_persistent;

u16 nvdata_version_default;

int debug_level;

u8 io_missing_delay;

u8 device_missing_delay;

SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */

SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */

u8 bus_type;

u32 mem_phys; /* == f4020000 (mmap) */

u32 pio_mem_phys; /* Programmed IO (downloadboot) */

int mem_size; /* mmap memory size */

int number_of_buses;

int devices_per_bus;

int alloc_total;

u32 last_state;

int active;

u8 *alloc; /* frames alloc ptr */

dma_addr_t alloc_dma;

u32 alloc_sz;

MPT_FRAME_HDR *reply_frames; /* Reply msg frames - rounded up! */ u32 reply_frames_low_dma;

int reply_depth; /* Num Allocated reply frames */

int reply_sz; /* Reply frame size */

int num_chain; /* Number of chain buffers */

/* Pool of buffers for chaining. ReqToChain

* and ChainToChain track index of chain buffers.

* ChainBuffer (DMA) virt/phys addresses.

* FreeChainQ (lock) locking mechanisms.

*/

int *ReqToChain;

int *RequestNB;

int *ChainToChain;

u8 *ChainBuffer;

dma_addr_t ChainBufferDMA;

struct list_head FreeChainQ;

spinlock_t FreeChainQlock;

/* We (host driver) get to manage our own RequestQueue! */

dma_addr_t req_frames_dma;

MPT_FRAME_HDR *req_frames; /* Request msg frames - rounded up! */ u32 req_frames_low_dma;

int req_depth; /* Number of request frames */

int req_sz; /* Request frame size (bytes) */

spinlock_t FreeQlock;

struct list_head FreeQ;

/* Pool of SCSI sense buffers for commands coming from

* the SCSI mid-layer. We have one 256 byte sense buffer

* for each REQ entry.

*/

u8 *sense_buf_pool;

dma_addr_t sense_buf_pool_dma;

u32 sense_buf_low_dma;

u8 *HostPageBuffer; /* SAS - host page buffer support */

u32 HostPageBuffer_sz;

dma_addr_t HostPageBuffer_dma;

int mtrr_reg;

struct pci_dev *pcidev; /* struct pci_dev pointer */

int bars; /* bitmask of BAR's that must be configured */

int msi_enable;

u8 __iomem *memmap; /* mmap address */

struct Scsi_Host *sh; /* Scsi Host pointer */

SpiCfgData spi_data; /* Scsi config. data */

RaidCfgData raid_data; /* Raid config. data */

SasCfgData sas_data; /* Sas config. data */

FcCfgData fc_data; /* Fc config. data */

MPT_IOCTL *ioctl; /* ioctl data pointer */

struct proc_dir_entry *ioc_dentry;

struct _MPT_ADAPTER *alt_ioc; /* ptr to 929 bound adapter port */

spinlock_t diagLock; /* diagnostic reset lock */

int diagPending;

u32 biosVersion; /* BIOS version from IO Unit Page 2 */

int eventTypes; /* Event logging parameters */

int eventContext; /* Next event context */

int eventLogSize; /* Max number of cached events */

struct _mpt_ioctl_events *events; /* pointer to event log */

u8 *cached_fw; /* Pointer to FW */

dma_addr_t cached_fw_dma;

struct list_head configQ; /* linked list of config. requests */

int hs_reply_idx;

#ifndef MFCNT

u32 pad0;

#else

u32 mfcnt;

#endif

u32 NB_for_64_byte_frame;

u32 hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)];

u16 hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)];

IOCFactsReply_t facts;

PortFactsReply_t pfacts[2];

FCPortPage0_t fc_port_page0[2];

struct timer_list persist_timer; /* persist table timer */

int persist_wait_done; /* persist completion flag */

u8 persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */

LANPage0_t lan_cnfg_page0;

LANPage1_t lan_cnfg_page1;

u8 ir_firmware; /* =1 if IR firmware detected */

/*

* Description: errata_flag_1064

* If a PCIX read occurs within 1 or 2 cycles after the chip receives

* a split completion for a read data, an internal address pointer incorrectly

* increments by 32 bytes

*/

int errata_flag_1064;

int aen_event_read_flag; /* flag to indicate event log was read*/

u8 FirstWhoInit;

u8 upload_fw; /* If set, do a fw upload */

u8 reload_fw; /* Force a FW Reload on next reset */

u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */ u8 pad1[4];

u8 DoneCtx;

u8 TaskCtx;

u8 InternalCtx;

spinlock_t initializing_hba_lock;

int initializing_hba_lock_flag;

struct list_head list;

struct net_device *netdev;

struct list_head sas_topology;

struct mutex sas_topology_mutex;

struct mutex sas_discovery_mutex;

u8 sas_discovery_runtime;

u8 sas_discovery_ignore_events;

int sas_index; /* index refrencing */

MPT_SAS_MGMT sas_mgmt;

struct work_struct sas_persist_task;

struct work_struct fc_setup_reset_work;

struct list_head fc_rports;

struct work_struct fc_lsc_work;

u8 fc_link_speed[2];

spinlock_t fc_rescan_work_lock;

struct work_struct fc_rescan_work;

char fc_rescan_work_q_name[KOBJ_NAME_LEN];

struct workqueue_struct *fc_rescan_work_q;

struct scsi_cmnd **ScsiLookup;

spinlock_t scsi_lookup_lock;

} MPT_ADAPTER;

获取id:

ioc->id = mpt_ids++;

关联MPT_ADAPTER与pci_dev:

ioc->pcidev = pdev;

(2)IO映射

调用mpt_mapresources

mpt_mapresources(ioc);

其中主要操作为:

a、开启设备寄存器映射到内存的功能

ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);

pci_enable_device_mem(pdev);

pci_request_selected_regions(pdev, ioc->bars, "mpt");

b、获得各项资源

pci_resource_flags;

pci_resource_start;

pci_resource_len;

在硬件加电初始化时,BIOS检查所有的PCI设备,并为它们分配了一个和其他互不冲突的地址,让它们的驱动程序可以向这些地址映射他们的寄存器,这些地址被BIOS写进了各个设备的配置空间,因为这个活动是一个PCI的标准的活动,所以写到设备的配置空间里而不是MPT adapter控制寄存器空间里。当操作系统初始化时,为每个PCI设备分配了pci_dev结构,并且把BIOS获得的、并写到了配置空间中的地址读出来写到了pci_dev中的resource字段中。该处读取pci_dev的resource字段来获取各项资源信息。

c、把得到的地址进行映射

mem = ioremap(mem_phys, msize);

ioremap是内核提供的用来映射外设寄存器到主存的函数,mem_phys、msize 是从pci_dev读出的映射地址信息。映射后mem就是第一个寄存器的地址,我们能够在内存中访问所有的寄存器进而操控它们了。

(3)检查”bound ports”(929, 929x, 1030, 1035)来减少重复重置

mpt_detect_bound_ports(ioc, pdev);

FC、SPI需要,SAS无关。

(4)初始化MPT adapter

调用mpt_do_ioc_recovery

r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP);

其中主要操作为:

a、将MPT adapter置于READY状态

调用MakeIocReady

hard_reset_done = MakeIocReady(ioc, hard, sleepFlag);

使得MPT adapter处于MPI_IOC_STATE_READY状态,在MakeIocReady中,如果ioc处于其他状态则会调用SendIocReset对其进行重置。

b、读取MPT adapter、Port 0的Facts信息

调用GetIocFacts

rc = GetIocFacts(ioc, sleepFlag, reason);

GetIocFacts具体完成了:

b1、调用mpt_handshake_req_reply_wait,读取MPT adapter的Facts信息,结果保存在MPT_ADAPTER中的IOCFactsReply_t facts结构体中。

IOCFactsReply_t的定义在Mpi_ioc.h中,用来描述Message Passing Interface 协议中MPT adapter的状态:

typedef struct _MSG_IOC_FACTS_REPLY

{

U16 MsgVersion; /* 00h */

U8 MsgLength; /* 02h */

U8 Function; /* 03h */

U16 HeaderVersion; /* 04h */

U8 IOCNumber; /* 06h */

U8 MsgFlags; /* 07h */

U32 MsgContext; /* 08h */

U16 IOCExceptions; /* 0Ch */

U16 IOCStatus; /* 0Eh */

U32 IOCLogInfo; /* 10h */

U8 MaxChainDepth; /* 14h */

U8 WhoInit; /* 15h */

U8 BlockSize; /* 16h */

U8 Flags; /* 17h */

U16 ReplyQueueDepth; /* 18h */

U16 RequestFrameSize; /* 1Ah */

U16 Reserved_0101_FWVersion; /* 1Ch */ /* obsolete 16-bit FWVersion */

U16 ProductID; /* 1Eh */

U32 CurrentHostMfaHighAddr; /* 20h */

U16 GlobalCredits; /* 24h */

U8 NumberOfPorts; /* 26h */

U8 EventState; /* 27h */

U32 CurrentSenseBufferHighAddr; /* 28h */

U16 CurReplyFrameSize; /* 2Ch */

U8 MaxDevices; /* 2Eh */

U8 MaxBuses; /* 2Fh */

U32 FWImageSize; /* 30h */

U32 IOCCapabilities; /* 34h */

MPI_FW_VERSION FWVersion; /* 38h */

U16 HighPriorityQueueDepth; /* 3Ch */

U16 Reserved2; /* 3Eh */

SGE_SIMPLE_UNION HostPageBufferSGE; /* 40h */

U32 ReplyFifoHostSignalingAddr; /* 4Ch */

} MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY, IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t;

b2、GetIocFacts根据设备返回的facts信息,设置MPT_ADAPTER的请求/响应帧大小及请求/响应队列深度。

b3、调用GetPortFacts,读取Port 0的Facts信息,结果保存在MPT_ADAPTER 中的PortFactsReply_t pfacts[0]结构体中。

r = GetPortFacts(ioc, 0, sleepFlag);

PortFactsReply_t的定义在Mpi_ioc.h中,用来描述Message Passing Interface 协议中MPT adapter某个Port的状态:

typedef struct _MSG_PORT_FACTS_REPLY

{

U16 Reserved; /* 00h */

U8 MsgLength; /* 02h */

U8 Function; /* 03h */

U16 Reserved1; /* 04h */

U8 PortNumber; /* 06h */

U8 MsgFlags; /* 07h */

U32 MsgContext; /* 08h */

U16 Reserved2; /* 0Ch */

U16 IOCStatus; /* 0Eh */

U32 IOCLogInfo; /* 10h */

U8 Reserved3; /* 14h */

U8 PortType; /* 15h */

U16 MaxDevices; /* 16h */

U16 PortSCSIID; /* 18h */

U16 ProtocolFlags; /* 1Ah */

U16 MaxPostedCmdBuffers; /* 1Ch */

U16 MaxPersistentIDs; /* 1Eh */

U16 MaxLanBuckets; /* 20h */

U8 MaxInitiators; /* 22h */

U8 Reserved4; /* 23h */

U32 Reserved5; /* 24h */

} MSG_PORT_FACTS_REPLY, MPI_POINTER PTR_MSG_PORT_FACTS_REPLY, PortFactsReply_t, MPI_POINTER pPortFactsReply_t;

c、重置Mpt adapter,并申请中断、初始化请求/响应队列

c1、重置Mpt adapter

c2、调用request_irq注册mpt_interrupt为中断处理函数。

rc = request_irq(ioc->pcidev->irq, mpt_interrupt,

IRQF_SHARED, ioc->name, ioc);

mpt_interrupt在mptbase.c中定义。

c3、调用PrimeIocFifos启动请求/响应队列

rc = PrimeIocFifos(ioc);

PrimeIocFifos为MPT请求/响应帧分配了DMA存储池,并建立了请求队列FreeQ、链缓冲区FreeChainQ、在响应帧中填入MPT adapter响应FIFO信息。

Fusion-MPT架构提供了两种I/O方法供主机和IOP通信:系统接口doorbell 和消息队列。

系统接口doorbell是一个简单的消息传递机制,允许PCI主机和IOP交换

32-bit的Dword消息。当主机写入doorbell时,LSISAS1068E硬件向IOP产生一个可屏蔽中断,然后可以读取doorbell的值,并采取适当的操作。当IOP写入doorbell时,LSISAS1068E硬件向主机发出一个可屏蔽中断。主机系统可以读取doorbell值并采取相应操作。

有两个32-bit的消息队列:请求队列和响应队列。主机通过请求队列向LSISAS1068E要求执行操作,LSISAS1068E使用响应队列向主机返回状态信息。请求队列包括request post FIFO,响应队列包含reply post FIFO和reply free FIFO。上下文RAM中包含消息队列。Fusion-MPT架构提供一个高优先级的请求FIFO 供高优先级的request free message到主机读取信息,并接收高优先级的request free message主机写信息。通过request post FIFO传递的是指向请求消息帧结构的指针,请求消息帧结构有128 bytes的长度,包含一个message header和载荷,载荷包含了特定请求信息。通过reply post FIFO传递的响应消息帧指针有两种格式。当一个SCSI I/O完成时,IOP使用Context Reply 格式指针。如果一个SCSI I/O没有成功完成,IOP使用Address Reply格式指针,在这种情况下,IOP 从reply free FIFO申请一个响应消息帧,在其中填入错误描述,将响应消息写入主机内存,然后将帧地址写入reply post FIFO,主机能够读取信息并采取相应操作。

d、使MPT adapter处于工作状态

调用SendIocInit,

rc = SendIocInit(ioc, sleepFlag);

SendIocInit中调用SendPortEnable,

SendPortEnable(ioc, 0, sleepFlag);

使MPT adapter处于工作状态。

e、启动MPT adapter的EventNotification基本驱动管理和EventAck处理

(void) SendEventNotification(ioc, 1);

f、释放所有目前不存在的设备的TargetID映射

ret = mptbase_sas_persist_operation(ioc,

MPI_SAS_OP_CLEAR_NOT_PRESENT);

g、确定隐藏的磁盘和RAID卷的ID

mpt_findImVolumes(ioc);

mpt_findImVolunmes首先清空MPT_ADAPTER的raid_data.inactive_list队列,mpt_inactive_raid_list_free(ioc);

然后mpt_findImVolunmes读取MPT adapter设备自身对RAID信息的记录,并保存在CONFIG_PAGE_IOC_2结构体中。CONFIG_PAGE_IOC_2结构体在Mpi_cnfg.h中定义:

typedef struct _CONFIG_PAGE_IOC_2

{

CONFIG_PAGE_HEADER Header; /* 00h */

U32 CapabilitiesFlags; /* 04h */

U8 NumActiveVolumes; /* 08h */ U8 MaxVolumes; /* 09h */ U8 NumActivePhysDisks; /* 0Ah */ U8 MaxPhysDisks; /* 0Bh */ CONFIG_PAGE_IOC_2_RAID_VOL

RaidVolume[MPI_IOC_PAGE_2_RAID_VOLUME_MAX];/* 0Ch */

} CONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2,

IOCPage2_t, MPI_POINTER pIOCPage2_t;

再次mpt_findImVolunmes读取MPT adapter设备自身对磁盘信息的记录,并保存在CONFIG_PAGE_IOC_3结构体中。CONFIG_PAGE_IOC_3结构体在Mpi_cnfg.h中定义:

typedef struct _CONFIG_PAGE_IOC_3

{

CONFIG_PAGE_HEADER Header; /* 00h */ U8 NumPhysDisks; /* 04h */ U8 Reserved1; /* 05h */ U16 Reserved2; /* 06h */ IOC_3_PHYS_DISK PhysDisk[MPI_IOC_PAGE_3_PHYSDISK_MAX]; /* 08h */ } CONFIG_PAGE_IOC_3, MPI_POINTER PTR_CONFIG_PAGE_IOC_3,

IOCPage3_t, MPI_POINTER pIOCPage3_t;

最后mpt_findImVolunmes调用mpt_inactive_raid_volumes将与RAID卷相关联的物理磁盘信息取出保存在inactive_raid_component_info结构体中,并

将inactive_raid_component_info结构体加入MPT_ADAPTER的raid_data.inactive_list队列。

inactive_raid_component_info结构体描述了RAID卷对应的物理磁盘信息,在Mptbase.h中定义:

struct inactive_raid_component_info {

struct list_head list;

u8 volumeID; /* volume target id */

u8 volumeBus; /* volume channel */

IOC_3_PHYS_DISK d; /* phys disk info */

};

其中IOC_3_PHYS_DISK结构体具体描述了物理磁盘信息,Mpi_cnfg.h中定义:typedef struct _IOC_3_PHYS_DISK

{

U8 PhysDiskID; /* 00h */

U8 PhysDiskBus; /* 01h */

U8 PhysDiskIOC; /* 02h */

U8 PhysDiskNum; /* 03h */

} IOC_3_PHYS_DISK, MPI_POINTER PTR_IOC_3_PHYS_DISK,

Ioc3PhysDisk_t, MPI_POINTER pIoc3PhysDisk_t;

至此mpt_do_ioc_recovery返回

(4)调用每个设备函数寻找入口点

mpt_do_ioc_recovery将MPT adapter设置成为可操作状态,返回mpt_attach。mpt_attach调用每个设备函数寻找入口点

MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);

至此mpt_attach返回

3.2 注册MPTSAS回调函数

Mptsas_probe调用mpt_attach,将MPT adapter设置为可操作状态,并以MPT_ADAPTER结构体来描述这个设备。

Mptsas_probe继续为这个设备注册mptsas驱动中的标准回调函数mptscsih_io_done、mptsas_taskmgmt_complete、mptscsih_scandv_complete、mptsas_mgmt_done:

ioc->DoneCtx = mptsasDoneCtx;

ioc->TaskCtx = mptsasTaskCtx;

ioc->InternalCtx = mptsasInternalCtx;

3.3 注册Scsi_Host、gendev

(1)建立Scsi_Host结构体

sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));

Scsi_Host结构体负责描述SCSI设备,定义在scsi_host.h中:

struct Scsi_Host{

/*

* __devices is protected by the host_lock, but you should

* usually use scsi_device_lookup / shost_for_each_device

* to access it and don't care about locking yourself.

* In the rare case of beeing in irq context you can use

* their __ prefixed variants with the lock held. NEVER

* access this list directly from a driver.

*/

struct list_head __devices;

struct list head __targets;

struct scsi_host_cmd_pool *cmd_pool;

spinlock_t free_list_lock;

struct list_head free_list; /* backup store of cmd structs */

struct list_head starved_list;

spinlock_t default_lock;

spinlock_t *host_lock;

struct mutex scan_mutex;/* serialize scanning activity */

struct list_head eh_cmd_q;

struct task_struct * ehandler; /* Error recovery thread. */

struct completion * eh_action; /* Wait for specific actions on the

host. */

wait_queue_head_t host_wait;

struct scsi_host_template *hostt;

struct scsi_transport_template *transportt;

/*

* Area to keep a shared tag map (if needed, will be

* NULL if not).

*/

struct blk_queue_tag *bqt;

/*

* The following two fields are protected with host_lock;

* however, eh routines can safely access during eh processing

* without acquiring the lock.

*/

unsigned int host_busy; /* commands actually active on low-level */ unsigned int host_failed; /* commands that failed. */

unsigned int host_eh_scheduled; /* EH scheduled without command */

unsigned int host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */

int resetting; /* if set, it means that last_reset is a valid value */

unsigned long last_reset;

/*

* These three parameters can be used to allow for wide scsi,

* and for host adapters that support multiple busses

* The first two should be set to 1 more than the actual max id

* or lun (i.e. 8 for normal systems).

*/

unsigned int max_id;

unsigned int max_lun;

unsigned int max_channel;

/*

* This is a unique identifier that must be assigned so that we

* have some way of identifying each detected host adapter properly

* and uniquely. For hosts that do not support more than one card

* in the system at one time, this does not need to be set. It is

* initialized to 0 in scsi_register.

*/

unsigned int unique_id;

/*

* The maximum length of SCSI commands that this host can accept.

* Probably 12 for most host adapters, but could be 16 for others.

* or 260 if the driver supports variable length cdbs.

* For drivers that don't set this field, a value of 12 is

* assumed.

*/

unsigned short max_cmd_len;

int this_id;

int can_queue;

short cmd_per_lun;

short unsigned int sg_tablesize;

short unsigned int max_sectors;

unsigned long dma_boundary;

windows设备管理与驱动程序

计算机可以配置许多I/O设备,种类很多,而且随着技术的发展新设备也不断出现。I/O 设备既是人机交互的界面,也是计算机与计算机通信的枢纽,需要处理的信息其原始形态是光波、电波、声波、红外线等各种不同的物理信号,它们承载的信息可以是文本、图像、声音、视频等各种不同的载体。这方面导致了计算机应用的多样性和普遍性,另一方面也使得I/O设备的管理相当复杂。 此外,I/O设备的速度比CPU和内存的速度要慢得多,它们经常成为系统性能的瓶颈。多任务处理是提高系统性能的一个途径,但是在多任务处理中,怎么保证I/O设备安全可靠而且被多个任务共享使用,这也是操作系统需要解决的一项任务。 为此,操作系统中的设备管理程序负责对系统中的各种输入/输出设备进行统一的管理,处理用户或应用程序的输入输出请求,方便、有效、安全地完成输入输出操作。 ⑴方便性。用户(程序)总是希望方便地使用I/O设备,但I/O过程非常复杂,如果直接控制或使用I/O设备,必须了解许多与应用本身没有直接关系的具体细节,工作量大,效率低,设备型号和系统配置的变化将引起程序的修改,影响程序的独立性和适应性。而且让程序员直接操作物理设备,也不利于设备及其数据的保护。 解决这个问题的方法是采用设备驱动程序。设备驱动程序处于操作系统的底层,它将具体物体设备的性质和硬件操作的细节予以品屏蔽和抽象,只向操作系统的高层和应用程序提供统一的建斌啊医用的抽象设备和逻辑操作,操作系统高层和应用程序通过驱动程序访问外设,由驱动程序负责把抽象设备的操作转换成具体物理设备的操作。这样一来,不同规格和性能参数的外部设别(如各种不同的打印机)通过安装各自定制的设备驱动程序,就能使系统和应用程序不需要进行任何修改就了直接使用该设备。通常,外设的生产厂商在提供硬件设备的同时必须提供该设备的驱动程序。 ⑵有效性。为了确保I/O设备多个任务所共享,设备管理程序必须解决许多问题。例如:设备的命名、登记、分配、回收及调度等。对于可并发共享的设备(如磁盘、显示器等),为了使设备的利用率达到最优,设备管理程序将根据每个设备的特点来全局调度和安排设备的操作。例如,对硬盘的多个读写要求可以进行进行排序,使得每次读写操作的磁头移动距离都尽可能短。对于独占设备(如打印机、绘图仪等),可以采用假脱机技术,把每一个要打印或绘制的文档,按先来先服务的顺序将其存放在队列中,然后以后台方式依次进行打印或绘图,从而大大提高了慢速独占设备的利用率。 为了解决I/O设备速度过慢,效率不高的问题,设备管理中大多应用了缓冲技术,以减少I/O操作的等待时间。虽然有些I/O设备或控制器内部已有硬件缓冲(如打印机和磁盘控制器内部有缓存存储器),但操作系统仍然在内存中开设I/O缓冲区和文件系统缓冲区。 ⑶安全性。在多任务系统中,由于I/O设备的数量有限,并不是每个任务随时都可以使用这些设备的。为了使用某个设备,必须先向设备管理程序提出申请,然后由设备管理程序按一定算法进行分配。如果申请没有成功,它就必须排队等待,只有分配到该设备并完成I/O操作后相关的任务才能继续执行下去。Windows就采用了这种安全分配方式。 在windows操作系统中,设备管理程序还支持即插即用功能,并按ACPI标准进行电源管理(系统的能耗状态可设置为工作状态、等待状态或休眠状态等多种),它能检测设备的闲置时间,当发现超过预定值时,就把设备切换到低能耗状态。 Windows操作系统中有一个称为设备管理器的工具程序,它可以利用我的电脑快捷菜单中的属性命令或通过控制面板中的系统启动。启动后用户可以按类型或链接方式来寻找所关心的设备,查看该设备的信息和当前工作状态,也可以修改或重新配置设备的操作环境。

Linux设备驱动程序学习(5)-高级字符驱动程序操作[(2)阻塞型IO和休眠]

Linux设备驱动程序学习(5)-高级字符驱动程序操作[(2)阻 塞型I/O和休眠] Linux设备驱动程序学习(5) -高级字符驱动程序操作[(2)阻塞型I/O和休眠]这一部分主要讨论:如果驱动程序无法立即满足请求,该如何响应?(65865346) 一、休眠 进程被置为休眠,意味着它被标识为处于一个特殊的状态并且从调度器的运行队列中移走。这个进程将不被在任何CPU 上调度,即将不会运行。直到发生某 些事情改变了那个状态。安全地进入休眠的两条规则: (1)永远不要在原子上下文中进入休眠,即当驱动在持有一个自旋锁、seqlock或者RCU 锁时不能睡眠;关闭中断也不能睡眠。持有一个信号量时休眠是 合法的,但你应当仔细查看代码:如果代码在持有一个信号量时睡眠,任何其他的等待这个信号量的线程也会休眠。因此发生在持有信号量时的休眠必须短暂, 而且决不能阻塞那个将最终唤醒你的进程。 (2)当进程被唤醒,它并不知道休眠了多长时间以及休眠时发生什么;也不知道是否另有进程也在休眠等待同一事件,且那个进程可能在它之前醒来并获取了 所等待的资源。所以不能对唤醒后的系统状态做任何的假设,并必须重新检查等待条件来确保正确的响应。 除非确信其他进程会在其他地方唤醒休眠的进程,否则也不能睡眠。使进程可被找到意味着:需要维护一个称为等待队列的数据结构。它是一个进程链表,其中饱含了等待某个特定事件的所有进程。在Linux 中,一个等待队列由一个wait_queue_head_t 结构体来管理,其定义在中。 wait_queue_head_t 类型的数据结构非常简单: 它包含一个自旋锁和一个链表。这个链表是一个等待队列入口,它被声明做wait_queue_t。wait_queue_head_t包含关于睡眠进程的信息和它想怎样被唤

windows驱动开发和调试环境搭建

Windows驱动开发和环境搭建 【文章标题】: Windows驱动开发和调试的环境设置 【文章作者】: haikerenwu 【使用工具】: VC6.0,VMware6.0.3,Windbg 【电脑配置】: 惠普笔记本xp sp3 (一)VMWare安装篇 VMWare的安装一路Next即可,关于其序列号,百度一下就能找到,虚拟机安装完成之后,需要安装操作系统,我在虚拟机中安装的是windows xp sp2系统。 点击“文件”----“新建”----“虚拟机” 进入新建虚拟机的向导,配置虚拟系统参数

选择虚拟系统文件的兼容格式(新手推荐选择默认选项) 按照默认设置继续点击下一步,选择好您需要的操作系统,此处我选择的是Windows XP Prefessional。 设置虚拟机名称和虚拟操作系统安装路径,我单独空出来一个F 盘,将虚拟机和虚拟操作系统全部装在该盘。

配置网络模式(推荐选择NA T,一般主机不用做任何的设置虚拟机就可以利用主机上网)。 配置虚拟磁盘的容量。在这里可以直接单击完成,来完成基本操作设置,磁盘默认空间是8GB,用户可以根据自己的实际使用情况来调整大小,也可以自定义分区。

操作完成之后,在“VM”菜单下有个“setting。。。”菜单,点击此菜单,在CD-ROM中选择合适的选项,我使用的是Use ISO image 选项,将我的xp sp2操作系统的ISO映像路径设置好,安装操作系统。点击ok之后,启动虚拟机,即开始安装操作系统,安装过程跟普通装机过程相同。安装完成之后,启动操作系统,然后在VM菜单下点击“Install VMWare Tools”,把虚拟操作系统的驱动装好。 (二)VMWare设置篇

Windows驱动程序手册

Windows驱动程序手册ELP-108/168/188ES(Rev.1.4)

目录 1.手册信息 (1) 2.操作系统 (1) 3.程序准备 (1) 4.驱动的安装 (2) 5.驱动的设置 (4) 5.1打印首选项 (4) 5.2其他设置 (9) 6.规格 (10) 6.1分辨率 (10) 6.2纸张规格 (10)

1.手册信息 本手册提供了Windows驱动程序安装说明和主要功能方面的信息。 我们致力于提高和升级产品的功能和质量,规格书的内容可能会更改,恕不另行通知。 2.操作系统 本打印机的Windows驱动适用于以下操作系统: ●Microsoft Windows8(32bit/64bit) ●Microsoft Windows7SPI(32bit/64bit) ●Microsoft Windows7SPI(32bit/64bit) ●Microsoft Windows7SPI(32bit/64bit) ●Microsoft Windows Vista SP2(32bit/64bit) ●Microsoft Windows XP Professional SP3(32bit) ●Microsoft Windows Server2012(64bit) ●Microsoft Windows Server2008R2 ●Microsoft Windows Server2008SP2(32bit/64bit) ●Microsoft Windows Server2003R2SP2(32bit/64bit) 3.程序准备 驱动程序包含在随机所附CD。 驱动文件命名为:Tengen ELP Label Driver-v-X.X.X.X.exe 如:Tengen ELP Label Driver-v-1.2.0.0.exe

设备驱动程序

驱动程序 驱动程序一般指的是设备驱动程序(Device Driver),是一种可以使计算机和设备通信的特殊程序。相当于硬件的接口,操作系统只有通过这个接口,才能控制硬件设备的工作,假如某设备的驱动程序未能正确安装,便不能正常工作。 因此,驱动程序被比作“硬件的灵魂”、“硬件的主宰”、和“硬件和系统之间的桥梁”等。 中文名 驱动程序 外文名 Device Driver 全称 设备驱动程序 性质 可使计算机和设备通信的特殊程序 目录 1定义 2作用 3界定 ?正式版 ?认证版 ?第三方 ?修改版 ?测试版 4驱动程序的开发 ?微软平台 ?Unix平台 5安装顺序 6inf文件 1定义 驱动程序(Device Driver)全称为“设备驱动程序”,是一种可以使计算机和设备通信的特殊程序,可以说相当于硬件的接口,操作系统只能通过这个接口,才能控制硬件设备的工作,假如某设备的驱动程序未能正确安装,便不能正常工作。 惠普显卡驱动安装 正因为这个原因,驱动程序在系统中的所占的地位十分重要,一般当操作系统安装完毕后,首要的便是安装硬件设备的驱动程序。不过,大多数情况下,我们并不需要安装所有硬件设备的驱动程序,例如硬盘、显示器、光驱等就不需要安装驱动程序,而显卡、声卡、扫描仪、摄像头、Modem等就需要安装驱动程序。另外,不同版本的操作系统对硬件设

备的支持也是不同的,一般情况下版本越高所支持的硬件设备也越多,例如笔者使用了Windows XP,装好系统后一个驱动程序也不用安装。 设备驱动程序用来将硬件本身的功能告诉操作系统,完成硬件设备电子信号与操作系统及软件的高级编程语言之间的互相翻译。当操作系统需要使用某个硬件时,比如:让声卡播放音乐,它会先发送相应指令到声卡驱动程序,声卡驱动程序接收到后,马上将其翻译成声卡才能听懂的电子信号命令,从而让声卡播放音乐。 所以简单的说,驱动程序提供了硬件到操作系统的一个接口以及协调二者之间的关系,而因为驱动程序有如此重要的作用,所以人们都称“驱动程序是硬件的灵魂”、“硬件的主宰”,同时驱动程序也被形象的称为“硬件和系统之间的桥梁”。 戴尔电脑驱动盘 驱动程序即添加到操作系统中的一小块代码,其中包含有关硬件设备的信息。有了此信息,计算机就可以与设备进行通信。驱动程序是硬件厂商根据操作系统编写的配置文件,可以说没有驱动程序,计算机中的硬件就无法工作。操作系统不同,硬件的驱动程序也不同,各个硬件厂商为了保证硬件的兼容性及增强硬件的功能会不断地升级驱动程序。如:Nvidia显卡芯片公司平均每个月会升级显卡驱动程序2-3次。驱动程序是硬件的一部分,当你安装新硬件时,驱动程序是一项不可或缺的重要元件。凡是安装一个原本不属于你电脑中的硬件设备时,系统就会要求你安装驱动程序,将新的硬件与电脑系统连接起来。驱动程序扮演沟通的角色,把硬件的功能告诉电脑系统,并且也将系统的指令传达给硬件,让它开始工作。 当你在安装新硬件时总会被要求放入“这种硬件的驱动程序”,很多人这时就开始头痛。不是找不到驱动程序的盘片,就是找不到文件的位置,或是根本不知道什么是驱动程序。比如安装打印机这类的硬件外设,并不是把连接线接上就算完成,如果你这时候开始使用,系统会告诉你,找不到驱动程序。怎么办呢参照说明书也未必就能顺利安装。其实在安装方面还是有一定的惯例与通则可寻的,这些都可以帮你做到无障碍安装。 在Windows系统中,需要安装主板、光驱、显卡、声卡等一套完整的驱动程序。如果你需要外接别的硬件设备,则还要安装相应的驱动程序,如:外接游戏硬件要安装手柄、方向盘、摇杆、跳舞毯等的驱动程序,外接打印机要安装打印机驱动程序,上网或接入局域网要安装网卡、Modem甚至ISDN、ADSL的驱动程序。说了这么多的驱动程序,你是否有一点头痛了。下面就介绍Windows系统中各种的不同硬件设备的驱动程序,希望能让你拨云见日。 在Windows 9x下,驱动程序按照其提供的硬件支持可以分为:声卡驱动程序、显卡驱动程序、鼠标驱动程序、主板驱动程序、网络设备驱动程序、打印机驱动程序、扫描仪驱动程序等等。为什么没有CPU、内存驱动程序呢因为CPU和内存无需驱动程序便可使用,不仅如此,绝大多数键盘、鼠标、硬盘、软驱、显示器和主板上的标准设备都可以用Windows 自带的标准驱动程序来驱动,当然其它特定功能除外。如果你需要在Windows系统中的DOS 模式下使用光驱,那么还需要在DOS模式下安装光驱驱动程序。多数显卡、声卡、网卡等内置扩展卡和打印机、扫描仪、外置Modem等外设都需要安装与设备型号相符的驱动程序,否则无法发挥其部分或全部功能。驱动程序一般可通过三种途径得到,一是购买的硬件附

如何配置VC编译Windows驱动程序

用VC IDE环境编译驱动程序目前Windows驱动程序分为两类,一类是不支持即插即用功能的NT式驱动程序,另一类是支持即插即用功能的WDM驱动程序。它们在用VC IDE编译驱动程序时有些不一样,下面分开说明: 一、NT驱动( 红色字体标注的地方是容易忽略的): (1)用VC建立一个新工程。在VC IDE环境下选择“File”“New”,弹出“New”对话框。在该对话框中,选择“Project”选项卡。在“Project”选项卡中,选择Win32 Application,在这个基础上进行修改。工程名为“XXXXXX”,。单击“OK”,进入下一个对框框,在该对话框中,选择一个空的工程。 (2)将驱动程序的两个源文件XXX.h和XXX.cpp拷贝到工程目录中,并添加到工程中(Project->Add To Project->File)。 (3)增加新的编译版本,去掉Debug和Release版本(Build->Configuration中添加一个Check)。 (4)修改工程属性。选择“Project”|“Setting”,在对话框中,选择“General”选项卡。 将Intermediate files和Output files改为XXX_Check。 (5)选择C/C++选项卡,将原有的Project Options内容中全部删除,替换成如下内容,/nologo /Gz /MLd /W3 /WX /Z7 /Od /D WIN32=100 /D _X86_=1 /D WINVER=0x500 /D DBG=1 /Fo”MyDriver_Check/” /Fd”MyDriver_Check/” /FD /c (6)选择Link选项卡,将原有的Project Options内容全部删除,替换成如下内容,ntoskrnl.lib /nologo /base:”0x10000”/stack:0x400000,0x1000 /entry:”DriverEntry” /subsystem:console /incremental:no /pdb:”MyDriver_Check/XXX.pdb”/debug /machine:I386 /nodefaultlib /out:”MyDriver_Check/XXX.sys”/pdbtype:sept /subsystem:native /driver /SECTION:INIT,D /RELEASE /IGNORE:4078 (7)修改VC的lib目录和include目录。在VC中选择“Tools”|“Options”,在弹出的对话框中选择“Directories”选项卡。在“Show directories for”下拉菜单选择“Include files”菜单。添加“D:\WINDDK\2600\INC\W2K”和“D:\WINDDK\2600\INC\DDK\W2K”,并将这两个目录置于最上。大家可以将这个目录“D:\WINDDK\2600”改成你们自己安装的目录。这里应该选择W2K子目录,DDK中还会有相应的XP子目录。但因为XP驱动编译时候需要高版本的VC编译

am335x_linux-3.14.43内核移植笔记

本文主要描述在EVB335X-II以Device Tree的方式移植新TI官网AM335X系列最新的linux-3.14.43版本内核以及移植Debian文件系统的过程及遇到的一些问题。整个Device Tree牵涉面比较广,即增加了新的用于描述设备硬件信息的文本格式(即.dts文件),又增加 了编译这一文本的工具,同时Bootloader也需要支持将编译后的Device Tree传递给Linux 内核。以下是修改步骤: 一、修改uboot,支持Device Tree EVB335X-II在linux-3.2版本内核移植的时候已经有uboot,因此只需在该uboot上增加Device Tree支持即可,以下是修改步骤: 1、修改include/configs/com335x.h文件,增加支持DT的宏定义: /* Flattened Device Tree */ #define CONFIG_OF_LIBFDT 2、修改uboot启动参数,增加dtb文件的加载和启动(由于目前只是移植EMMC版本的EVB335X-II,因此只需修改EMMC的启动参数即可,大概在405行),修改如下: #elif defined(CONFIG_EMMC_BOOT) #define CONFIG_BOOTCOMMAND \ "run mmcboot;" #define CONFIG_EXTRA_ENV_SETTINGS \ "lcdtype=AUO_AT070TN94\0" \ "console=ttyO0,115200n8\0" \ "mmcroot=/dev/mmcblk0p2 rw\0" \ "mmcrootfstype=ext4 rootwait\0" \ "mmcargs=setenv bootargs console=${console} noinitrd root=${mmcroot} rootfstype=${mmcrootfstype} lcdtype=${lcdtype} consoleblank=0\0" \ "mmcdev=" MMCDEV "\0" \ "loadaddr=0x81000000\0" \ "dtbfile=evb335x-ii-emmc.dtb\0" \ "bootenv=uEnv.txt\0" \ "bootpart=" BOOTPART "\0" \ "loadbootenv=load mmc ${mmcdev} ${loadaddr} ${bootenv}\0" \ "importbootenv=echo Importing environment from mmc ...; " \ "env import -t $loadaddr ${filesize}\0" \ "loadaddr-dtb=0x82000000\0" \ "loadimage=load mmc ${bootpart} ${loadaddr} uImage\0" \ "loaddtb=load mmc ${bootpart} ${loadaddr-dtb} ${dtbfile}\0" \ "mmcboot=mmc dev ${mmcdev}; " \ "if mmc rescan; then " \ "echo SD/MMC found on device ${mmcdev};" \ "if run loadbootenv; then " \ "echo Loaded environment from ${bootenv};" \ "run importbootenv;" \ "fi;" \ "run mmcargs;" \

Windows驱动开发培训

Windows驱动开发培训 培训流程: 一、基础知识 在开始驱动开发之前,您应该知道操作系统原理以及驱动程序是如何在操作系统中进行工作的,了解这些基本原理将有助于您做出正确的设计决策并简化您的开发过程。 1、了解Windows操作系统构造\\ 可以链接进去 2、安装WDK,参考相关文档,熟悉WDK的内容\\ 可以链接进去 二、Windows驱动开发\\ 可以链接进去 一、基础知识 在开始驱动开发之前,您应该知道操作系统原理以及驱动程序是如何在操作系统中进行工作的,了解这些基本原理将有助于您做出正确的设计决策并简化您的开发过程。 1、了解Windows操作系统构造 (1)培训目标 深入了解Windows操作系统的系统结构以及工作原理 (2)培训内容 阅读书籍《深入解析Windows操作系统》的第3、4、6、7、9章,重点关注第九章“I/O系统” (3)培训任务 ①掌握Windows操作系统的系统结构 ②理解ISR、IRP、IRQL、DCP等概念的含义 ③了解注册表的用法,掌握注册表数据的查看和修改方法 ④了解进程和线程的内部机理以及线程的调度策略 ⑤了解I/O系统的内容,理解I/O请求以及I/O处理过程 注:以上相关内容,请在一周内完成。

2、安装WDK,参考相关文档,熟悉WDK的内容 (1)培训目标 了解WDK的安装过程,熟悉WDK的编译环境,掌握如何使用WDK的相关帮助文档;了解WDM驱动程序的基本结构 (2)培训内容 ①.阅读文档\\10.151.131.12\book\windows\MSWDM.chm,掌握WDM驱动程序的基本结构以及基本的编程技术。 ②.参考WDK的帮助文档:WDK documentation ,了解WDK的基本内容 (3)培训任务 ①理解分层驱动结构的含义,掌握设备和驱动程序的层次结构 ②理解“驱动对象”和“设备对象”的概念 ③理解2个基本例程:DriverEntry 和addDevice ④了解IRP的结构以及IRP处理的流程 ⑤初步了解I/O的控制操作 注:以上相关内容,请在一周内完成。 二、Windows驱动开发 学习如何基于WDK进行驱动程序的开发 1、培训目标 (1)学会根据WDK开发一个基本的Windows驱动程序和测试程序 (2)学会利用不同的IOCTL方式在内核模式和用户模式之间进行通讯 (3)学会如何在内核模式下和用户模式下访问注册表 (4)利用WinDbg跟踪程序,学会使用WinDbg进行调试 2、培训内容 (1)阅读\src\general\ioctl中的示例代码 (2)build并运行应用程序和驱动程序

在 Windows XP 下无法安装驱动程序,怎么办

故障现象 ?安装驱动程序时连接、识别打印机出现问题,提示连接、识别失败。 ?安装驱动程序时搜索不到 USB 设备,安装失败。 注意事项 在安装驱动程序过程中建议您关闭防火墙软件和杀毒软件,这些软件会限制打印机程序调用系统文件,导致打印机在安装/使用过程中出现问题。 必须确认已经删除了原先安装的驱动程序,电脑上曾经安装过 HP LaserJet 激光打印机的驱动程序,重新安装驱动程序之前,需要先删除以前安装的驱动程序,否则可能会出现无法找到设备或者安装不上驱动程序的现象。 解决方法 1.依次点击“开始”→“打印机和传真”。 2.在“打印机和传真”窗口中,依次点击“文件”→“添加打印机”,进 入“添加打印机向导”窗口。如图 1 打印机和传真所示: 图 1: 打印机和传真 3.在“欢迎使用添加打印机向导”窗口中,点击“下一步”按钮。

4.在“本地或网络打印机”窗口中,选择“连接到此计算机的本地打印 机”选项,勾除“自动检测并安装即插即用打印机”选项,然后点击“下一步”按钮。如图 2 本地或网络打印机所示: 图 2: 本地或网络打印机 5.在“选择打印机端口”窗口中,从“使用以下端口”下拉列表中选择 USB 端口,然后点击“下一步”按钮。 o下拉列表中有多个 USB 端口时,选择数字最大的 USB 端口。例如:有“USB001”、“USB002”两个端口,应该选择“USB002”端口。 o下拉列表中没有 USB 端口时,需要先开启打印机电源,然后将打印机 USB 连接线连接到电脑,操作系统会自动创建 USB 端口。 关闭“添加打印机向导”窗口,重新开始添加打印机即可。 如图 3 选择打印机端口所示: 图 3: 选择打印机端口

linux笔记

20150526 echo adfkjeroiu > /var/www/html/index.html service httpd restart ifconfig XXX.XXX.XXX.XXX elinks XXX.XXX.XXX.XXX web地址栏:XXX.XXX.XXX.XXX 20150527 方法一:Setup 设置IP 方法二:vim /etc/sysconfig/network-XXX/ifcfg-eth0 onboot=no改onboot=yes service network restart 虚拟机中安装2个linux,有时2个linux无法连接网络,即使是DHCP自动获取,也不可以;解决办法:打开其中一个linux虚拟机,单机“右下角-小电脑图标” —“设置”—“桥接模式(B);直接连接屋里网络” ,确定即可; 20150528 more /etc/issue 查看当前linux是centos还是redhat; man 命令查看当前命令的使用方法及参数 table 当一个命令不记得全部字母,可以双击table补齐; ctrl +c 终止当前程序 ctrl +l 清屏 20150529 ls -l查看命令;(-l显示更多属性) ls –a 查看隐藏文件; cp -r /etc/aaa /home/bbb复制/etc下的aaa 到/home下,并且改名bbb; (-r是整个文件夹的意思,如果,没有-r是复制单个文件) mv /etc/aaa /home/bbb 移动/etc下的aaa 到/home下,并且改名bbb;

rm –r 删除一个文件;(如果要是一个文件夹,就有询问yes或no) rm –rf 删除一个文件夹;(如果要是一个文件夹,就无询问) touch 创建文件; pwd 查看当前路径; cd.. 返回相对路径; cd / 返回绝对路径; cd- 返回刚才的路径; su – root或其它用户切换用户; mkdir 创建新目录; cat 查看文件内容; more或less 逐屏查看文件内容; useradd 新添加的用户,在没有更改密码前,无法登陆; passwd 更改密码;但是,密码必须符合复杂性; groupadd 添加一个组; 20150602 w 查看谁登陆过本计算机以及对方的IP; last 查看用户的登录日志; lastlog 查看每个用户最后登录的情况;(一般用于电脑被黑了之后); more /var/log/secure who /var/log/wtmp 干了些什么? root账户下输入su - username 切换到username下输入 history 能看到这个用户历史命令,默认最近的1000条 Linux查看History记录加时间戳小技巧 1.[root@servyou_web ~]# export HISTTIMEFORMAT="%F %T `whoami` " 2.[root@servyou_web ~]# history | tail 3. 1014 2011-06-22 19:17:29 root 15 2011-06-22 19:13:02 root ./test.sh 4. 1015 2011-06-22 19:17:29 root 16 2011-06-22 19:13:02 root vim test.sh 5. 1016 2011-06-22 19:17:29 root 17 2011-06-22 19:13:02 root ./test.sh 6. 1017 2011-06-22 19:17:29 root 18 2011-06-22 19:13:02 root vim test.sh 7. 1018 2011-06-22 19:17:29 root 19 2011-06-22 19:13:02 root ./test.sh 8. 1019 2011-06-22 19:17:29 root 20 2011-06-22 19:13:02 root vim test.sh 9. 1020 2011-06-22 19:17:29 root 21 2011-06-22 19:13:02 root ./test.sh

操作系统与驱动开发试题

河北科技大学硕士学位研究生 2014——2015学年第1学期 《操作系统与驱动开发》课程期末考试试卷 学院信息学院专业电路与系统姓名程莉学号 2201414007 题号一二三四五六总分 得分 一.单项选择题(每小题1分,共10分) 1.操作系统的 D 管理部分负责对进程进行调度。 A.主存储器 B.控制器 C.运算器 D.处理机 2.分时操作系统通常采用 B 策略为用户服务。 A.可靠性和灵活性 B.时间片轮转 C.时间片加权分配 D.短作业优先 3.很好地解决了“零头”问题的存储管理方法是 A 。 A 页式存储管理 B 段式存储管理 C 多重分区管理 D 可变式分区管理 4.用WAIT、SIGNAL操作管理临界区时,信号量的初值应定义为 B 。 A.-1 B.0 C.1 D.任意值 5.在进程管理中,当 C 时,进程从阻塞状态变为就绪状态。 A.进程被进程调度程序选中 B.等待某一事件 C.等待的事件发生 D.时间片用完 6.某系统中有3个并发进程,都需要同类资源4个,试问该系统不会发生死锁的最少资源数 B 。 A.9 B.10 C.11 D.12 7.虚拟存储器管理系统的基础是程序的 B 理论。 A.全局性 B.局部性 C. 动态性 D.虚拟性 8.从用户的角度看,引入文件系统的主要目的是 D A.实现虚拟存储 B.保存系统文档

C.保存用户和系统文档 D.实现对文件的按名存取 9.操作系统中采用多道程序设计技术提高CPU和外部设备的 A A.利用率 B.可靠性 C.稳定性 D.兼容性 10.缓冲技术中缓冲池在 C 中。 A.主存 B. 外存 C. ROM D. 时间片轮转 二.填空(每空0.5分,共15分)。 11.进程存在的唯一标志是PCB 。 12.通常进程实体是由程序块、进程控制块和数据块三部分组成。 13.磁盘访问时间由寻道时间、旋转延迟时间和传输时间组成。 14.作业调度是从后备作业队列中选一些作业,为它们分配资源,并为它们创建进程。 15.文件的物理组织有顺序、链接和索引。 16.若一个进程已经进入临界区,则其它欲要进入临界区的进程必须___等待____。 17.信号量的物理意义是,当信号量值大于零时其值表示可分配资源的个数;当信号 量值小于零时,其绝对值表示等待使用该资源的进程的个数。 18.静态重定位在程序装入时进行; 而动态重定位在程序运行时进行。 19.分区管理中采用“最佳适应”分配算法时,宜把空闲区按长度递增次序登记在空闲 区表中。 20.所谓系统调用,就是用户在程序中调用操作系统所提供的一些子功能。 21.把逻辑地址映射为物理地址的工作称为地址映射。 22.设备管理中采用的数据结构有设备控制表、控制器控制表、通道控制表、 系统设备表等四种。 23.从资源管理(分配)的角度,I/O设备可分为独占设备、共享设备和虚 拟设备三种。 24.设备与控制器之间的接口信号主要包括数据、状态和控制。 25.DMA控制器由三部分组成,分别为主机与DMA控制器的接口、 DMA控制器与块设备的接 口和 I/O控制逻辑。 三.名词解释(每小题2.5分,共10分)。 26.虚拟存储器 答:虚拟存储器是指在具有层次结构存储器的计算机系统中,自动实现部分装入和部分替换功能,能从逻辑上为用户提供一个比物理贮存容量大得多,可寻址的“主存储器”。

Windows驱动开发入门

接触windows驱动开发有一个月了,感觉Windows驱动编程并不像传说中的那么神秘。为了更好地为以后的学习打下基础,记录下来这些学习心得,也为像跟我一样致力于驱动开发却苦于没有门路的菜鸟朋友们抛个砖,引个玉。 我的开发环境:Windows xp 主机+ VMW ARE虚拟机(windows 2003 server系统)。编译环境:WinDDK6001.18002。代码编辑工具:SourceInsight。IDE:VS2005/VC6.0。调试工具:WinDBG,DbgView.exe, SRVINSTW.EXE 上面所有工具均来自互联网。 对于初学者,DbgView.exe和SRVINSTW.EXE是非常简单有用的两个工具,一定要装上。前者用于查看日志信息,后者用于加载驱动。 下面从最简单的helloworld说起吧。Follow me。 驱动程序的入口函数叫做DriverEntry(PDRIVER_OBJECT pDriverObj,PUNICODE_STRING pRegisgryString)。两个参数,一个是驱动对象,代表该驱动程序;另一个跟注册表相关,是驱动程序在注册表中的服务名,暂时不用管它。DriverEntry 类似于C语言中的main函数。它跟main的差别就是,main完全按照顺序调用的方法执行,所有东西都按照程序员预先设定的顺序依次发生;而DriverEntry则有它自己的规则,程序员只需要填写各个子例程,至于何时调用,谁先调,由操作系统决定。我想这主要是因为驱动偏底层,而底层与硬件打交道,硬件很多都是通过中断来与操作系统通信,中断的话就比较随机了。但到了上层应用程序,我们是看不到中断的影子的。说到中断,驱动程序中可以人为添加软中断,__asm int 3或者Int_3();前者是32位操作系统用的,后者是64位用的。64位驱动不允许内嵌汇编。下面是我的一个helloworld的源码:

linux读书笔记

12.29 Linux系统 Linux是真正的多用户、多任务操作系统。它继承了UNIX系统的主要特征,具有强大的信息处理功能,特别在Internet和Intranet的应用中占有明显优势。是一个完整的UNIX类操作系统。它允许多个用户同时在一个系统上运行多道程序。真正的32位操作系统。 用户接口 用户接口定义了用户和计算机交互作用的方式。Linux操作系统提供4种不同的用户接口。命令行接口 命令行是为具有操作系统使用经验,熟悉所用命令和系统结构的人员设计的。功能强大,使用方便的命令行是UNIX/Linux系统的一个显著特征。支持命令行的系统程序是命令解释程序。它的主要功能是接收用户输入的命令,然后予以解释并执行。 “$ ”是系统提示符。 在UNIX/Linux系统中,通常将命令解释程序称为shell。各种Linux环境下都安装了多种shell。这些shell由不同的人编写并得到一部分用户的青睐,各有其优势,最常用的几种是Bourne shell(sh),C shell(csh),Bourne Again shell(bash)和Korn shell(ksh)。红旗Linux 的默认shell是bash。 Bash 菜单 图形用户接口 程序接口 程序接口也称为系统调用接口。用户在自己的C程序中使用系统调用,从而获得系统提供的更基层的服务。 系统调用是操作系统内核与用户程序,应用程序之间的接口。在UNIX/Linux系统中,系统调用以C函数的形式出现。例如:fd=fopen(“file1.c”,2);其中,open是系统调用。 所有内核之外的程序都必须经由系统调用才能获得操作系统的服务。系统调用只能在C程序中使用,不能作为命令在终端上执行。由于系统调用能直接进入内核执行,所以其执行效率高。 Linux的版本 Linux有两种版本:核心(Kernel)版本和发行(Distribution)版本。 核心版本 核心版本主要是Linux的内核。Linux内核的官方版本由Linus Torvalds本人维护着。核心版本的序号由三部分数字构成,其形式为:major.minor.patchlevel 其中,major是主版本号,minor是次版本号,二者共同构成了当前核心版本好;patchlevel 表示对当前版本的修订次数。例如:2.6.34表示对2.6核心版本的第34次修订。

Windows驱动程序开发环境配置

Windows驱动程序开发笔记 一、WDK与DDK环境 最新版的WDK 微软已经不提供下载了这里:https://https://www.360docs.net/doc/3c5733815.html,/ 可以下并且这里有好多好东东! 不要走进一个误区:下最新版的就好,虽然最新版是Windows Driver Kit (WDK) 7_0_0,支持windows7,vista 2003 xp等但是它的意思是指在windows7操作系统下安装能编写针对windows xp vista的驱动程序, 但是不能在xp 2003环境下安装Windows Driver Kit (WDK) 7_0_0这个高版本,否则你在build的时候会有好多好多的问题. 上文build指:首先安装好WDK/DDK,然后进入"开始"->"所有程序"->"Windows Driver Kits"->"WDK XXXX.XXXX.X" ->"Windows XP"->"x86 Checked Build Environment"在弹出来的命令行窗口中输入"Build",让它自动生成所需要的库 如果你是要给xp下的开发环境还是老老实实的找针对xp的老版DDK吧,并且xp无WDK 版只有DDK版build自己的demo 有个常见问题: 'jvc' 不是内部或外部命令,也不是可运行的程序。 解决办法:去掉build路径中的空格。 二、下载 WDK 开发包的步骤 1、访问Microsoft Connect Web site站点 2、使用微软 Passport 账户登录站点 3、登录进入之后,点击站点目录链接 4、在左侧的类别列表中选择开发人员工具,在右侧打开的类别:开发人员工具目录中找到Windows Driver Kit (WDK) and Windows Driver Framework (WDF)并添加到您的控制面板中 5、添加该项完毕后,选择您的控制面板,就可以看到新添加进来的项了。 6、点击Windows Driver Kit (WDK) and Windows Driver Framework (WDF),看到下面有下载链接,OK,下载开始。下载后的文件名为: 6.1.6001.18002.081017-1400_wdksp-WDK18002SP_EN_DVD.iso将近600M大小。

linux驱动学习笔记LED

LED驱动学习: 是一个char字符类型的驱动 //配置模式为输出端口 static unsigned int led_cfg_table [] = { S3C2410_GPB5_OUTP, S3C2410_GPB6_OUTP, S3C2410_GPB7_OUTP, S3C2410_GPB8_OUTP, }; s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPB5_OUTP); s3c2410_gpio_cfgpin(37, 0x01 << 10); 这个在\arch\arm\mach-s3c2410\include\mach\regs-gpio.h中定义 #define S3C2410_GPB5 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5) #define S3C2410_GPB5_INP (0x00 << 10) #define S3C2410_GPB5_OUTP (0x01 << 10) #define S3C2410_GPB5_nXBACK (0x02 << 10) S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5) #define S3C2410_GPIONO(bank,offset) ((bank) + (offset)) #define S3C2410_GPIO_BANKA (32*0) #define S3C2410_GPIO_BANKB(32*1) static int __init dev_init(void) { int ret; int i; for (i = 0; i < 4; i++) { s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]); s3c2410_gpio_setpin(led_table[i], 0); } 在驱动的初始化函数中经常看到,__init 前缀,这个在下面文件中定义 file:/include/linux/init.h ? /* These macros are used to mark some functions or ?* initialized data (doesn't apply to uninitialized data) ?* as `initialization' functions. The kernel can take this ?* as hint that the function is used only during the initialization ?* phase and free up used memory resources after ?* ?* Usage: ?* For functions: ?* ?* You should add __init immediately before the function name, like: ?*

linux笔记

1.ls:查看当前路径下的文件以及文件夹的名字 2.ls /bin:查看根目录下的bin文件夹的东西 3.cd Desktop进入到Desktop文件夹 4.cd ..跳转到当前路径的上一层 5.pwd:显示当前操作的路径(绝对路径) 6.clear:清屏 7.绝对路径:/home/python 8.相对路径:cd downloads 9..表示当前路径 10...表示上一层路径 11.c d -:跳转到上一层所在的路径 12.t ab自动补全 13.t ouch 1.txt 创建文件 14.l s * 表示显示所有文件 15.l s *.txt 表示显示以所有.txt结尾的文件 16.l s*.t[xn]t 表示显示以txt或者tnt结尾的所有文件 17.m ore 查看文件的内容 18.l s–alh | more 查看文件的内容并以管道符号进行连接 19.c d ~切换到当前用户的主目录 20.m kdir 创建文件夹 21.m kdira/b/c –p 连续创建文件夹 22.t ree 以目录数的方式显示

23.r mdir 删除文件夹(必须是空目录) 24.实物图操作的文件不会被删除直接进回收站 25.用命令删除的文件是不会进入回收站的 26.r m 删除文件/文件夹 27.r m haha.txt –r 直接删除文件夹(-r表示递归的删除) 28.r m haha.txt –i 给将删除的文件一个删除提示 29.r m haha.txt –f 强制删除 30.l inux建立链接影响(相当于创建windows下的快捷方式) 31.l n 01.txt 创建快捷方式 32.g edit 01.txt 编辑文件的内容 33.c at 01.txt 查看所编辑的内容 34.c at 01.txt > 02.txt 合并文件 35.g rep–n ‘a’grep.txt 搜素文件当中带a的文件 36.g rep–i ‘a’grep.txt搜素文件当中带a的文件(忽略大小写) 37.–-help 查找帮助文档 38.f ind 查找文件 39.c p a b 将a文件下的内容整体复制到b文件夹下(无效的文 件无法复制) 40.c p a/* b 将a文件夹下的所有内容复制到b文件夹下 41.m v a b 将a文件夹整体移动到b文件夹下 42.–v 显示移动进度 43.–I 表示操作的时候显示的提示(y表示确定)

相关文档
最新文档