USB系列之八:透过ASPI执行SCSI命令

在《USB系列之七》里我们介绍了ASPI的规范,并对一系列ASPI的命令做了测试,其中的02号命令是执行SCSI命令,我们专门在这篇文章中介绍,在《USB系列七》中,我们已经了解了调用ASPI的方法,主要是要填一个SRB(SCSI Request Block)的表,在以前的《USB系列之三:从你的U盘里读出更多的内容》文章中我们通过DOSUSB已经实现了许多SCSI命令,这些命令包括:

  • SCSI INQUIRY Command
  • SCSI READ CAPACITY (10) Command
  • SCSI REQUEST SENSE Command
  • SCSI TEST UNIT READY Command
  • SCSI READ (10) Command

《USB系列之四:向U盘上写数据》一文中,我们又实现了SCSI WRITE(10) Command,所以我们已经实现过6个SCSI命令了,先让我们回顾一下以前的SCSI命令我们是如何实现的。
    按照《USB Mass Storage Class -- Bulk Only Transport》(这个文档在USB系列之三中有过介绍并提供了下载)的说明,我们首先要填写一个CBW(Command Block Wrapper)表,在这个表中中的最后有一个不定长的部分叫做CBWCB,这部分的长度及字段含义视发出的SCSI命令不同而不同,实际上,这个部分就是描述SCSI命令的,在SCSI的规范中,这个部分叫做CDB(Command Descriptor Block),它和CBWCB完全是一个东西,在本文中,我们沿用SCSI规范中的叫法,把这个表叫做CDB。
    了解SCSI命令,需要了解两个规范SPC-3和SBC-2,这两个文档在USB系列之三中都有介绍并提供了下载,鉴于以前我们已经实现过许多SCSI命令,在本文中我们仅就最重要的三个SCSI命令进行实现,它们是:

  • SCSI TEST UNIT READY Command
  • SCSI READ (10) Command
  • SCSI WRITE (10) Command

相信读者可以自行实现其它的命令。
    为了清晰地表现读、写扇区的操作,我们用两个源程序来分别测试读、写扇区,第一个程序叫aspiread,专门测试读扇区,通过这个程序,我们有把握使用其中的SCSI READ(10)命令把指定的扇区内容读出;第二个程序叫aspiwrit,专门测试写扇区操作,因为写扇区本身是看不见什么的,要靠读扇区命令把写入的内容读出来才能验证,这也就是我们为什么单独测试读扇区命令的原因。
    这两个程序的下载地址如下:
    aspiread下载:http://blog.hengch.com/source/aspiread.zip
    aspiwrit下载:http://blog.hengch.com/source/aspiwrit.zip
    我们需要对这两个程序分别做一下说明。

先说aspiread程序
    这个程序在我的环境下执行后的结果如下:

    ASPI Reading test program v1.00.

    Open SCSIMRG success!    ASPI entry : 0786:6a5c

    Test unit ready......
    Command Status: 01    Host Adapter Status: 00
    Target Status: 00
    Press any key when ready......

    Reading.........
    Command Status: 01    Host Adapter Status: 00
    Target Status: 00    Residual Byte: 0000
    Data in buffer: fa 33 c0 8e d0 bc 00 7c 16 07 bb 78 06 8d 87 8a fb ba 80 01 b9 1d f5 16 cd 13 72 e4 53 cb af 29 b3 04 80 3c 80 74 0e 80 3c 00 75 1c 83 c6 10 fe cb 75 ef cd 18 8b 14 8b 4c 02 8b ee 83 c6 10 fe cb 74 1a 80 3c 00 74 f4 be 8b 06 ac 3c 00 74 0b 56 bb 07 00 b4 0e cd 10 5e eb f0 eb fe bf 05 00 bb 00 7c b8 01 02 57 cd 13 5f 73 0c 33 c0 cd 13 4f 75 ed be a3 06 eb d3 be c2 06 bf fe 7d 81 3d 55 aa 75 c7 8b f5 ea 00 7c 00 00 49 6e 76 61 6c 69 64 20 70 61 72 74 69 74 69 6f 6e 20 74 61 62 6c 65 00 45 72 72 6f 72 20 6c 6f 61 64 69 6e 67 20 6f 70 65 72 61 74 69 6e 67 20 73 79 73 74 65 6d 00 4d 69 73 73 69 6e 67 20 6f 70 65 72 61 74 69 6e 67 20 73 79 73 74 65 6d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 01 01 00 01 01 20 f4 20 00 00 00 20 3d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa 

