Linux那些事儿之我是U盘(43)迷雾重重的Bulk传输(一) – fudan

2006年的最后一个星期,来到了北京,开始了北漂的生活.和上海不同的是,在这里待了三个月之后,发现竟然没有下过一次雨,难怪日本小孩说:”你们北京小孩真幸福,城外就是大沙漠,出了城就可以骑骆驼看日落了.”不过,今天下雨了,下了大雨,好大好大,一阵阵的闪电,回家的时候下半身都湿了…(天哪,怎么写着写着又往那个方向走去了…算了,我承认我只是一个用下半身思考的男青年.)

很累,但是听着北京不眠夜,又不想入睡,听着刘杨的声音,心里感到特别温暖,这些年里,从长沙,到上海,再到北京,每每只有在夜深人静的时候,听着广播,才能忘却一些绝望.于是继续写吧,既然人生的幕布已经拉开,就一定要积极的演出;既然脚步已经跨出,风雨坎坷也不能退步;既然我已把希望播在这里,就一定要坚持到胜利的谢幕.

375行,us->proto_handler()其实是一个函数指针,知道它指向什么吗?不要说你不知道,早年我们在storage_probe()中,确切的说,在get_protocol()就赋了值,当时只知道是get protocol,却不知道究竟干什么用,现在该用上了,别以为写代码的都是傻子,一个指针要是没什么用人家才不会为它赋值呢.当初我们就讲了,对于U盘,proto_handler被赋值为usb_stor_transparent_scsi_command,所以我们来看后者吧. 后者定义于drivers/usb/storage/protocol.c:

172 void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb, 173 struct us_data *us) 174 { 175 /* send the command to the transport layer */ 176 usb_stor_invoke_transport(srb, us); 177 178 if (srb->result == SAM_STAT_GOOD) { 179 /* Fix the READ CAPACITY result if necessary */ 180 if (us->flags & US_FL_FIX_CAPACITY) 181 fix_read_capacity(srb); 182 } 183 }

首先注意到的是usb_stor_invoke_transport()函数这个函数可不简单.咱们先做好思想准备, 接下来就去见识一下她的庐山真面目. 她来自drivers/usb/storage/transport.c:

