diff options
Diffstat (limited to 'Documentation/userspace-api/ioctl/hdio.rst')
-rw-r--r-- | Documentation/userspace-api/ioctl/hdio.rst | 547 |
1 files changed, 547 insertions, 0 deletions
diff --git a/Documentation/userspace-api/ioctl/hdio.rst b/Documentation/userspace-api/ioctl/hdio.rst new file mode 100644 index 000000000..6ee8fc886 --- /dev/null +++ b/Documentation/userspace-api/ioctl/hdio.rst @@ -0,0 +1,547 @@ +============================== +Summary of `HDIO_` ioctl calls +============================== + +- Edward A. Falk <efalk@google.com> + +November, 2004 + +This document attempts to describe the ioctl(2) calls supported by +the HD/IDE layer. These are by-and-large implemented (as of Linux 5.11) +drivers/ata/libata-scsi.c. + +ioctl values are listed in <linux/hdreg.h>. As of this writing, they +are as follows: + + ioctls that pass argument pointers to user space: + + ======================= ======================================= + HDIO_GETGEO get device geometry + HDIO_GET_32BIT get current io_32bit setting + HDIO_GET_IDENTITY get IDE identification info + HDIO_DRIVE_TASKFILE execute raw taskfile + HDIO_DRIVE_TASK execute task and special drive command + HDIO_DRIVE_CMD execute a special drive command + ======================= ======================================= + + ioctls that pass non-pointer values: + + ======================= ======================================= + HDIO_SET_32BIT change io_32bit flags + ======================= ======================================= + + +The information that follows was determined from reading kernel source +code. It is likely that some corrections will be made over time. + +------------------------------------------------------------------------------ + +General: + + Unless otherwise specified, all ioctl calls return 0 on success + and -1 with errno set to an appropriate value on error. + + Unless otherwise specified, all ioctl calls return -1 and set + errno to EFAULT on a failed attempt to copy data to or from user + address space. + + Unless otherwise specified, all data structures and constants + are defined in <linux/hdreg.h> + +------------------------------------------------------------------------------ + +HDIO_GETGEO + get device geometry + + + usage:: + + struct hd_geometry geom; + + ioctl(fd, HDIO_GETGEO, &geom); + + + inputs: + none + + + + outputs: + hd_geometry structure containing: + + + ========= ================================== + heads number of heads + sectors number of sectors/track + cylinders number of cylinders, mod 65536 + start starting sector of this partition. + ========= ================================== + + + error returns: + - EINVAL + + if the device is not a disk drive or floppy drive, + or if the user passes a null pointer + + + notes: + Not particularly useful with modern disk drives, whose geometry + is a polite fiction anyway. Modern drives are addressed + purely by sector number nowadays (lba addressing), and the + drive geometry is an abstraction which is actually subject + to change. Currently (as of Nov 2004), the geometry values + are the "bios" values -- presumably the values the drive had + when Linux first booted. + + In addition, the cylinders field of the hd_geometry is an + unsigned short, meaning that on most architectures, this + ioctl will not return a meaningful value on drives with more + than 65535 tracks. + + The start field is unsigned long, meaning that it will not + contain a meaningful value for disks over 219 Gb in size. + + + +HDIO_GET_IDENTITY + get IDE identification info + + + usage:: + + unsigned char identity[512]; + + ioctl(fd, HDIO_GET_IDENTITY, identity); + + inputs: + none + + + + outputs: + ATA drive identity information. For full description, see + the IDENTIFY DEVICE and IDENTIFY PACKET DEVICE commands in + the ATA specification. + + error returns: + - EINVAL Called on a partition instead of the whole disk device + - ENOMSG IDENTIFY DEVICE information not available + + notes: + Returns information that was obtained when the drive was + probed. Some of this information is subject to change, and + this ioctl does not re-probe the drive to update the + information. + + This information is also available from /proc/ide/hdX/identify + + + +HDIO_GET_32BIT + get current io_32bit setting + + + usage:: + + long val; + + ioctl(fd, HDIO_GET_32BIT, &val); + + inputs: + none + + + + outputs: + The value of the current io_32bit setting + + + + notes: + 0=16-bit, 1=32-bit, 2,3 = 32bit+sync + + + +HDIO_DRIVE_TASKFILE + execute raw taskfile + + + Note: + If you don't have a copy of the ANSI ATA specification + handy, you should probably ignore this ioctl. + + - Execute an ATA disk command directly by writing the "taskfile" + registers of the drive. Requires ADMIN and RAWIO access + privileges. + + usage:: + + struct { + + ide_task_request_t req_task; + u8 outbuf[OUTPUT_SIZE]; + u8 inbuf[INPUT_SIZE]; + } task; + memset(&task.req_task, 0, sizeof(task.req_task)); + task.req_task.out_size = sizeof(task.outbuf); + task.req_task.in_size = sizeof(task.inbuf); + ... + ioctl(fd, HDIO_DRIVE_TASKFILE, &task); + ... + + inputs: + + (See below for details on memory area passed to ioctl.) + + ============ =================================================== + io_ports[8] values to be written to taskfile registers + hob_ports[8] high-order bytes, for extended commands. + out_flags flags indicating which registers are valid + in_flags flags indicating which registers should be returned + data_phase see below + req_cmd command type to be executed + out_size size of output buffer + outbuf buffer of data to be transmitted to disk + inbuf buffer of data to be received from disk (see [1]) + ============ =================================================== + + outputs: + + =========== ==================================================== + io_ports[] values returned in the taskfile registers + hob_ports[] high-order bytes, for extended commands. + out_flags flags indicating which registers are valid (see [2]) + in_flags flags indicating which registers should be returned + outbuf buffer of data to be transmitted to disk (see [1]) + inbuf buffer of data to be received from disk + =========== ==================================================== + + error returns: + - EACCES CAP_SYS_ADMIN or CAP_SYS_RAWIO privilege not set. + - ENOMSG Device is not a disk drive. + - ENOMEM Unable to allocate memory for task + - EFAULT req_cmd == TASKFILE_IN_OUT (not implemented as of 2.6.8) + - EPERM + + req_cmd == TASKFILE_MULTI_OUT and drive + multi-count not yet set. + - EIO Drive failed the command. + + notes: + + [1] READ THE FOLLOWING NOTES *CAREFULLY*. THIS IOCTL IS + FULL OF GOTCHAS. Extreme caution should be used with using + this ioctl. A mistake can easily corrupt data or hang the + system. + + [2] Both the input and output buffers are copied from the + user and written back to the user, even when not used. + + [3] If one or more bits are set in out_flags and in_flags is + zero, the following values are used for in_flags.all and + written back into in_flags on completion. + + * IDE_TASKFILE_STD_IN_FLAGS | (IDE_HOB_STD_IN_FLAGS << 8) + if LBA48 addressing is enabled for the drive + * IDE_TASKFILE_STD_IN_FLAGS + if CHS/LBA28 + + The association between in_flags.all and each enable + bitfield flips depending on endianness; fortunately, TASKFILE + only uses inflags.b.data bit and ignores all other bits. + The end result is that, on any endian machines, it has no + effect other than modifying in_flags on completion. + + [4] The default value of SELECT is (0xa0|DEV_bit|LBA_bit) + except for four drives per port chipsets. For four drives + per port chipsets, it's (0xa0|DEV_bit|LBA_bit) for the first + pair and (0x80|DEV_bit|LBA_bit) for the second pair. + + [5] The argument to the ioctl is a pointer to a region of + memory containing a ide_task_request_t structure, followed + by an optional buffer of data to be transmitted to the + drive, followed by an optional buffer to receive data from + the drive. + + Command is passed to the disk drive via the ide_task_request_t + structure, which contains these fields: + + ============ =============================================== + io_ports[8] values for the taskfile registers + hob_ports[8] high-order bytes, for extended commands + out_flags flags indicating which entries in the + io_ports[] and hob_ports[] arrays + contain valid values. Type ide_reg_valid_t. + in_flags flags indicating which entries in the + io_ports[] and hob_ports[] arrays + are expected to contain valid values + on return. + data_phase See below + req_cmd Command type, see below + out_size output (user->drive) buffer size, bytes + in_size input (drive->user) buffer size, bytes + ============ =============================================== + + When out_flags is zero, the following registers are loaded. + + ============ =============================================== + HOB_FEATURE If the drive supports LBA48 + HOB_NSECTOR If the drive supports LBA48 + HOB_SECTOR If the drive supports LBA48 + HOB_LCYL If the drive supports LBA48 + HOB_HCYL If the drive supports LBA48 + FEATURE + NSECTOR + SECTOR + LCYL + HCYL + SELECT First, masked with 0xE0 if LBA48, 0xEF + otherwise; then, or'ed with the default + value of SELECT. + ============ =============================================== + + If any bit in out_flags is set, the following registers are loaded. + + ============ =============================================== + HOB_DATA If out_flags.b.data is set. HOB_DATA will + travel on DD8-DD15 on little endian machines + and on DD0-DD7 on big endian machines. + DATA If out_flags.b.data is set. DATA will + travel on DD0-DD7 on little endian machines + and on DD8-DD15 on big endian machines. + HOB_NSECTOR If out_flags.b.nsector_hob is set + HOB_SECTOR If out_flags.b.sector_hob is set + HOB_LCYL If out_flags.b.lcyl_hob is set + HOB_HCYL If out_flags.b.hcyl_hob is set + FEATURE If out_flags.b.feature is set + NSECTOR If out_flags.b.nsector is set + SECTOR If out_flags.b.sector is set + LCYL If out_flags.b.lcyl is set + HCYL If out_flags.b.hcyl is set + SELECT Or'ed with the default value of SELECT and + loaded regardless of out_flags.b.select. + ============ =============================================== + + Taskfile registers are read back from the drive into + {io|hob}_ports[] after the command completes iff one of the + following conditions is met; otherwise, the original values + will be written back, unchanged. + + 1. The drive fails the command (EIO). + 2. One or more than one bits are set in out_flags. + 3. The requested data_phase is TASKFILE_NO_DATA. + + ============ =============================================== + HOB_DATA If in_flags.b.data is set. It will contain + DD8-DD15 on little endian machines and + DD0-DD7 on big endian machines. + DATA If in_flags.b.data is set. It will contain + DD0-DD7 on little endian machines and + DD8-DD15 on big endian machines. + HOB_FEATURE If the drive supports LBA48 + HOB_NSECTOR If the drive supports LBA48 + HOB_SECTOR If the drive supports LBA48 + HOB_LCYL If the drive supports LBA48 + HOB_HCYL If the drive supports LBA48 + NSECTOR + SECTOR + LCYL + HCYL + ============ =============================================== + + The data_phase field describes the data transfer to be + performed. Value is one of: + + =================== ======================================== + TASKFILE_IN + TASKFILE_MULTI_IN + TASKFILE_OUT + TASKFILE_MULTI_OUT + TASKFILE_IN_OUT + TASKFILE_IN_DMA + TASKFILE_IN_DMAQ == IN_DMA (queueing not supported) + TASKFILE_OUT_DMA + TASKFILE_OUT_DMAQ == OUT_DMA (queueing not supported) + TASKFILE_P_IN unimplemented + TASKFILE_P_IN_DMA unimplemented + TASKFILE_P_IN_DMAQ unimplemented + TASKFILE_P_OUT unimplemented + TASKFILE_P_OUT_DMA unimplemented + TASKFILE_P_OUT_DMAQ unimplemented + =================== ======================================== + + The req_cmd field classifies the command type. It may be + one of: + + ======================== ======================================= + IDE_DRIVE_TASK_NO_DATA + IDE_DRIVE_TASK_SET_XFER unimplemented + IDE_DRIVE_TASK_IN + IDE_DRIVE_TASK_OUT unimplemented + IDE_DRIVE_TASK_RAW_WRITE + ======================== ======================================= + + [6] Do not access {in|out}_flags->all except for resetting + all the bits. Always access individual bit fields. ->all + value will flip depending on endianness. For the same + reason, do not use IDE_{TASKFILE|HOB}_STD_{OUT|IN}_FLAGS + constants defined in hdreg.h. + + + +HDIO_DRIVE_CMD + execute a special drive command + + + Note: If you don't have a copy of the ANSI ATA specification + handy, you should probably ignore this ioctl. + + usage:: + + u8 args[4+XFER_SIZE]; + + ... + ioctl(fd, HDIO_DRIVE_CMD, args); + + inputs: + Commands other than WIN_SMART: + + ======= ======= + args[0] COMMAND + args[1] NSECTOR + args[2] FEATURE + args[3] NSECTOR + ======= ======= + + WIN_SMART: + + ======= ======= + args[0] COMMAND + args[1] SECTOR + args[2] FEATURE + args[3] NSECTOR + ======= ======= + + outputs: + args[] buffer is filled with register values followed by any + + + data returned by the disk. + + ======== ==================================================== + args[0] status + args[1] error + args[2] NSECTOR + args[3] undefined + args[4+] NSECTOR * 512 bytes of data returned by the command. + ======== ==================================================== + + error returns: + - EACCES Access denied: requires CAP_SYS_RAWIO + - ENOMEM Unable to allocate memory for task + - EIO Drive reports error + + notes: + + [1] For commands other than WIN_SMART, args[1] should equal + args[3]. SECTOR, LCYL and HCYL are undefined. For + WIN_SMART, 0x4f and 0xc2 are loaded into LCYL and HCYL + respectively. In both cases SELECT will contain the default + value for the drive. Please refer to HDIO_DRIVE_TASKFILE + notes for the default value of SELECT. + + [2] If NSECTOR value is greater than zero and the drive sets + DRQ when interrupting for the command, NSECTOR * 512 bytes + are read from the device into the area following NSECTOR. + In the above example, the area would be + args[4..4+XFER_SIZE]. 16bit PIO is used regardless of + HDIO_SET_32BIT setting. + + [3] If COMMAND == WIN_SETFEATURES && FEATURE == SETFEATURES_XFER + && NSECTOR >= XFER_SW_DMA_0 && the drive supports any DMA + mode, IDE driver will try to tune the transfer mode of the + drive accordingly. + + + +HDIO_DRIVE_TASK + execute task and special drive command + + + Note: If you don't have a copy of the ANSI ATA specification + handy, you should probably ignore this ioctl. + + usage:: + + u8 args[7]; + + ... + ioctl(fd, HDIO_DRIVE_TASK, args); + + inputs: + Taskfile register values: + + ======= ======= + args[0] COMMAND + args[1] FEATURE + args[2] NSECTOR + args[3] SECTOR + args[4] LCYL + args[5] HCYL + args[6] SELECT + ======= ======= + + outputs: + Taskfile register values: + + + ======= ======= + args[0] status + args[1] error + args[2] NSECTOR + args[3] SECTOR + args[4] LCYL + args[5] HCYL + args[6] SELECT + ======= ======= + + error returns: + - EACCES Access denied: requires CAP_SYS_RAWIO + - ENOMEM Unable to allocate memory for task + - ENOMSG Device is not a disk drive. + - EIO Drive failed the command. + + notes: + + [1] DEV bit (0x10) of SELECT register is ignored and the + appropriate value for the drive is used. All other bits + are used unaltered. + + + +HDIO_SET_32BIT + change io_32bit flags + + + usage:: + + int val; + + ioctl(fd, HDIO_SET_32BIT, val); + + inputs: + New value for io_32bit flag + + + + outputs: + none + + + + error return: + - EINVAL Called on a partition instead of the whole disk device + - EACCES Access denied: requires CAP_SYS_ADMIN + - EINVAL value out of range [0 3] + - EBUSY Controller busy |