阅读:4242回复:32
scsi miniport的问题
我在写一个虚拟scsi设备的driver,使用ScsiPortNotification来返回srb到portdriver.但是因为是虚拟设备,所以没有真正的中断,目前是用ScsiPortNotification(RequestTimerCall,)来返回数据,但是好像这个timer最小间隔是10 milliseconds。这样很影响效率,请问一下大家有没有什么办法,可以直接ScsiPortNotification返回给port driver,或者什么方法可以提高效率?
|
|
最新喜欢:![]() |
沙发#
发布于:2003-12-25 15:35
效率要求很高吗?
我就是使用TimerCall的,不觉得有什么问题呀. >> 但是好像这个timer最小间隔是10 milliseconds 10 milliseconds是指系统调度Timer的时间精度,但是TimerCall是以microseconds为单位的,意思是最差情况下你可能要等上10ms,但正常情况下应该不用等那么久,平均就5ms吧. 如果不涉及读硬盘的操作,正常的SRB可以直接Complete,这个效率应该很高,涉及读盘的时候,读盘加线程切换也要花点时间吧,这样算下来其实你并没有在TimerCall那里损失太多的时间. 事实是,我使用1000 microseconds进行TimerCall,从虚拟设备上往硬盘上拷东西跟在硬盘的不同分区之间拷东西,基本感觉不到什么速度差异. |
|
|
板凳#
发布于:2003-12-25 16:05
〉〉10 milliseconds是指系统调度Timer的时间精度,但是TimerCall是以microseconds为单位的,意思是最差情况下你可能要等上10ms,但正常情况下应该不用等那么久,平均就5ms吧.
这点我同意,通常timercall返回的时间是不到10ms,但是在我的设备里就是这个timercall影响了我的效率,现在我的设备用iometer测试下来是大概4MB左右,里面很多时间是被这个消耗的,你说正常的SRB可以直接Complete,这个我曾经试过,但是好像不起作用,portdriver好像没收到一样,几秒钟以后就一个resetbus了,不知道你直接complete怎么做的? |
|
地板#
发布于:2003-12-25 16:23
不太明白你的意思,你是说对于 *每一个SRB* 你都要进行一次TimerCall吗?
对于那些可以立即完成的操作(比如EjectMedia或ModeSense或TestUnitReady之类的)也使用TimerCall? 我使用TimerCall的地方仅限于那些在DISPATCH_LEVEL上不能完成的或必须在指定的线程上下文环境中完成的操作(如打开文件,读文件,写文件之类的), 其它的SRB一律是处理完之后马上就: ScsiPortNotification(RequestComplete, Extension, Srb); 然后 ScsiPortNotification(NextRequest, Extension, NULL); |
|
|
地下室#
发布于:2003-12-25 16:25
〉〉10 milliseconds是指系统调度Timer的时间精度,但是TimerCall是以microseconds为单位的,意思是最差情况下你可能要等上10ms,但正常情况下应该不用等那么久,平均就5ms吧. Complete一个SRB可以用: ScsiPortNotification( NotificationType = RequestComplete ) 注意设置状态SrbStatus 和ScsiStatus。 再调用: ScsiPortNotification( NotificationType = NextRequest ) 接受下一个请求。 |
|
|
5楼#
发布于:2003-12-25 16:47
>>不太明白你的意思,你是说对于 *每一个SRB* 你都要进行一次TimerCall吗?
当然不是每一个srb用一次timercall,我是把所有的srb放到一个list上面,然后一次timercall以后把所有执行完了的srb都return回去。 >>Complete一个SRB可以用: >>ScsiPortNotification( NotificationType = RequestComplete ) >>注意设置状态SrbStatus 和ScsiStatus。 >>再调用: >>ScsiPortNotification( NotificationType = NextRequest ) >>接受下一个请求。 我只用了ScsiPortNotification( NotificationType = RequestComplete ),没有调用nextrequest.会怎么样呢? |
|
6楼#
发布于:2003-12-25 16:55
>> 当然不是每一个srb用一次timercall,我是把所有的srb放到
>> 一个list上面,然后一次timercall以后把所有执行完了的srb >> 都return回去 这样不好,应该是能Complete的直接Complete,不能Complete的才放在List里在TimerCall里Complete. 注意,不管你有没有Complete,在返回SRB给SCSIPort之前,你都应该调用NextRequest. >> 我只用了ScsiPortNotification( NotificationType = >> RequestComplete ),没有调用nextrequest.会怎么样呢? SCSIPort会超时,然后送一个RESET_BUS下来,呵呵.:):):):) |
|
|
7楼#
发布于:2003-12-25 17:01
ScsiPortNotification( RequestComplete,HwDeviceExtension,Srb );
ScsiPortNotification(NextRequest, HwDeviceExtension, NULL); 都用上了,不好使啊。依然timeout |
|
8楼#
发布于:2003-12-25 17:42
ScsiPortNotification( RequestComplete,HwDeviceExtension,Srb ); 注意设置状态SrbStatus 和ScsiStatus。 |
|
|
9楼#
发布于:2003-12-25 18:39
ScsiPortNotification( RequestComplete,HwDeviceExtension,Srb ); 不知道你的处理过程是什么样的,我吧我的过程给你看看,这个肯定能工作: 定义两个队列: QUEUE RequestQueue; QUEUE CompleteQueue; BOOLEAN __stdcall ScsiMiniPortStartIo(PVOID Ext, PSCSI_REQUEST_BLOCK Srb) { if(能处理) { // 处理,并设置: // Srb->SrbStatus // Srb->SenseInfoBuffer // Srb->SenseInfoBufferLength // Srb->ScsiStatus; // Srb->SrbStatus一定不要设置成SRB_STATUS_PENDING; } else { Srb->SrbStatus = SRB_STATUS_PENDING; RequestQueue.Enqueue(Srb); // 放队列里等线程处理 } if(Srb->SrbStatus == SRB_STATUS_PENDING) { //启动Timer ScsiPortNotification(RequestTimerCall, Ext,ScsiTimer,1000); } else { //完成它 ScsiPortNotification(RequestComplete, Ext, Srb); } //千万别忘了这个 ScsiPortNotification(NextRequest, Ext, NULL); return TRUE; } 系统线程里: Thread() { while(true) { Srb = RequestQueue.Dequeue(); //处理Srb并设置: // Srb->SrbStatus // Srb->SenseInfoBuffer // Srb->SenseInfoBufferLength // Srb->ScsiStatus; // Srb->SrbStatus一定不要设置成SRB_STATUS_PENDING; CompleteQueue.Enqueue(Srb); //放到完成队列里等Timer处理 } } Timer里: void __stdcall ScsiTimer(PVOID Ext) { // 完成所有CompleteQueue里的Srb while((Srb = CompleteQueue.Dequeue()) != NULL) { //完成它 ScsiPortNotification(RequestComplete, Ext, Srb); } //如果还有没处理的Srb,一定要记得再起Timer if(!RequestQueue.IsEmpty()) { ScsiPortNotification(RequestTimerCall, Ext,ScsiTimer,1000); } } 以上只是一个粗略的流程,里面有许多地方需要同步保护,你自己加。另外,你并不一定非得起一个系统线程,使用QueueWorkItem之类的也能达到同样的效果,想必这对你不是什么问题。 |
|
|
10楼#
发布于:2003-12-29 15:24
你和我程序的唯一的区别就是,你在startio里面起的requestimercall,而我是用一个timer反复的call,这样改变不了效率啊。不知道你的device的performance怎么样,能帮忙看一看么?
[编辑 - 12/29/03 by terrychen] |
|
11楼#
发布于:2003-12-29 16:47
if(Srb->SrbStatus == SRB_STATUS_PENDING)
{ //启动Timer ScsiPortNotification(RequestTimerCall, Ext,ScsiTimer,1000); } else { //完成它 ScsiPortNotification(RequestComplete, Ext, Srb); } 我只是PENDING的时候RequestTimerCall(换句话说,象TestUnitReady或ModeSense之类的SRB通通不用TimerCall),而听前几篇帖子你的意思是你把所有的SRB都给Mark成Pending,然后\"全部\"在TimerCall里Complete,是这样吗?如果是,那当然有效率问题. 我以前写的那个是一个Virtual Optical Disk(也就是个可移动硬盘),在两个虚拟设备之间拷文件(也就是说所有的数据都要从我的驱动程序里过),也没发现有什么太大的效率问题(大约达到80%-90%的硬盘速度),不知道你的驱动跟真正的硬盘比起来效率损失有多大? |
|
|
12楼#
发布于:2003-12-29 17:23
实际上TestUnitReady和mode_sense在这里很小一部分,大概占1%都不到,主要是write和read问题了,效率主要就是timercall实际上消耗了太多时间。而且system好像发srb也不是很频繁。现在我实现的这个速度也不是很慢,copy东西什么的,感觉还可以,但是microsoft有个tools,测出来是我10倍,所以很郁闷
|
|
13楼#
发布于:2003-12-30 20:07
加cache可能会有改善。我们就是这样提速的,差不多在10倍左右。用Nero测试下来,Burst Rate在60M左右。
|
|
|
14楼#
发布于:2003-12-31 08:59
加cache,能不能说具体一点呢?我PORT_CONFIGURATION_INFORMATION里面的cachedata也true了,没有什么反映啊,版主说说吧
|
|
15楼#
发布于:2003-12-31 19:42
如果你是用文件虚拟设备的话,加cache不是很必要,应为文件系统本来就有cache(注意WRITE_THROUGH只控制写,而INTERMEDIATE_BUFFER不能控制FileSystem的cache)。
你可以把MaximumTransferLength加大点儿试试。 |
|
|
16楼#
发布于:2003-12-31 21:23
这个我已经改了,改成了128k,但是一般系统不会一次i/o请求超过64k的,所以没什么用,估计miniport没戏了,得用别的port driver了
|
|
17楼#
发布于:2004-04-02 17:21
问问各位大牛:俺在Read10中调用如下SubRequest,之后在一个线程中接受事件来处理该Srb,之后将处理的Srb放到定时器的TimerCall中
完成提交,但在重新启动时好像死机一样,好像是Scsi miniport加载时一直处于等待状态,大家说一下我的这种做法可以吗?正确该怎么做呢 BOOLEAN CVThreadDevice::SubmitRequest(PSCSI_REQUEST_BLOCK Srb) { Srb->SrbStatus = SRB_STATUS_PENDING; if( KeGetCurrentIrql()>DISPATCH_LEVEL ) { VPrint(("Current IRQL: %x\n",KeGetCurrentIrql() )); // // KeSetEvent can only be running at DISPATCH_LEVEL and less // LoadStatus(Srb,recNOT_READY); // // use RequestReturn of base class here! // CVDevice::RequestReturn(Srb); return TRUE; } ((PSRB_EXTENSION)Srb->SrbExtension)->Srb = Srb; ExInterlockedInsertTailList( &RequestHead, &((PSRB_EXTENSION)Srb->SrbExtension)->ListEntry, &ListLock ); // // Signal the worker for processing // KeSetEvent( &ThreadEvent, IO_NO_INCREMENT, FALSE ); return TRUE; } |
|
18楼#
发布于:2004-04-16 11:57
seaquester 大虾,救救小弟阿
把这段代码放到链表中,同时在线程中处理,就出现超时,但如果先把srb放到list中,并马上取出执行,就没有任何问题,请问这是怎么回事. Srb->SrbStatus = SRB_STATUS_SUCCESS; Srb->ScsiStatus = SCSISTAT_GOOD; DbgPrint(\"this=%x,m_ScsiHBA=%x\\n\",this,m_ScsiHBA); (this->*m_CmdTable[Srb->Cdb[0]])(Srb); ScsiPortNotification(NextRequest, (PVOID)m_ScsiHBA, Srb ); ScsiPortNotification(RequestComplete, (PVOID)m_ScsiHBA, Srb ); |
|
19楼#
发布于:2004-04-21 17:49
terrychen:
你的scsi效率提高了吗?有没有比较好的方法亚 |
|
上一页
下一页