iPXE
Data Structures | Functions | Variables
ata.c File Reference

ATA block device. More...

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/list.h>
#include <ipxe/interface.h>
#include <ipxe/blockdev.h>
#include <ipxe/edd.h>
#include <ipxe/ata.h>

Go to the source code of this file.

Data Structures

struct  ata_device
 An ATA device. More...
struct  ata_command
 An ATA command. More...
struct  ata_command_type
 An ATA command type. More...
struct  ata_identify_private
 ATA IDENTIFY private data. More...

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
int ata_command (struct interface *control, struct interface *data, struct ata_cmd *command)
 Issue ATA command.
static LIST_HEAD (ata_commands)
 List of all ATA commands.
static __attribute__ ((always_inline))
 Get reference to ATA device.
static void atacmd_free (struct refcnt *refcnt)
 Free ATA command.
static void atacmd_close (struct ata_command *atacmd, int rc)
 Close ATA command.
static void atacmd_done (struct ata_command *atacmd, int rc)
 Handle ATA command completion.
static void atacmd_data_buffer (struct ata_command *atacmd __unused, userptr_t buffer, size_t len, userptr_t *data, size_t *data_len)
 Use provided data buffer for ATA command.
static void atacmd_data_none (struct ata_command *atacmd __unused, userptr_t buffer __unused, size_t len __unused, userptr_t *data __unused, size_t *data_len __unused)
 Use no data buffer for ATA command.
static void atacmd_data_priv (struct ata_command *atacmd, userptr_t buffer __unused, size_t len __unused, userptr_t *data, size_t *data_len)
 Use private data buffer for ATA command.
static const char * ata_model (struct ata_identity *identity)
 Return ATA model string (for debugging)
static void atacmd_identify_done (struct ata_command *atacmd, int rc)
 Handle ATA IDENTIFY command completion.
static int atadev_command (struct ata_device *atadev, struct interface *block, struct ata_command_type *type, uint64_t lba, unsigned int count, userptr_t buffer, size_t len)
 Create ATA command.
static int atadev_read (struct ata_device *atadev, struct interface *block, uint64_t lba, unsigned int count, userptr_t buffer, size_t len)
 Issue ATA block read.
static int atadev_write (struct ata_device *atadev, struct interface *block, uint64_t lba, unsigned int count, userptr_t buffer, size_t len)
 Issue ATA block write.
static int atadev_read_capacity (struct ata_device *atadev, struct interface *block)
 Read ATA device capacity.
static void atadev_close (struct ata_device *atadev, int rc)
 Close ATA device.
static int atadev_edd_describe (struct ata_device *atadev, struct edd_interface_type *type, union edd_device_path *path)
 Describe ATA device using EDD.
int ata_open (struct interface *block, struct interface *ata, unsigned int device, unsigned int max_count)
 Open ATA device.

Variables

static struct ata_command_type atacmd_read
 ATA READ command type.
static struct ata_command_type atacmd_write
 ATA WRITE command type.
static struct ata_command_type atacmd_identify
 ATA IDENTITY command type.
static struct interface_operation atacmd_block_op []
 ATA command block interface operations.
static struct interface_descriptor atacmd_block_desc
 ATA command block interface descriptor.
static struct interface_operation atacmd_ata_op []
 ATA command ATA interface operations.
static struct interface_descriptor atacmd_ata_desc
 ATA command ATA interface descriptor.
static struct interface_operation atadev_block_op []
 ATA device block interface operations.
static struct interface_descriptor atadev_block_desc
 ATA device block interface descriptor.
static struct interface_operation atadev_ata_op []
 ATA device ATA interface operations.
static struct interface_descriptor atadev_ata_desc
 ATA device ATA interface descriptor.

Detailed Description

ATA block device.

Definition in file ata.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
int ata_command ( struct interface control,
struct interface data,
struct ata_cmd command 
)

Issue ATA command.

Parameters:
controlATA control interface
dataATA data interface
commandATA command
Return values:
tagCommand tag, or negative error

Definition at line 59 of file ata.c.

References ata_command_TYPE, dest, EOPNOTSUPP, intf_get_dest_op, intf_object(), intf_put(), op, and tag.

                                            {
        struct interface *dest;
        ata_command_TYPE ( void * ) *op =
                intf_get_dest_op ( control, ata_command, &dest );
        void *object = intf_object ( dest );
        int tag;

        if ( op ) {
                tag = op ( object, data, command );
        } else {
                /* Default is to fail to issue the command */
                tag = -EOPNOTSUPP;
        }

        intf_put ( dest );
        return tag;
}
static LIST_HEAD ( ata_commands  ) [static]

