USB协议学习(三)大容量存储设备SCSI协议分析

笔者来简单介绍一下SCSI得协议命令

1、SCSI协议认识

  • SCSI:Small Computer System Interface,用于计算机外部设备得接口标准,定义了与外部设备得一套协议。所以SCSI是纯软件的,与硬件无关,可以在USB协议之上,也可以在UFS协议之上。
  • SCSI标准协议族支持很多钟SCSI设备,像盘,打印机,扫描仪等等)。这个标准定义了一个支持所有SCSI设备得设备模型。其他SCS命令标准扩展了通用得SCSI设备模型,以满足适配特定得SCIS设备。
  • SCSI用CDB来描述命令协议,CDB:command description block,主要有6字节、10字节、12字节、16字节命令协议。通常第一个字节用于描述命令码、操作码。
  • lun:logci unit number,逻辑单元号,指逻辑设备ID,通过该ID可以寻找SCSI下面挂载的设备。

2、SCSI协议命令

首先介绍一下CDB命令格式以及参数得意义,然后介绍各自SCSI命令。

2.1 、CDB命令格式

比如6字节命令。

  • OPERATION CODE:操作码
  • LOGICAL BLOCK ADDRESS:逻辑块地址,以块为单位的地址,例如块大小为4K,那么1的地址就是0x1000,2就是0x2000,
  • TRANSFER LENGTH / PARAMETER LIST LENGTH/ ALLOCATION LENGTH:传输长度/参数长度/分配长度,传输的长度也是以块为单位的,块的大小,总共地址的大小,可以通过read Capcacity来读取回来。
  • CONTROL:控制type,所有的命令都有。
    在这里插入图片描述
    可以看到6字节 的块地址只占2个Byte,length 只占1个Byte,所以其寻址的范围是有限的。
    例如:Block_Size = 0x1000
  • Block_addr_end = 0x10000 * 0x1000 = 256M B。
  • 一次读的数据长度也有限制, 0x100*0x1000 =1MB。
    对于大容量存储的设备来说,明显不够,所以后面由推出了10Byte、12Byte、16Byte、32Byte的命令格式。
    在这里插入图片描述
    在这里插入图片描述
    由上图来看,明显是增加了logic block address 的位数以及length的位数,可以访问的地址范围更大,
  • address:4Byte,end = 16TB,还是以Block Size=4K来算。
  • length:4Byte,

2.2 、CDB具体命令

2.2.1 Test_Unit_Ready

用来询问设备是否处于ready状态,是否可以正常接收媒介数据访问命令并正确处理。

  • 注意其不是一个请求自我测试的命令
  • 可以通过start unit命令让其处于ready状态。
  • 如果处于不可操作的状态,则会返回NOT Ready的sense key。
    在这里插入图片描述
    命令直接填个00就可以,比较简单。
    在这里插入图片描述
    如果是ready状态,device不回复SCSI的数据。从下面代码中可以看到,如果是异常会,返回NOT_Ready的Sense key。
