AIX SCSI Driver 编程实质

本文详细介绍了AIX系统中SCSI I/O操作的具体流程,包括从structsc_buf与structbuf结构定义开始,到I/O请求的发起、处理及完成的全过程。重点关注了关键步骤,如structbuf中字段buf->b_iodone的使用,以及如何通过iodone()函数确保I/O操作的正确完成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

by sinister

1、首先定义struct sc_buf与struct buf结构,sc_buf用于接收/发送SCSI command,如填写相关CBD等,此结构中一个字段用于与block device进行通信,名为sc_buf->bufstruct,它指向了block layer的struct buf结构,这样既完成了SCSI driver与BLOCK driver的关联。


2、填写struct buf中相关字段,其中关键的一个字段buf->b_iodone为完成I/O处理的callback函数,系统规定其要在INTIODONE的interrupt priority级别中调用,所以在函数中先要使用disable_lock()(SMP下用它来替代i_disable()函数)来raises interrupt priority。继而设置buf->flags为B_DONE。


3、使用e_wakeup()函数来唤醒buf->b_event事件。因为b_iodone所指向的callback函数要在interrupt level上运行,不能被交换出去,事先要使用pincode()函数将代码固定在内存中。如果是SMP环境下跑,那么还需要设置buf->b_flags相关位为B_MPSAFE。待struct buf填充完毕后,接下来即为其建立cross memory。


4、使用xmattach()与xmemdma()函数为DMA准备好相关页面,然后让其指向buf->b_xmemd字段。这时即可调用devstart()进行I/O传输(DMA),此函数实则是调用block device的ddstrategy例程。调用成功后使用disable_lock()调整interurpt priority为INTCLASS1,并循环判断B_DONE是否设置,是则认为一次I/O完成。


5、在block device的ddstrategy中完成一次I/O动作多数情况下是显示的调用iodone()函数完成的,这个在AIX的KERNEL开发手册中没有明确指出,只是提到了buf->b_iodone这个callback函数是由相关的strategy来触发完成I/O的,其实很多情况下即使不在该例程中仍需显示的调用iodone()来完成I/O。


6、为了明白I/O complete的最终动作,我反汇编了iodone()函数。该函数首先判断当前的interrupt level是否大于INTIODONE,如果大于调用i_disable()禁止中断并将interrupt priority调整至INTIODONE,使用(*buf->b_iodone)(buf)方法触发回调函数,接着调用i_enable()函数开中断后函数返回。


7、当前interrupt priority小于等于INTIODONE,使用disable_lock()自旋锁,调整至INTMAX级别,并将当前的struct buf插入到系统全局变量g_iodonelist中,调用mpc_send()->pal_i_soft()函数投递一个INTIODONE中断,unlock_enable()后返回。当priority调整后iodone()被再次调用,满足条件触发回调。


8、在回调前会设置struct buf->b_flags=| B_DONE;这样SCSI driver等待循环才会满足条件。INTIODONE是soft interrupt priority。AIX KERNEL下priority越小级别越高,前面判断大于INTIODONE即是优先级低于则调用回调函数。明白了iodone函数也就明白了我前面说的VMM的page fault绕过fs调用的实现。


注1:刚开始反汇编iodone()时不明白为什么在处理struct buf->b_iodone回调时用的是i_disable()/i_enable()函数,按理说我的AIX是SMP结构的,只应该是使用disable_lock()/unlock_enable()函数。后来经过分析才明白原来其是 per CPU 的,g_iodonelist才是全局的,才需要disable_lock()保护。

注2:AIX的cross memory实则是专用于share的,比如一个kernel driver在任意context访问或修改一个用户态进程地址空间中的数据,又或两个kernel process之间访问,再或在inerrupt context下使用其来访问用户进程空间,还有DMA等等...都需要使用到cross memory。kernel api xmattach()函数用于建立这种memory。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值