From bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 Mon Sep 17 00:00:00 2001 From: RajithaY Date: Tue, 25 Apr 2017 03:31:15 -0700 Subject: 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 --- qemu/roms/ipxe/src/drivers/block/ata.c | 683 --------------------- qemu/roms/ipxe/src/drivers/block/ibft.c | 497 --------------- qemu/roms/ipxe/src/drivers/block/scsi.c | 1003 ------------------------------- qemu/roms/ipxe/src/drivers/block/srp.c | 829 ------------------------- 4 files changed, 3012 deletions(-) delete mode 100644 qemu/roms/ipxe/src/drivers/block/ata.c delete mode 100644 qemu/roms/ipxe/src/drivers/block/ibft.c delete mode 100644 qemu/roms/ipxe/src/drivers/block/scsi.c delete mode 100644 qemu/roms/ipxe/src/drivers/block/srp.c (limited to 'qemu/roms/ipxe/src/drivers/block') 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 . - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** @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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** @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 "") - */ -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 = \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 = \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 . - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** @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 . - * 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 -#include -#include -#include -#include -#include -#include - -/** - * @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; -} -- cgit 1.2.3-korg