这个程序我们先发出SCSI命令Test Unit Ready,用以观察设备是否处于Ready状态,然后我们读取LBA = 0的扇区,因为我们可以保证这个扇区是有内容的,肯定不会是全0,如果希望读取其它扇区,把相关语句该一下就可以了,在执行SCSI READ(10)命令时,有下面几点需要注意一下:
    1、我们在USB系列之七中的测试已经表明,在我的环境下,只有Host Adapter Number = 0和Target ID = 0是合法的,所以,程序中对这两项均没有填写,因为在初始化SRB后,本身所有项就都是0,如果在执行USB系列之七中的程序发现这个数据有变,请自行在程序中填写。
    2、注意一定要填写SCSI Request Flags字段,在程序中我们填为0ch,即bit2和bit3为1,其它为0,从ASPI的规范中可以看到,bit2为1表明剩余字符报告使能,bit3为1表明数据传输方向是从SCSI Target到Host,就是从U盘到主机的意思,这一位是一定要设的,否则无法成功完成读扇区的动作;bit2这一位如果不设,那么在完成读扇区的动作时,Data Allocation Length这个字段仍然是512(和我们调用ASPI前设置的一样),如果设置,这个字段在调用后一般会为0,表明我们所要求的512个字节都读出来了,没有剩余字符。
    3、执行完读操作后,Command Status = 01,表明动作已经完成,如果不是01,则buffer中的内容无效,可以从返回的Command Status以及Host Status和Target Status返回的状态上分析原因。

下面说说aspiwrit这个程序
    这个程序首先要初始化一下buffer,把内容变成00--0ffh的两次循环,然后把buffer中的数据写到LBA = 50h的扇区中(注意:这里可能会破坏已有的文件数据,所以请使用一个空的U盘,或者没有存放有用数据的U盘),写完成后我们把buffer清为全0,然后把LBA = 50h的扇区读出,并显示读出的内容。
    一下是aspiwrit的执行结果:

   ASPI Reading test program v1.00.

    Open SCSIMRG success!    ASPI entry : 0786:6a5c

    Test unit ready......
    Command Status: 01    Host Adapter Status: 00
    Target Status: 00
    Press any key when ready......

    Writing.........
    Command Status: 01    Host Adapter Status: 00
    Data in buffer: 00    Residual Byte: 0000
    Press any key when ready......

    Reading.........
    Command Status: 01    Host Adapter Status: 00
    Target Status: 00    Residual Byte: 0000
    Data in buffer: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 

在前面说明aspiread时已经说明的要点在这里就不再重复了。
    1、在执行SCSI WRITE(10)命令时,SRB中SCSI Request Flags字段在程序中我们填为14h,即bit2和bit4为1,其它为0,bit3和bit4组成二进制的10,从ASPI的规范中可以看出表明数据传输方向是从Host到SCSI Target,就是从主机到U盘的意思。
    2、在USB系列之三中,我们介绍过SCSI的一个重要规范SPC-3,并提供了下载,在这份规范中,有一个SCSI命令叫做REQUEST SENSE,当执行命令出错时,可以使用这个命令获得Device的Sense Data,进而判断错误情况,当然我们也可以透过ASPI执行这个SCSI命令,但似乎ASPI已经帮我们想到了这一点,这就是ASPI For DOS这个规范中SRB表中的Sense Allocation Area这个字段的意义,当执行SCSI命令出错时,你会在这里得到Sense Data,得到的数据长度小于等于Sense Allocation Length字段设置的值。

好了,掌握这些知识后,我们已经具备了使用ASPI编写一个U盘的设备驱动程序的能力,我们会在下一篇文章中涉及这个问题。

时间: 2024-10-08 12:51:21

USB系列之八:透过ASPI执行SCSI命令的相关文章

USB系列之七:ASPI介绍及命令测试

在以前的一篇博文<关于构建DOS下编程平台的总结>中曾经介绍了一种在DOS下驱动U盘的方法,我们大致回顾一下.在config.sys中加入两个驱动程序,就可以驱动U盘:    device = aspiohci.sys    device=di1000dd.sys    这两个驱动程序在上述博文中有下载.    如果大家仔细地阅读过我关于USB的文章的话,应该对OHCI这个东西不会陌生,在USB系列文章中,用大量的篇幅介绍了OHCI,这是因为OHCI这种符合USB1.1的控制器在使用上比UHC

katalon系列十四:执行Windows命令&amp;获取项目路径

