您的位置:首页 > 运维架构 > Linux

《Linux那些事儿之我是USB》我是U盘(36)迷雾重重的批量传输(五)

2012-03-08 22:09 369 查看
在讲数据传输阶段之前,先解决刚才的历史遗留问题。usb_stor_bulk_transfer_buf()中,406行,有一个很有趣的函数interpret_urb_result()被调用。这个函数同样来自drivers/usb/storage/transport.c中:

265 static int interpret_urb_result(struct us_data*us, unsigned int pipe,

266 unsigned int length, int result, unsigned int partial)

267 {

268 US_DEBUGP("Status code %d; transferred%u/%u\n",

269 result, partial,length);

270 switch (result) {

271

272 /* no error code; did we send all the data? */

273 case 0:

274 if (partial != length) {

275 US_DEBUGP("-- shorttransfer\n");

276 return USB_STOR_XFER_SHORT;

277 }

278

279 US_DEBUGP("-- transfer complete\n");

280 return USB_STOR_XFER_GOOD;

281

282 /* stalled */

283 case -EPIPE:

284 /* for control endpoints, (used by CB[I]) astall indicates

285 * afailed command */

286 if (usb_pipecontrol(pipe)) {

287 US_DEBUGP("-- stall oncontrol pipe\n");

288 return USB_STOR_XFER_STALLED;

289 }

290

291 /* for other sorts of endpoint, clear thestall */

292 US_DEBUGP("clearing endpoint halt forpipe 0x%x\n", pipe);

293 if (usb_stor_clear_halt(us, pipe) < 0)

294 return USB_STOR_XFER_ERROR;

295 return USB_STOR_XFER_STALLED;

296

297 /* babble - the device tried to send morethan we wanted to read */

298 case -EOVERFLOW:

299 US_DEBUGP("-- babble\n");

300 return USB_STOR_XFER_LONG;

301

302 /* the transfer was cancelled by abort, disconnect,or timeout */

303 case -ECONNRESET:

304 US_DEBUGP("-- transfercancelled\n");

305 return USB_STOR_XFER_ERROR;

306

307 /* short scatter-gather read transfer */

308 case -EREMOTEIO:

309 US_DEBUGP("-- short readtransfer\n");

310 return USB_STOR_XFER_SHORT;

311

312 /* abort or disconnect in progress */

313 case -EIO:

314 US_DEBUGP("-- abort or disconnect inprogress\n");

315 return USB_STOR_XFER_ERROR;

316

317 /* the catch-all error case */

318 default:

319 US_DEBUGP("-- unknown error\n");

320 return USB_STOR_XFER_ERROR;

321 }

322 }

应该说这个函数的作用是一目了然,就是根据传进来的参数result进行判断,从而采取相应的行动。partial是实际传输的长度,而length是期望传输的长度,传输结束了当然要比较这两者,因为有所期待,才会失望。result是usb_stor_ msg_common()函数的返回值,其实就是状态代码。如果为0说明一切都很顺利,结果也是成功的。268这行,打印结果,同时打印出partial和length的比,注意两个%u中间那个“/”,就是除号,或者说分割分子和分母的符号。

然后通过一个switch语句判断result,为0,说明至少数据有传输。然后有两种情况,于是返回不同的值,USB_STOR_XFER_SHORT和USB_STOR_XFER_GOOD。至于返回这些值之后会得到什么反应,让我们边走边看。目前只需要知道的是,对于真正传输完全令人满意的情况,返回值只能是USB_STOR_XFER_GOOD。返回其他值都说明有问题。而这里作为传递给switch的result,实际上是USB Core那一层传过来的值。

而我们注意到,interpret_urb_result这个函数整个是被作为一个返回值出现在usb_stor_bulk_transfer_buf()中的。换而言之,前者返回之后,后者也马上就返回了,即再次返回到了usb_stor_Bulk_transport()中。因此,我们把视线拉回usb_stor_Bulk_transport(),981行,如果result不为USB_STOR_XFER_GOOD,就说明有一些问题,于是索性usb_stor_Bulk_transport()也返回,没必要再进行下一阶段的传输了。否则,才可以进行下一阶段。

下一个阶段是所谓的Bulk-only传输,总共就是三个阶段,即命令传输阶段、数据传输阶段、状态传输阶段。很显然,真正最有意义的阶段就是数据传输阶段,而在此之前,我们已经讲了第一阶段,即命令传输阶段。下面我们可以来看一下数据阶段。

