summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/drivers/block
diff options
context:
space:
mode:
authorRajithaY <rajithax.yerrumsetty@intel.com>2017-04-25 03:31:15 -0700
committerRajitha Yerrumchetty <rajithax.yerrumsetty@intel.com>2017-05-22 06:48:08 +0000
commitbb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch)
treeca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/roms/ipxe/src/drivers/block
parenta14b48d18a9ed03ec191cf16b162206998a895ce (diff)
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to kvmfornfv repo and make use of the updated latest qemu for the execution of all testcase Change-Id: I1280af507a857675c7f81d30c95255635667bdd7 Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/roms/ipxe/src/drivers/block')
-rw-r--r--qemu/roms/ipxe/src/drivers/block/ata.c683
-rw-r--r--qemu/roms/ipxe/src/drivers/block/ibft.c497
-rw-r--r--qemu/roms/ipxe/src/drivers/block/scsi.c1003
-rw-r--r--qemu/roms/ipxe/src/drivers/block/srp.c829
4 files changed, 0 insertions, 3012 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;
-}
diff --git a/qemu/roms/ipxe/src/drivers/block/ibft.c b/qemu/roms/ipxe/src/drivers/block/ibft.c
deleted file mode 100644
index 6aabd766a..000000000
--- a/qemu/roms/ipxe/src/drivers/block/ibft.c
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * Copyright Fen Systems Ltd. 2007. Portions of this code are derived
- * from IBM Corporation Sample Programs. Copyright IBM Corporation
- * 2004, 2007. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-FILE_LICENCE ( BSD2 );
-
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <byteswap.h>
-#include <ipxe/pci.h>
-#include <ipxe/acpi.h>
-#include <ipxe/in.h>
-#include <ipxe/netdevice.h>
-#include <ipxe/ethernet.h>
-#include <ipxe/vlan.h>
-#include <ipxe/dhcp.h>
-#include <ipxe/iscsi.h>
-#include <ipxe/ibft.h>
-
-/** @file
- *
- * iSCSI boot firmware table
- *
- * The information in this file is derived from the document "iSCSI
- * Boot Firmware Table (iBFT)" as published by IBM at
- *
- * ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf
- *
- */
-
-/**
- * An iBFT created by iPXE
- *
- */
-struct ipxe_ibft {
- /** The fixed section */
- struct ibft_table table;
- /** The Initiator section */
- struct ibft_initiator initiator __attribute__ (( aligned ( 16 ) ));
- /** The NIC section */
- struct ibft_nic nic __attribute__ (( aligned ( 16 ) ));
- /** The Target section */
- struct ibft_target target __attribute__ (( aligned ( 16 ) ));
- /** Strings block */
- char strings[0];
-} __attribute__ (( packed, aligned ( 16 ) ));
-
-/**
- * iSCSI string block descriptor
- *
- * This is an internal structure that we use to keep track of the
- * allocation of string data.
- */
-struct ibft_strings {
- /** The iBFT containing these strings */
- struct ibft_table *table;
- /** Offset of first free byte within iBFT */
- size_t offset;
- /** Total length of the iBFT */
- size_t len;
-};
-
-/**
- * Fill in an IP address field within iBFT
- *
- * @v ipaddr IP address field
- * @v in IPv4 address
- */
-static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) {
- memset ( ipaddr, 0, sizeof ( *ipaddr ) );
- if ( in.s_addr ) {
- ipaddr->in = in;
- ipaddr->ones = 0xffff;
- }
-}
-
-/**
- * Fill in an IP address within iBFT from configuration setting
- *
- * @v settings Parent settings block, or NULL
- * @v ipaddr IP address field
- * @v setting Configuration setting
- * @v count Maximum number of IP addresses
- */
-static void ibft_set_ipaddr_setting ( struct settings *settings,
- struct ibft_ipaddr *ipaddr,
- const struct setting *setting,
- unsigned int count ) {
- struct in_addr in[count];
- unsigned int i;
-
- fetch_ipv4_array_setting ( settings, setting, in, count );
- for ( i = 0 ; i < count ; i++ ) {
- ibft_set_ipaddr ( &ipaddr[i], in[i] );
- }
-}
-
-/**
- * Read IP address from iBFT (for debugging)
- *
- * @v strings iBFT string block descriptor
- * @v string String field
- * @ret ipaddr IP address string
- */
-static const char * ibft_ipaddr ( struct ibft_ipaddr *ipaddr ) {
- return inet_ntoa ( ipaddr->in );
-}
-
-/**
- * Allocate a string within iBFT
- *
- * @v strings iBFT string block descriptor
- * @v string String field to fill in
- * @v len Length of string to allocate (excluding NUL)
- * @ret dest String destination, or NULL
- */
-static char * ibft_alloc_string ( struct ibft_strings *strings,
- struct ibft_string *string, size_t len ) {
-
- if ( ( strings->offset + len ) >= strings->len )
- return NULL;
-
- string->offset = cpu_to_le16 ( strings->offset );
- string->len = cpu_to_le16 ( len );
- strings->offset += ( len + 1 );
-
- return ( ( ( char * ) strings->table ) + string->offset );
-}
-
-/**
- * Fill in a string field within iBFT
- *
- * @v strings iBFT string block descriptor
- * @v string String field
- * @v data String to fill in, or NULL
- * @ret rc Return status code
- */
-static int ibft_set_string ( struct ibft_strings *strings,
- struct ibft_string *string, const char *data ) {
- char *dest;
-
- if ( ! data )
- return 0;
-
- dest = ibft_alloc_string ( strings, string, strlen ( data ) );
- if ( ! dest )
- return -ENOBUFS;
- strcpy ( dest, data );
-
- return 0;
-}
-
-/**
- * Fill in a string field within iBFT from configuration setting
- *
- * @v settings Parent settings block, or NULL
- * @v strings iBFT string block descriptor
- * @v string String field
- * @v setting Configuration setting
- * @ret rc Return status code
- */
-static int ibft_set_string_setting ( struct settings *settings,
- struct ibft_strings *strings,
- struct ibft_string *string,
- const struct setting *setting ) {
- struct settings *origin;
- struct setting fetched;
- int len;
- char *dest;
-
- len = fetch_setting ( settings, setting, &origin, &fetched, NULL, 0 );
- if ( len < 0 ) {
- string->offset = 0;
- string->len = 0;
- return 0;
- }
-
- dest = ibft_alloc_string ( strings, string, len );
- if ( ! dest )
- return -ENOBUFS;
- fetch_string_setting ( origin, &fetched, dest, ( len + 1 ));
-
- return 0;
-}
-
-/**
- * Read string from iBFT (for debugging)
- *
- * @v strings iBFT string block descriptor
- * @v string String field
- * @ret data String content (or "<empty>")
- */
-static const char * ibft_string ( struct ibft_strings *strings,
- struct ibft_string *string ) {
- return ( string->offset ?
- ( ( ( char * ) strings->table ) + string->offset ) : NULL );
-}
-
-/**
- * Fill in NIC portion of iBFT
- *
- * @v nic NIC portion of iBFT
- * @v strings iBFT string block descriptor
- * @v netdev Network device
- * @ret rc Return status code
- */
-static int ibft_fill_nic ( struct ibft_nic *nic,
- struct ibft_strings *strings,
- struct net_device *netdev ) {
- struct ll_protocol *ll_protocol = netdev->ll_protocol;
- struct in_addr netmask_addr = { 0 };
- unsigned int netmask_count = 0;
- struct settings *parent = netdev_settings ( netdev );
- struct settings *origin;
- int rc;
-
- /* Fill in common header */
- nic->header.structure_id = IBFT_STRUCTURE_ID_NIC;
- nic->header.version = 1;
- nic->header.length = cpu_to_le16 ( sizeof ( *nic ) );
- nic->header.flags = ( IBFT_FL_NIC_BLOCK_VALID |
- IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED );
-
- /* Determine origin of IP address */
- fetch_setting ( parent, &ip_setting, &origin, NULL, NULL, 0 );
- nic->origin = ( ( origin == parent ) ?
- IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP );
- DBG ( "iBFT NIC origin = %d\n", nic->origin );
-
- /* Extract values from configuration settings */
- ibft_set_ipaddr_setting ( parent, &nic->ip_address, &ip_setting, 1 );
- DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) );
- ibft_set_ipaddr_setting ( parent, &nic->gateway, &gateway_setting, 1 );
- DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) );
- ibft_set_ipaddr_setting ( NULL, &nic->dns[0], &dns_setting,
- ( sizeof ( nic->dns ) /
- sizeof ( nic->dns[0] ) ) );
- DBG ( "iBFT NIC DNS = %s", ibft_ipaddr ( &nic->dns[0] ) );
- DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) );
- if ( ( rc = ibft_set_string_setting ( NULL, strings, &nic->hostname,
- &hostname_setting ) ) != 0 )
- return rc;
- DBG ( "iBFT NIC hostname = %s\n",
- ibft_string ( strings, &nic->hostname ) );
-
- /* Derive subnet mask prefix from subnet mask */
- fetch_ipv4_setting ( parent, &netmask_setting, &netmask_addr );
- while ( netmask_addr.s_addr ) {
- if ( netmask_addr.s_addr & 0x1 )
- netmask_count++;
- netmask_addr.s_addr >>= 1;
- }
- nic->subnet_mask_prefix = netmask_count;
- DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix );
-
- /* Extract values from net-device configuration */
- nic->vlan = cpu_to_le16 ( vlan_tag ( netdev ) );
- DBG ( "iBFT NIC VLAN = %02x\n", le16_to_cpu ( nic->vlan ) );
- if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr,
- nic->mac_address ) ) != 0 ) {
- DBG ( "Could not determine iBFT MAC: %s\n", strerror ( rc ) );
- return rc;
- }
- DBG ( "iBFT NIC MAC = %s\n", eth_ntoa ( nic->mac_address ) );
- nic->pci_bus_dev_func = cpu_to_le16 ( netdev->dev->desc.location );
- DBG ( "iBFT NIC PCI = %04x\n", le16_to_cpu ( nic->pci_bus_dev_func ) );
-
- return 0;
-}
-
-/**
- * Fill in Initiator portion of iBFT
- *
- * @v initiator Initiator portion of iBFT
- * @v strings iBFT string block descriptor
- * @v iscsi iSCSI session
- * @ret rc Return status code
- */
-static int ibft_fill_initiator ( struct ibft_initiator *initiator,
- struct ibft_strings *strings,
- struct iscsi_session *iscsi ) {
- int rc;
-
- /* Fill in common header */
- initiator->header.structure_id = IBFT_STRUCTURE_ID_INITIATOR;
- initiator->header.version = 1;
- initiator->header.length = cpu_to_le16 ( sizeof ( *initiator ) );
- initiator->header.flags = ( IBFT_FL_INITIATOR_BLOCK_VALID |
- IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED );
-
- /* Fill in hostname */
- if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name,
- iscsi->initiator_iqn ) ) != 0 )
- return rc;
- DBG ( "iBFT initiator hostname = %s\n",
- ibft_string ( strings, &initiator->initiator_name ) );
-
- return 0;
-}
-
-/**
- * Fill in Target CHAP portion of iBFT
- *
- * @v target Target portion of iBFT
- * @v strings iBFT string block descriptor
- * @v iscsi iSCSI session
- * @ret rc Return status code
- */
-static int ibft_fill_target_chap ( struct ibft_target *target,
- struct ibft_strings *strings,
- struct iscsi_session *iscsi ) {
- int rc;
-
- if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_FORWARD_REQUIRED ) )
- return 0;
-
- assert ( iscsi->initiator_username );
- assert ( iscsi->initiator_password );
-
- target->chap_type = IBFT_CHAP_ONE_WAY;
- if ( ( rc = ibft_set_string ( strings, &target->chap_name,
- iscsi->initiator_username ) ) != 0 )
- return rc;
- DBG ( "iBFT target username = %s\n",
- ibft_string ( strings, &target->chap_name ) );
- if ( ( rc = ibft_set_string ( strings, &target->chap_secret,
- iscsi->initiator_password ) ) != 0 )
- return rc;
- DBG ( "iBFT target password = <redacted>\n" );
-
- return 0;
-}
-
-/**
- * Fill in Target Reverse CHAP portion of iBFT
- *
- * @v target Target portion of iBFT
- * @v strings iBFT string block descriptor
- * @v iscsi iSCSI session
- * @ret rc Return status code
- */
-static int ibft_fill_target_reverse_chap ( struct ibft_target *target,
- struct ibft_strings *strings,
- struct iscsi_session *iscsi ) {
- int rc;
-
- if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) )
- return 0;
-
- assert ( iscsi->initiator_username );
- assert ( iscsi->initiator_password );
- assert ( iscsi->target_username );
- assert ( iscsi->target_password );
-
- target->chap_type = IBFT_CHAP_MUTUAL;
- if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name,
- iscsi->target_username ) ) != 0 )
- return rc;
- DBG ( "iBFT target reverse username = %s\n",
- ibft_string ( strings, &target->chap_name ) );
- if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_secret,
- iscsi->target_password ) ) != 0 )
- return rc;
- DBG ( "iBFT target reverse password = <redacted>\n" );
-
- return 0;
-}
-
-/**
- * Fill in Target portion of iBFT
- *
- * @v target Target portion of iBFT
- * @v strings iBFT string block descriptor
- * @v iscsi iSCSI session
- * @ret rc Return status code
- */
-static int ibft_fill_target ( struct ibft_target *target,
- struct ibft_strings *strings,
- struct iscsi_session *iscsi ) {
- struct sockaddr_in *sin_target =
- ( struct sockaddr_in * ) &iscsi->target_sockaddr;
- int rc;
-
- /* Fill in common header */
- target->header.structure_id = IBFT_STRUCTURE_ID_TARGET;
- target->header.version = 1;
- target->header.length = cpu_to_le16 ( sizeof ( *target ) );
- target->header.flags = ( IBFT_FL_TARGET_BLOCK_VALID |
- IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED );
-
- /* Fill in Target values */
- ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr );
- DBG ( "iBFT target IP = %s\n", ibft_ipaddr ( &target->ip_address ) );
- target->socket = cpu_to_le16 ( ntohs ( sin_target->sin_port ) );
- DBG ( "iBFT target port = %d\n", target->socket );
- memcpy ( &target->boot_lun, &iscsi->lun, sizeof ( target->boot_lun ) );
- DBG ( "iBFT target boot LUN = " SCSI_LUN_FORMAT "\n",
- SCSI_LUN_DATA ( target->boot_lun ) );
- if ( ( rc = ibft_set_string ( strings, &target->target_name,
- iscsi->target_iqn ) ) != 0 )
- return rc;
- DBG ( "iBFT target name = %s\n",
- ibft_string ( strings, &target->target_name ) );
- if ( ( rc = ibft_fill_target_chap ( target, strings, iscsi ) ) != 0 )
- return rc;
- if ( ( rc = ibft_fill_target_reverse_chap ( target, strings,
- iscsi ) ) != 0 )
- return rc;
-
- return 0;
-}
-
-/**
- * Fill in iBFT
- *
- * @v iscsi iSCSI session
- * @v acpi ACPI table
- * @v len Length of ACPI table
- * @ret rc Return status code
- */
-int ibft_describe ( struct iscsi_session *iscsi,
- struct acpi_description_header *acpi,
- size_t len ) {
- struct ipxe_ibft *ibft =
- container_of ( acpi, struct ipxe_ibft, table.acpi );
- struct ibft_strings strings = {
- .table = &ibft->table,
- .offset = offsetof ( typeof ( *ibft ), strings ),
- .len = len,
- };
- struct net_device *netdev;
- int rc;
-
- /* Ugly hack. Now that we have a generic interface mechanism
- * that can support ioctls, we can potentially eliminate this.
- */
- netdev = last_opened_netdev();
- if ( ! netdev ) {
- DBGC ( iscsi, "iSCSI %p cannot guess network device\n",
- iscsi );
- return -ENODEV;
- }
-
- /* Fill in ACPI header */
- ibft->table.acpi.signature = cpu_to_le32 ( IBFT_SIG );
- ibft->table.acpi.length = cpu_to_le32 ( len );
- ibft->table.acpi.revision = 1;
-
- /* Fill in Control block */
- ibft->table.control.header.structure_id = IBFT_STRUCTURE_ID_CONTROL;
- ibft->table.control.header.version = 1;
- ibft->table.control.header.length =
- cpu_to_le16 ( sizeof ( ibft->table.control ) );
- ibft->table.control.initiator =
- cpu_to_le16 ( offsetof ( typeof ( *ibft ), initiator ) );
- ibft->table.control.nic_0 =
- cpu_to_le16 ( offsetof ( typeof ( *ibft ), nic ) );
- ibft->table.control.target_0 =
- cpu_to_le16 ( offsetof ( typeof ( *ibft ), target ) );
-
- /* Fill in NIC, Initiator and Target blocks */
- if ( ( rc = ibft_fill_nic ( &ibft->nic, &strings, netdev ) ) != 0 )
- return rc;
- if ( ( rc = ibft_fill_initiator ( &ibft->initiator, &strings,
- iscsi ) ) != 0 )
- return rc;
- if ( ( rc = ibft_fill_target ( &ibft->target, &strings,
- iscsi ) ) != 0 )
- return rc;
-
- return 0;
-}
diff --git a/qemu/roms/ipxe/src/drivers/block/scsi.c b/qemu/roms/ipxe/src/drivers/block/scsi.c
deleted file mode 100644
index fd5f82b9f..000000000
--- a/qemu/roms/ipxe/src/drivers/block/scsi.c
+++ /dev/null
@@ -1,1003 +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 <byteswap.h>
-#include <errno.h>
-#include <ipxe/list.h>
-#include <ipxe/process.h>
-#include <ipxe/xfer.h>
-#include <ipxe/blockdev.h>
-#include <ipxe/scsi.h>
-
-/** @file
- *
- * SCSI block device
- *
- */
-
-/** Maximum number of command retries */
-#define SCSICMD_MAX_RETRIES 10
-
-/* Error numbers generated by SCSI sense data */
-#define EIO_NO_SENSE __einfo_error ( EINFO_EIO_NO_SENSE )
-#define EINFO_EIO_NO_SENSE \
- __einfo_uniqify ( EINFO_EIO, 0x00, "No sense" )
-#define EIO_RECOVERED_ERROR __einfo_error ( EINFO_EIO_RECOVERED_ERROR )
-#define EINFO_EIO_RECOVERED_ERROR \
- __einfo_uniqify ( EINFO_EIO, 0x01, "Recovered error" )
-#define EIO_NOT_READY __einfo_error ( EINFO_EIO_NOT_READY )
-#define EINFO_EIO_NOT_READY \
- __einfo_uniqify ( EINFO_EIO, 0x02, "Not ready" )
-#define EIO_MEDIUM_ERROR __einfo_error ( EINFO_EIO_MEDIUM_ERROR )
-#define EINFO_EIO_MEDIUM_ERROR \
- __einfo_uniqify ( EINFO_EIO, 0x03, "Medium error" )
-#define EIO_HARDWARE_ERROR __einfo_error ( EINFO_EIO_HARDWARE_ERROR )
-#define EINFO_EIO_HARDWARE_ERROR \
- __einfo_uniqify ( EINFO_EIO, 0x04, "Hardware error" )
-#define EIO_ILLEGAL_REQUEST __einfo_error ( EINFO_EIO_ILLEGAL_REQUEST )
-#define EINFO_EIO_ILLEGAL_REQUEST \
- __einfo_uniqify ( EINFO_EIO, 0x05, "Illegal request" )
-#define EIO_UNIT_ATTENTION __einfo_error ( EINFO_EIO_UNIT_ATTENTION )
-#define EINFO_EIO_UNIT_ATTENTION \
- __einfo_uniqify ( EINFO_EIO, 0x06, "Unit attention" )
-#define EIO_DATA_PROTECT __einfo_error ( EINFO_EIO_DATA_PROTECT )
-#define EINFO_EIO_DATA_PROTECT \
- __einfo_uniqify ( EINFO_EIO, 0x07, "Data protect" )
-#define EIO_BLANK_CHECK __einfo_error ( EINFO_EIO_BLANK_CHECK )
-#define EINFO_EIO_BLANK_CHECK \
- __einfo_uniqify ( EINFO_EIO, 0x08, "Blank check" )
-#define EIO_VENDOR_SPECIFIC __einfo_error ( EINFO_EIO_VENDOR_SPECIFIC )
-#define EINFO_EIO_VENDOR_SPECIFIC \
- __einfo_uniqify ( EINFO_EIO, 0x09, "Vendor specific" )
-#define EIO_COPY_ABORTED __einfo_error ( EINFO_EIO_COPY_ABORTED )
-#define EINFO_EIO_COPY_ABORTED \
- __einfo_uniqify ( EINFO_EIO, 0x0a, "Copy aborted" )
-#define EIO_ABORTED_COMMAND __einfo_error ( EINFO_EIO_ABORTED_COMMAND )
-#define EINFO_EIO_ABORTED_COMMAND \
- __einfo_uniqify ( EINFO_EIO, 0x0b, "Aborted command" )
-#define EIO_RESERVED __einfo_error ( EINFO_EIO_RESERVED )
-#define EINFO_EIO_RESERVED \
- __einfo_uniqify ( EINFO_EIO, 0x0c, "Reserved" )
-#define EIO_VOLUME_OVERFLOW __einfo_error ( EINFO_EIO_VOLUME_OVERFLOW )
-#define EINFO_EIO_VOLUME_OVERFLOW \
- __einfo_uniqify ( EINFO_EIO, 0x0d, "Volume overflow" )
-#define EIO_MISCOMPARE __einfo_error ( EINFO_EIO_MISCOMPARE )
-#define EINFO_EIO_MISCOMPARE \
- __einfo_uniqify ( EINFO_EIO, 0x0e, "Miscompare" )
-#define EIO_COMPLETED __einfo_error ( EINFO_EIO_COMPLETED )
-#define EINFO_EIO_COMPLETED \
- __einfo_uniqify ( EINFO_EIO, 0x0f, "Completed" )
-#define EIO_SENSE( key ) \
- EUNIQ ( EINFO_EIO, (key), EIO_NO_SENSE, EIO_RECOVERED_ERROR, \
- EIO_NOT_READY, EIO_MEDIUM_ERROR, EIO_HARDWARE_ERROR, \
- EIO_ILLEGAL_REQUEST, EIO_UNIT_ATTENTION, \
- EIO_DATA_PROTECT, EIO_BLANK_CHECK, EIO_VENDOR_SPECIFIC, \
- EIO_COPY_ABORTED, EIO_ABORTED_COMMAND, EIO_RESERVED, \
- EIO_VOLUME_OVERFLOW, EIO_MISCOMPARE, EIO_COMPLETED )
-
-/******************************************************************************
- *
- * Utility functions
- *
- ******************************************************************************
- */
-
-/**
- * Parse SCSI LUN
- *
- * @v lun_string LUN string representation
- * @v lun LUN to fill in
- * @ret rc Return status code
- */
-int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun ) {
- char *p;
- int i;
-
- memset ( lun, 0, sizeof ( *lun ) );
- if ( lun_string ) {
- p = ( char * ) lun_string;
- for ( i = 0 ; i < 4 ; i++ ) {
- lun->u16[i] = htons ( strtoul ( p, &p, 16 ) );
- if ( *p == '\0' )
- break;
- if ( *p != '-' )
- return -EINVAL;
- p++;
- }
- if ( *p )
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * Parse SCSI sense data
- *
- * @v data Raw sense data
- * @v len Length of raw sense data
- * @v sense Descriptor-format sense data to fill in
- */
-void scsi_parse_sense ( const void *data, size_t len,
- struct scsi_sns_descriptor *sense ) {
- const union scsi_sns *sns = data;
-
- /* Avoid returning uninitialised data */
- memset ( sense, 0, sizeof ( *sense ) );
-
- /* Copy, assuming descriptor-format data */
- if ( len < sizeof ( sns->desc ) )
- return;
- memcpy ( sense, &sns->desc, sizeof ( *sense ) );
-
- /* Convert fixed-format to descriptor-format, if applicable */
- if ( len < sizeof ( sns->fixed ) )
- return;
- if ( ! SCSI_SENSE_FIXED ( sns->code ) )
- return;
- sense->additional = sns->fixed.additional;
-}
-
-/******************************************************************************
- *
- * Interface methods
- *
- ******************************************************************************
- */
-
-/**
- * Issue SCSI command
- *
- * @v control SCSI control interface
- * @v data SCSI data interface
- * @v command SCSI command
- * @ret tag Command tag, or negative error
- */
-int scsi_command ( struct interface *control, struct interface *data,
- struct scsi_cmd *command ) {
- struct interface *dest;
- scsi_command_TYPE ( void * ) *op =
- intf_get_dest_op ( control, scsi_command, &dest );
- void *object = intf_object ( dest );
- int tap;
-
- if ( op ) {
- tap = op ( object, data, command );
- } else {
- /* Default is to fail to issue the command */
- tap = -EOPNOTSUPP;
- }
-
- intf_put ( dest );
- return tap;
-}
-
-/**
- * Report SCSI response
- *
- * @v interface SCSI command interface
- * @v response SCSI response
- */
-void scsi_response ( struct interface *intf, struct scsi_rsp *response ) {
- struct interface *dest;
- scsi_response_TYPE ( void * ) *op =
- intf_get_dest_op ( intf, scsi_response, &dest );
- void *object = intf_object ( dest );
-
- if ( op ) {
- op ( object, response );
- } else {
- /* Default is to ignore the response */
- }
-
- intf_put ( dest );
-}
-
-/******************************************************************************
- *
- * SCSI devices and commands
- *
- ******************************************************************************
- */
-
-/** A SCSI device */
-struct scsi_device {
- /** Reference count */
- struct refcnt refcnt;
- /** Block control interface */
- struct interface block;
- /** SCSI control interface */
- struct interface scsi;
-
- /** SCSI LUN */
- struct scsi_lun lun;
- /** Flags */
- unsigned int flags;
-
- /** TEST UNIT READY interface */
- struct interface ready;
- /** TEST UNIT READY process */
- struct process process;
-
- /** List of commands */
- struct list_head cmds;
-};
-
-/** SCSI device flags */
-enum scsi_device_flags {
- /** TEST UNIT READY has been issued */
- SCSIDEV_UNIT_TESTED = 0x0001,
- /** TEST UNIT READY has completed successfully */
- SCSIDEV_UNIT_READY = 0x0002,
-};
-
-/** A SCSI command */
-struct scsi_command {
- /** Reference count */
- struct refcnt refcnt;
- /** SCSI device */
- struct scsi_device *scsidev;
- /** List of SCSI commands */
- struct list_head list;
-
- /** Block data interface */
- struct interface block;
- /** SCSI data interface */
- struct interface scsi;
-
- /** Command type */
- struct scsi_command_type *type;
- /** Starting logical block address */
- uint64_t lba;
- /** Number of blocks */
- unsigned int count;
- /** Data buffer */
- userptr_t buffer;
- /** Length of data buffer */
- size_t len;
- /** Command tag */
- uint32_t tag;
-
- /** Retry count */
- unsigned int retries;
-
- /** Private data */
- uint8_t priv[0];
-};
-
-/** A SCSI command type */
-struct scsi_command_type {
- /** Name */
- const char *name;
- /** Additional working space */
- size_t priv_len;
- /**
- * Construct SCSI command IU
- *
- * @v scsicmd SCSI command
- * @v command SCSI command IU
- */
- void ( * cmd ) ( struct scsi_command *scsicmd,
- struct scsi_cmd *command );
- /**
- * Handle SCSI command completion
- *
- * @v scsicmd SCSI command
- * @v rc Reason for completion
- */
- void ( * done ) ( struct scsi_command *scsicmd, int rc );
-};
-
-/**
- * Get reference to SCSI device
- *
- * @v scsidev SCSI device
- * @ret scsidev SCSI device
- */
-static inline __attribute__ (( always_inline )) struct scsi_device *
-scsidev_get ( struct scsi_device *scsidev ) {
- ref_get ( &scsidev->refcnt );
- return scsidev;
-}
-
-/**
- * Drop reference to SCSI device
- *
- * @v scsidev SCSI device
- */
-static inline __attribute__ (( always_inline )) void
-scsidev_put ( struct scsi_device *scsidev ) {
- ref_put ( &scsidev->refcnt );
-}
-
-/**
- * Get reference to SCSI command
- *
- * @v scsicmd SCSI command
- * @ret scsicmd SCSI command
- */
-static inline __attribute__ (( always_inline )) struct scsi_command *
-scsicmd_get ( struct scsi_command *scsicmd ) {
- ref_get ( &scsicmd->refcnt );
- return scsicmd;
-}
-
-/**
- * Drop reference to SCSI command
- *
- * @v scsicmd SCSI command
- */
-static inline __attribute__ (( always_inline )) void
-scsicmd_put ( struct scsi_command *scsicmd ) {
- ref_put ( &scsicmd->refcnt );
-}
-
-/**
- * Get SCSI command private data
- *
- * @v scsicmd SCSI command
- * @ret priv Private data
- */
-static inline __attribute__ (( always_inline )) void *
-scsicmd_priv ( struct scsi_command *scsicmd ) {
- return scsicmd->priv;
-}
-
-/**
- * Free SCSI command
- *
- * @v refcnt Reference count
- */
-static void scsicmd_free ( struct refcnt *refcnt ) {
- struct scsi_command *scsicmd =
- container_of ( refcnt, struct scsi_command, refcnt );
-
- /* Remove from list of commands */
- list_del ( &scsicmd->list );
- scsidev_put ( scsicmd->scsidev );
-
- /* Free command */
- free ( scsicmd );
-}
-
-/**
- * Close SCSI command
- *
- * @v scsicmd SCSI command
- * @v rc Reason for close
- */
-static void scsicmd_close ( struct scsi_command *scsicmd, int rc ) {
- struct scsi_device *scsidev = scsicmd->scsidev;
-
- if ( rc != 0 ) {
- DBGC ( scsidev, "SCSI %p tag %08x closed: %s\n",
- scsidev, scsicmd->tag, strerror ( rc ) );
- }
-
- /* Shut down interfaces */
- intf_shutdown ( &scsicmd->scsi, rc );
- intf_shutdown ( &scsicmd->block, rc );
-}
-
-/**
- * Construct and issue SCSI command
- *
- * @ret rc Return status code
- */
-static int scsicmd_command ( struct scsi_command *scsicmd ) {
- struct scsi_device *scsidev = scsicmd->scsidev;
- struct scsi_cmd command;
- int tag;
- int rc;
-
- /* Construct command */
- memset ( &command, 0, sizeof ( command ) );
- memcpy ( &command.lun, &scsidev->lun, sizeof ( command.lun ) );
- scsicmd->type->cmd ( scsicmd, &command );
-
- /* Issue command */
- if ( ( tag = scsi_command ( &scsidev->scsi, &scsicmd->scsi,
- &command ) ) < 0 ) {
- rc = tag;
- DBGC ( scsidev, "SCSI %p could not issue command: %s\n",
- scsidev, strerror ( rc ) );
- return rc;
- }
-
- /* Record tag */
- if ( scsicmd->tag ) {
- DBGC ( scsidev, "SCSI %p tag %08x is now tag %08x\n",
- scsidev, scsicmd->tag, tag );
- }
- scsicmd->tag = tag;
- DBGC2 ( scsidev, "SCSI %p tag %08x %s " SCSI_CDB_FORMAT "\n",
- scsidev, scsicmd->tag, scsicmd->type->name,
- SCSI_CDB_DATA ( command.cdb ) );
-
- return 0;
-}
-
-/**
- * Handle SCSI command completion
- *
- * @v scsicmd SCSI command
- * @v rc Reason for close
- */
-static void scsicmd_done ( struct scsi_command *scsicmd, int rc ) {
- struct scsi_device *scsidev = scsicmd->scsidev;
-
- /* Restart SCSI interface */
- intf_restart ( &scsicmd->scsi, rc );
-
- /* SCSI targets have an annoying habit of returning occasional
- * pointless "error" messages such as "power-on occurred", so
- * we have to be prepared to retry commands.
- */
- if ( ( rc != 0 ) && ( scsicmd->retries++ < SCSICMD_MAX_RETRIES ) ) {
- /* Retry command */
- DBGC ( scsidev, "SCSI %p tag %08x failed: %s\n",
- scsidev, scsicmd->tag, strerror ( rc ) );
- DBGC ( scsidev, "SCSI %p tag %08x retrying (retry %d)\n",
- scsidev, scsicmd->tag, scsicmd->retries );
- if ( ( rc = scsicmd_command ( scsicmd ) ) == 0 )
- return;
- }
-
- /* If we didn't (successfully) reissue the command, hand over
- * to the command completion handler.
- */
- scsicmd->type->done ( scsicmd, rc );
-}
-
-/**
- * Handle SCSI response
- *
- * @v scsicmd SCSI command
- * @v response SCSI response
- */
-static void scsicmd_response ( struct scsi_command *scsicmd,
- struct scsi_rsp *response ) {
- struct scsi_device *scsidev = scsicmd->scsidev;
- size_t overrun;
- size_t underrun;
- int rc;
-
- if ( response->status == 0 ) {
- scsicmd_done ( scsicmd, 0 );
- } else {
- DBGC ( scsidev, "SCSI %p tag %08x status %02x",
- scsidev, scsicmd->tag, response->status );
- if ( response->overrun > 0 ) {
- overrun = response->overrun;
- DBGC ( scsidev, " overrun +%zd", overrun );
- } else if ( response->overrun < 0 ) {
- underrun = -(response->overrun);
- DBGC ( scsidev, " underrun -%zd", underrun );
- }
- DBGC ( scsidev, " sense %02x key %02x additional %04x\n",
- ( response->sense.code & SCSI_SENSE_CODE_MASK ),
- ( response->sense.key & SCSI_SENSE_KEY_MASK ),
- ntohs ( response->sense.additional ) );
-
- /* Construct error number from sense data */
- rc = -EIO_SENSE ( response->sense.key & SCSI_SENSE_KEY_MASK );
- scsicmd_done ( scsicmd, rc );
- }
-}
-
-/**
- * Construct SCSI READ command
- *
- * @v scsicmd SCSI command
- * @v command SCSI command IU
- */
-static void scsicmd_read_cmd ( struct scsi_command *scsicmd,
- struct scsi_cmd *command ) {
-
- if ( ( scsicmd->lba + scsicmd->count ) > SCSI_MAX_BLOCK_10 ) {
- /* Use READ (16) */
- command->cdb.read16.opcode = SCSI_OPCODE_READ_16;
- command->cdb.read16.lba = cpu_to_be64 ( scsicmd->lba );
- command->cdb.read16.len = cpu_to_be32 ( scsicmd->count );
- } else {
- /* Use READ (10) */
- command->cdb.read10.opcode = SCSI_OPCODE_READ_10;
- command->cdb.read10.lba = cpu_to_be32 ( scsicmd->lba );
- command->cdb.read10.len = cpu_to_be16 ( scsicmd->count );
- }
- command->data_in = scsicmd->buffer;
- command->data_in_len = scsicmd->len;
-}
-
-/** SCSI READ command type */
-static struct scsi_command_type scsicmd_read = {
- .name = "READ",
- .cmd = scsicmd_read_cmd,
- .done = scsicmd_close,
-};
-
-/**
- * Construct SCSI WRITE command
- *
- * @v scsicmd SCSI command
- * @v command SCSI command IU
- */
-static void scsicmd_write_cmd ( struct scsi_command *scsicmd,
- struct scsi_cmd *command ) {
-
- if ( ( scsicmd->lba + scsicmd->count ) > SCSI_MAX_BLOCK_10 ) {
- /* Use WRITE (16) */
- command->cdb.write16.opcode = SCSI_OPCODE_WRITE_16;
- command->cdb.write16.lba = cpu_to_be64 ( scsicmd->lba );
- command->cdb.write16.len = cpu_to_be32 ( scsicmd->count );
- } else {
- /* Use WRITE (10) */
- command->cdb.write10.opcode = SCSI_OPCODE_WRITE_10;
- command->cdb.write10.lba = cpu_to_be32 ( scsicmd->lba );
- command->cdb.write10.len = cpu_to_be16 ( scsicmd->count );
- }
- command->data_out = scsicmd->buffer;
- command->data_out_len = scsicmd->len;
-}
-
-/** SCSI WRITE command type */
-static struct scsi_command_type scsicmd_write = {
- .name = "WRITE",
- .cmd = scsicmd_write_cmd,
- .done = scsicmd_close,
-};
-
-/** SCSI READ CAPACITY private data */
-struct scsi_read_capacity_private {
- /** Use READ CAPACITY (16) */
- int use16;
- /** Data buffer for READ CAPACITY commands */
- union {
- /** Data buffer for READ CAPACITY (10) */
- struct scsi_capacity_10 capacity10;
- /** Data buffer for READ CAPACITY (16) */
- struct scsi_capacity_16 capacity16;
- } capacity;
-};
-
-/**
- * Construct SCSI READ CAPACITY command
- *
- * @v scsicmd SCSI command
- * @v command SCSI command IU
- */
-static void scsicmd_read_capacity_cmd ( struct scsi_command *scsicmd,
- struct scsi_cmd *command ) {
- struct scsi_read_capacity_private *priv = scsicmd_priv ( scsicmd );
- struct scsi_cdb_read_capacity_16 *readcap16 = &command->cdb.readcap16;
- struct scsi_cdb_read_capacity_10 *readcap10 = &command->cdb.readcap10;
- struct scsi_capacity_16 *capacity16 = &priv->capacity.capacity16;
- struct scsi_capacity_10 *capacity10 = &priv->capacity.capacity10;
-
- if ( priv->use16 ) {
- /* Use READ CAPACITY (16) */
- readcap16->opcode = SCSI_OPCODE_SERVICE_ACTION_IN;
- readcap16->service_action =
- SCSI_SERVICE_ACTION_READ_CAPACITY_16;
- readcap16->len = cpu_to_be32 ( sizeof ( *capacity16 ) );
- command->data_in = virt_to_user ( capacity16 );
- command->data_in_len = sizeof ( *capacity16 );
- } else {
- /* Use READ CAPACITY (10) */
- readcap10->opcode = SCSI_OPCODE_READ_CAPACITY_10;
- command->data_in = virt_to_user ( capacity10 );
- command->data_in_len = sizeof ( *capacity10 );
- }
-}
-
-/**
- * Handle SCSI READ CAPACITY command completion
- *
- * @v scsicmd SCSI command
- * @v rc Reason for completion
- */
-static void scsicmd_read_capacity_done ( struct scsi_command *scsicmd,
- int rc ) {
- struct scsi_read_capacity_private *priv = scsicmd_priv ( scsicmd );
- struct scsi_capacity_16 *capacity16 = &priv->capacity.capacity16;
- struct scsi_capacity_10 *capacity10 = &priv->capacity.capacity10;
- struct block_device_capacity capacity;
-
- /* Close if command failed */
- if ( rc != 0 ) {
- scsicmd_close ( scsicmd, rc );
- return;
- }
-
- /* Extract capacity */
- if ( priv->use16 ) {
- capacity.blocks = ( be64_to_cpu ( capacity16->lba ) + 1 );
- capacity.blksize = be32_to_cpu ( capacity16->blksize );
- } else {
- capacity.blocks = ( be32_to_cpu ( capacity10->lba ) + 1 );
- capacity.blksize = be32_to_cpu ( capacity10->blksize );
-
- /* If capacity range was exceeded (i.e. capacity.lba
- * was 0xffffffff, meaning that blockdev->blocks is
- * now zero), use READ CAPACITY (16) instead. READ
- * CAPACITY (16) is not mandatory, so we can't just
- * use it straight off.
- */
- if ( capacity.blocks == 0 ) {
- priv->use16 = 1;
- if ( ( rc = scsicmd_command ( scsicmd ) ) != 0 ) {
- scsicmd_close ( scsicmd, rc );
- return;
- }
- return;
- }
- }
- capacity.max_count = -1U;
-
- /* Return capacity to caller */
- block_capacity ( &scsicmd->block, &capacity );
-
- /* Close command */
- scsicmd_close ( scsicmd, 0 );
-}
-
-/** SCSI READ CAPACITY command type */
-static struct scsi_command_type scsicmd_read_capacity = {
- .name = "READ CAPACITY",
- .priv_len = sizeof ( struct scsi_read_capacity_private ),
- .cmd = scsicmd_read_capacity_cmd,
- .done = scsicmd_read_capacity_done,
-};
-
-/**
- * Construct SCSI TEST UNIT READY command
- *
- * @v scsicmd SCSI command
- * @v command SCSI command IU
- */
-static void scsicmd_test_unit_ready_cmd ( struct scsi_command *scsicmd __unused,
- struct scsi_cmd *command ) {
- struct scsi_cdb_test_unit_ready *testready = &command->cdb.testready;
-
- testready->opcode = SCSI_OPCODE_TEST_UNIT_READY;
-}
-
-/** SCSI TEST UNIT READY command type */
-static struct scsi_command_type scsicmd_test_unit_ready = {
- .name = "TEST UNIT READY",
- .cmd = scsicmd_test_unit_ready_cmd,
- .done = scsicmd_close,
-};
-
-/** SCSI command block interface operations */
-static struct interface_operation scsicmd_block_op[] = {
- INTF_OP ( intf_close, struct scsi_command *, scsicmd_close ),
-};
-
-/** SCSI command block interface descriptor */
-static struct interface_descriptor scsicmd_block_desc =
- INTF_DESC_PASSTHRU ( struct scsi_command, block,
- scsicmd_block_op, scsi );
-
-/** SCSI command SCSI interface operations */
-static struct interface_operation scsicmd_scsi_op[] = {
- INTF_OP ( intf_close, struct scsi_command *, scsicmd_done ),
- INTF_OP ( scsi_response, struct scsi_command *, scsicmd_response ),
-};
-
-/** SCSI command SCSI interface descriptor */
-static struct interface_descriptor scsicmd_scsi_desc =
- INTF_DESC_PASSTHRU ( struct scsi_command, scsi,
- scsicmd_scsi_op, block );
-
-/**
- * Create SCSI command
- *
- * @v scsidev SCSI device
- * @v block Block data interface
- * @v type SCSI 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 scsidev_command ( struct scsi_device *scsidev,
- struct interface *block,
- struct scsi_command_type *type,
- uint64_t lba, unsigned int count,
- userptr_t buffer, size_t len ) {
- struct scsi_command *scsicmd;
- int rc;
-
- /* Allocate and initialise structure */
- scsicmd = zalloc ( sizeof ( *scsicmd ) + type->priv_len );
- if ( ! scsicmd ) {
- rc = -ENOMEM;
- goto err_zalloc;
- }
- ref_init ( &scsicmd->refcnt, scsicmd_free );
- intf_init ( &scsicmd->block, &scsicmd_block_desc, &scsicmd->refcnt );
- intf_init ( &scsicmd->scsi, &scsicmd_scsi_desc,
- &scsicmd->refcnt );
- scsicmd->scsidev = scsidev_get ( scsidev );
- list_add ( &scsicmd->list, &scsidev->cmds );
- scsicmd->type = type;
- scsicmd->lba = lba;
- scsicmd->count = count;
- scsicmd->buffer = buffer;
- scsicmd->len = len;
-
- /* Issue SCSI command */
- if ( ( rc = scsicmd_command ( scsicmd ) ) != 0 )
- goto err_command;
-
- /* Attach to parent interface, mortalise self, and return */
- intf_plug_plug ( &scsicmd->block, block );
- ref_put ( &scsicmd->refcnt );
- return 0;
-
- err_command:
- scsicmd_close ( scsicmd, rc );
- ref_put ( &scsicmd->refcnt );
- err_zalloc:
- return rc;
-}
-
-/**
- * Issue SCSI block read
- *
- * @v scsidev SCSI 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 scsidev_read ( struct scsi_device *scsidev,
- struct interface *block,
- uint64_t lba, unsigned int count,
- userptr_t buffer, size_t len ) {
- return scsidev_command ( scsidev, block, &scsicmd_read,
- lba, count, buffer, len );
-}
-
-/**
- * Issue SCSI block write
- *
- * @v scsidev SCSI 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 scsidev_write ( struct scsi_device *scsidev,
- struct interface *block,
- uint64_t lba, unsigned int count,
- userptr_t buffer, size_t len ) {
- return scsidev_command ( scsidev, block, &scsicmd_write,
- lba, count, buffer, len );
-}
-
-/**
- * Read SCSI device capacity
- *
- * @v scsidev SCSI device
- * @v block Block data interface
- * @ret rc Return status code
- */
-static int scsidev_read_capacity ( struct scsi_device *scsidev,
- struct interface *block ) {
- return scsidev_command ( scsidev, block, &scsicmd_read_capacity,
- 0, 0, UNULL, 0 );
-}
-
-/**
- * Test to see if SCSI device is ready
- *
- * @v scsidev SCSI device
- * @v block Block data interface
- * @ret rc Return status code
- */
-static int scsidev_test_unit_ready ( struct scsi_device *scsidev,
- struct interface *block ) {
- return scsidev_command ( scsidev, block, &scsicmd_test_unit_ready,
- 0, 0, UNULL, 0 );
-}
-
-/**
- * Check SCSI device flow-control window
- *
- * @v scsidev SCSI device
- * @ret len Length of window
- */
-static size_t scsidev_window ( struct scsi_device *scsidev ) {
-
- /* Refuse commands until unit is confirmed ready */
- if ( ! ( scsidev->flags & SCSIDEV_UNIT_READY ) )
- return 0;
-
- return xfer_window ( &scsidev->scsi );
-}
-
-/**
- * Close SCSI device
- *
- * @v scsidev SCSI device
- * @v rc Reason for close
- */
-static void scsidev_close ( struct scsi_device *scsidev, int rc ) {
- struct scsi_command *scsicmd;
- struct scsi_command *tmp;
-
- /* Stop process */
- process_del ( &scsidev->process );
-
- /* Shut down interfaces */
- intf_shutdown ( &scsidev->block, rc );
- intf_shutdown ( &scsidev->scsi, rc );
- intf_shutdown ( &scsidev->ready, rc );
-
- /* Shut down any remaining commands */
- list_for_each_entry_safe ( scsicmd, tmp, &scsidev->cmds, list ) {
- scsicmd_get ( scsicmd );
- scsicmd_close ( scsicmd, rc );
- scsicmd_put ( scsicmd );
- }
-}
-
-/** SCSI device block interface operations */
-static struct interface_operation scsidev_block_op[] = {
- INTF_OP ( xfer_window, struct scsi_device *, scsidev_window ),
- INTF_OP ( block_read, struct scsi_device *, scsidev_read ),
- INTF_OP ( block_write, struct scsi_device *, scsidev_write ),
- INTF_OP ( block_read_capacity, struct scsi_device *,
- scsidev_read_capacity ),
- INTF_OP ( intf_close, struct scsi_device *, scsidev_close ),
-};
-
-/** SCSI device block interface descriptor */
-static struct interface_descriptor scsidev_block_desc =
- INTF_DESC_PASSTHRU ( struct scsi_device, block,
- scsidev_block_op, scsi );
-
-/**
- * Handle SCSI TEST UNIT READY response
- *
- * @v scsidev SCSI device
- * @v rc Reason for close
- */
-static void scsidev_ready ( struct scsi_device *scsidev, int rc ) {
-
- /* Shut down interface */
- intf_shutdown ( &scsidev->ready, rc );
-
- /* Close device on failure */
- if ( rc != 0 ) {
- DBGC ( scsidev, "SCSI %p not ready: %s\n",
- scsidev, strerror ( rc ) );
- scsidev_close ( scsidev, rc );
- return;
- }
-
- /* Mark device as ready */
- scsidev->flags |= SCSIDEV_UNIT_READY;
- xfer_window_changed ( &scsidev->block );
- DBGC ( scsidev, "SCSI %p unit is ready\n", scsidev );
-}
-
-/** SCSI device TEST UNIT READY interface operations */
-static struct interface_operation scsidev_ready_op[] = {
- INTF_OP ( intf_close, struct scsi_device *, scsidev_ready ),
-};
-
-/** SCSI device TEST UNIT READY interface descriptor */
-static struct interface_descriptor scsidev_ready_desc =
- INTF_DESC ( struct scsi_device, ready, scsidev_ready_op );
-
-/**
- * SCSI TEST UNIT READY process
- *
- * @v scsidev SCSI device
- */
-static void scsidev_step ( struct scsi_device *scsidev ) {
- int rc;
-
- /* Do nothing if we have already issued TEST UNIT READY */
- if ( scsidev->flags & SCSIDEV_UNIT_TESTED )
- return;
-
- /* Wait until underlying SCSI device is ready */
- if ( xfer_window ( &scsidev->scsi ) == 0 )
- return;
-
- DBGC ( scsidev, "SCSI %p waiting for unit to become ready\n",
- scsidev );
-
- /* Mark TEST UNIT READY as sent */
- scsidev->flags |= SCSIDEV_UNIT_TESTED;
-
- /* Issue TEST UNIT READY command */
- if ( ( rc = scsidev_test_unit_ready ( scsidev, &scsidev->ready )) !=0){
- scsidev_close ( scsidev, rc );
- return;
- }
-}
-
-/** SCSI device SCSI interface operations */
-static struct interface_operation scsidev_scsi_op[] = {
- INTF_OP ( xfer_window_changed, struct scsi_device *, scsidev_step ),
- INTF_OP ( intf_close, struct scsi_device *, scsidev_close ),
-};
-
-/** SCSI device SCSI interface descriptor */
-static struct interface_descriptor scsidev_scsi_desc =
- INTF_DESC_PASSTHRU ( struct scsi_device, scsi,
- scsidev_scsi_op, block );
-
-/** SCSI device process descriptor */
-static struct process_descriptor scsidev_process_desc =
- PROC_DESC_ONCE ( struct scsi_device, process, scsidev_step );
-
-/**
- * Open SCSI device
- *
- * @v block Block control interface
- * @v scsi SCSI control interface
- * @v lun SCSI LUN
- * @ret rc Return status code
- */
-int scsi_open ( struct interface *block, struct interface *scsi,
- struct scsi_lun *lun ) {
- struct scsi_device *scsidev;
-
- /* Allocate and initialise structure */
- scsidev = zalloc ( sizeof ( *scsidev ) );
- if ( ! scsidev )
- return -ENOMEM;
- ref_init ( &scsidev->refcnt, NULL );
- intf_init ( &scsidev->block, &scsidev_block_desc, &scsidev->refcnt );
- intf_init ( &scsidev->scsi, &scsidev_scsi_desc, &scsidev->refcnt );
- intf_init ( &scsidev->ready, &scsidev_ready_desc, &scsidev->refcnt );
- process_init ( &scsidev->process, &scsidev_process_desc,
- &scsidev->refcnt );
- INIT_LIST_HEAD ( &scsidev->cmds );
- memcpy ( &scsidev->lun, lun, sizeof ( scsidev->lun ) );
- DBGC ( scsidev, "SCSI %p created for LUN " SCSI_LUN_FORMAT "\n",
- scsidev, SCSI_LUN_DATA ( scsidev->lun ) );
-
- /* Attach to SCSI and parent interfaces, mortalise self, and return */
- intf_plug_plug ( &scsidev->scsi, scsi );
- intf_plug_plug ( &scsidev->block, block );
- ref_put ( &scsidev->refcnt );
- return 0;
-}
diff --git a/qemu/roms/ipxe/src/drivers/block/srp.c b/qemu/roms/ipxe/src/drivers/block/srp.c
deleted file mode 100644
index 7edf69ace..000000000
--- a/qemu/roms/ipxe/src/drivers/block/srp.c
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-FILE_LICENCE ( BSD2 );
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <ipxe/scsi.h>
-#include <ipxe/xfer.h>
-#include <ipxe/features.h>
-#include <ipxe/srp.h>
-
-/**
- * @file
- *
- * SCSI RDMA Protocol
- *
- */
-
-FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
-
-/** Maximum length of any initiator-to-target IU that we will send
- *
- * The longest IU is a SRP_CMD with no additional CDB and two direct
- * data buffer descriptors, which comes to 80 bytes.
- */
-#define SRP_MAX_I_T_IU_LEN 80
-
-/* Error numbers generated by SRP login rejection */
-#define EINFO_SRP_LOGIN_REJ( reason, desc ) \
- __einfo_uniqify ( EINFO_EPERM, ( (reason) & 0x0f ), desc )
-#define EPERM_UNKNOWN \
- __einfo_error ( EINFO_EPERM_UNKNOWN )
-#define EINFO_EPERM_UNKNOWN EINFO_SRP_LOGIN_REJ ( \
- SRP_LOGIN_REJ_REASON_UNKNOWN, \
- "Unable to establish RDMA channel, no reason specified" )
-#define EPERM_INSUFFICIENT_RESOURCES \
- __einfo_error ( EINFO_EPERM_INSUFFICIENT_RESOURCES )
-#define EINFO_EPERM_INSUFFICIENT_RESOURCES EINFO_SRP_LOGIN_REJ ( \
- SRP_LOGIN_REJ_REASON_INSUFFICIENT_RESOURCES, \
- "Insufficient RDMA channel resources" )
-#define EPERM_BAD_MAX_I_T_IU_LEN \
- __einfo_error ( EINFO_EPERM_BAD_MAX_I_T_IU_LEN )
-#define EINFO_EPERM_BAD_MAX_I_T_IU_LEN EINFO_SRP_LOGIN_REJ ( \
- SRP_LOGIN_REJ_REASON_BAD_MAX_I_T_IU_LEN, \
- "Requested maximum initiator to target IU length value too large" )
-#define EPERM_CANNOT_ASSOCIATE \
- __einfo_error ( EINFO_EPERM_CANNOT_ASSOCIATE )
-#define EINFO_EPERM_CANNOT_ASSOCIATE EINFO_SRP_LOGIN_REJ ( \
- SRP_LOGIN_REJ_REASON_CANNOT_ASSOCIATE, \
- "Unable to associate RDMA channel with specified I_T nexus" )
-#define EPERM_UNSUPPORTED_BUFFER_FORMAT \
- __einfo_error ( EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT )
-#define EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT EINFO_SRP_LOGIN_REJ ( \
- SRP_LOGIN_REJ_REASON_UNSUPPORTED_BUFFER_FORMAT, \
- "One or more requested data buffer descriptor formats not supported" )
-#define EPERM_NO_MULTIPLE_CHANNELS \
- __einfo_error ( EINFO_EPERM_NO_MULTIPLE_CHANNELS )
-#define EINFO_EPERM_NO_MULTIPLE_CHANNELS EINFO_SRP_LOGIN_REJ ( \
- SRP_LOGIN_REJ_REASON_NO_MULTIPLE_CHANNELS, \
- "SRP target does not support multiple RDMA channels per I_T nexus" )
-#define EPERM_NO_MORE_CHANNELS \
- __einfo_error ( EINFO_EPERM_NO_MORE_CHANNELS )
-#define EINFO_EPERM_NO_MORE_CHANNELS EINFO_SRP_LOGIN_REJ ( \
- SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS, \
- "RDMA channel limit reached for this initiator" )
-#define EPERM_LOGIN_REJ( reason_nibble ) \
- EUNIQ ( EINFO_EPERM, (reason_nibble), EPERM_UNKNOWN, \
- EPERM_INSUFFICIENT_RESOURCES, EPERM_BAD_MAX_I_T_IU_LEN, \
- EPERM_CANNOT_ASSOCIATE, EPERM_UNSUPPORTED_BUFFER_FORMAT, \
- EPERM_NO_MULTIPLE_CHANNELS, EPERM_NO_MORE_CHANNELS )
-
-/** An SRP device */
-struct srp_device {
- /** Reference count */
- struct refcnt refcnt;
-
- /** SCSI command issuing interface */
- struct interface scsi;
- /** Underlying data transfer interface */
- struct interface socket;
-
- /** RDMA memory handle */
- uint32_t memory_handle;
- /** Login completed successfully */
- int logged_in;
-
- /** Initiator port ID (for boot firmware table) */
- union srp_port_id initiator;
- /** Target port ID (for boot firmware table) */
- union srp_port_id target;
- /** SCSI LUN (for boot firmware table) */
- struct scsi_lun lun;
-
- /** List of active commands */
- struct list_head commands;
-};
-
-/** An SRP command */
-struct srp_command {
- /** Reference count */
- struct refcnt refcnt;
- /** SRP device */
- struct srp_device *srpdev;
- /** List of active commands */
- struct list_head list;
-
- /** SCSI command interface */
- struct interface scsi;
- /** Command tag */
- uint32_t tag;
-};
-
-/**
- * Get reference to SRP device
- *
- * @v srpdev SRP device
- * @ret srpdev SRP device
- */
-static inline __attribute__ (( always_inline )) struct srp_device *
-srpdev_get ( struct srp_device *srpdev ) {
- ref_get ( &srpdev->refcnt );
- return srpdev;
-}
-
-/**
- * Drop reference to SRP device
- *
- * @v srpdev SRP device
- */
-static inline __attribute__ (( always_inline )) void
-srpdev_put ( struct srp_device *srpdev ) {
- ref_put ( &srpdev->refcnt );
-}
-
-/**
- * Get reference to SRP command
- *
- * @v srpcmd SRP command
- * @ret srpcmd SRP command
- */
-static inline __attribute__ (( always_inline )) struct srp_command *
-srpcmd_get ( struct srp_command *srpcmd ) {
- ref_get ( &srpcmd->refcnt );
- return srpcmd;
-}
-
-/**
- * Drop reference to SRP command
- *
- * @v srpcmd SRP command
- */
-static inline __attribute__ (( always_inline )) void
-srpcmd_put ( struct srp_command *srpcmd ) {
- ref_put ( &srpcmd->refcnt );
-}
-
-/**
- * Free SRP command
- *
- * @v refcnt Reference count
- */
-static void srpcmd_free ( struct refcnt *refcnt ) {
- struct srp_command *srpcmd =
- container_of ( refcnt, struct srp_command, refcnt );
-
- assert ( list_empty ( &srpcmd->list ) );
-
- srpdev_put ( srpcmd->srpdev );
- free ( srpcmd );
-}
-
-/**
- * Close SRP command
- *
- * @v srpcmd SRP command
- * @v rc Reason for close
- */
-static void srpcmd_close ( struct srp_command *srpcmd, int rc ) {
- struct srp_device *srpdev = srpcmd->srpdev;
-
- if ( rc != 0 ) {
- DBGC ( srpdev, "SRP %p tag %08x closed: %s\n",
- srpdev, srpcmd->tag, strerror ( rc ) );
- }
-
- /* Remove from list of commands */
- if ( ! list_empty ( &srpcmd->list ) ) {
- list_del ( &srpcmd->list );
- INIT_LIST_HEAD ( &srpcmd->list );
- srpcmd_put ( srpcmd );
- }
-
- /* Shut down interfaces */
- intf_shutdown ( &srpcmd->scsi, rc );
-}
-
-/**
- * Close SRP device
- *
- * @v srpdev SRP device
- * @v rc Reason for close
- */
-static void srpdev_close ( struct srp_device *srpdev, int rc ) {
- struct srp_command *srpcmd;
- struct srp_command *tmp;
-
- if ( rc != 0 ) {
- DBGC ( srpdev, "SRP %p closed: %s\n",
- srpdev, strerror ( rc ) );
- }
-
- /* Shut down interfaces */
- intf_shutdown ( &srpdev->socket, rc );
- intf_shutdown ( &srpdev->scsi, rc );
-
- /* Shut down any active commands */
- list_for_each_entry_safe ( srpcmd, tmp, &srpdev->commands, list ) {
- srpcmd_get ( srpcmd );
- srpcmd_close ( srpcmd, rc );
- srpcmd_put ( srpcmd );
- }
-}
-
-/**
- * Identify SRP command by tag
- *
- * @v srpdev SRP device
- * @v tag Command tag
- * @ret srpcmd SRP command, or NULL
- */
-static struct srp_command * srp_find_tag ( struct srp_device *srpdev,
- uint32_t tag ) {
- struct srp_command *srpcmd;
-
- list_for_each_entry ( srpcmd, &srpdev->commands, list ) {
- if ( srpcmd->tag == tag )
- return srpcmd;
- }
- return NULL;
-}
-
-/**
- * Choose an SRP command tag
- *
- * @v srpdev SRP device
- * @ret tag New tag, or negative error
- */
-static int srp_new_tag ( struct srp_device *srpdev ) {
- static uint16_t tag_idx;
- unsigned int i;
-
- for ( i = 0 ; i < 65536 ; i++ ) {
- tag_idx++;
- if ( srp_find_tag ( srpdev, tag_idx ) == NULL )
- return tag_idx;
- }
- return -EADDRINUSE;
-}
-
-/**
- * Transmit SRP login request
- *
- * @v srpdev SRP device
- * @v initiator Initiator port ID
- * @v target Target port ID
- * @v tag Command tag
- * @ret rc Return status code
- */
-static int srp_login ( struct srp_device *srpdev, union srp_port_id *initiator,
- union srp_port_id *target, uint32_t tag ) {
- struct io_buffer *iobuf;
- struct srp_login_req *login_req;
- int rc;
-
- /* Allocate I/O buffer */
- iobuf = xfer_alloc_iob ( &srpdev->socket, sizeof ( *login_req ) );
- if ( ! iobuf )
- return -ENOMEM;
-
- /* Construct login request IU */
- login_req = iob_put ( iobuf, sizeof ( *login_req ) );
- memset ( login_req, 0, sizeof ( *login_req ) );
- login_req->type = SRP_LOGIN_REQ;
- login_req->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
- login_req->tag.dwords[1] = htonl ( tag );
- login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
- login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
- memcpy ( &login_req->initiator, initiator,
- sizeof ( login_req->initiator ) );
- memcpy ( &login_req->target, target, sizeof ( login_req->target ) );
-
- DBGC ( srpdev, "SRP %p tag %08x LOGIN_REQ:\n", srpdev, tag );
- DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
-
- /* Send login request IU */
- if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
- DBGC ( srpdev, "SRP %p tag %08x could not send LOGIN_REQ: "
- "%s\n", srpdev, tag, strerror ( rc ) );
- return rc;
- }
-
- return 0;
-}
-
-/**
- * Receive SRP login response
- *
- * @v srpdev SRP device
- * @v data SRP IU
- * @v len Length of SRP IU
- * @ret rc Return status code
- */
-static int srp_login_rsp ( struct srp_device *srpdev,
- const void *data, size_t len ) {
- const struct srp_login_rsp *login_rsp = data;
-
- /* Sanity check */
- if ( len < sizeof ( *login_rsp ) ) {
- DBGC ( srpdev, "SRP %p LOGIN_RSP too short (%zd bytes)\n",
- srpdev, len );
- return -EINVAL;
- }
- DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n",
- srpdev, ntohl ( login_rsp->tag.dwords[1] ) );
- DBGC_HDA ( srpdev, 0, data, len );
-
- /* Mark as logged in */
- srpdev->logged_in = 1;
- DBGC ( srpdev, "SRP %p logged in\n", srpdev );
-
- /* Notify of window change */
- xfer_window_changed ( &srpdev->scsi );
-
- return 0;
-}
-
-/**
- * Receive SRP login rejection
- *
- * @v srpdev SRP device
- * @v data SRP IU
- * @v len Length of SRP IU
- * @ret rc Return status code
- */
-static int srp_login_rej ( struct srp_device *srpdev,
- const void *data, size_t len ) {
- const struct srp_login_rej *login_rej = data;
- uint32_t reason;
-
- /* Sanity check */
- if ( len < sizeof ( *login_rej ) ) {
- DBGC ( srpdev, "SRP %p LOGIN_REJ too short (%zd bytes)\n",
- srpdev, len );
- return -EINVAL;
- }
- reason = ntohl ( login_rej->reason );
- DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n",
- srpdev, ntohl ( login_rej->tag.dwords[1] ), reason );
- DBGC_HDA ( srpdev, 0, data, len );
-
- /* Login rejection always indicates an error */
- return ( SRP_LOGIN_REJ_REASON_DEFINED ( reason ) ?
- -EPERM_LOGIN_REJ ( reason ) : -EACCES );
-}
-
-/**
- * Transmit SRP SCSI command
- *
- * @v srpdev SRP device
- * @v command SCSI command
- * @v tag Command tag
- * @ret rc Return status code
- */
-static int srp_cmd ( struct srp_device *srpdev,
- struct scsi_cmd *command,
- uint32_t tag ) {
- struct io_buffer *iobuf;
- struct srp_cmd *cmd;
- struct srp_memory_descriptor *data_out;
- struct srp_memory_descriptor *data_in;
- int rc;
-
- /* Sanity check */
- if ( ! srpdev->logged_in ) {
- DBGC ( srpdev, "SRP %p tag %08x cannot send CMD before "
- "login completes\n", srpdev, tag );
- return -EBUSY;
- }
-
- /* Allocate I/O buffer */
- iobuf = xfer_alloc_iob ( &srpdev->socket, SRP_MAX_I_T_IU_LEN );
- if ( ! iobuf )
- return -ENOMEM;
-
- /* Construct base portion */
- cmd = iob_put ( iobuf, sizeof ( *cmd ) );
- memset ( cmd, 0, sizeof ( *cmd ) );
- cmd->type = SRP_CMD;
- cmd->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
- cmd->tag.dwords[1] = htonl ( tag );
- memcpy ( &cmd->lun, &command->lun, sizeof ( cmd->lun ) );
- memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) );
-
- /* Construct data-out descriptor, if present */
- if ( command->data_out ) {
- cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
- data_out = iob_put ( iobuf, sizeof ( *data_out ) );
- data_out->address =
- cpu_to_be64 ( user_to_phys ( command->data_out, 0 ) );
- data_out->handle = ntohl ( srpdev->memory_handle );
- data_out->len = ntohl ( command->data_out_len );
- }
-
- /* Construct data-in descriptor, if present */
- if ( command->data_in ) {
- cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
- data_in = iob_put ( iobuf, sizeof ( *data_in ) );
- data_in->address =
- cpu_to_be64 ( user_to_phys ( command->data_in, 0 ) );
- data_in->handle = ntohl ( srpdev->memory_handle );
- data_in->len = ntohl ( command->data_in_len );
- }
-
- DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n",
- srpdev, tag, SCSI_CDB_DATA ( cmd->cdb ) );
-
- /* Send IU */
- if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
- DBGC ( srpdev, "SRP %p tag %08x could not send CMD: %s\n",
- srpdev, tag, strerror ( rc ) );
- return rc;
- }
-
- return 0;
-}
-
-/**
- * Receive SRP SCSI response
- *
- * @v srpdev SRP device
- * @v data SRP IU
- * @v len Length of SRP IU
- * @ret rc Returns status code
- */
-static int srp_rsp ( struct srp_device *srpdev,
- const void *data, size_t len ) {
- const struct srp_rsp *rsp = data;
- struct srp_command *srpcmd;
- struct scsi_rsp response;
- ssize_t data_out_residual_count;
- ssize_t data_in_residual_count;
-
- /* Sanity check */
- if ( ( len < sizeof ( *rsp ) ) ||
- ( len < ( sizeof ( *rsp ) +
- srp_rsp_response_data_len ( rsp ) +
- srp_rsp_sense_data_len ( rsp ) ) ) ) {
- DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
- srpdev, len );
- return -EINVAL;
- }
- DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires "
- "%08x valid %02x%s%s%s%s%s%s\n",
- srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status,
- ntohl ( rsp->data_out_residual_count ),
- ntohl ( rsp->data_in_residual_count ), rsp->valid,
- ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ),
- ( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ),
- ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ),
- ( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ),
- ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ),
- ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) );
-
- /* Identify command by tag */
- srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) );
- if ( ! srpcmd ) {
- DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n",
- srpdev, ntohl ( rsp->tag.dwords[1] ) );
- return -ENOENT;
- }
-
- /* Hold command reference for remainder of function */
- srpcmd_get ( srpcmd );
-
- /* Build SCSI response */
- memset ( &response, 0, sizeof ( response ) );
- response.status = rsp->status;
- data_out_residual_count = ntohl ( rsp->data_out_residual_count );
- data_in_residual_count = ntohl ( rsp->data_in_residual_count );
- if ( rsp->valid & SRP_RSP_VALID_DOOVER ) {
- response.overrun = data_out_residual_count;
- } else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) {
- response.overrun = -(data_out_residual_count);
- } else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) {
- response.overrun = data_in_residual_count;
- } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
- response.overrun = -(data_in_residual_count);
- }
- scsi_parse_sense ( srp_rsp_sense_data ( rsp ),
- srp_rsp_sense_data_len ( rsp ), &response.sense );
-
- /* Report SCSI response */
- scsi_response ( &srpcmd->scsi, &response );
-
- /* Close SCSI command */
- srpcmd_close ( srpcmd, 0 );
-
- /* Drop temporary command reference */
- srpcmd_put ( srpcmd );
-
- return 0;
-}
-
-/**
- * Receive SRP unrecognised response IU
- *
- * @v srpdev SRP device
- * @v data SRP IU
- * @v len Length of SRP IU
- * @ret rc Returns status code
- */
-static int srp_unrecognised ( struct srp_device *srpdev,
- const void *data, size_t len ) {
- const struct srp_common *common = data;
-
- DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n",
- srpdev, ntohl ( common->tag.dwords[1] ), common->type );
- DBGC_HDA ( srpdev, 0, data, len );
-
- return -ENOTSUP;
-}
-
-/** SRP command SCSI interface operations */
-static struct interface_operation srpcmd_scsi_op[] = {
- INTF_OP ( intf_close, struct srp_command *, srpcmd_close ),
-};
-
-/** SRP command SCSI interface descriptor */
-static struct interface_descriptor srpcmd_scsi_desc =
- INTF_DESC ( struct srp_command, scsi, srpcmd_scsi_op );
-
-/**
- * Issue SRP SCSI command
- *
- * @v srpdev SRP device
- * @v parent Parent interface
- * @v command SCSI command
- * @ret tag Command tag, or negative error
- */
-static int srpdev_scsi_command ( struct srp_device *srpdev,
- struct interface *parent,
- struct scsi_cmd *command ) {
- struct srp_command *srpcmd;
- int tag;
- int rc;
-
- /* Allocate command tag */
- tag = srp_new_tag ( srpdev );
- if ( tag < 0 ) {
- rc = tag;
- goto err_tag;
- }
-
- /* Allocate and initialise structure */
- srpcmd = zalloc ( sizeof ( *srpcmd ) );
- if ( ! srpcmd ) {
- rc = -ENOMEM;
- goto err_zalloc;
- }
- ref_init ( &srpcmd->refcnt, srpcmd_free );
- intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt );
- srpcmd->srpdev = srpdev_get ( srpdev );
- list_add ( &srpcmd->list, &srpdev->commands );
- srpcmd->tag = tag;
-
- /* Send command IU */
- if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 )
- goto err_cmd;
-
- /* Attach to parent interface, leave reference with command
- * list, and return.
- */
- intf_plug_plug ( &srpcmd->scsi, parent );
- return srpcmd->tag;
-
- err_cmd:
- srpcmd_close ( srpcmd, rc );
- err_zalloc:
- err_tag:
- return rc;
-}
-
-/**
- * Receive data from SRP socket
- *
- * @v srpdev SRP device
- * @v iobuf Datagram I/O buffer
- * @v meta Data transfer metadata
- * @ret rc Return status code
- */
-static int srpdev_deliver ( struct srp_device *srpdev,
- struct io_buffer *iobuf,
- struct xfer_metadata *meta __unused ) {
- struct srp_common *common = iobuf->data;
- int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
- int rc;
-
- /* Sanity check */
- if ( iob_len ( iobuf ) < sizeof ( *common ) ) {
- DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n",
- srpdev, iob_len ( iobuf ) );
- rc = -EINVAL;
- goto err;
- }
-
- /* Determine IU type */
- switch ( common->type ) {
- case SRP_LOGIN_RSP:
- type = srp_login_rsp;
- break;
- case SRP_LOGIN_REJ:
- type = srp_login_rej;
- break;
- case SRP_RSP:
- type = srp_rsp;
- break;
- default:
- type = srp_unrecognised;
- break;
- }
-
- /* Handle IU */
- if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 )
- goto err;
-
- free_iob ( iobuf );
- return 0;
-
- err:
- DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n",
- srpdev, strerror ( rc ) );
- DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
- free_iob ( iobuf );
- srpdev_close ( srpdev, rc );
- return rc;
-}
-
-/**
- * Check SRP device flow-control window
- *
- * @v srpdev SRP device
- * @ret len Length of window
- */
-static size_t srpdev_window ( struct srp_device *srpdev ) {
- return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
-}
-
-/**
- * A (transport-independent) sBFT created by iPXE
- */
-struct ipxe_sbft {
- /** The table header */
- struct sbft_table table;
- /** The SCSI subtable */
- struct sbft_scsi_subtable scsi;
- /** The SRP subtable */
- struct sbft_srp_subtable srp;
-} __attribute__ (( packed, aligned ( 16 ) ));
-
-/**
- * Describe SRP device in an ACPI table
- *
- * @v srpdev SRP device
- * @v acpi ACPI table
- * @v len Length of ACPI table
- * @ret rc Return status code
- */
-static int srpdev_describe ( struct srp_device *srpdev,
- struct acpi_description_header *acpi,
- size_t len ) {
- struct ipxe_sbft *sbft =
- container_of ( acpi, struct ipxe_sbft, table.acpi );
- int rc;
-
- /* Sanity check */
- if ( len < sizeof ( *sbft ) )
- return -ENOBUFS;
-
- /* Populate table */
- sbft->table.acpi.signature = cpu_to_le32 ( SBFT_SIG );
- sbft->table.acpi.length = cpu_to_le32 ( sizeof ( *sbft ) );
- sbft->table.acpi.revision = 1;
- sbft->table.scsi_offset =
- cpu_to_le16 ( offsetof ( typeof ( *sbft ), scsi ) );
- memcpy ( &sbft->scsi.lun, &srpdev->lun, sizeof ( sbft->scsi.lun ) );
- sbft->table.srp_offset =
- cpu_to_le16 ( offsetof ( typeof ( *sbft ), srp ) );
- memcpy ( &sbft->srp.initiator, &srpdev->initiator,
- sizeof ( sbft->srp.initiator ) );
- memcpy ( &sbft->srp.target, &srpdev->target,
- sizeof ( sbft->srp.target ) );
-
- /* Ask transport layer to describe transport-specific portions */
- if ( ( rc = acpi_describe ( &srpdev->socket, acpi, len ) ) != 0 ) {
- DBGC ( srpdev, "SRP %p cannot describe transport layer: %s\n",
- srpdev, strerror ( rc ) );
- return rc;
- }
-
- return 0;
-}
-
-/** SRP device socket interface operations */
-static struct interface_operation srpdev_socket_op[] = {
- INTF_OP ( xfer_deliver, struct srp_device *, srpdev_deliver ),
- INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
-};
-
-/** SRP device socket interface descriptor */
-static struct interface_descriptor srpdev_socket_desc =
- INTF_DESC_PASSTHRU ( struct srp_device, socket, srpdev_socket_op,
- scsi );
-
-/** SRP device SCSI interface operations */
-static struct interface_operation srpdev_scsi_op[] = {
- INTF_OP ( scsi_command, struct srp_device *, srpdev_scsi_command ),
- INTF_OP ( xfer_window, struct srp_device *, srpdev_window ),
- INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
- INTF_OP ( acpi_describe, struct srp_device *, srpdev_describe ),
-};
-
-/** SRP device SCSI interface descriptor */
-static struct interface_descriptor srpdev_scsi_desc =
- INTF_DESC_PASSTHRU ( struct srp_device, scsi, srpdev_scsi_op, socket );
-
-/**
- * Open SRP device
- *
- * @v block Block control interface
- * @v socket Socket interface
- * @v initiator Initiator port ID
- * @v target Target port ID
- * @v memory_handle RDMA memory handle
- * @v lun SCSI LUN
- * @ret rc Return status code
- */
-int srp_open ( struct interface *block, struct interface *socket,
- union srp_port_id *initiator, union srp_port_id *target,
- uint32_t memory_handle, struct scsi_lun *lun ) {
- struct srp_device *srpdev;
- int tag;
- int rc;
-
- /* Allocate and initialise structure */
- srpdev = zalloc ( sizeof ( *srpdev ) );
- if ( ! srpdev ) {
- rc = -ENOMEM;
- goto err_zalloc;
- }
- ref_init ( &srpdev->refcnt, NULL );
- intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt );
- intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt );
- INIT_LIST_HEAD ( &srpdev->commands );
- srpdev->memory_handle = memory_handle;
- DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev,
- ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ),
- ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ),
- ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
- ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );
-
- /* Preserve parameters required for boot firmware table */
- memcpy ( &srpdev->initiator, initiator, sizeof ( srpdev->initiator ) );
- memcpy ( &srpdev->target, target, sizeof ( srpdev->target ) );
- memcpy ( &srpdev->lun, lun, sizeof ( srpdev->lun ) );
-
- /* Attach to socket interface and initiate login */
- intf_plug_plug ( &srpdev->socket, socket );
- tag = srp_new_tag ( srpdev );
- assert ( tag >= 0 ); /* Cannot fail when no commands in progress */
- if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 )
- goto err_login;
-
- /* Attach SCSI device to parent interface */
- if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) {
- DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n",
- srpdev, strerror ( rc ) );
- goto err_scsi_open;
- }
-
- /* Mortalise self and return */
- ref_put ( &srpdev->refcnt );
- return 0;
-
- err_scsi_open:
- err_login:
- srpdev_close ( srpdev, rc );
- ref_put ( &srpdev->refcnt );
- err_zalloc:
- return rc;
-}