List of all ATA commands.

static __attribute__ ( (always_inline)  ) [inline, static]

Get reference to ATA device.

Get ATA command private data.

Drop reference to ATA command.

Get reference to ATA command.

Drop reference to ATA device.

Parameters:
atadevATA device
Return values:
atadevATA device
Parameters:
atadevATA device
atacmdATA command
Return values:
atacmdATA command
Parameters:
atacmdATA command
atacmdATA command
Return values:
privPrivate data

Definition at line 181 of file ata.c.

References ata_command::atadev, and ref_get.

                                         {
        ref_get ( &atadev->refcnt );
        return atadev;
}
static void atacmd_free ( struct refcnt refcnt) [static]

Free ATA command.

Parameters:
refcntReference count

Definition at line 235 of file ata.c.

References ata_command::atadev, container_of, free, ata_command::list, and list_del.

Referenced by atadev_command().

                                                  {
        struct ata_command *atacmd =
                container_of ( refcnt, struct ata_command, refcnt );

        /* Remove from list of commands */
        list_del ( &atacmd->list );
        atadev_put ( atacmd->atadev );

        /* Free command */
        free ( atacmd );
}
static void atacmd_close ( struct ata_command atacmd,
int  rc 
) [static]

Close ATA command.

Parameters:
atacmdATA command
rcReason for close

Definition at line 253 of file ata.c.

References ata_command::ata, ata_command::atadev, ata_command::block, DBGC, intf_shutdown(), strerror(), and ata_command::tag.

Referenced by atacmd_identify_done(), atadev_close(), and atadev_command().

                                                                {
        struct ata_device *atadev = atacmd->atadev;

        if ( rc != 0 ) {
                DBGC ( atadev, "ATA %p tag %08x closed: %s\n",
                       atadev, atacmd->tag, strerror ( rc ) );
        }

        /* Shut down interfaces */
        intf_shutdown ( &atacmd->ata, rc );
        intf_shutdown ( &atacmd->block, rc );
}
static void atacmd_done ( struct ata_command atacmd,
int  rc 
) [static]

Handle ATA command completion.

Parameters:
atacmdATA command
rcReason for close

Definition at line 272 of file ata.c.

References ata_command_type::done, and ata_command::type.

                                                               {

        /* Hand over to the command completion handler */
        atacmd->type->done ( atacmd, rc );
}
static void atacmd_data_buffer ( struct ata_command *atacmd  __unused,
userptr_t  buffer,
size_t  len,
userptr_t data,
size_t data_len 
) [static]

Use provided data buffer for ATA command.

Parameters:
atacmdATA command
bufferAvailable buffer
lenAvailable buffer length
Return values:
dataData buffer
data_lenData buffer length

Definition at line 287 of file ata.c.

References buffer, and len.

                                                                     {
        *data = buffer;
        *data_len = len;
}
static void atacmd_data_none ( struct ata_command *atacmd  __unused,
userptr_t buffer  __unused,
size_t len  __unused,
userptr_t *data  __unused,
size_t *data_len  __unused 
) [static]

Use no data buffer for ATA command.

Parameters:
atacmdATA command
bufferAvailable buffer
lenAvailable buffer length
Return values:
dataData buffer
data_lenData buffer length

Definition at line 303 of file ata.c.

                                                           {
        /* Nothing to do */
}
static void atacmd_data_priv ( struct ata_command atacmd,
userptr_t buffer  __unused,
size_t len  __unused,
userptr_t data,
size_t data_len 
) [static]

Use private data buffer for ATA command.

Parameters:
atacmdATA command
bufferAvailable buffer
lenAvailable buffer length
Return values:
dataData buffer
data_lenData buffer length

Definition at line 319 of file ata.c.

References ata_command_type::priv_len, ata_command::type, and virt_to_user().

                                                                   {
        *data = virt_to_user ( atacmd_priv ( atacmd ) );
        *data_len = atacmd->type->priv_len;
}
static const char* ata_model ( struct ata_identity identity) [static]

Return ATA model string (for debugging)

Parameters:
identifyATA identity data
Return values:
modelModel string

Definition at line 358 of file ata.c.

References bswap_16, and ata_identity::model.

Referenced by atacmd_identify_done().

                                                                {
        static union {
                uint16_t words[ sizeof ( identity->model ) / 2 ];
                char text[ sizeof ( identity->model ) + 1 /* NUL */ ];
        } buf;
        unsigned int i;

        for ( i = 0 ; i < ( sizeof ( identity->model ) / 2 ) ; i++ )
                buf.words[i] = bswap_16 ( identity->model[i] );

        return buf.text;
}
static void atacmd_identify_done ( struct ata_command atacmd,
int  rc 
) [static]