989行,990行,实在没话可说,某些公司的产品在命令阶段和数据阶段居然还得延时100μs,最早时只发现了Genesys Logic公司的产品有这个问题,后来又发现更多的产品也有同样的问题。所以使用了US_FL_GO_SLOW这个flag,如果你有兴趣看一下早期的Linux Kernel,你会发现那时候其实没有这个flag,那时候定义了一个USB_VENDOR_ID_GENESYS,直接比较这个产品是不是Genesys Logic公司的,如果是的,那就考虑这个延时,否则就不用。

993行,transfer_length可能为0,因为有的命令并不需要您传输数据,所以它没有数据阶段。而对于那些有数据阶段的情况,我们进入if这一段。

994行,没什么可说的,就是根据数据传输方向确定用接收管道还是发送管道。

然后,996行,usb_stor_bulk_transfer_sg()函数真正地执行批量数据传输。这个函数来自drivers/usb/storage/transport.c中:

470 int usb_stor_bulk_transfer_sg(struct us_data*us, unsigned int pipe,

471 void *buf, unsigned int length_left, int use_sg, int *residual)

472 {

473 int result;

474 unsigned int partial;

475

476 /* are we scatter-gathering? */

477 if (use_sg) {

478 /* use the usb core scatter-gather primitives*/

479 result = usb_stor_bulk_transfer_sglist(us,pipe,

480 (structscatterlist *) buf, use_sg,

481 length_left,&partial);

482 length_left -= partial;

483 } else {

484 /* no scatter-gather, just make the request */

485 result = usb_stor_bulk_transfer_buf(us, pipe,buf,

486 length_left,&partial);

487 length_left -= partial;

488 }

489

490 /* store the residual and return the error code*/

491 if (residual)

492 *residual = length_left;

493 return result;

494 }

注释说得很清楚,这个函数是一个壳,真正干活的是它所调用或者说利用的那两个函数:usb_stor_bulk_transfer_sglist()和usb_stor_bulk_transfer_buf()。后者刚才已经遇到过了,而前者是专门为scatter-gather传输准备的函数,它也来自drivers/usb/storage/transport.c中:

416 static int usb_stor_bulk_transfer_sglist(structus_data *us, unsigned int pipe,

417 struct scatterlist *sg, int num_sg, unsigned int length,

418 unsigned int *act_len)

419 {

420 int result;

421

422 /*don't submit s-g requests during abort/disconnect processing */

423 if (us->flags &ABORTING_OR_DISCONNECTING)

424 return USB_STOR_XFER_ERROR;

425

426 /* initialize the scatter-gather request block*/

427 US_DEBUGP("%s: xfer %u Bytes, %dentries\n", __FUNCTION__,

428 length, num_sg);

429 result = usb_sg_init(&us->current_sg,us->pusb_dev, pipe, 0,

430 sg, num_sg, length,GFP_NOIO);

431 if (result) {

432 US_DEBUGP("usb_sg_init returned%d\n", result);

433 return USB_STOR_XFER_ERROR;

434 }

435

436 /* since the block has been initializedsuccessfully, it's now

437 * okayto cancel it */

438 set_bit(US_FLIDX_SG_ACTIVE,&us->flags);

439

440 /* did an abort/disconnect occur during thesubmission? */

441 if (us->flags &ABORTING_OR_DISCONNECTING) {

442

443 /* cancel the request, if it hasn't beencancelled already */

444 if (test_and_clear_bit(US_FLIDX_SG_ACTIVE,&us->flags)) {

445 US_DEBUGP("--cancelling sg request\n");

446 usb_sg_cancel(&us->current_sg);

447 }

448 }

449

450 /* wait for the completion of the transfer */

451 usb_sg_wait(&us->current_sg);

452 clear_bit(US_FLIDX_SG_ACTIVE, &us->flags);

453

454 result = us->current_sg.status;

455 if (act_len)

456 *act_len = us->current_sg.Bytes;

457 return interpret_urb_result(us, pipe, length,result,

458 us->current_sg.Bytes);

459 }

在usb_stor_bulk_transfer_sg()函数中,判断use_sg是否为0,从而确定是否用scatter-gather。对于use_sg等于0的情况,表示不用scatter-gather,那么调用usb_stor_bulk_transfer_buf()发送scsi命令。实际传递的数据长度用partial记录,然后length_left就记录还剩下多少没传递,初值当然就是期望传递的那个长度。每次减去实际传递的长度即可。对于use_sg不等于0的情况,usb_stor_bulk_transfer_sglist()函数被调用。我们来看这个函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: