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

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 }

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

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

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

 

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

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

 

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

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值