iPXE
Data Structures | Defines | Functions | Variables
sanboot.c File Reference

SAN booting. More...

#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/xfer.h>
#include <ipxe/open.h>
#include <ipxe/timer.h>
#include <ipxe/process.h>
#include <ipxe/iso9660.h>
#include <ipxe/dhcp.h>
#include <ipxe/settings.h>
#include <ipxe/quiesce.h>
#include <ipxe/sanboot.h>

Go to the source code of this file.

Data Structures

struct  san_command_rw_params
 SAN device read/write command parameters. More...
union  san_command_params
 SAN device command parameters. More...

Defines

#define SAN_DEFAULT_DRIVE   0x80
 Default SAN drive number.
#define SAN_COMMAND_TIMEOUT   ( 15 * TICKS_PER_SEC )
 Timeout for block device commands (in ticks)
#define SAN_DEFAULT_RETRIES   10
 Default number of times to retry commands.
#define SAN_REOPEN_DELAY_SECS   5
 Delay between reopening attempts.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 LIST_HEAD (san_devices)
 List of SAN devices.
struct san_devicesandev_find (unsigned int drive)
 Find SAN device by drive number.
static void sandev_free (struct refcnt *refcnt)
 Free SAN device.
static void sandev_command_close (struct san_device *sandev, int rc)
 Close SAN device command.
static void sandev_command_capacity (struct san_device *sandev, struct block_device_capacity *capacity)
 Record SAN device capacity.
static void sandev_command_expired (struct retry_timer *timer, int over __unused)
 Handle SAN device command timeout.
static int sanpath_open (struct san_path *sanpath)
 Open SAN path.
static void sanpath_close (struct san_path *sanpath, int rc)
 Close SAN path.
static void sanpath_block_close (struct san_path *sanpath, int rc)
 Handle closure of underlying block device interface.
static size_t sanpath_block_window (struct san_path *sanpath __unused)
 Check flow control window.
static void sanpath_step (struct san_path *sanpath)
 SAN path process.
static void sandev_restart (struct san_device *sandev, int rc)
 Restart SAN device interface.
int sandev_reopen (struct san_device *sandev)
 (Re)open SAN device
static int sandev_command_rw (struct san_device *sandev, const union san_command_params *params)
 Initiate SAN device read/write command.
static int sandev_command_read_capacity (struct san_device *sandev, const union san_command_params *params __unused)
 Initiate SAN device read capacity command.
static int sandev_command (struct san_device *sandev, int(*command)(struct san_device *sandev, const union san_command_params *params), const union san_command_params *params)
 Execute a single SAN device command and wait for completion.
int sandev_reset (struct san_device *sandev)
 Reset SAN device.
static int sandev_rw (struct san_device *sandev, uint64_t lba, unsigned int count, userptr_t buffer, int(*block_rw)(struct interface *control, struct interface *data, uint64_t lba, unsigned int count, userptr_t buffer, size_t len))
 Read from or write to SAN device.
int sandev_read (struct san_device *sandev, uint64_t lba, unsigned int count, userptr_t buffer)
 Read from SAN device.
int sandev_write (struct san_device *sandev, uint64_t lba, unsigned int count, userptr_t buffer)
 Write to SAN device.
static int sandev_describe (struct san_device *sandev)
 Describe SAN device.
static void sandev_undescribe (struct san_device *sandev)
 Remove SAN device descriptors.
static int sandev_parse_iso9660 (struct san_device *sandev)
 Configure SAN device as a CD-ROM, if applicable.
struct san_devicealloc_sandev (struct uri **uris, unsigned int count, size_t priv_size)
 Allocate SAN device.
int register_sandev (struct san_device *sandev, unsigned int drive, unsigned int flags)
 Register SAN device.
void unregister_sandev (struct san_device *sandev)
 Unregister SAN device.
struct setting san_drive_setting __setting (SETTING_SANBOOT_EXTRA, san-drive)
 The "san-drive" setting.
unsigned int san_default_drive (void)
 Get default SAN drive number.
static int sandev_apply (void)
 Apply SAN boot settings.

Variables

static unsigned long san_retries = SAN_DEFAULT_RETRIES
 Number of times to retry commands.
static struct interface_operation sandev_command_op []
 SAN device command interface operations.
static struct interface_descriptor sandev_command_desc
 SAN device command interface descriptor.
static struct interface_operation sanpath_block_op []
 SAN path block interface operations.
static struct interface_descriptor sanpath_block_desc
 SAN path block interface descriptor.
static struct process_descriptor sanpath_process_desc
 SAN path process descriptor.
struct settings_applicator
sandev_applicator 
__settings_applicator
 Settings applicator.

Detailed Description

SAN booting.

Definition in file sanboot.c.


Define Documentation

#define SAN_DEFAULT_DRIVE   0x80

Default SAN drive number.

