Recently, smartctl was used to identify SMART information obtained from a USB hard disk. So I checked the reason carefully. At the same time, remember that when hdparm is used together to sleep the hard disk, the USB hard disk is also a problem. What pass through method is used? At that time, I did not have a deep understanding of it. This time I took a closer look at the Code and related issues. Keywords
Hdparm, smartctl, ATA/atapi command set, SCSI command set, SAT, atacb
Problems to be Solved
1: Why does smartctl fail on the USB device? Is there a solution?
2: Does hdparm take effective for smartctl after a USB failure?
Search Ideas
Because the smartctl tool is used to disable the USB hard disk, use strace to debug which IOCTL is used by smartctl.
IOCTL (3, sg_io, {'s ', sg_dxfer_from_dev, CMD [16] = [85, 08, 0e, 00, 00, 00
Search for the kernel code and find that 0x85 is ata_16 and is an ATA pass through command.
The function for converting the SCSI command to the ATA command is ata_scsi_queuecmd --- >__ ata_scsi_queuecmd.
This function follows the SAT (SCSI to ATA translate spec) standard, that is, how to convert SCSI commands into ata commands.
In this function, it is found that, after being converted to the ATA command, it is sent to the SATA controller using: ata_scsi_translate;
The existing data used to simulate the SCSI command is ata_scsi_simulate.
It must be noted that these two functions are part of the SAT standard, but some SCSI command results do not need to be sent to the SATA controller, as long as the data is known, the return value can be filled.
Ata_scsi_translate
Its function is to find the appropriate conversion function based on the SCSI command. That is, ata_get_xlat_func returns an appropriate function based on the SCSI command.
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;
}
Through this function, we can see that the Read and Write Functions are basically used for the ATA command.
However, there are many ata command set commands, such as smart, power management, and hPa. However, none of the above functions are processed. So how do we deal with these functions? This removes the two most important commands in the sat spec: ata_12 and ata_16.
These two commands tell satl that the SCSI command set CDB contains not a SCSI command, but a real ata command. satl only needs to send the complete ata device. The conversion function is ata_scsi_pass_thru.
The above is a simple SATA hard drive receiving command process.
There is another problem: if the user program, for example, the SCSI Command sent by smartctl, is not ata_12/16, but the smart-related ata command, isn't satl unable to handle it? Yes. If sg_io is still used, the standard ata command is sent. This is an error. Sg_io can only be used to send sat messages.
Command supported by spec. Otherwise, it will be discarded.
However, when using strace hdparm-y/dev/SDA, I found that hdparm is not using sg_io, and the command is a standard ata command. So how are they implemented?
IOCTL (3, 0x31f, 0x7fffadc97e10) = 0
Check the kernel code 0x31f = hdio_drive_cmd. IOCTL execution: sd_ioctl -- scsi_1__ioctl --- scsi_ioctl -- SDEV-> host-> hostt-> IOCTL
The IOCTL of SCSI host is ata_scsi_ioctl --- "ata_cmd_ioctl. This function is used to convert the standard ata command to ata_16 according to the SAT spec, generate a request, insert it into the request queue, and return to ata_scsi_queuecmd.
In this way, although the ioctl of the two tools is different, they eventually come together in the kernel.
Here we first solve problem 2, that is, the cause of hdparm failure to the USB device: the SCSI host template of the USB storage is: struct scsi_host_template usb_stor_host_template. There is no IOCTL for this data, so there is no way to execute the 0x31f command, so no executable function can be found in the scsi_ioctl function, and only return-einval;
If we change the Command sent by hdparm to the sg_io method. No error occurs. The modified code is as follows:
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};/* 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.systolic = 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;
}
Use the sg_io command. The command is a standard SCSI command, which can be used to process start_stop in ata_get_xlat_func.
But this is only for a normal SATA hard disk. Will it be like this for a USB hard disk?
USB hard drive
The command set in USB storage is described in USB storage spec.
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;
This is based on the subclass of the USB controller chip to select the appropriate command set. We generally see us_ SC _scsi. At least I have never seen other types. This indicates that the command set is SCSI, that is, it is not converted into ata command in the driver. This conversion is completed in the USB chip.
But we failed to use smartctl. Why? The following content is found in 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:
Command |
USB Bridges |
Smartctl Option |
48-bit atasupport |
Comment |
Sat atapass-through 12 and 16 |
Various (initio, Oxford ,...) |
-D sat [, 16];-D sat, 12 |
Requires '-d sat [, 16]' |
Older linux kernels may require '-D sat, 12' |
Cypress atacb |
Cypress cy7c68300b/C (at2lp), cy7c68310 (ISD-300LP) |
-D usbcypress [, CMD] |
No |
Cy7c68300a (AT2) may not work. |
Jmicron atapass-through |
Jmicron jm20329, JM20335-39 |
-D usbjmicron [, X] [, port] |
No: jm20327, yes: jm20336/9 |
'-D usbjmicron, x' enables 48-bit support |
Sunplus atapass-through |
Sunplus spif215/6, spif225/6 |
-D usbsunplus |
Yes |
|
Smartmontools was successfully tested with customized 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-through |
Smartmontools supports SCSI |
... Supports USB |
... Auto-detection |
... In smartd devicescan |
Comment |
Linux |
Yes |
Yes |
Yes |
Yes |
Yes |
See comment about sat in above table |
MacOS X |
No |
No |
No |
No |
No |
USB works with e.g. XP in a VM |
FreeBSD |
Yes |
Yes |
Yes |
Yes |
Yes |
|
NetBSD |
Yes |
Yes |
Yes |
No |
No |
|
OpenBSD |
Yes |
Yes |
Yes |
No |
No |
|
Solaris |
Yes |
Yes |
Yes |
No |
No |
|
QNX |
? |
No |
No |
No |
No |
|
OS/2 |
? |
No |
No |
No |
No |
|
Windows NT/2 k/XP/Vista |
Yes |
Yes |
Yes |
Yes |
No |
Auto-detection is slow due to the use of 'wmic.exe' |
Windows 9x/me |
Yes |
Yes |
Yes |
No |
No |
Requires ASPI driver |
The USB chip does not convert all SCSI commands to ATA according to sat. Therefore, some commands are not supported. Currently, the USB storage chip: 1: supports the standard sat, using ata_12/162: supports your own special commands such as atacb, similar to ata_12/16, such as the cypress chip. In the linux-2.6.28 of the cypress-atacb.c is the second solution: Support for emulating sat (ATA pass through) on devices based on the cypress USB/ATA bridge supporting atacb. The function to do this is cypress_atacb_passthrough. The reason why hdparm and smartctl do not work on USB hard disks is different. If you use sdparm USB, you can. However, smartctl is supported by chips. Therefore, add a parameter after-D in the latest smartctl. Enter the standard ata_16 or vendor spec Comand based on their respective chips. You can find the supported USB chips on the home page of smartctl.
Whether the USB chip supports SAT or special atacb, you need to check datasheet.