Skip to content

Commit

Permalink
[block] Allow SAN retry count to be reconfigured
Browse files Browse the repository at this point in the history
Allow the SAN retry count to be configured via the ${san-retry}
setting, defaulting to the current value of 10 retries if not
specified.

Note that setting a retry count of zero is inadvisable, since iSCSI
targets in particular will often report spurious errors such as "power
on occurred" for the first few commands.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Mar 27, 2017
1 parent 6bd0060 commit 6b385c9
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 17 deletions.
69 changes: 52 additions & 17 deletions src/core/sanboot.c
Expand Up @@ -65,18 +65,21 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define SAN_COMMAND_TIMEOUT ( 15 * TICKS_PER_SEC )

/**
* Number of times to retry commands
* 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".
*/
#define SAN_COMMAND_MAX_RETRIES 10
#define SAN_DEFAULT_RETRIES 10

/** List of SAN devices */
LIST_HEAD ( san_devices );

/** Number of times to retry commands */
static unsigned long san_retries = SAN_DEFAULT_RETRIES;

/**
* Find SAN device by drive number
*
Expand All @@ -101,13 +104,13 @@ struct san_device * sandev_find ( unsigned int drive ) {
static void sandev_free ( struct refcnt *refcnt ) {
struct san_device *sandev =
container_of ( refcnt, struct san_device, refcnt );
struct san_path *sanpath;
unsigned int i;

assert ( ! timer_running ( &sandev->timer ) );
assert ( ! sandev->active );
assert ( list_empty ( &sandev->opened ) );
list_for_each_entry ( sanpath, &sandev->closed, list )
uri_put ( sanpath->uri );
for ( i = 0 ; i < sandev->paths ; i++ )
uri_put ( sandev->path[i].uri );
free ( sandev );
}

Expand Down Expand Up @@ -469,38 +472,39 @@ sandev_command ( struct san_device *sandev,
int ( * command ) ( struct san_device *sandev,
const union san_command_params *params ),
const union san_command_params *params ) {
unsigned int retries;
unsigned int retries = 0;
int rc;

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

/* (Re)try command */
for ( retries = 0 ; retries < SAN_COMMAND_MAX_RETRIES ; retries++ ) {
do {

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

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

/* Initiate command */
if ( ( rc = command ( sandev, params ) ) != 0 ) {
stop_timer ( &sandev->timer );
if ( ( rc = command ( sandev, params ) ) != 0 )
continue;
}

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

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

/* Exit on success */
if ( ( rc = sandev->command_rc ) == 0 )
return 0;
}
/* Check command status */
if ( ( rc = sandev->command_rc ) != 0 )
continue;

return 0;

} while ( ++retries <= san_retries );

/* Sanity check */
assert ( ! timer_running ( &sandev->timer ) );
Expand Down Expand Up @@ -676,6 +680,7 @@ struct san_device * alloc_sandev ( struct uri **uris, unsigned int count,
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++ ) {
Expand Down Expand Up @@ -767,3 +772,33 @@ unsigned int san_default_drive ( void ) {
/* Otherwise, default to booting from first hard disk */
return SAN_DEFAULT_DRIVE;
}

/** The "san-retries" setting */
const struct setting san_retries_setting __setting ( SETTING_SANBOOT_EXTRA,
san-retries ) = {
.name = "san-retries",
.description = "SAN retry count",
.tag = DHCP_EB_SAN_RETRY,
.type = &setting_type_int8,
};

/**
* Apply SAN boot settings
*
* @ret rc Return status code
*/
static int sandev_apply ( void ) {

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

return 0;
}

/** Settings applicator */
struct settings_applicator sandev_applicator __settings_applicator = {
.apply = sandev_apply,
};
7 changes: 7 additions & 0 deletions src/include/ipxe/dhcp.h
Expand Up @@ -433,6 +433,13 @@ struct dhcp_netdev_desc {
/** Use cached network settings (obsolete; do not reuse this value) */
#define DHCP_EB_USE_CACHED DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb2 )

/** SAN retry count
*
* This is the maximum number of times that SAN operations will be
* retried.
*/
#define DHCP_EB_SAN_RETRY DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xbb )

/** SAN drive number
*
* This is the drive number for a SAN-hooked drive. For BIOS, 0x80 is
Expand Down
2 changes: 2 additions & 0 deletions src/include/ipxe/sanboot.h
Expand Up @@ -71,6 +71,8 @@ struct san_device {
/** Driver private data */
void *priv;

/** Number of paths */
unsigned int paths;
/** Current active path */
struct san_path *active;
/** List of opened SAN paths */
Expand Down

0 comments on commit 6b385c9

Please sign in to comment.