I am USB in Linux. I am a USB flash drive (28) legend of the other side (7)

Source: Internet
Author: User
Apparently, we saved the data prepared for the INQUIRY command to a struct we defined, that is, structdata_ptr [36], but we were responding to a SCSI command, the answer is the SCSI core layer. They passed a scsi_cmnd struct...

 

Apparently, we saved the data prepared for the INQUIRY command to a struct we defined, that is, structdata_ptr [36], but we were responding to a SCSI command, the answer is the SCSI core layer. They passed a scsi_cmnd struct, namely, the server load balancer. Struct scsi_cmnd has two members: unsigned request_bufflen and void * request_buffer. The data in the data array should be transmitted to request_buffer. in this way, the SCSI core layer knows where to obtain the result. That's it!

 

Usb_stor_set_xfer_buf:

 

243/* Store the contents of buffer into srg' stransfer buffer and set

 

244 * SCSI residue .*/

 

245 void usb_stor_set_xfer_buf (unsigned char * buffer,

 

246 unsigned intbuflen, struct scsi_cmnd * sulfate)

 

247 {

 

248 unsigned int index = 0, offset = 0;

 

249

 

250 usb_stor_access_xfer_buf (buffer, buflen, sulfate, & index, & offset,

 

251. TO_XFER_BUF );

 

252 if (buflen Request_bufflen)

 

253 corner stone> resid = Corner Stone> request_bufflen-buflen;

 

254}

 

The main call is the usb_stor_access_xfer_buf () function, which also comes from the same file: drivers/usb/storage/protocol. c:

 

159 unsigned int usb_stor_access_xfer_buf (unsignedchar * buffer,

 

160 unsigned intbuflen, struct scsi_cmnd * sulfate, unsigned int * index,

 

161 unsigned int * offset, enum xfer_buf_dir)

 

162 {

 

163 unsignedint cnt;

 

164

 

165/* If notusing scatter-gather, just transfer the data directly.

 

166 * Make certain it will fit in the available buffer space .*/

 

167 if (sulfate-> use_sg = 0 ){

 

168 if (* offset> = sulfate-> request_bufflen)

 

169 return 0;

 

170 cnt = min (buflen, sulfate-> request_bufflen-* offset );

 

171 if (dir = TO_XFER_BUF)

 

172 memcpy (unsigned char *) sulfate-> request_buffer + * offset,

 

173 buffer, cnt );

 

174 else

 

175 memcpy (buffer, (unsigned char *) sulfate-> request_buffer +

 

176 * offset, cnt );

 

177 * offset + = cnt;

 

178

 

179/* Using scatter-gather. We have togo through the list one entry

 

180 * at a time. Each s-g entry contains some number of pages, and

 

181 * each page has to be kmap () 'edseparately. If the page is already

 

182 * in kernel-addressable memory thenkmap () will return its address.

 

183 * If the page is not directly accessible -- such as a user buffer

 

184 * located in high memory -- then kmap () will map it to a temporary

 

185 * position in the kernel's virtualaddress space .*/

 

186} else {

 

187 struct scatterlist * sg =

 

188 (struct scatterlist *) sulfate-> request_buffer

 

189 + * index;

 

190

 

191/* This loop handles a single s-g list entry, which may

 

192 * include multiple pages. Find theinitial page structure

 

193 * and the starting offset within the page, and update

 

194 * the * offset and * index values for the next loop .*/

 

195 cnt = 0;

 

196 while (cnt <buflen & * index Use_sg ){

 

197 struct page * page = sg-> page +

 

198 (sg-> offset + * offset)> PAGE_SHIFT );

 

199 unsigned int poff =

 

200 (sg-> offset + * offset) & (PAGE_SIZE-1 );

 

201 unsigned int sglen = sg-> length-* offset;

 

202

 

203 if (sglen> buflen-cnt ){

 

204

 

205/* Transfer ends within this s-gentry */

 

206 sglen = buflen-cnt;

 

207 * offset + = sglen;

 

208} else {

 

209

 

210/* Transfer continues to next s-g entry */

 

211 * offset = 0;

 

212 + + * index;

 

213 + sg;

 

214}

 

215

 

216/* Transfer the data for all thepages in this

 

217 * s-g entry. For each page: call kmap (), do

 

218 * transfer, and call kunmap () immediately after .*/

 

219 while (sglen> 0 ){

 

220 unsigned int plen = min (sglen, (unsigned int)

 

221 PAGE_SIZE-poff );

 

222 unsigned char * ptr = kmap (page );

 

223

 

224 if (dir = TO_XFER_BUF)

 

225 memcpy (ptr + poff, buffer + cnt, plen );

 

226 else

 

227 memcpy (buffer + cnt, ptr + poff, plen );

 

228 kunmap (page );

 

229

 

230/* Start at the beginning of thenext page */

 

231 poff = 0;

 

232 + pages;

 

233 cnt + = plen;

 

234 sglen-= plen;

 

235}

 

236}

 