The drive number is a meaningful concept only in a BIOS environment, where it represents the INT13 drive number (0x80 for the first hard disk). We retain it in other environments to allow for a simple way for iPXE commands to refer to SAN drives.

Definition at line 55 of file sanboot.c.

Referenced by san_default_drive().

#define SAN_COMMAND_TIMEOUT   ( 15 * TICKS_PER_SEC )

Timeout for block device commands (in ticks)

Underlying devices should ideally never become totally stuck. However, if they do, then the blocking SAN APIs provide no means for the caller to cancel the operation, and the machine appears to hang. Use an overall timeout for all commands to avoid this problem and bounce timeout failures to the caller.

Definition at line 66 of file sanboot.c.

Referenced by sandev_command().

#define SAN_DEFAULT_RETRIES   10

Default number of times to retry commands.

We may need to retry commands. For example, the underlying connection may be closed by the SAN target due to an inactivity timeout, or the SAN target may return pointless "error" messages such as "SCSI power-on occurred".

Definition at line 76 of file sanboot.c.

Referenced by sandev_apply().

#define SAN_REOPEN_DELAY_SECS   5

Delay between reopening attempts.

Some SAN targets will always accept connections instantly and report a temporary unavailability by e.g. failing the TEST UNIT READY command. Avoid bombarding such targets by introducing a small delay between attempts.

Definition at line 86 of file sanboot.c.

Referenced by sandev_command().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

List of SAN devices.

struct san_device* sandev_find ( unsigned int  drive) [read]

Find SAN device by drive number.

Parameters:
driveDrive number
Return values:
sandevSAN device, or NULL

Definition at line 100 of file sanboot.c.

References san_device::drive, san_device::list, list_for_each_entry, NULL, and san_devices.

Referenced by dummy_san_unhook(), efi_block_boot(), efi_block_unhook(), int13_unhook(), and register_sandev().

                                                       {
        struct san_device *sandev;

        list_for_each_entry ( sandev, &san_devices, list ) {
                if ( sandev->drive == drive )
                        return sandev;
        }
        return NULL;
}
static void sandev_free ( struct refcnt refcnt) [static]

Free SAN device.

Parameters:
refcntReference count

Definition at line 115 of file sanboot.c.

References san_device::active, assert, container_of, san_path::desc, free, list_empty, NULL, san_device::opened, san_device::path, san_device::paths, san_device::timer, san_path::uri, and uri_put().

Referenced by alloc_sandev().

                                                  {
        struct san_device *sandev =
                container_of ( refcnt, struct san_device, refcnt );
        unsigned int i;

        assert ( ! timer_running ( &sandev->timer ) );
        assert ( ! sandev->active );
        assert ( list_empty ( &sandev->opened ) );
        for ( i = 0 ; i < sandev->paths ; i++ ) {
                uri_put ( sandev->path[i].uri );
                assert ( sandev->path[i].desc == NULL );
        }
        free ( sandev );
}
static void sandev_command_close ( struct san_device sandev,
int  rc 
) [static]

Close SAN device command.

Parameters:
sandevSAN device
rcReason for close

Definition at line 136 of file sanboot.c.

References san_device::command, san_device::command_rc, intf_restart(), rc, stop_timer(), and san_device::timer.

Referenced by sandev_command_expired(), sandev_restart(), and sanpath_close().

                                                                       {

        /* Stop timer */
        stop_timer ( &sandev->timer );

        /* Restart interface */
        intf_restart ( &sandev->command, rc );

        /* Record command status */
        sandev->command_rc = rc;
}
static void sandev_command_capacity ( struct san_device sandev,
struct block_device_capacity capacity 
) [static]

Record SAN device capacity.

Parameters:
sandevSAN device
capacitySAN device capacity

Definition at line 154 of file sanboot.c.

References san_device::capacity, and memcpy().

                                                                               {

        /* Record raw capacity information */
        memcpy ( &sandev->capacity, capacity, sizeof ( sandev->capacity ) );
}
static void sandev_command_expired ( struct retry_timer timer,
int over  __unused 
) [static]

Handle SAN device command timeout.

Parameters:
retryRetry timer

Definition at line 177 of file sanboot.c.

References container_of, ETIMEDOUT, and sandev_command_close().

Referenced by alloc_sandev().

                                                         {
        struct san_device *sandev =
                container_of ( timer, struct san_device, timer );

        sandev_command_close ( sandev, -ETIMEDOUT );
}
static int sanpath_open ( struct san_path sanpath) [static]

Open SAN path.

Parameters:
sanpathSAN path
Return values:
rcReturn status code

Definition at line 191 of file sanboot.c.

References acpi_add(), acpi_del(), acpi_describe(), san_path::block, san_device::closed, DBGC, san_path::desc, san_device::drive, EINPROGRESS, san_device::flags, san_path::index, san_path::list, san_device::list, list_add_tail, list_check_contains_entry, list_del, san_device::opened, san_path::path_rc, san_path::process, process_add(), rc, SAN_NO_DESCRIBE, san_path::sandev, strerror(), san_path::uri, and xfer_open_uri().

