[block] Allow SAN retry count to be reconfigured
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>
This commit is contained in:
parent
6bd0060f26
commit
6b385c9da3
|
@ -65,18 +65,21 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
#define SAN_COMMAND_TIMEOUT ( 15 * TICKS_PER_SEC )
|
#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
|
* We may need to retry commands. For example, the underlying
|
||||||
* connection may be closed by the SAN target due to an inactivity
|
* connection may be closed by the SAN target due to an inactivity
|
||||||
* timeout, or the SAN target may return pointless "error" messages
|
* timeout, or the SAN target may return pointless "error" messages
|
||||||
* such as "SCSI power-on occurred".
|
* such as "SCSI power-on occurred".
|
||||||
*/
|
*/
|
||||||
#define SAN_COMMAND_MAX_RETRIES 10
|
#define SAN_DEFAULT_RETRIES 10
|
||||||
|
|
||||||
/** List of SAN devices */
|
/** List of SAN devices */
|
||||||
LIST_HEAD ( 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
|
* Find SAN device by drive number
|
||||||
*
|
*
|
||||||
|
@ -101,13 +104,13 @@ struct san_device * sandev_find ( unsigned int drive ) {
|
||||||
static void sandev_free ( struct refcnt *refcnt ) {
|
static void sandev_free ( struct refcnt *refcnt ) {
|
||||||
struct san_device *sandev =
|
struct san_device *sandev =
|
||||||
container_of ( refcnt, struct san_device, refcnt );
|
container_of ( refcnt, struct san_device, refcnt );
|
||||||
struct san_path *sanpath;
|
unsigned int i;
|
||||||
|
|
||||||
assert ( ! timer_running ( &sandev->timer ) );
|
assert ( ! timer_running ( &sandev->timer ) );
|
||||||
assert ( ! sandev->active );
|
assert ( ! sandev->active );
|
||||||
assert ( list_empty ( &sandev->opened ) );
|
assert ( list_empty ( &sandev->opened ) );
|
||||||
list_for_each_entry ( sanpath, &sandev->closed, list )
|
for ( i = 0 ; i < sandev->paths ; i++ )
|
||||||
uri_put ( sanpath->uri );
|
uri_put ( sandev->path[i].uri );
|
||||||
free ( sandev );
|
free ( sandev );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,14 +472,14 @@ sandev_command ( struct san_device *sandev,
|
||||||
int ( * command ) ( struct san_device *sandev,
|
int ( * command ) ( struct san_device *sandev,
|
||||||
const union san_command_params *params ),
|
const union san_command_params *params ),
|
||||||
const union san_command_params *params ) {
|
const union san_command_params *params ) {
|
||||||
unsigned int retries;
|
unsigned int retries = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
assert ( ! timer_running ( &sandev->timer ) );
|
assert ( ! timer_running ( &sandev->timer ) );
|
||||||
|
|
||||||
/* (Re)try command */
|
/* (Re)try command */
|
||||||
for ( retries = 0 ; retries < SAN_COMMAND_MAX_RETRIES ; retries++ ) {
|
do {
|
||||||
|
|
||||||
/* Reopen block device if applicable */
|
/* Reopen block device if applicable */
|
||||||
if ( sandev_needs_reopen ( sandev ) &&
|
if ( sandev_needs_reopen ( sandev ) &&
|
||||||
|
@ -484,23 +487,24 @@ sandev_command ( struct san_device *sandev,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initiate command */
|
||||||
|
if ( ( rc = command ( sandev, params ) ) != 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Start expiry timer */
|
/* Start expiry timer */
|
||||||
start_timer_fixed ( &sandev->timer, SAN_COMMAND_TIMEOUT );
|
start_timer_fixed ( &sandev->timer, SAN_COMMAND_TIMEOUT );
|
||||||
|
|
||||||
/* Initiate command */
|
|
||||||
if ( ( rc = command ( sandev, params ) ) != 0 ) {
|
|
||||||
stop_timer ( &sandev->timer );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for command to complete */
|
/* Wait for command to complete */
|
||||||
while ( timer_running ( &sandev->timer ) )
|
while ( timer_running ( &sandev->timer ) )
|
||||||
step();
|
step();
|
||||||
|
|
||||||
/* Exit on success */
|
/* Check command status */
|
||||||
if ( ( rc = sandev->command_rc ) == 0 )
|
if ( ( rc = sandev->command_rc ) != 0 )
|
||||||
return 0;
|
continue;
|
||||||
}
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} while ( ++retries <= san_retries );
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
assert ( ! timer_running ( &sandev->timer ) );
|
assert ( ! timer_running ( &sandev->timer ) );
|
||||||
|
@ -676,6 +680,7 @@ struct san_device * alloc_sandev ( struct uri **uris, unsigned int count,
|
||||||
intf_init ( &sandev->command, &sandev_command_desc, &sandev->refcnt );
|
intf_init ( &sandev->command, &sandev_command_desc, &sandev->refcnt );
|
||||||
timer_init ( &sandev->timer, sandev_command_expired, &sandev->refcnt );
|
timer_init ( &sandev->timer, sandev_command_expired, &sandev->refcnt );
|
||||||
sandev->priv = ( ( ( void * ) sandev ) + size );
|
sandev->priv = ( ( ( void * ) sandev ) + size );
|
||||||
|
sandev->paths = count;
|
||||||
INIT_LIST_HEAD ( &sandev->opened );
|
INIT_LIST_HEAD ( &sandev->opened );
|
||||||
INIT_LIST_HEAD ( &sandev->closed );
|
INIT_LIST_HEAD ( &sandev->closed );
|
||||||
for ( i = 0 ; i < count ; i++ ) {
|
for ( i = 0 ; i < count ; i++ ) {
|
||||||
|
@ -767,3 +772,33 @@ unsigned int san_default_drive ( void ) {
|
||||||
/* Otherwise, default to booting from first hard disk */
|
/* Otherwise, default to booting from first hard disk */
|
||||||
return SAN_DEFAULT_DRIVE;
|
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,
|
||||||
|
};
|
||||||
|
|
|
@ -433,6 +433,13 @@ struct dhcp_netdev_desc {
|
||||||
/** Use cached network settings (obsolete; do not reuse this value) */
|
/** Use cached network settings (obsolete; do not reuse this value) */
|
||||||
#define DHCP_EB_USE_CACHED DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb2 )
|
#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
|
/** SAN drive number
|
||||||
*
|
*
|
||||||
* This is the drive number for a SAN-hooked drive. For BIOS, 0x80 is
|
* This is the drive number for a SAN-hooked drive. For BIOS, 0x80 is
|
||||||
|
|
|
@ -71,6 +71,8 @@ struct san_device {
|
||||||
/** Driver private data */
|
/** Driver private data */
|
||||||
void *priv;
|
void *priv;
|
||||||
|
|
||||||
|
/** Number of paths */
|
||||||
|
unsigned int paths;
|
||||||
/** Current active path */
|
/** Current active path */
|
||||||
struct san_path *active;
|
struct san_path *active;
|
||||||
/** List of opened SAN paths */
|
/** List of opened SAN paths */
|
||||||
|
|
Reference in New Issue