smartctl/hdparm对usb 硬盘识别的原因

最近使用smartctl对usb硬盘获取smart信息识别。所以就仔细查了看原因。同时又记起一起使用hdparm对硬盘休眠时,usb硬盘也是有问题,使用了什么pass through方法?那时没有深入的去了解,这次正好仔细看了看代码和相关问题。

关键字

hdparm、smartctl、ATA/ATAPI command set、scsi command set、SAT、ATACB

要解决的问题

1:什么smartctl对usb设备会失败?能否有解决的方法?

2:hdparm对usb失败后,采取的方法能否对smartctl是否有效?

 

查找思路

是用smartctl工具对usb硬盘失效的,所以就使用strace调试smartctl到底使用哪些ioctl。

ioctl(3, SG_IO, {'S', SG_DXFER_FROM_DEV, cmd[16]=[85, 08, 0e, 00, 00, 00

查找内核代码发现,0x85是ATA_16是个ata pass through命令。

sata硬盘将scsi命令转换ata命令的函数是:ata_scsi_queuecmd--->__ata_scsi_queuecmd

该函数遵循的标准是SAT(scsi to ata translate spec),即如何将scsi命令转成ata命令

在这个函数中发现:真正转成ata命令后,发送到sata控制器是使用:ata_scsi_translate;

而使用已有的数据来模拟scsi命令的是ata_scsi_simulate。

     这里必须说明一点的是,这两个函数都是SAT标准的一部分,只是一些scsi命令的结果不需要再向sata 控制器发送,只要根据已知数据就可以填充返回值。

ata_scsi_translate

    其功能就是根据scsi命令找到合适的转换函数。即ata_get_xlat_func根据scsi命令返回合适的函数。

static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
{
 switch (cmd) {
 case READ_6:
 case READ_10:
 case READ_16:

 case WRITE_6:
 case WRITE_10:
 case WRITE_16:
  return ata_scsi_rw_xlat;

 case SYNCHRONIZE_CACHE:
  if (ata_try_flush_cache(dev))
   return ata_scsi_flush_xlat;
  break;

 case VERIFY:
 case VERIFY_16:
  return ata_scsi_verify_xlat;

 case ATA_12:
 case ATA_16:
  return ata_scsi_pass_thru;

 case START_STOP:/*power management*/
  return ata_scsi_start_stop_xlat;
 }

 return NULL;
}

通过这个函数可以看出,真正装换ata命令的基本都是读写函数。

但是ata command set命令很多,比如:smart相关、power management、hpa相关。但是上面的函数均没有处理。那么这些函数该如何处理的?这就迁出了SAT spec中最重要的两个命令:ATA_12、ATA_16.

    这两个命令就是告诉SATL,scsi命令集cdb中包含不是scsi command,而是真正的ata 命令,SATL只需要将其完整的发送ATA 设备即可。转换的函数是ata_scsi_pass_thru。

     以上就是一个简单的sata硬盘接收命令的过程

     这里又有一个问题:如果用户程序例如smartctl发送的scsi命令不是ATA_12/16,而是直接的smart相关ata命令,那么是不是SATL就无法处理?是的如果仍然使用SG_IO,发送的是标准ATA command这是错误。使用SG_IO,只能发送SAT spec支持的命令.否则就会被丢弃。

    但是我使用strace hdparm -y /dev/sda时发现hdparm使用的不是SG_IO,命令是标准的ATA命令。那么它们是如何实现的?
ioctl(3, 0x31f, 0x7fffadc97e10)         = 0

查内核代码0x31f=HDIO_DRIVE_CMD。ioctl的执行情况:sd_ioctl--》scsi_cmd_ioctl---》scsi_ioctl--》sdev->host->hostt->ioctl

而scsi host的ioctl是ata_scsi_ioctl---》ata_cmd_ioctl。该函数的功能是将标准ATA命令,按照SAT SPEC转换成ATA_16命令后,生成request插入request 队列,回到了ata_scsi_queuecmd。
   这样虽然两个工具的ioctl不同,但是在内核中最终走到一起。

   我们这里先解决问题2,即hdparm对usb设备失败的原因:usb存储的scsi host template是:struct scsi_host_template usb_stor_host_template。这个数据没有ioctl,所以0x31f命令是没有办法执行的,所以在scsi_ioctl函数中找不到任何可以执行的函数,就只能return -EINVAL;

   如果我们将hdparm发送的命令改成SG_IO方式。就不会出错了。下面是改后的代码:
 int dm_start_hdardisk_standby(const char * disk_name)
{
        int fd = 0;
        struct sg_io_hdr io_hdr;
        unsigned char ssuBlk[START_STOP_CMDLEN] = {START_STOP_CMD, 0, 0, 0, 0, 0}; /*cdb*/
        unsigned char sense_b[SENSE_BUFF_LEN];
        int time_secs;
 
        if (disk_name == NULL){
                printf("%s(%d):parameter error:%s/n", __FUNCTION__, __LINE__, disk_name);
                return DM_ERR_PARAM;
        }
        
 
        fd = open(disk_name, O_RDONLY);
 
        if (fd < 0){
                printf("%s(%d): open %s error(%s)l/n", __FUNCTION__, __LINE__, disk_name, strerror(errno));
                return DM_EOPEN;
        }
 
        if ( system("sync") != 0 )
        {
            printf("%s(%d): system(sync): fail(%s)/n", __FUNCTION__, __LINE__,strerror(errno));
        }
 
         ssuBlk[4] = 0;/*from active to standby*/
        
         memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
         io_hdr.interface_id = 'S';
         io_hdr.dxfer_direction = SG_DXFER_NONE;
         io_hdr.cmdp = ssuBlk;
         io_hdr.cmd_len = START_STOP_CMDLEN;
 
         memset(sense_b, 0, SENSE_BUFF_LEN);
         io_hdr.sbp = sense_b;
         io_hdr.mx_sb_len = SENSE_BUFF_LEN;
         io_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) :  DEF_TIMEOUT);
 
          if (ioctl(fd, SG_IO, &io_hdr) < 0){
                        printf("ioctl error(%s)/n", strerror(errno));
                        close(fd);
                        return DM_EIOCTL;
          }

使用SG_IO命令,command是标准的scsi命令,在ata_get_xlat_func中有对START_STOP的处理。

但是这仅仅是对正常的sata硬盘而言,那么对usb硬盘会这样吗?

 

usb硬盘

usb storage spec中说明了usb存储中的command set。

static int get_protocol(struct us_data *us)
{
 switch (us->subclass) {
 case US_SC_RBC:
  us->protocol_name = "Reduced Block Commands (RBC)";
  us->proto_handler = usb_stor_transparent_scsi_command;
  break;

 case US_SC_8020:
  us->protocol_name = "8020i";
  us->proto_handler = usb_stor_ATAPI_command;
  us->max_lun = 0;
  break;

 case US_SC_QIC:
  us->protocol_name = "QIC-157";
  us->proto_handler = usb_stor_qic157_command;
  us->max_lun = 0;
  break;

 case US_SC_8070:
  us->protocol_name = "8070i";
  us->proto_handler = usb_stor_ATAPI_command;
  us->max_lun = 0;
  break;

 case US_SC_SCSI:
  us->protocol_name = "Transparent SCSI";
  us->proto_handler = usb_stor_transparent_scsi_command;
  break;

 case US_SC_UFI:
  us->protocol_name = "Uniform Floppy Interface (UFI)";
  us->proto_handler = usb_stor_ufi_command;
  break;

这是根据usb 控制器芯片的subclass来选择合适的命令集,我们一般见到的都是US_SC_SCSI。至少我没有见过其他类型的。这说明命令集是scsi,即在驱动中并不转成ata command,这个转换是在usb芯片中完成的。

    但是我们使用smartctl时是失败,那么这是什么原因?查看smartctl发现有下面的内容:

USB devices and smartmontools

To access USB storage devices, the operating system sends SCSI commands through the USB transport to the device. If the USB device is actually a PATA or SATA disk in an USB enclosure, the firmware of its USB bridge chip translates these commands into the corresponding ATA commands. This works straightforward for read and write commands, but not for SMART commands.

To access SMART functionality, smartmontools must be able to send ATA commands directly to the disk. For USB devices, at least the following conditions must be met:

  • The USB bridge provides an ATA pass-through command.
  • This command is supported by smartmontools.
  • The operating system provides a SCSI pass-through I/O-control which works through its USB-layer.
  • SCSI support is implemented in the operating system interface of smartmontools.

Some recent USB bridges already support the vendor independent SAT (SCSI/ATA Translation, ANSI INCITS 431-2007) standard. Other USB bridges provide vendor specific ATA pass-through commands. The current version of smartmontools supports the following pass-through commands and USB bridges:

CommandUSB bridgessmartctl option48-bit ATAsupportComment
SAT ATApass-through 12 and 16various (Initio, Oxford, ...)-d sat[,16]; -d sat,12requires '-d sat[,16]'Older Linux kernels may require '-d sat,12'
Cypress ATACBCypress CY7C68300B/C (AT2LP), CY7C68310 (ISD-300LP)-d usbcypress[,CMD]NoCY7C68300A (AT2) may not work.
JMicron ATApass-throughJMicron JM20329, JM20335-39-d usbjmicron[,x][,PORT]No:JM20327, Yes:JM20336/9'-d usbjmicron,x' enables 48-bit support
Sunplus ATApass-throughSunplus SPIF215/6, SPIF225/6-d usbsunplusYes 

Smartmontools was successfully tested with many USB devices on several Platforms. This will never work on MacOS X unless someone adds SCSI pass-through support to this OS. If the USB ID can be obtained from the operating system, smartmontools also supports auto-detection of (the already tested) USB devices. Then it is not necessary to specify the '-d' option. See the following table for details:

Platform...has SCSIpass-throughsmartmontools supports SCSI... supports USB... auto-detection... in smartd DEVICESCANComment
LinuxYesYesYESYESYESSee comment about SAT in above table
MacOS XNoNoNoNoNoUSB works with e.g. XP in a VM
FreeBSDYesYesYESYESYES 
NetBSDYesYesYESNoNo 
OpenBSDYesYesYESNoNo 
SolarisYesYesYESNoNo 
QNX?NoNoNoNo 
OS/2?NoNoNoNo 
Windows NT/2K/XP/VistaYesYesYESYESNoAuto-detection is slow due to the use of 'wmic.exe'
Windows 9x/MEYesYesYESNoNoRequires ASPI driver

目前usb存储芯片:
1:支持标准SAT,使用ATA_12/16
2:支持自己的特殊命令如ATACB,类似于ATA_12/16,比如cypress公司的芯片。
在linux-2.6.28中的cypress-atacb.c中就是第二中方案:Support for emulating SAT (ata pass through) on devices based  on the Cypress USB/ATA bridge supporting ATACB.
  完成该功能的函数是cypress_atacb_passthrough。
  目前可以说hdparm和smartctl对usb硬盘不工作的原因是不同的。如果使用sdparm usb就会可以。但是smartctl是需要芯片支持的。所以在最新的smartctl中使用-d后面加参数。就是根据各自的芯片,填写标准ATA_16或者vendor spec comand。
 
  可以在smartctl的主页中查找支持哪些usb芯片。
   usb芯片是否支持SAT或者特殊的如ATACB,需要看datasheet
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值