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.

217 (void) (&_x == &_y); \<br />

218 _x > _y ? _x : _y; })<br />

而208 行比较的是一个buflen,一个srb->request_bufflen-*<strong>of</strong>fset,咱们这次要传送的数据长度是<br />

buflen,但是显然也不能够超过后者,所以就取其中小的那个,调用memcpy copy,然后215 行*<strong>of</strong>fset 加<br />

上copy 的字节cnt,对于这种不采用scatter gather 方式的传输,那么到这里就可以返回了,直接就到278<br />

行,返回cnt 即可.<br />

但是对于使用scatter gather 方式的传输,情况当然不一样了.从224 行开始往下看,显然如咱们所说,<br />

得定义一个struct scatterlist 结构体的指针,由于struct scatterlist 是和体系结构有关的,作为曾经的<br />

Intel 人,我没有任何犹豫的应该以i386 的为例,include/i386/scatterlist.h:<br />

4 struct scatterlist {<br />

5 struct page *page;<br />

6 unsigned int <strong>of</strong>fset;<br />

7 dma_addr_t dma_address;<br />

8 unsigned int length;<br />

9 };<br />

这个结构并不复杂,其中page 指针通常指向将要进行scatter gather 操作的buffer.而length 表示<br />

buffer 的长度,<strong>of</strong>fset 表示buffer 在page 内的偏移量.225 行,定义一个struct scatterlist 指针sg,然<br />

后<br />

令她指向(struct scatterlist*)srb->request_buffer+*index,搜索一下内核代码就可以知道,每次<br />

*index 都是被初始化为0 然后才调用usb_stor_access_xfer_buf()的,233 行,cnt 设为0,234 行开<br />

始<br />

进入循环,循环的条件是cnt 小于buflen,同时*index 小于srb->use_sg, srb->use_sg 咱们刚才说过<br />

了,只要她不是0,那么她里边的冬冬就代表了scatter gather 传输时数组元素的个数.<br />

观众朋友们请注意,225 行这里让sg 等于srb->request_buffer,(当然还要加上*index,如果index 不<br />

为0 的话),那么request_buffer 究竟是什么?对于使用scatter/gather 传输的情况,request_buffer<br />

里<br />

边实际上是一个数组,每一个元素都是一个struct scatterlist 的指针,而每一个scatterlist 指针的page<br />

里边包含了一些page(而不是一个page),而<strong>of</strong>fset 里边包含的是每一个DMA buffer 的总的偏移量,她由<br />

两部分组成,高位部分标志着page 号,低位部分标志着具体某个page 中的偏移量,高位低位由<br />

PAGE_SHIFT 宏来划分,不同的硬件平台PAGE_SHIFT 值不一样,因为不同的硬件平台page 的大小也<br />

不<br />

一样,即这里的PAGE_SIZE 不一样,目前比较前卫的硬件平台其page size 有4k 或者8k 的,而<br />

PAGE_SHIFT 也就是12 或者13,换言之,sg-><strong>of</strong>fset 去掉低12 位或者低13 位就是page 号,而低12<br />

137<br />

位或者低13 位恰恰是在该page 内的偏移量.之所以可以把一个sg-><strong>of</strong>fset 起两个作用,正是因为page<br />

size 只需要12 位或者13 位就足够了,或者说偏移量本身只有12 位或者13 位,而一个int 型变量显然可<br />

以包含比12 位或13 位更多的信息.我们最终是要把buffer(即前面说的那个36 个bytes 的标准的<br />

INQUIRY data buffer)里边的冬冬copy 至DMA buffer 中,buffer 我们已经知道,她就是<br />

usb_stor_access_xfer_buf()函数传递进来的参数,而DMA buffer 在哪呢?只要我们知道她在哪个<br />

page 中,知道她的<strong>of</strong>fset,那么有一个函数可以帮助我们获得她对应的内核虚拟地址,而这个地址正是我们<br />

需要的,有了她,我们就能调用memcpy 函数来copy 数据了.所以235 行到238 行,就是计算出究竟是哪<br />

个page,究竟是多少<strong>of</strong>fset,后者用被赋给了unsigned int 变量p<strong>of</strong>f,*<strong>of</strong>fset 是<br />

usb_stor_access_xfer_buf()函数传递进来的参数,她也可以控制我们要传送数据的DMA buffer 对应<br />

的<strong>of</strong>fset,不过这里我们传递进来的是0.所以不去care.

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

Saved successfully!

Ooh no, something went wrong!