Handle ATA IDENTIFY command completion.

Parameters:
atacmdATA command
rcReason for completion

Definition at line 377 of file ata.c.

References ata_model(), ATA_SECTOR_SIZE, ATA_SUPPORTS_LBA48, atacmd_close(), ata_command::atadev, block_device_capacity::blksize, ata_command::block, block_capacity(), block_device_capacity::blocks, cpu_to_le16, DBGC, ata_identify_private::identity, ata_device::lba48, ata_identity::lba48_sectors, ata_identity::lba_sectors, le32_to_cpu, le64_to_cpu, block_device_capacity::max_count, ata_device::max_count, priv, and ata_identity::supports_lba48.

                                                                        {
        struct ata_device *atadev = atacmd->atadev;
        struct ata_identify_private *priv = atacmd_priv ( atacmd );
        struct ata_identity *identity = &priv->identity;
        struct block_device_capacity capacity;

        /* Close if command failed */
        if ( rc != 0 ) {
                atacmd_close ( atacmd, rc );
                return;
        }

        /* Extract capacity */
        if ( identity->supports_lba48 & cpu_to_le16 ( ATA_SUPPORTS_LBA48 ) ) {
                atadev->lba48 = 1;
                capacity.blocks = le64_to_cpu ( identity->lba48_sectors );
        } else {
                capacity.blocks = le32_to_cpu ( identity->lba_sectors );
        }
        capacity.blksize = ATA_SECTOR_SIZE;
        capacity.max_count = atadev->max_count;
        DBGC ( atadev, "ATA %p is a %s\n", atadev, ata_model ( identity ) );
        DBGC ( atadev, "ATA %p has %#llx blocks (%ld MB) and uses %s\n",
               atadev, capacity.blocks,
               ( ( signed long ) ( capacity.blocks >> 11 ) ),
               ( atadev->lba48 ? "LBA48" : "LBA" ) );

        /* Return capacity to caller */
        block_capacity ( &atacmd->block, &capacity );

        /* Close command */
        atacmd_close ( atacmd, 0 );
}
static int atadev_command ( struct ata_device atadev,
struct interface block,
struct ata_command_type type,
uint64_t  lba,
unsigned int  count,
userptr_t  buffer,
size_t  len 
) [static]

Create ATA command.

Parameters:
atadevATA device
blockBlock data interface
typeATA command type
lbaStarting logical block address
countNumber of blocks to transfer
bufferData buffer
lenLength of data buffer
Return values:
rcReturn status code

Definition at line 454 of file ata.c.

References ata_device::ata, ata_command::ata, ATA_DEV_LBA, ATA_DEV_OBSOLETE, ATA_SECTOR_SIZE, atacmd_close(), atacmd_free(), ata_command::atadev, ata_command::block, ata_lba::bytes, ata_cmd::cb, ata_command_type::cmd_lba, ata_command_type::cmd_lba48, ata_cb::cmd_stat, ata_cb::count, count, ata_command_type::data_in, ata_cmd::data_in, ata_cmd::data_in_len, ata_command_type::data_out, ata_cmd::data_out, ata_cmd::data_out_len, DBGC, DBGC2, ata_device::device, ata_cb::device, EINVAL, ENOMEM, intf_init(), intf_plug_plug(), lba, ata_cb::lba, ata_device::lba48, ata_cb::lba48, ata_command::list, list_add, ata_lba::low_prev, memset(), ata_command_type::name, ata_lba::native, ata_fifo::native, ata_command_type::priv_len, rc, ref_init, ref_put, ata_command::refcnt, strerror(), ata_command::tag, tag, ata_command::type, type, and zalloc().

