summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/drivers/block/ata.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/ipxe/src/drivers/block/ata.c')
-rw-r--r--qemu/roms/ipxe/src/drivers/block/ata.c683
1 files changed, 0 insertions, 683 deletions
diff --git a/qemu/roms/ipxe/src/drivers/block/ata.c b/qemu/roms/ipxe/src/drivers/block/ata.c
deleted file mode 100644
index b1c6855a0..000000000
--- a/qemu/roms/ipxe/src/drivers/block/ata.c
+++ /dev/null
@@ -1,683 +0,0 @@
-/*
- * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- * You can also choose to distribute this program under the terms of
- * the Unmodified Binary Distribution Licence (as given in the file
- * COPYING.UBDL), provided that you have satisfied its requirements.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#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>
-
-/** @file
- *
- * ATA block device
- *
- */
-
-/******************************************************************************
- *
- * Interface methods
- *
- ******************************************************************************
- */
-
-/**
- * Issue ATA command
- *
- * @v control ATA control interface
- * @v data ATA data interface
- * @v command ATA command
- * @ret tag Command tag, or negative error
- */
-int ata_command ( struct interface *control, struct interface *data,
- struct ata_cmd *command ) {
- 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;
-}
-
-/******************************************************************************
- *
- * ATA devices and commands
- *
- ******************************************************************************
- */
-
-/** List of all ATA commands */
-static LIST_HEAD ( ata_commands );
-
-/** An ATA device */
-struct ata_device {
- /** Reference count */
- struct refcnt refcnt;
- /** Block control interface */
- struct interface block;
- /** ATA control interface */
- struct interface ata;
-
- /** Device number
- *
- * Must be ATA_DEV_MASTER or ATA_DEV_SLAVE.
- */
- unsigned int device;
- /** Maximum number of blocks per single transfer */
- unsigned int max_count;
- /** Device uses LBA48 extended addressing */
- int lba48;
-};
-
-/** An ATA command */
-struct ata_command {
- /** Reference count */
- struct refcnt refcnt;
- /** ATA device */
- struct ata_device *atadev;
- /** List of ATA commands */
- struct list_head list;
-
- /** Block data interface */
- struct interface block;
- /** ATA data interface */
- struct interface ata;
-
- /** Command type */
- struct ata_command_type *type;
- /** Command tag */
- uint32_t tag;
-
- /** Private data */
- uint8_t priv[0];
-};
-
-/** An ATA command type */
-struct ata_command_type {
- /** Name */
- const char *name;
- /** Additional working space */
- size_t priv_len;
- /** Command for non-LBA48-capable devices */
- uint8_t cmd_lba;
- /** Command for LBA48-capable devices */
- uint8_t cmd_lba48;
- /**
- * Calculate data-in buffer
- *
- * @v atacmd ATA command
- * @v buffer Available buffer
- * @v len Available buffer length
- * @ret data_in Data-in buffer
- * @ret data_in_len Data-in buffer length
- */
- void ( * data_in ) ( struct ata_command *atacmd, userptr_t buffer,
- size_t len, userptr_t *data_in,
- size_t *data_in_len );
- /**
- * Calculate data-out buffer
- *
- *
- * @v atacmd ATA command
- * @v buffer Available buffer
- * @v len Available buffer length
- * @ret data_out Data-out buffer
- * @ret data_out_len Data-out buffer length
- */
- void ( * data_out ) ( struct ata_command *atacmd, userptr_t buffer,
- size_t len, userptr_t *data_out,
- size_t *data_out_len );
- /**
- * Handle ATA command completion
- *
- * @v atacmd ATA command
- * @v rc Reason for completion
- */
- void ( * done ) ( struct ata_command *atacmd, int rc );
-};
-
-/**
- * Get reference to ATA device
- *
- * @v atadev ATA device
- * @ret atadev ATA device
- */
-static inline __attribute__ (( always_inline )) struct ata_device *
-atadev_get ( struct ata_device *atadev ) {
- ref_get ( &atadev->refcnt );
- return atadev;
-}
-
-/**
- * Drop reference to ATA device
- *
- * @v atadev ATA device
- */
-static inline __attribute__ (( always_inline )) void
-atadev_put ( struct ata_device *atadev ) {
- ref_put ( &atadev->refcnt );
-}
-
-/**
- * Get reference to ATA command
- *
- * @v atacmd ATA command
- * @ret atacmd ATA command
- */
-static inline __attribute__ (( always_inline )) struct ata_command *
-atacmd_get ( struct ata_command *atacmd ) {
- ref_get ( &atacmd->refcnt );
- return atacmd;
-}
-
-/**
- * Drop reference to ATA command
- *
- * @v atacmd ATA command
- */
-static inline __attribute__ (( always_inline )) void
-atacmd_put ( struct ata_command *atacmd ) {
- ref_put ( &atacmd->refcnt );
-}
-
-/**
- * Get ATA command private data
- *
- * @v atacmd ATA command
- * @ret priv Private data
- */
-static inline __attribute__ (( always_inline )) void *
-atacmd_priv ( struct ata_command *atacmd ) {
- return atacmd->priv;
-}
-
-/**
- * Free ATA command
- *
- * @v refcnt Reference count
- */
-static void atacmd_free ( struct refcnt *refcnt ) {
- 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 );
-}
-
-/**
- * Close ATA command
- *
- * @v atacmd ATA command
- * @v rc Reason for close
- */
-static void atacmd_close ( struct ata_command *atacmd, int rc ) {
- 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 );
-}
-
-/**
- * Handle ATA command completion
- *
- * @v atacmd ATA command
- * @v rc Reason for close
- */
-static void atacmd_done ( struct ata_command *atacmd, int rc ) {
-
- /* Hand over to the command completion handler */
- atacmd->type->done ( atacmd, rc );
-}
-
-/**
- * Use provided data buffer for ATA command
- *
- * @v atacmd ATA command
- * @v buffer Available buffer
- * @v len Available buffer length
- * @ret data Data buffer
- * @ret data_len Data buffer length
- */
-static void atacmd_data_buffer ( struct ata_command *atacmd __unused,
- userptr_t buffer, size_t len,
- userptr_t *data, size_t *data_len ) {
- *data = buffer;
- *data_len = len;
-}
-
-/**
- * Use no data buffer for ATA command
- *
- * @v atacmd ATA command
- * @v buffer Available buffer
- * @v len Available buffer length
- * @ret data Data buffer
- * @ret data_len Data buffer length
- */
-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 ) {
- /* Nothing to do */
-}
-
-/**
- * Use private data buffer for ATA command
- *
- * @v atacmd ATA command
- * @v buffer Available buffer
- * @v len Available buffer length
- * @ret data Data buffer
- * @ret data_len Data buffer length
- */
-static void atacmd_data_priv ( struct ata_command *atacmd,
- userptr_t buffer __unused, size_t len __unused,
- userptr_t *data, size_t *data_len ) {
- *data = virt_to_user ( atacmd_priv ( atacmd ) );
- *data_len = atacmd->type->priv_len;
-}
-
-/** ATA READ command type */
-static struct ata_command_type atacmd_read = {
- .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 WRITE command type */
-static struct ata_command_type atacmd_write = {
- .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 IDENTIFY private data */
-struct ata_identify_private {
- /** Identity data */
- struct ata_identity identity;
-};
-
-/**
- * Return ATA model string (for debugging)
- *
- * @v identify ATA identity data
- * @ret model Model string
- */
-static const char * ata_model ( struct ata_identity *identity ) {
- 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;
-}
-
-/**
- * Handle ATA IDENTIFY command completion
- *
- * @v atacmd ATA command
- * @v rc Reason for completion
- */
-static void atacmd_identify_done ( struct ata_command *atacmd, int rc ) {
- 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 );
-}
-
-/** ATA IDENTITY command type */
-static struct ata_command_type atacmd_identify = {
- .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 command block interface operations */
-static struct interface_operation atacmd_block_op[] = {
- INTF_OP ( intf_close, struct ata_command *, atacmd_close ),
-};
-
-/** ATA command block interface descriptor */
-static struct interface_descriptor atacmd_block_desc =
- INTF_DESC_PASSTHRU ( struct ata_command, block,
- atacmd_block_op, ata );
-
-/** ATA command ATA interface operations */
-static struct interface_operation atacmd_ata_op[] = {
- INTF_OP ( intf_close, struct ata_command *, atacmd_done ),
-};
-
-/** ATA command ATA interface descriptor */
-static struct interface_descriptor atacmd_ata_desc =
- INTF_DESC_PASSTHRU ( struct ata_command, ata,
- atacmd_ata_op, block );
-
-/**
- * Create ATA command
- *
- * @v atadev ATA device
- * @v block Block data interface
- * @v type ATA command type
- * @v lba Starting logical block address
- * @v count Number of blocks to transfer
- * @v buffer Data buffer
- * @v len Length of data buffer
- * @ret rc Return status code
- */
-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 ) {
- 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;
-}
-
-/**
- * Issue ATA block read
- *
- * @v atadev ATA device
- * @v block Block data interface
- * @v lba Starting logical block address
- * @v count Number of blocks to transfer
- * @v buffer Data buffer
- * @v len Length of data buffer
- * @ret rc Return status code
-
- */
-static int atadev_read ( struct ata_device *atadev,
- struct interface *block,
- uint64_t lba, unsigned int count,
- userptr_t buffer, size_t len ) {
- return atadev_command ( atadev, block, &atacmd_read,
- lba, count, buffer, len );
-}
-
-/**
- * Issue ATA block write
- *
- * @v atadev ATA device
- * @v block Block data interface
- * @v lba Starting logical block address
- * @v count Number of blocks to transfer
- * @v buffer Data buffer
- * @v len Length of data buffer
- * @ret rc Return status code
- */
-static int atadev_write ( struct ata_device *atadev,
- struct interface *block,
- uint64_t lba, unsigned int count,
- userptr_t buffer, size_t len ) {
- return atadev_command ( atadev, block, &atacmd_write,
- lba, count, buffer, len );
-}
-
-/**
- * Read ATA device capacity
- *
- * @v atadev ATA device
- * @v block Block data interface
- * @ret rc Return status code
- */
-static int atadev_read_capacity ( struct ata_device *atadev,
- struct interface *block ) {
- 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 );
-}
-
-/**
- * Close ATA device
- *
- * @v atadev ATA device
- * @v rc Reason for close
- */
-static void atadev_close ( struct ata_device *atadev, int rc ) {
- 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 );
- }
-}
-
-/**
- * Describe ATA device using EDD
- *
- * @v atadev ATA device
- * @v type EDD interface type
- * @v path EDD device path
- * @ret rc Return status code
- */
-static int atadev_edd_describe ( struct ata_device *atadev,
- struct edd_interface_type *type,
- union edd_device_path *path ) {
-
- type->type = cpu_to_le64 ( EDD_INTF_TYPE_ATA );
- path->ata.slave = ( ( atadev->device == ATA_DEV_SLAVE ) ? 0x01 : 0x00 );
- return 0;
-}
-
-/** ATA device block interface operations */
-static struct interface_operation atadev_block_op[] = {
- INTF_OP ( block_read, struct ata_device *, atadev_read ),
- INTF_OP ( block_write, struct ata_device *, atadev_write ),
- INTF_OP ( block_read_capacity, struct ata_device *,
- atadev_read_capacity ),
- INTF_OP ( intf_close, struct ata_device *, atadev_close ),
- INTF_OP ( edd_describe, struct ata_device *, atadev_edd_describe ),
-};
-
-/** ATA device block interface descriptor */
-static struct interface_descriptor atadev_block_desc =
- INTF_DESC_PASSTHRU ( struct ata_device, block,
- atadev_block_op, ata );
-
-/** ATA device ATA interface operations */
-static struct interface_operation atadev_ata_op[] = {
- INTF_OP ( intf_close, struct ata_device *, atadev_close ),
-};
-
-/** ATA device ATA interface descriptor */
-static struct interface_descriptor atadev_ata_desc =
- INTF_DESC_PASSTHRU ( struct ata_device, ata,
- atadev_ata_op, block );
-
-/**
- * Open ATA device
- *
- * @v block Block control interface
- * @v ata ATA control interface
- * @v device ATA device number
- * @v max_count Maximum number of blocks per single transfer
- * @ret rc Return status code
- */
-int ata_open ( struct interface *block, struct interface *ata,
- unsigned int device, unsigned int max_count ) {
- 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;
-}