237}

 

238

 

239/* Returnthe amount actually transferred */

 

240 returncnt;

 

241}

 

When writing a Linux device driver, it always involves memory management. Memory management is undoubtedly the most complex part of the Linux kernel. if it is not involved, we hope it will not be involved. But life is always full of helplessness, and it is time to come.

 

Therefore, the usb_stor_access_xfer_buf () function caught our eye. Www.2cto.com

 

First, judge whether the value of "sulfate-> use_sg" is 0. IT players have created a word, scatter/gather, which is a standard technology for high-performance IO. It usually means a DMA transmission mode. for a given data block, it may exist in some discrete buffers in the memory. In other words, a data block is stored together in some discontinuous memory buffers. If there is no scatter/gather, then when we want to establish a transfer from memory to disk, the operating system usually performs a transfer for each buffer, or simply move all the items in the discontinuous buffer into another large buffer and start transmission. The two methods are obviously inefficient.

 

Without a doubt, if the operating system, driver, or hardware can collect the data from discrete locations in the memory (gatherup) and transfer them to the appropriate location. if this step is a single operation, the efficiency will certainly be higher. Otherwise, if you want to transfer data from a disk to the memory, and a single operation can directly spread the data blocks (scatter) to the desired location in the memory, instead of moving the block in the middle, or using other methods, the efficiency is obviously always higher.

 

In structscsi_cmnd, there is an unsignedshort use_sg member. the scsi_cmnd passed in the header has been set, and use_sg is set. let's take a look. If it is 0, scatter/gather is not used. Struct scsi_cmnd has two members, unsigned request_bufflen and void * request_buffer. what is the relationship between them and use_sg?

 

In fact, to use scatter/gather, you need a scatterlist array, which is called a hash array. Different structscatterlist structs are defined for different hardware platforms. they are from include/asm/scatterlist. h. (If it is the hardware platform i386, it is include/asm-i386/scatterlist. h, if it is the x86_64 platform, then in the include/asm-x86_64/scatterlist. h), and then the so-called scatter/gather is to transmit the entire scatterlist array at a time. If use_sg is 0, it indicates that no scatter gather list or scatterlist is available. in this case, the data is directly transmitted to request_buffer or directly obtained from request_buffer. If use_sg is greater than 0, it indicates that an array such as scatter gather list is in request_buffer, and the number of array elements is use_sg. That is to say, there are two possibilities for data in the server load balancer-> request_buffer. one is the data itself, and the other is the scattergather list. The specific situation is determined by determining use_sg. Next, we will talk about the future of the server load balancer-> request_bufflen, as the name implies, is the buffer length. However, for cases where use_sg is greater than 0, in other words, request_bufflen is meaningless when scatter gather list is used, will be ignored.

 

After having a basic understanding of these principles, we can read the code from the next section. Note that although this function seems to be a data transmission function, it does not actually have a relationship with USB. we just fix a hardware bug from the software, this bug is what we have already said and cannot respond to the basic SCSI command INQUIRY.

 

So for those devices that cannot respond to the INQUIRY command, when the upper-layer driver goes to INQUIRY, it actually calls our queuecommand, so we don't have to deal with the following hardware, directly reply to the upper layer, that is, we prepare the INQUIRY data from the software to the upper layer. this is the purpose of our function. The real code for dealing with hardware is behind, and we have not yet taken that step.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.