现在的位置: 首页 > 综合 > 正文

Linux那些事儿之我是U盘(38)彼岸花的传说(六)

2013年11月02日 ⁄ 综合 ⁄ 共 3175字 ⁄ 字号 评论关闭

七年前,在那个千禧年里,凭借<<我的父亲母亲>>获得金鸡奖最佳女主角的章子怡姐姐说:"我长得挺漂亮,又是单身,男人不可能对我没兴趣!"是的,古人云,男人分两种,一种是好色,一种是十分好色.所以章子怡这话一点没错.不过,对于大多数80后来说,他们早已不再像十年前那么另类,那么出格,因为他们生活压力很重,他们很老实,很现实,一个显而易见的事实,yy章子怡不如老老实实的学Linux.虽然很多人对两者都有兴趣.但至少学会了后者,可以混口饭吃,谁叫我们都是知识混子呢.

此时,镜头一转,我们继续接着上一节往下看.fill_inquiry_response(),这个函数来自drivers/usb/storage/usb.c,

240 /*
    241  * fill_inquiry_response takes an unsigned char array (which must
    242  * be at least 36 characters) and populates the vendor name,
    243  * product name, and revision fields. Then the array is copied
    244  * into the SCSI command's response buffer (oddly enough
    245  * called request_buffer). data_len contains the length of the
    246  * data array, which again must be at least 36.
    247  */
    248
    249 void fill_inquiry_response(struct us_data *us, unsigned char *data,
    250                 unsigned int data_len)
    251 {
    252         if (data_len<36) // You lose.
    253                 return;
    254
    255         if(data[0]&0x20) { /* USB device currently not connected. Return
    256                               peripheral qualifier 001b ("...however, the
    257                               physical device is not currently connected
    258                               to this logical unit") and leave vendor and
    259                               product identification empty. ("If the target
    260                               does store some of the INQUIRY data on the
    261                               device, it may return zeros or ASCII spaces
    262                               (20h) in those fields until the data is
    263                               available from the device."). */
    264                 memset(data+8,0,28);
    265         } else {
    266                 memcpy(data+8, us->unusual_dev->vendorName,
    267                         strlen(us->unusual_dev->vendorName) > 8 ? 8 :
    268                         strlen(us->unusual_dev->vendorName));
    269                 memcpy(data+16, us->unusual_dev->productName,
    270                         strlen(us->unusual_dev->productName) > 16 ? 16 :
    271                         strlen(us->unusual_dev->productName));
    272                 data[32] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>12) & 0x0F);
    273                 data[33] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>8) & 0x0F);
    274                 data[34] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>4) & 0x0F);
    275                 data[35] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice) & 0x0F);
    276         }
    277
    278         usb_stor_set_xfer_buf(data, data_len, us->srb);
    279 }

故事发生的太突然,会让人产生幻觉. 本来我们正儿八经用来处理scsi命令的函数是后面将要讲的proto_handler(),但想不到我们在这里开始接触scsi命令了.理由正是因为像Sony这几款PEG产品做的不好,连最基本的scsi命令INQUIRY都不支持,完了又想在Linux中使用,那没办法了,Sony毕竟是大公司,连欧洲冠军杯都是他们家和喜力给赞助的,开源社区没有必要得罪他们,所以就准备一个函数来fix这个问题吧,毫无疑问,这属于硬件上的一个bug.

那么什么是INQUIRY命令?曾经也提过,INQUIRY命令是最最基本的一个SCSI命令,比如主机第一次探测设备的时候就要用INQUIRY命令来了解这是一个什么设备,比如scsi总线上有一个插槽插了一个设备,那么scsi主机就问它,你是scsi磁盘呢,还是scsi磁带,又或是scsiCD ROM?作为设备,它内部一定有一段固件程序,即所谓的firmware.它就在接收到主机的INQUIRY命令之后作出回答.具体应该怎么回答?当然是依据scsi协议里规定的格式了.不仅仅INQUIRY命令,对于每一个命令都应该如此.只要对方问:天王盖地虎.你作为设备就该回答,宝塔镇河妖.这其实就好比我们对对联,人家问天恢弘,地恢弘,天地恢弘,就得对你妈的,他妈的,你他妈的.这都是不成文的规矩,而开发scsi的人把这些写成了规范,它就变成了成文的规矩了.具体来说, 设备在受到INQUIRY命令查询时,她的相应遵从scsi协议里面规定的标准格式,标准格式规定了,响应数据必须至少包含36个字节,所以252,如果data_len小于36,那就甭往下走了,返回吧.您违规了.

如果你对scsi协议很陌生,还是没有明白INQUIRY命令究竟是做什么,那么推荐一个工具给你,你可以试一试,以便有个直观的印象,其实INQUIRY命令就是如其字面意思一样

抱歉!评论已关闭.