Katalon Studio中也可以运行Windows命令执行一些系统操作. 根据官方文档,在test case中输入命令:cmd = 'del E:\\shot\\*.xlsx E:\\shot\\*.zip'Runtime.getRuntime().exec(cmd) 运行报错 网上搜到解决方案,修改cmd如下cmd = 'cmd.exe /c del E:\\shot\\*.xlsx E:\\shot\\*.zip' 运行成功 除了直接运行cmd命令,也可以执行.bat文件,代码示例如下

USB系列之九:基于ASPI的U盘驱动程序

USB系列之七和之八介绍了ASPI,并通过一些实例说明了基于ASPI的编程方法,本文使用前两篇文章介绍的知识以及以前介绍的有关DOS驱动程序下驱动程序的内容实际完成一个简单的基于ASPI的U盘驱动程序,算是对ASPI应用的一个总结.    在<USB系列之六>中,我们完成了一个简单的基于DOSUSB的U盘驱动程序,实际上我们今天的程序是在那个程序的基础上改的,基本结构完全相同,思路也完全一样,只是由于有ASPI的支持,无需再读取各种描述符表,读盘.写盘的操作也显得简洁了很多,希望对本文有兴趣的

USB系列之三:从你的U盘里读出更多的内容

U盘是我们最常使用的一种USB设备,本文继续使用DOSUSB做驱动,试图以读取扇区的方式读取你的U盘.    本文可能涉及的协议可能会比较多.一.了解你的U盘    首先我们用上一篇文章介绍的程序usbview.exe去看一下你的U盘,我在本文中用于测试的U盘情况如下: Device Descriptor: (设备描述符) USB Address: 1 Length: 18 Descriptor Type: 1 USB Specification nr.: 0x0110 Calss Code:

Ansible Tower系列 四(使用tower执行一个命令)【转】

在主机清单页面中,选择一个主机清单,进入后,选择hosts里的主机 Paste_Image.png 点击 RUN COMMANDS MODULE 选择 commandARGUMENTS 填写 ifconfig eth0MACHINE CREDENTIAL 选择 ssh登陆账号Verbosity 选择 3 (Debug) Paste_Image.png 点击 Launch,查看输出 转自 Ansible Tower系列 四(使用tower执行一个命令) - 简书http://www.jianshu

Abp框架之执行Update-Database 命令系列错误

废话不多说,直接开门见山.首先的 第一个错误:一般都是,碰到这个问题不要慌,先不要急着去查看sql服务是否开启,首先按F5启动项目,报错之后直接终止项目,然后再执行Update-Database命令  或者Update-Database  -ConnectionStringName "Default" 第二个错误:是执行Update-Database  -ConnectionStringName "Default"说找不到Default这个连接字符串,这个错误只需要

mongo 3.4分片集群系列之八:分片管理

这个系列大致想跟大家分享以下篇章: 1.mongo 3.4分片集群系列之一:浅谈分片集群 2.mongo 3.4分片集群系列之二:搭建分片集群--哈希分片 3.mongo 3.4分片集群系列之三:搭建分片集群--哈希分片 + 安全 4.mongo 3.4分片集群系列之四:搭建分片集群--哈希分片 + 安全 + 区域 5.mongo 3.4分片集群系列之五:详解平衡器 6.mongo 3.4分片集群系列之六:详解配置数据库 7.mongo 3.4分片集群系列之七:配置数据库管理 8.mongo 3

让你提前认识软件开发(23):如何在C语言中执行shell命令?

第1部分 重新认识C语言 如何在C语言中执行shell命令? [文章摘要] Linux操作系统具备开源等诸多优秀特性,因此在许多通信类软件(主流开发语言为C语言)中,开发平台都迁移到了Linux上,同时shell操作在Linux的编程中占有很重要的地位,这就需要开发人员熟练掌握在C语言中执行shell命令的相关操作. 本文用实际的代码演示了如何在C语言程序中执行shell命令,为相关软件开发工作的开展提供了参考. [关键词] Linux  C语言  shell  命令  开发 一.程序执行流程

穿越之旅之--android中如何执行java命令

android的程序基于java开发,当我们接上调试器,执行adb shell,就可以执行linux命令,但是却并不能执行java命令. 那么在android的shell中是否就不能执行java程序了呢. 答案是否定的.我们可以通过app_process来执行java程序. 写一个hello world吧,就是刚开始学java的时候 写得那个hello world,这次要在android上运行. 用记事本新建hello.java文件,编写如下代码: public static class hel