static int8_t SCSI_TestUnitReady(uint8_t lun, uint8_t *params)
{
  
  /* case 9 : Hi > D0 */
  if (MSC_BOT_cbw.dDataLength != 0)
  {
    SCSI_SenseCode(MSC_BOT_cbw.bLUN, 
                   ILLEGAL_REQUEST, 
                   INVALID_CDB);
    return -1;
  }  
  
  if(USBD_STORAGE_fops->IsReady(lun) !=0 )
  {
    SCSI_SenseCode(lun,
                   NOT_READY, 
                   MEDIUM_NOT_PRESENT);
    return -1;
  } 
  MSC_BOT_DataLen = 0;
  re
2.2.2 Inquiry

在这里插入图片描述

  • Length:可以填35,获取标准的厂商设备信息查询
  • 其他字段都可以填0
    响应格式:
  • Device Type:存储设备类型
  • length:返回的数据长度
  • verdor : 厂商信息
  • product:产品信息
  • product version:版本信息
    在这里插入图片描述
    在这里插入图片描述
    一般标志的设备信息,都默认36字节,如果多个设备,通过lun去偏移。

//USB Mass storage 标准查询数据(每个lun占36字节)
const int8_t  STORAGE_Inquirydata[] = { 
  
	/* LUN 0 */ 
	0x00,		
	0x80,		
	0x02,		
	0x02,
	(USBD_STD_INQUIRY_LENGTH - 4),
	0x00,
	0x00,	
	0x00,
    /* Vendor Identification */
    'A', 'L', 'I', 'E', 'N', 'T', 'E', 'K', ' ',//9字节
    /* Product Identification */
    'S', 'P', 'I', ' ', 'F', 'l', 'a', 's', 'h',//15字节
    ' ','D', 'i', 's', 'k', ' ',
    /* Product Revision Level */	
    '1', '.', '0', ' ',							//4字节		
	
	/* LUN 1 */
	0x00,
	0x80,		
	0x02,		
	0x02,
	(USBD_STD_INQUIRY_LENGTH - 4),
	0x00,
	0x00,	
	0x00,
	/* Vendor Identification */
	'A', 'L', 'I', 'E', 'N', 'T', 'E', 'K',' ',	//9字节
	/* Product Identification */				
    'N', 'A', 'N', 'D', ' ', 'F', 'l', 'a', 's', 'h',//15字节
	' ','D', 'i', 's', 'k', 
    /* Product Revision Level */
	'1', '.', '0' ,' ',                      	//4字节
	
	/* LUN 2 */
	0x00,
	0x80,		
	0x02,		
	0x02,
	(USBD_STD_INQUIRY_LENGTH - 4),
	0x00,
	0x00,	
	0x00,
	/* Vendor Identification */
	'A', 'L', 'I', 'E', 'N', 'T', 'E', 'K',' ',	//9字节
	/* Product Identification */				
	'S', 'D', ' ', 'F', 'l', 'a', 's', 'h', ' ',//15字节
	'D', 'i', 's', 'k', ' ', ' ',  
    /* Product Revision Level */
	'1', '.', '0' ,' ',                      	//4字节
}; 

static int8_t  SCSI_Inquiry(uint8_t lun, uint8_t *params)
{
  uint8_t* pPage;
  uint16_t len;
  
  if (params[1] & 0x01)/*Evpd is set*/
  {
    pPage = (uint8_t *)MSC_Page00_Inquiry_Data;
    len = LENGTH_INQUIRY_PAGE00;
  }
  else
  {
    
    pPage = (uint8_t *)STORAGE_Inquirydata[lun * USBD_STD_INQUIRY_LENGTH];
    len = pPage[4] + 5;
    
    if (params[4] <= len)
    {
      len = params[4];
    }
  }
  MSC_BOT_DataLen = len;
  
  while (len) 
  {
    len--;
    MSC_BOT_Data[len] = pPage[len];
  }
  r
2.2.3 Read

read10命令
主要关注的 address、length,其他填0,可以读device中的数据。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2.4 Write

write10命令。
主要关注的 address、length,其他填0,可以向device写数据。
在这里插入图片描述

2.2.5 ReadCapacity

read10 命令:获取device设备的容量以及块大小。
PMI以及 LBA均填0则行。
在这里插入图片描述
响应值:
returned logical block address:返回的最大的逻辑块的地址
在这里插入图片描述
在这里插入图片描述
由下面代码可以看出,返回的就是逻辑块的size和逻辑块的最大地址。

int8_t STORAGE_GetCapacity (uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{     
	switch(lun)
	{
		case 0://SPI FLASH
			*block_size=512;  
			*block_num=1024*1024*25/512;	//SPI FLASH的前面25M字节,文件系统用
			break;
		case 1://NAND FLASH
			*block_size=512;  
			*block_num=nand_dev.valid_blocknum*nand_dev.block_pagenum*nand_dev.page_mainsize/512;
  			break;
		case 2://SD卡
			*block_size=512;  
			*block_num=SDCardInfo.CardCapacity/512; 
			break; 
	}  	
	return 0; 
} 
static int8_t SCSI_ReadCapacity10(uint8_t lun, uint8_t *params)
{
  
  if(USBD_STORAGE_fops->GetCapacity(lun, &SCSI_blk_nbr[lun], &SCSI_blk_size) != 0)
  {
    SCSI_SenseCode(lun,
                   NOT_READY, 
                   MEDIUM_NOT_PRESENT);
    return -1;
  } 
  else
  {
    
    MSC_BOT_Data[0] = (uint8_t)((SCSI_blk_nbr[lun] - 1) >> 24);
    MSC_BOT_Data[1] = (uint8_t)((SCSI_blk_nbr[lun] - 1) >> 16);
    MSC_BOT_Data[2] = (uint8_t)((SCSI_blk_nbr[lun] - 1) >>  8);
    MSC_BOT_Data[3] = (uint8_t)(SCSI_blk_nbr[lun] - 1);
    
    MSC_BOT_Data[4] = (uint8_t)(SCSI_blk_size >>  24);
    MSC_BOT_Data[5] = (uint8_t)(SCSI_blk_size >>  16);
    MSC_BOT_Data[6] = (uint8_t)(SCSI_blk_size >>  8);
    MSC_BOT_Data[7] = (uint8_t)(SCSI_blk_size);
    
    MSC_BOT_DataLen = 8;
    return 0;
  }
}

2.2.6 Request SenseCode

用来请求sense data,sense data则是记录通信过程中的错误信息。
DESC Bit:用来决定返回的响应值是哪种格式。
在这里插入图片描述
主要关注三个值即可。
SENSE KEY
ADDITIONAL SENSE CODE
ADDITIONAL SENSE CODE QUALIFIER
可以依次理解为:主错误码、子错误码和子子错误码的意思。
如果DESC置1,则是下面这张响应格式
在这里插入图片描述
如果是0,则是固定的格式
在这里插入图片描述

3、SCSI协议命令测试

3.1 Test_Unit_Ready

主机询问是否TestReady,从机什么都不回复就正常,如果有异常,csw 会返回failed,从而通过sense key返回错误状态。
在这里插入图片描述
如果data length不等于0,则会返回无效请求的错误信息。
在这里插入图片描述
此时csw 会返回failed的status=1,然后就会通过sense data来知道是什么错误信息。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
sense key = 0x5,无效的请求
ASC= 0x20,无效的CDB命令。
正常Test unit ready命令,data len = 0,但是上面的cbw data transfer length =8,就会引发device回复错误,看上面代码。

3.2 ReadCapacity

在这里插入图片描述
最大的地址=0xC800,50K个块数据
块size = 0x200,512Byte

3.3 Write

地址=0x010000 ,长度为512。
在这里插入图片描述

3.4 Read

块size = 0x200,所以read的len=0x1,则data length 需要设置512,否则就会报错。
然后通过write写进去的数据,可以通过read读出来。
在这里插入图片描述

3.5 Inquiry Data

需要设置读取的数据长度是多少,返回的数据就是多少,如果是0,肯呢个会出现异常。
在这里插入图片描述

4、BusHound 抓包说明

1、勾选Devices,就可以抓对应设备的USB协议包
在这里插入图片描述
2、选择Setting

  • 可以选择需要抓的包的类型,比如SCSI Command,USB control transfer命令,
  • 也可以修改左上角的抓包限制,改最大,避免抓包的长度太小,没有记录到需要的数据。
  • 左下角可以选择触发暂停,比如下图中出现无效的命令时暂停,
    在这里插入图片描述
    3、选择Capature,点击start,就可以看到抓包的数据。
    在这里插入图片描述
    4、点击Devices,双击设备,可以出现Bus Commander,可以用来发送USB命令或者SCSI命令,方便调试协议。
    在这里插入图片描述
  • 11
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张一西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值