519 /*********************************************************************** 520 * Transport routines 521 ***********************************************************************/ 522 523 /* Invoke the transport and basic error-handling/recovery methods 524 * 525 * This is used by the protocol layers to actually send the message to 526 * the device and receive the response. 527 */ 528 void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) 529 { 530 int need_auto_sense; 531 int result; 532 533 /* send the command to the transport layer */ 534 srb->resid = 0; 535 result = us->transport(srb, us); 536 537 /* if the command gets aborted by the higher layers, we need to 538 * short-circuit all other processing 539 */ 540 if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { 541 US_DEBUGP("– command was aborted/n"); 542 goto Handle_Abort; 543 } 544 545 /* if there is a transport error, reset and don’t auto-sense */ 546 if (result == USB_STOR_TRANSPORT_ERROR) { 547 US_DEBUGP("– transport indicates error, resetting/n"); 548 us->transport_reset(us); 549 srb->result = DID_ERROR << 16; 550 return; 551 } 552 553 /* if the transport provided its own sense data, don’t auto-sense */ 554 if (result == USB_STOR_TRANSPORT_NO_SENSE) { 555 srb->result = SAM_STAT_CHECK_CONDITION; 556 return; 557 } 558 559 srb->result = SAM_STAT_GOOD; 560 561 /* Determine if we need to auto-sense 562 * 563 * I normally don’t use a flag like this, but it’s almost impossible 564 * to understand what’s going on here if I don’t. 565 */ 566 need_auto_sense = 0; 567 568 /* 569 * If we’re running the CB transport, which is incapable 570 * of determining status on its own, we will auto-sense 571 * unless the operation involved a data-in transfer. Devices 572 * can signal most data-in errors by stalling the bulk-in pipe. 573 */ 574 if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && 575 srb->sc_data_direction != DMA_FROM_DEVICE) { 576 US_DEBUGP("– CB transport device requiring auto-sense/n"); 577 need_auto_sense = 1; 578 } 579 580 /* 581 * If we have a failure, we’re going to do a REQUEST_SENSE 582 * automatically. Note that we differentiate between a command 583 * "failure" and an "error" in the transport mechanism. 584 */ 585 if (result == USB_STOR_TRANSPORT_FAILED) { 586 US_DEBUGP("– transport indicates command failure/n"); 587 need_auto_sense = 1; 588 } 589 590 /* 591 * A short transfer on a command where we don’t expect it 592 * is unusual, but it doesn’t mean we need to auto-sense. 593 */ 594 if ((srb->resid > 0) && 595 !((srb->cmnd[0] == REQUEST_SENSE) || 596 (srb->cmnd[0] == INQUIRY) || 597 (srb->cmnd[0] == MODE_SENSE) || 598 (srb->cmnd[0] == LOG_SENSE) || 599 (srb->cmnd[0] == MODE_SENSE_10))) { 600 US_DEBUGP("– unexpectedly short transfer/n"); 601 } 602 603 /* Now, if we need to do the auto-sense, let’s do it */ 604 if (need_auto_sense) { 605 int temp_result; 606 void* old_request_buffer; 607 unsigned short old_sg; 608 unsigned old_request_bufflen; 609 unsigned char old_sc_data_direction; 610 unsigned char old_cmd_len; 611 unsigned char old_cmnd[MAX_COMMAND_SIZE]; 612 unsigned long old_serial_number; 613 int old_resid; 614 615 US_DEBUGP("Issuing auto-REQUEST_SENSE/n"); 616 617 /* save the old command */ 618 memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE); 619 old_cmd_len = srb->cmd_len; 620 621 /* set the command and the LUN */ 622 memset(srb->cmnd, 0, MAX_COMMAND_SIZE); 623 srb->cmnd[0] = REQUEST_SENSE; 624 srb->cmnd[1] = old_cmnd[1] & 0xE0; 625 srb->cmnd[4] = 18; 626 627 /* FIXME: we must do the protocol translation here */ 628 if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI) 629 srb->cmd_len = 6; 630 else 631 srb->cmd_len = 12; 632 633 /* set the transfer direction */ 634 old_sc_data_direction = srb->sc_data_direction; 635 srb->sc_data_direction = DMA_FROM_DEVICE; 636 637 /* use the new buffer we have */ 638 old_request_buffer = srb->request_buffer; 639 srb->request_buffer = srb->sense_buffer; 640 641 /* set the buffer length for transfer */ 642 old_request_bufflen = srb->request_bufflen; 643 srb->request_bufflen = 18; 644 645 /* set up for no scatter-gather use */ 646 old_sg = srb->use_sg; 647 srb->use_sg = 0; 648 649 /* change the serial number — toggle the high bit*/ 650 old_serial_number = srb->serial_number; 651 srb->serial_number ^= 0x80000000; 652 653 /* issue the auto-sense command */ 654 old_resid = srb->resid; 655 srb->resid = 0; 656 temp_result = us->transport(us->srb, us); 657 658 /* let’s clean up right away */ 659 srb->resid = old_resid; 660 srb->request_buffer = old_request_buffer; 661 srb->request_bufflen = old_request_bufflen; 662 srb->use_sg = old_sg; 663 srb->serial_number = old_serial_number; 664 srb->sc_data_direction = old_sc_data_direction; 665 srb->cmd_len = old_cmd_len; 666 memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); 667 668 if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { 669 US_DEBUGP("– auto-sense aborted/n"); 670 goto Handle_Abort; 671 } 672 if (temp_result != USB_STOR_TRANSPORT_GOOD) { 673 US_DEBUGP("– auto-sense failure/n"); 674 675 /* we skip the reset if this happens to be a 676 * multi-target device, since failure of an 677 * auto-sense is perfectly valid 678 */ 679 if (!(us->flags & US_FL_SCM_MULT_TARG)) 680 us->transport_reset(us); 681 srb->result = DID_ERROR << 16; 682 return; 683 } 684 685 US_DEBUGP("– Result from auto-sense is %d/n", temp_result); 686 US_DEBUGP("– code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x/n", 687 srb->sense_buffer[0], 688 srb->sense_buffer[2] & 0xf, 689 srb->sense_buffer[12], 690 srb->sense_buffer[13]); 691 #ifdef CONFIG_USB_STORAGE_DEBUG 692 usb_stor_show_sense( 693 srb->sense_buffer[2] & 0xf, 694 srb->sense_buffer[12], 695 srb->sense_buffer[13]); 696 #endif 697 698 /* set the result so the higher layers expect this data */ 699 srb->result = SAM_STAT_CHECK_CONDITION; 700 701 /* If things are really okay, then let’s show that. Zero 702 * out the sense buffer so the higher layers won’t realize 703 * we did an unsolicited auto-sense. */ 704 if (result == USB_STOR_TRANSPORT_GOOD && 705 /* Filemark 0, ignore EOM, ILI 0, no sense */ 706 (srb->sense_buffer[2] & 0xaf) == 0 && 707 /* No ASC or ASCQ */ 708 srb->sense_buffer[12] == 0 && 709 srb->sense_buffer[13] == 0) { 710 srb->result = SAM_STAT_GOOD; 711 srb->sense_buffer[0] = 0x0; 712 } 713 } 714 715 /* Did we transfer less than the minimum amount required? */ 716 if (srb->result == SAM_STAT_GOOD && 717 srb->request_bufflen – srb->resid < srb->underflow) 718 srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24); 719 720 return; 721 722 /* abort processing: the bulk-only transport requires a reset 723 * following an abort */ 724 Handle_Abort: 725 srb->result = DID_ABORT << 16; 726 if (us->protocol == US_PR_BULK) 727 us->transport_reset(us); 728 }

好家伙,洋洋洒洒两百余行的一个函数,怎一个壮观二字了得! 欧阳修大哥曾经的一首蝶恋花把这个复杂的函数可谓描绘的淋漓尽致.

庭院深深深几许?杨柳堆烟,帘幕无重数.

玉勒雕鞍游冶处,楼高不见章台路.

雨横风狂三月暮,门掩黄昏,无计留春住.

泪眼问花花不语,乱红飞过秋千去.

上片深几许,无重数,不见章台路正是写的这段代码的复杂,调用关系一层又一层,让很多新手看了感觉无可奈何,如果没有高人的指导,盲目的去阅读代码或者去看那些很垃圾的书,那么无异于对美好生命的戕害.下片狂风暴雨正是比喻这种盲目的学习的害处,词中以花被摧残喻读代码者自己青春被毁.韶华空逝,人生易老.何必呢?

偶尔因高山流水的美丽停留,

Linux那些事儿之我是U盘(43)迷雾重重的Bulk传输(一) – fudan

相关文章:

你感兴趣的文章:

标签云: