最近使用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,命令是标准的