Referenced by sandev_reopen().

                                                     {
        struct san_device *sandev = sanpath->sandev;
        int rc;

        /* Sanity check */
        list_check_contains_entry ( sanpath, &sandev->closed, list );

        /* Open interface */
        if ( ( rc = xfer_open_uri ( &sanpath->block, sanpath->uri ) ) != 0 ) {
                DBGC ( sandev, "SAN %#02x.%d could not (re)open URI: "
                       "%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
                return rc;
        }

        /* Update ACPI descriptor, if applicable */
        if ( ! ( sandev->flags & SAN_NO_DESCRIBE ) ) {
                if ( sanpath->desc )
                        acpi_del ( sanpath->desc );
                sanpath->desc = acpi_describe ( &sanpath->block );
                if ( sanpath->desc )
                        acpi_add ( sanpath->desc );
        }

        /* Start process */
        process_add ( &sanpath->process );

        /* Mark as opened */
        list_del ( &sanpath->list );
        list_add_tail ( &sanpath->list, &sandev->opened );

        /* Record as in progress */
        sanpath->path_rc = -EINPROGRESS;

        return 0;
}
static void sanpath_close ( struct san_path sanpath,
int  rc 
) [static]

Close SAN path.

Parameters:
sanpathSAN path
rcReason for close

Definition at line 233 of file sanboot.c.

References san_device::active, san_path::block, san_device::closed, san_device::command, intf_restart(), intfs_restart(), san_path::list, list_add_tail, list_del, NULL, san_path::path_rc, san_path::process, process_del(), rc, san_path::sandev, and sandev_command_close().

Referenced by sandev_restart(), sanpath_block_close(), and sanpath_step().

                                                               {
        struct san_device *sandev = sanpath->sandev;

        /* Record status */
        sanpath->path_rc = rc;

        /* Mark as closed */
        list_del ( &sanpath->list );
        list_add_tail ( &sanpath->list, &sandev->closed );

        /* Stop process */
        process_del ( &sanpath->process );

        /* Restart interfaces, avoiding potential loops */
        if ( sanpath == sandev->active ) {
                intfs_restart ( rc, &sandev->command, &sanpath->block, NULL );
                sandev->active = NULL;
                sandev_command_close ( sandev, rc );
        } else {
                intf_restart ( &sanpath->block, rc );
        }
}
static void sanpath_block_close ( struct san_path sanpath,
int  rc 
) [static]

Handle closure of underlying block device interface.

Parameters:
sanpathSAN path
rcReason for close

Definition at line 262 of file sanboot.c.

References DBGC, san_device::drive, ENOTCONN, san_path::index, san_path::sandev, sanpath_close(), and strerror().

                                                                     {
        struct san_device *sandev = sanpath->sandev;

        /* Any closure is an error from our point of view */
        if ( rc == 0 )
                rc = -ENOTCONN;
        DBGC ( sandev, "SAN %#02x.%d closed: %s\n",
               sandev->drive, sanpath->index, strerror ( rc ) );

        /* Close path */
        sanpath_close ( sanpath, rc );
}
static size_t sanpath_block_window ( struct san_path *sanpath  __unused) [static]

Check flow control window.

Parameters:
sanpathSAN path

Definition at line 280 of file sanboot.c.

                                                                         {

        /* We are never ready to receive data via this interface.
         * This prevents objects that support both block and stream
         * interfaces from attempting to send us stream data.
         */
        return 0;
}
static void sanpath_step ( struct san_path sanpath) [static]

SAN path process.

Parameters:
sanpathSAN path

Definition at line 294 of file sanboot.c.

References san_device::active, san_path::block, DBGC, san_device::drive, san_path::index, san_path::path_rc, san_path::sandev, sanpath_close(), and xfer_window().

                                                      {
        struct san_device *sandev = sanpath->sandev;

        /* Ignore if we are already the active device */
        if ( sanpath == sandev->active )
                return;

        /* Wait until path has become available */
        if ( ! xfer_window ( &sanpath->block ) )
                return;

        /* Record status */
        sanpath->path_rc = 0;

        /* Mark as active path or close as applicable */
        if ( ! sandev->active ) {
                DBGC ( sandev, "SAN %#02x.%d is active\n",
                       sandev->drive, sanpath->index );
                sandev->active = sanpath;
        } else {
                DBGC ( sandev, "SAN %#02x.%d is available\n",
                       sandev->drive, sanpath->index );
                sanpath_close ( sanpath, 0 );
        }
}
static void sandev_restart ( struct san_device sandev,
int  rc 
) [static]

Restart SAN device interface.

Parameters:
sandevSAN device
rcReason for restart

Definition at line 341 of file sanboot.c.

References san_device::active, san_path::list, list_first_entry, NULL, san_device::opened, sandev_command_close(), and sanpath_close().

Referenced by register_sandev(), sandev_reopen(), and unregister_sandev().

                                                                 {
        struct san_path *sanpath;

        /* Restart all block device interfaces */
        while ( ( sanpath = list_first_entry ( &sandev->opened,
                                               struct san_path, list ) ) ) {
                sanpath_close ( sanpath, rc );
        }

        /* Clear active path */
        sandev->active = NULL;

        /* Close any outstanding command */
        sandev_command_close ( sandev, rc );
}
int sandev_reopen ( struct san_device sandev)

(Re)open SAN device

Parameters:
sandevSAN device
Return values:
rcReturn status code

This function will block until the device is available.

Definition at line 365 of file sanboot.c.

References san_device::active, assert, san_device::closed, DBGC, san_device::drive, ECONNRESET, ENODEV, san_path::list, list_empty, list_first_entry, list_for_each_entry, NULL, san_device::opened, san_path::path_rc, rc, sandev_restart(), sanpath_open(), step(), strerror(), and unquiesce().

Referenced by int13_device_path_info(), register_sandev(), sandev_command(), and sandev_reset().

                                                {
        struct san_path *sanpath;
        int rc;

        /* Unquiesce system */
        unquiesce();

        /* Close any outstanding command and restart interfaces */
        sandev_restart ( sandev, -ECONNRESET );
        assert ( sandev->active == NULL );
        assert ( list_empty ( &sandev->opened ) );

        /* Open all paths */
        while ( ( sanpath = list_first_entry ( &sandev->closed,
                                               struct san_path, list ) ) ) {
                if ( ( rc = sanpath_open ( sanpath ) ) != 0 )
                        goto err_open;
        }

        /* Wait for any device to become available, or for all devices
         * to fail.
         */
        while ( sandev->active == NULL ) {
                step();
                if ( list_empty ( &sandev->opened ) ) {
                        /* Get status of the first device to be
                         * closed.  Do this on the basis that earlier
                         * errors (e.g. "invalid IQN") are probably
                         * more interesting than later errors
                         * (e.g. "TCP timeout").
                         */
                        rc = -ENODEV;
                        list_for_each_entry ( sanpath, &sandev->closed, list ) {
                                rc = sanpath->path_rc;
                                break;
                        }
                        DBGC ( sandev, "SAN %#02x never became available: %s\n",
                               sandev->drive, strerror ( rc ) );
                        goto err_none;
                }
        }

        assert ( ! list_empty ( &sandev->opened ) );
        return 0;

 err_none:
 err_open:
        sandev_restart ( sandev, rc );
        return rc;
}
static int sandev_command_rw ( struct san_device sandev,
const union san_command_params params 
) [static]

Initiate SAN device read/write command.

Parameters:
sandevSAN device
paramsCommand parameters
Return values:
rcReturn status code

Definition at line 443 of file sanboot.c.

References san_device::active, assert, block_device_capacity::blksize, san_path::block, san_command_rw_params::block_rw, san_command_rw_params::buffer, san_device::capacity, san_device::command, san_command_rw_params::count, DBGC, san_device::drive, san_path::index, san_command_rw_params::lba, len, NULL, rc, san_command_params::rw, and strerror().

Referenced by sandev_rw().

                                                                        {
        struct san_path *sanpath = sandev->active;
        size_t len = ( params->rw.count * sandev->capacity.blksize );
        int rc;

        /* Sanity check */
        assert ( sanpath != NULL );

        /* Initiate read/write command */
        if ( ( rc = params->rw.block_rw ( &sanpath->block, &sandev->command,
                                          params->rw.lba, params->rw.count,
                                          params->rw.buffer, len ) ) != 0 ) {
                DBGC ( sandev, "SAN %#02x.%d could not initiate read/write: "
                       "%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int sandev_command_read_capacity ( struct san_device sandev,
const union san_command_params *params  __unused 
) [static]

Initiate SAN device read capacity command.

Parameters:
sandevSAN device
paramsCommand parameters
Return values:
rcReturn status code

Definition at line 472 of file sanboot.c.

References san_device::active, assert, san_path::block, block_read_capacity(), san_device::command, DBGC, san_device::drive, san_path::index, NULL, rc, and strerror().

Referenced by register_sandev().

                                                                               {
        struct san_path *sanpath = sandev->active;
        int rc;

        /* Sanity check */
        assert ( sanpath != NULL );

        /* Initiate read capacity command */
        if ( ( rc = block_read_capacity ( &sanpath->block,
                                          &sandev->command ) ) != 0 ) {
                DBGC ( sandev, "SAN %#02x.%d could not initiate read capacity: "
                       "%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int sandev_command ( struct san_device sandev,
int(*)(struct san_device *sandev, const union san_command_params *params)  command,
const union san_command_params params 
) [static]

Execute a single SAN device command and wait for completion.

Parameters:
sandevSAN device
commandCommand
paramsCommand parameters (if required)
Return values:
rcReturn status code

Definition at line 500 of file sanboot.c.

References assert, san_device::command_rc, san_device::paths, rc, SAN_COMMAND_TIMEOUT, SAN_REOPEN_DELAY_SECS, san_retries, sandev_needs_reopen(), sandev_reopen(), sleep_fixed(), start_timer_fixed(), step(), san_device::timer, and unquiesce().

Referenced by register_sandev(), and sandev_rw().

                                                          {
        unsigned int retries = 0;
        int rc;

        /* Sanity check */
        assert ( ! timer_running ( &sandev->timer ) );

        /* Unquiesce system */
        unquiesce();

        /* (Re)try command */
        do {

                /* Reopen block device if applicable */
                if ( sandev_needs_reopen ( sandev ) &&
                     ( ( rc = sandev_reopen ( sandev ) ) != 0 ) ) {

                        /* Delay reopening attempts */
                        sleep_fixed ( SAN_REOPEN_DELAY_SECS );

                        /* Retry opening indefinitely for multipath devices */
                        if ( sandev->paths <= 1 )
                                retries++;

                        continue;
                }

                /* Initiate command */
                if ( ( rc = command ( sandev, params ) ) != 0 ) {
                        retries++;
                        continue;
                }

                /* Start expiry timer */
                start_timer_fixed ( &sandev->timer, SAN_COMMAND_TIMEOUT );

                /* Wait for command to complete */
                while ( timer_running ( &sandev->timer ) )
                        step();

                /* Check command status */
                if ( ( rc = sandev->command_rc ) != 0 ) {
                        retries++;
                        continue;
                }

                return 0;

        } while ( retries <= san_retries );

        /* Sanity check */
        assert ( ! timer_running ( &sandev->timer ) );

        return rc;
}
int sandev_reset ( struct san_device sandev)

Reset SAN device.

Parameters:
sandevSAN device
Return values:
rcReturn status code

Definition at line 565 of file sanboot.c.

References DBGC, san_device::drive, rc, and sandev_reopen().

Referenced by efi_block_io_reset(), and int13_reset().

                                               {
        int rc;

        DBGC ( sandev, "SAN %#02x reset\n", sandev->drive );

        /* Close and reopen underlying block device */
        if ( ( rc = sandev_reopen ( sandev ) ) != 0 )
                return rc;

        return 0;
}
static int sandev_rw ( struct san_device sandev,
uint64_t  lba,
unsigned int  count,
userptr_t  buffer,
int(*)(struct interface *control, struct interface *data, uint64_t lba, unsigned int count, userptr_t buffer, size_t len block_rw 
) [static]

Read from or write to SAN device.

Parameters:
sandevSAN device
lbaStarting logical block address
countNumber of logical blocks
bufferData buffer
block_rwBlock read/write method
Return values:
rcReturn status code

Definition at line 587 of file sanboot.c.

References block_device_capacity::blksize, san_device::blksize_shift, san_command_rw_params::block_rw, buffer, san_command_rw_params::buffer, san_device::capacity, san_command_rw_params::count, san_command_rw_params::lba, block_device_capacity::max_count, rc, san_command_params::rw, sandev_command(), sandev_command_rw(), and userptr_add().

Referenced by efi_block_rw(), int13_extended_rw(), int13_rw_sectors(), sandev_read(), and sandev_write().

                                                                             {
        union san_command_params params;
        unsigned int remaining;
        size_t frag_len;
        int rc;

        /* Initialise command parameters */
        params.rw.block_rw = block_rw;
        params.rw.buffer = buffer;
        params.rw.lba = ( lba << sandev->blksize_shift );
        params.rw.count = sandev->capacity.max_count;
        remaining = ( count << sandev->blksize_shift );

        /* Read/write fragments */
        while ( remaining ) {

                /* Determine fragment length */
                if ( params.rw.count > remaining )
                        params.rw.count = remaining;

                /* Execute command */
                if ( ( rc = sandev_command ( sandev, sandev_command_rw,
                                             &params ) ) != 0 )
                        return rc;

                /* Move to next fragment */
                frag_len = ( sandev->capacity.blksize * params.rw.count );
                params.rw.buffer = userptr_add ( params.rw.buffer, frag_len );
                params.rw.lba += params.rw.count;
                remaining -= params.rw.count;
        }

        return 0;
}
int sandev_read ( struct san_device sandev,
uint64_t  lba,
unsigned int  count,
userptr_t  buffer 
)

Read from SAN device.

Parameters:
sandevSAN device
lbaStarting logical block address
countNumber of logical blocks
bufferData buffer
Return values:
rcReturn status code

Definition at line 636 of file sanboot.c.

References block_read(), rc, and sandev_rw().

Referenced by efi_block_io_read(), int13_cdrom_read_boot_catalog(), int13_extended_read(), int13_guess_geometry_hdd(), int13_parse_eltorito(), int13_read_sectors(), and sandev_parse_iso9660().

                                                         {
        int rc;

        /* Read from device */
        if ( ( rc = sandev_rw ( sandev, lba, count, buffer, block_read ) ) != 0 )
                return rc;

        return 0;
}
int sandev_write ( struct san_device sandev,
uint64_t  lba,
unsigned int  count,
userptr_t  buffer 
)

Write to SAN device.

Parameters:
sandevSAN device
lbaStarting logical block address
countNumber of logical blocks
bufferData buffer
Return values:
rcReturn status code

Definition at line 656 of file sanboot.c.

References block_write(), quiesce(), rc, and sandev_rw().

Referenced by efi_block_io_write(), int13_extended_write(), and int13_write_sectors().

                                                          {
        int rc;

        /* Write to device */
        if ( ( rc = sandev_rw ( sandev, lba, count, buffer, block_write ) ) != 0 )
                return rc;

        /* Quiesce system.  This is a heuristic designed to ensure
         * that the system is quiesced before Windows starts up, since
         * a Windows SAN boot will typically write a status flag to
         * the disk as its last action before transferring control to
         * the native drivers.
         */
        quiesce();

        return 0;
}
static int sandev_describe ( struct san_device sandev) [static]

Describe SAN device.

Parameters:
sandevSAN device
Return values:
rcReturn status code

Allow connections to progress until all existent path descriptors are complete.

Definition at line 684 of file sanboot.c.

References san_device::closed, acpi_model::complete, DBGC, san_path::desc, san_device::drive, san_path::index, acpi_descriptor::list, list_for_each_entry, acpi_descriptor::model, san_device::opened, rc, step(), and strerror().

Referenced by register_sandev().

                                                         {
        struct san_path *sanpath;
        struct acpi_descriptor *desc;
        int rc;

        /* Wait for all paths to be either described or closed */
        while ( 1 ) {

                /* Allow connections to progress */
                step();

                /* Fail if any closed path has an incomplete descriptor */
                list_for_each_entry ( sanpath, &sandev->closed, list ) {
                        desc = sanpath->desc;
                        if ( ! desc )
                                continue;
                        if ( ( rc = desc->model->complete ( desc ) ) != 0 ) {
                                DBGC ( sandev, "SAN %#02x.%d could not be "
                                       "described: %s\n", sandev->drive,
                                       sanpath->index, strerror ( rc ) );
                                return rc;
                        }
                }

                /* Succeed if no paths have an incomplete descriptor */
                rc = 0;
                list_for_each_entry ( sanpath, &sandev->opened, list ) {
                        desc = sanpath->desc;
                        if ( ! desc )
                                continue;
                        if ( ( rc = desc->model->complete ( desc ) ) != 0 )
                                break;
                }
                if ( rc == 0 )
                        return 0;
        }
}
static void sandev_undescribe ( struct san_device sandev) [static]

Remove SAN device descriptors.

Parameters:
sandevSAN device

Definition at line 727 of file sanboot.c.

References acpi_del(), san_path::desc, NULL, san_device::path, and san_device::paths.

Referenced by register_sandev(), and unregister_sandev().

                                                            {
        struct san_path *sanpath;
        unsigned int i;

        /* Remove all ACPI descriptors */
        for ( i = 0 ; i < sandev->paths ; i++ ) {
                sanpath = &sandev->path[i];
                if ( sanpath->desc ) {
                        acpi_del ( sanpath->desc );
                        sanpath->desc = NULL;
                }
        }
}
static int sandev_parse_iso9660 ( struct san_device sandev) [static]

Configure SAN device as a CD-ROM, if applicable.

Parameters:
sandevSAN device
Return values:
rcReturn status code

Both BIOS and UEFI require SAN devices to be accessed with a block size of 2048. While we could require the user to configure the block size appropriately, this is non-trivial and would impose a substantial learning effort on the user. Instead, we check for the presence of the ISO9660 primary volume descriptor and, if found, then we force a block size of 2048 and map read/write requests appropriately.

Definition at line 755 of file sanboot.c.

References block_device_capacity::blksize, blksize, san_device::blksize_shift, bytes, san_device::capacity, count, DBGC, san_device::drive, ENOMEM, free, san_device::is_cdrom, ISO9660_BLKSIZE, ISO9660_ID, ISO9660_PRIMARY_LBA, ISO9660_TYPE_PRIMARY, lba, malloc(), memcmp(), rc, sandev_read(), strerror(), iso9660_primary_descriptor_fixed::type, and virt_to_user().

Referenced by register_sandev().

                                                              {
        static const struct iso9660_primary_descriptor_fixed primary_check = {
                .type = ISO9660_TYPE_PRIMARY,
                .id = ISO9660_ID,
        };
        union {
                struct iso9660_primary_descriptor primary;
                char bytes[ISO9660_BLKSIZE];
        } *scratch;
        unsigned int blksize;
        unsigned int blksize_shift;
        unsigned int lba;
        unsigned int count;
        int rc;

        /* Calculate required blocksize shift for potential CD-ROM access */
        blksize = sandev->capacity.blksize;
        blksize_shift = 0;
        while ( blksize < ISO9660_BLKSIZE ) {
                blksize <<= 1;
                blksize_shift++;
        }
        if ( blksize > ISO9660_BLKSIZE ) {
                /* Cannot be a CD-ROM.  This is not an error. */
                rc = 0;
                goto invalid_blksize;
        }
        lba = ( ISO9660_PRIMARY_LBA << blksize_shift );
        count = ( 1 << blksize_shift );

        /* Allocate scratch area */
        scratch = malloc ( ISO9660_BLKSIZE );
        if ( ! scratch ) {
                rc = -ENOMEM;
                goto err_alloc;
        }

        /* Read primary volume descriptor */
        if ( ( rc = sandev_read ( sandev, lba, count,
                                  virt_to_user ( scratch ) ) ) != 0 ) {
                DBGC ( sandev, "SAN %#02x could not read ISO9660 primary"
                       "volume descriptor: %s\n",
                       sandev->drive, strerror ( rc ) );
                goto err_rw;
        }

        /* Configure as CD-ROM if applicable */
        if ( memcmp ( &scratch->primary.fixed, &primary_check,
                      sizeof ( primary_check ) ) == 0 ) {
                DBGC ( sandev, "SAN %#02x contains an ISO9660 filesystem; "
                       "treating as CD-ROM\n", sandev->drive );
                sandev->blksize_shift = blksize_shift;
                sandev->is_cdrom = 1;
        }

 err_rw:
        free ( scratch );
 err_alloc:
 invalid_blksize:
        return rc;
}
struct san_device* alloc_sandev ( struct uri **  uris,
unsigned int  count,
size_t  priv_size 
) [read]

Allocate SAN device.

Parameters:
urisList of URIs
countNumber of URIs
priv_sizeSize of private data
Return values:
sandevSAN device, or NULL

Definition at line 825 of file sanboot.c.

References san_path::block, san_device::closed, san_device::command, count, EINPROGRESS, san_path::index, INIT_LIST_HEAD, intf_init(), san_path::list, list_add_tail, NULL, san_device::opened, san_device::path, san_path::path_rc, san_device::paths, san_device::priv, san_path::process, process_init_stopped(), ref_init, san_device::refcnt, san_path::sandev, sandev_command_expired(), sandev_free(), size, san_device::timer, san_path::uri, uri_get(), and zalloc().

Referenced by dummy_san_hook(), efi_block_hook(), and int13_hook().

                                                      {
        struct san_device *sandev;
        struct san_path *sanpath;
        size_t size;
        unsigned int i;

        /* Allocate and initialise structure */
        size = ( sizeof ( *sandev ) + ( count * sizeof ( sandev->path[0] ) ) );
        sandev = zalloc ( size + priv_size );
        if ( ! sandev )
                return NULL;
        ref_init ( &sandev->refcnt, sandev_free );
        intf_init ( &sandev->command, &sandev_command_desc, &sandev->refcnt );
        timer_init ( &sandev->timer, sandev_command_expired, &sandev->refcnt );
        sandev->priv = ( ( ( void * ) sandev ) + size );
        sandev->paths = count;
        INIT_LIST_HEAD ( &sandev->opened );
        INIT_LIST_HEAD ( &sandev->closed );
        for ( i = 0 ; i < count ; i++ ) {
                sanpath = &sandev->path[i];
                sanpath->sandev = sandev;
                sanpath->index = i;
                sanpath->uri = uri_get ( uris[i] );
                list_add_tail ( &sanpath->list, &sandev->closed );
                intf_init ( &sanpath->block, &sanpath_block_desc,
                            &sandev->refcnt );
                process_init_stopped ( &sanpath->process, &sanpath_process_desc,
                                       &sandev->refcnt );
                sanpath->path_rc = -EINPROGRESS;
        }

        return sandev;
}
int register_sandev ( struct san_device sandev,
unsigned int  drive,
unsigned int  flags 
)

Register SAN device.

Parameters:
sandevSAN device
driveDrive number
flagsFlags
Return values:
rcReturn status code

Definition at line 868 of file sanboot.c.

References DBGC, san_device::drive, drive, EADDRINUSE, san_device::flags, flags, san_device::list, list_add_tail, list_del, NULL, rc, san_devices, sandev_command(), sandev_command_read_capacity(), sandev_describe(), sandev_find(), sandev_parse_iso9660(), sandev_reopen(), sandev_restart(), and sandev_undescribe().

Referenced by dummy_san_hook(), efi_block_hook(), and int13_hook().

                                           {
        int rc;

        /* Check that drive number is not in use */
        if ( sandev_find ( drive ) != NULL ) {
                DBGC ( sandev, "SAN %#02x is already in use\n", drive );
                rc = -EADDRINUSE;
                goto err_in_use;
        }

        /* Record drive number and flags */
        sandev->drive = drive;
        sandev->flags = flags;

        /* Check that device is capable of being opened (i.e. that all
         * URIs are well-formed and that at least one path is
         * working).
         */
        if ( ( rc = sandev_reopen ( sandev ) ) != 0 )
                goto err_reopen;

        /* Describe device */
        if ( ( rc = sandev_describe ( sandev ) ) != 0 )
                goto err_describe;

        /* Read device capacity */
        if ( ( rc = sandev_command ( sandev, sandev_command_read_capacity,
                                     NULL ) ) != 0 )
                goto err_capacity;

        /* Configure as a CD-ROM, if applicable */
        if ( ( rc = sandev_parse_iso9660 ( sandev ) ) != 0 )
                goto err_iso9660;

        /* Add to list of SAN devices */
        list_add_tail ( &sandev->list, &san_devices );
        DBGC ( sandev, "SAN %#02x registered\n", sandev->drive );

        return 0;

        list_del ( &sandev->list );
 err_iso9660:
 err_capacity:
 err_describe:
 err_reopen:
        sandev_restart ( sandev, rc );
        sandev_undescribe ( sandev );
 err_in_use:
        return rc;
}
void unregister_sandev ( struct san_device sandev)

Unregister SAN device.

Parameters:
sandevSAN device

Definition at line 925 of file sanboot.c.

References assert, DBGC, san_device::drive, san_device::list, list_del, sandev_restart(), sandev_undescribe(), and san_device::timer.

Referenced by dummy_san_hook(), dummy_san_unhook(), efi_block_hook(), efi_block_unhook(), int13_hook(), and int13_unhook().

                                                     {

        /* Sanity check */
        assert ( ! timer_running ( &sandev->timer ) );

        /* Remove from list of SAN devices */
        list_del ( &sandev->list );

        /* Shut down interfaces */
        sandev_restart ( sandev, 0 );

        /* Remove ACPI descriptors */
        sandev_undescribe ( sandev );

        DBGC ( sandev, "SAN %#02x unregistered\n", sandev->drive );
}
struct setting san_retries_setting __setting ( SETTING_SANBOOT_EXTRA  ,
san-  drive 
) [read]
Initial value:
 {
        .name = "san-retries",
        .description = "SAN retry count",
        .tag = DHCP_EB_SAN_RETRY,
        .type = &setting_type_int8,
}

The "san-drive" setting.

The "san-retries" setting.

unsigned int san_default_drive ( void  )

Get default SAN drive number.

Return values:
driveDefault drive number

Definition at line 956 of file sanboot.c.

References drive, fetch_uint_setting(), NULL, and SAN_DEFAULT_DRIVE.

Referenced by netboot(), and sanboot_core_exec().

                                        {
        unsigned long drive;

        /* Use "san-drive" setting, if specified */
        if ( fetch_uint_setting ( NULL, &san_drive_setting, &drive ) >= 0 )
                return drive;

        /* Otherwise, default to booting from first hard disk */
        return SAN_DEFAULT_DRIVE;
}
static int sandev_apply ( void  ) [static]

Apply SAN boot settings.

Return values:
rcReturn status code

Definition at line 981 of file sanboot.c.

References fetch_uint_setting(), NULL, SAN_DEFAULT_RETRIES, and san_retries.

                                 {

        /* Apply "san-retries" setting */
        if ( fetch_uint_setting ( NULL, &san_retries_setting,
                                  &san_retries ) < 0 ) {
                san_retries = SAN_DEFAULT_RETRIES;
        }

        return 0;
}

Variable Documentation

unsigned long san_retries = SAN_DEFAULT_RETRIES [static]

Number of times to retry commands.

Definition at line 92 of file sanboot.c.

Referenced by sandev_apply(), and sandev_command().

Initial value:

SAN device command interface operations.

Definition at line 162 of file sanboot.c.

Initial value:

SAN device command interface descriptor.

Definition at line 169 of file sanboot.c.

Initial value:

SAN path block interface operations.

Definition at line 321 of file sanboot.c.

Initial value:

SAN path block interface descriptor.

Definition at line 328 of file sanboot.c.

Initial value:

SAN path process descriptor.

Definition at line 332 of file sanboot.c.

struct settings_applicator sandev_applicator __settings_applicator
Initial value:
 {
        .apply = sandev_apply,
}

Settings applicator.

Definition at line 993 of file sanboot.c.