07.06.2013 Views

Scsi - Index of

Scsi - Index of

Scsi - Index of

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

239 行对unsigned int sglen 赋值,sg->length 实际上就是DMA buffer 的长度.所以显然我们copy<br />

冬冬不能超过这个长度,如果我们还指定了*<strong>of</strong>fset,就表明DMA buffer 中从*<strong>of</strong>fset 开始装,那么就不能<br />

超<br />

过sg->length-*<strong>of</strong>fset.<br />

241 行,由于我们现在还在while 循环中,所以先看第一次执行到241 行,这时cnt 等于0,buflen 就是那<br />

个data buffer 的长度,传进来的是36.sglen 表征了DMA buffer 里边可以装多少,如果sglen 比buflen<br />

要大,那么很好,一次就可以装满,因为这就好比buflen 是一吨沙子,而sglen 则表示装沙车载重两吨或者<br />

更<br />

多,比如三吨.这样244行245行,其作用就是做个标记,比如sglen被用来记录实际装载了多少重量的沙子,<br />

而*<strong>of</strong>fset 则表征了装沙车用了多少了,如果还没卸货下次又要继续往里装那就装吧,反正没满就可以装.那<br />

么如果sglen 比buflen 要小或者刚好够大,那么*<strong>of</strong>fset 肯定就被设为0,因为这一车必然会被装满,要再<br />

装<br />

沙子只能调用下一辆车,所以同时sg 和*index 也自加.<br />

然后来看257 行了,sglen 一开始肯定应该大于0 吧,她表征的是实际装了多少,但是内存管理机制有一个<br />

限制,memcpy 传输不能够跨页,也就是说不能跨page,一次最多就是把本page 的冬冬给copy 走,如果<br />

你<br />

的数据超过了一个page,那你还得再copy 一次或者多次,因为这里咱们用了循环.每一次真正copy 的长<br />

度<br />

用plen 来表征,所以271 行和272 行,cnt 是计数的,所以她要加上一个plen,而sglen 也是一个计数的,<br />

但是她是反着计,所以她每次要减掉一个plen.而p<strong>of</strong>f 和page 一个设为0,一个自加,这个道理很简单,从下<br />

一页开头进行继续copy.而258 行再次调用强大的min()函数也正是为了保证每次copy 不能跨页.260<br />

和266行这对冤家的出现,kmap()和kunmap(),道理也很简单.这对冤家是内核中的内存管理部门提供给<br />

咱们的重要函数,其中kmap()函数的作用就是传递给她一个struct page 指针,她能返回这个page 指针<br />

所指的那个page 的内核虚拟地址,而有了这个page 对应的虚拟地址,加上咱们前面已经知道的偏移量,咱<br />

们就可以调用memcpy 函数来copy 数据了.至于kunmap,古书有云:凡是kmap()建立起来的良好关系<br />

必须由kunmap()来摧毁.<br />

然后,262 到265 行的两个memcpy 无需再讲了.<br />

278 行,返回实际传输的字节数.<br />

至此,usb_stor_access_xfer_buf()这个函数的每一点每一滴都讲完了.让我们欢呼吧!这一刻,我们不<br />

是一个人在战斗.(注:应该说如果不是很有悟性的话,这段代码要看懂还是挺难的,虽说不至于让你哭得花枝<br />

乱颤,但也足以令你看得眼花缭乱.正式版中关于这个函数应该有一个比较好的图解,来描述这个双重循环,<br />

须知外循环是按sg entry 来循环,即一个sg entry 循环一次,而内循环是按page 来循环,我们说过,一个<br />

sg entry 可以有多个page,而因为我们没有办法跨page 映射,所以只能每个page 映射一次,所以才需要<br />

循环.)<br />

138<br />

回到usb_stor_set_xfer_buf()中来,也只剩下一句话了,如果我们要传递的36 个字节还不足以填满这<br />

辆装沙车的话,那就让我们记录下这辆车还能装多少沙子吧,srb->resid 正是扮演着这个记录者的角色.<br />

然后我们回到fill_inquiry_response()中来,一看,嗬,这个函数也结束了.我们再一次回到了那个不死的<br />

精灵进程,usb_stor_control_thread()中来,这个函数俨然就像当年圣斗士星矢中的不死鸟一辉,总也死<br />

不了,隔一会又会出现.对于INQUIRY 命令,咱们在fill_inquiry_response()之后,把srb->result 设为了<br />

SAM_STAT_GOOD,她是scsi 系统里边定义的一个宏,include/scsi/scsi.h 中:<br />

117 /*<br />

118 * SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft<br />

119 * T10/1561-D Revision 4 Draft dated 7th November 2002.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!