Referenced by atadev_read(), atadev_read_capacity(), and atadev_write().

                                                           {
        struct ata_command *atacmd;
        struct ata_cmd command;
        int tag;
        int rc;

        /* Allocate and initialise structure */
        atacmd = zalloc ( sizeof ( *atacmd ) + type->priv_len );
        if ( ! atacmd ) {
                rc = -ENOMEM;
                goto err_zalloc;
        }
        ref_init ( &atacmd->refcnt, atacmd_free );
        intf_init ( &atacmd->block, &atacmd_block_desc, &atacmd->refcnt );
        intf_init ( &atacmd->ata, &atacmd_ata_desc,
                    &atacmd->refcnt );
        atacmd->atadev = atadev_get ( atadev );
        list_add ( &atacmd->list, &ata_commands );
        atacmd->type = type;

        /* Sanity check */
        if ( len != ( count * ATA_SECTOR_SIZE ) ) {
                DBGC ( atadev, "ATA %p tag %08x buffer length mismatch (count "
                       "%d len %zd)\n", atadev, atacmd->tag, count, len );
                rc = -EINVAL;
                goto err_len;
        }

        /* Construct command */
        memset ( &command, 0, sizeof ( command ) );
        command.cb.lba.native = lba;
        command.cb.count.native = count;
        command.cb.device = ( atadev->device | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
        command.cb.lba48 = atadev->lba48;
        if ( ! atadev->lba48 )
                command.cb.device |= command.cb.lba.bytes.low_prev;
        command.cb.cmd_stat =
                ( atadev->lba48 ? type->cmd_lba48 : type->cmd_lba );
        type->data_in ( atacmd, buffer, len,
                        &command.data_in, &command.data_in_len );
        type->data_out ( atacmd, buffer, len,
                         &command.data_out, &command.data_out_len );

        /* Issue command */
        if ( ( tag = ata_command ( &atadev->ata, &atacmd->ata,
                                   &command ) ) < 0 ) {
                rc = tag;
                DBGC ( atadev, "ATA %p tag %08x could not issue command: %s\n",
                       atadev, atacmd->tag, strerror ( rc ) );
                goto err_command;
        }
        atacmd->tag = tag;

        DBGC2 ( atadev, "ATA %p tag %08x %s cmd %02x dev %02x LBA%s %08llx "
                "count %04x\n", atadev, atacmd->tag, atacmd->type->name,
                command.cb.cmd_stat, command.cb.device,
                ( command.cb.lba48 ? "48" : "" ),
                ( unsigned long long ) command.cb.lba.native,
                command.cb.count.native );

        /* Attach to parent interface, mortalise self, and return */
        intf_plug_plug ( &atacmd->block, block );
        ref_put ( &atacmd->refcnt );
        return 0;

 err_command:
 err_len:
        atacmd_close ( atacmd, rc );
        ref_put ( &atacmd->refcnt );
 err_zalloc:
        return rc;
}
static int atadev_read ( struct ata_device atadev,
struct interface block,
uint64_t  lba,
unsigned int  count,
userptr_t  buffer,
size_t  len 
) [static]

Issue ATA block read.

Parameters:
atadevATA device
blockBlock data interface
lbaStarting logical block address
countNumber of blocks to transfer
bufferData buffer
lenLength of data buffer
Return values:
rcReturn status code

Definition at line 543 of file ata.c.

References atadev_command().

                                                        {
        return atadev_command ( atadev, block, &atacmd_read,
                                lba, count, buffer, len );
}
static int atadev_write ( struct ata_device atadev,
struct interface block,
uint64_t  lba,
unsigned int  count,
userptr_t  buffer,
size_t  len 
) [static]

Issue ATA block write.

Parameters:
atadevATA device
blockBlock data interface
lbaStarting logical block address
countNumber of blocks to transfer
bufferData buffer
lenLength of data buffer
Return values:
rcReturn status code

Definition at line 562 of file ata.c.

References atadev_command().

                                                         {
        return atadev_command ( atadev, block, &atacmd_write,
                                lba, count, buffer, len );
}
static int atadev_read_capacity ( struct ata_device atadev,
struct interface block 
) [static]

Read ATA device capacity.

Parameters:
atadevATA device
blockBlock data interface
Return values:
rcReturn status code

Definition at line 577 of file ata.c.

References assert, ATA_SECTOR_SIZE, atadev_command(), ata_command_type::priv_len, and UNULL.

                                                            {
        struct ata_identity *identity;

        assert ( atacmd_identify.priv_len == sizeof ( *identity ) );
        assert ( atacmd_identify.priv_len == ATA_SECTOR_SIZE );
        return atadev_command ( atadev, block, &atacmd_identify,
                                0, 1, UNULL, ATA_SECTOR_SIZE );
}
static void atadev_close ( struct ata_device atadev,
int  rc 
) [static]

Close ATA device.

Parameters:
atadevATA device
rcReason for close

Definition at line 593 of file ata.c.

References ata_device::ata, atacmd_close(), ata_command::atadev, ata_device::block, intf_shutdown(), ata_command::list, and list_for_each_entry_safe.

                                                               {
        struct ata_command *atacmd;
        struct ata_command *tmp;

        /* Shut down interfaces */
        intf_shutdown ( &atadev->block, rc );
        intf_shutdown ( &atadev->ata, rc );

        /* Shut down any remaining commands */
        list_for_each_entry_safe ( atacmd, tmp, &ata_commands, list ) {
                if ( atacmd->atadev != atadev )
                        continue;
                atacmd_get ( atacmd );
                atacmd_close ( atacmd, rc );
                atacmd_put ( atacmd );
        }
}
static int atadev_edd_describe ( struct ata_device atadev,
struct edd_interface_type type,
union edd_device_path path 
) [static]

Describe ATA device using EDD.

Parameters:
atadevATA device
typeEDD interface type
pathEDD device path
Return values:
rcReturn status code

Definition at line 619 of file ata.c.

References ATA_DEV_SLAVE, cpu_to_le64, ata_device::device, EDD_INTF_TYPE_ATA, edd_device_path::slave, and edd_interface_type::type.

                                                               {

        type->type = cpu_to_le64 ( EDD_INTF_TYPE_ATA );
        path->ata.slave = ( ( atadev->device == ATA_DEV_SLAVE ) ? 0x01 : 0x00 );
        return 0;
}
int ata_open ( struct interface block,
struct interface ata,
unsigned int  device,
unsigned int  max_count 
)

Open ATA device.

Parameters:
blockBlock control interface
ataATA control interface
deviceATA device number
max_countMaximum number of blocks per single transfer
Return values:
rcReturn status code

Definition at line 662 of file ata.c.

References ata_device::ata, ata_device::block, ata_device::device, device, ENOMEM, intf_init(), intf_plug_plug(), ata_device::max_count, NULL, ref_init, ref_put, ata_device::refcnt, and zalloc().

Referenced by aoedev_open().

                                                             {
        struct ata_device *atadev;

        /* Allocate and initialise structure */
        atadev = zalloc ( sizeof ( *atadev ) );
        if ( ! atadev )
                return -ENOMEM;
        ref_init ( &atadev->refcnt, NULL );
        intf_init ( &atadev->block, &atadev_block_desc, &atadev->refcnt );
        intf_init ( &atadev->ata, &atadev_ata_desc, &atadev->refcnt );
        atadev->device = device;
        atadev->max_count = max_count;

        /* Attach to ATA and parent and interfaces, mortalise self,
         * and return
         */
        intf_plug_plug ( &atadev->ata, ata );
        intf_plug_plug ( &atadev->block, block );
        ref_put ( &atadev->refcnt );
        return 0;
}

Variable Documentation

struct ata_command_type atacmd_read [static]
Initial value:
 {
        .name = "READ",
        .cmd_lba = ATA_CMD_READ,
        .cmd_lba48 = ATA_CMD_READ_EXT,
        .data_in = atacmd_data_buffer,
        .data_out = atacmd_data_none,
        .done = atacmd_close,
}

ATA READ command type.

Definition at line 327 of file ata.c.

struct ata_command_type atacmd_write [static]
Initial value:
 {
        .name = "WRITE",
        .cmd_lba = ATA_CMD_WRITE,
        .cmd_lba48 = ATA_CMD_WRITE_EXT,
        .data_in = atacmd_data_none,
        .data_out = atacmd_data_buffer,
        .done = atacmd_close,
}

ATA WRITE command type.

Definition at line 337 of file ata.c.

Initial value:
 {
        .name = "IDENTIFY",
        .priv_len = sizeof ( struct ata_identify_private ),
        .cmd_lba = ATA_CMD_IDENTIFY,
        .cmd_lba48 = ATA_CMD_IDENTIFY,
        .data_in = atacmd_data_priv,
        .data_out = atacmd_data_none,
        .done = atacmd_identify_done,
}

ATA IDENTITY command type.

Definition at line 412 of file ata.c.

Initial value:

ATA command block interface operations.

Definition at line 423 of file ata.c.

Initial value:

ATA command block interface descriptor.

Definition at line 428 of file ata.c.

Initial value:

ATA command ATA interface operations.

Definition at line 433 of file ata.c.

Initial value:

ATA command ATA interface descriptor.

Definition at line 438 of file ata.c.

Initial value:

ATA device block interface operations.

Definition at line 629 of file ata.c.

Initial value:

ATA device block interface descriptor.

Definition at line 639 of file ata.c.

Initial value:

ATA device ATA interface operations.

Definition at line 644 of file ata.c.

Initial value:

ATA device ATA interface descriptor.

Definition at line 649 of file ata.c.