From d9886f1961f9970b4354442e84b98727b69cd73a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 7 Mar 2017 16:11:22 +0000 Subject: [block] Retry any SAN device operation The SCSI layer currently implements a retry loop in order to retry commands that fail due to spurious "error" conditions such as "power on occurred". Move this retry loop to the generic SAN device layer: this allow for retries due to other transient error conditions such as an iSCSI target having dropped the connection due to inactivity. Signed-off-by: Michael Brown --- src/core/sanboot.c | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) (limited to 'src/core') diff --git a/src/core/sanboot.c b/src/core/sanboot.c index 42a30839..85d0bc7f 100644 --- a/src/core/sanboot.c +++ b/src/core/sanboot.c @@ -64,6 +64,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #define SAN_COMMAND_TIMEOUT ( 15 * TICKS_PER_SEC ) +/** + * 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 + /** List of SAN devices */ LIST_HEAD ( san_devices ); @@ -331,36 +341,42 @@ 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; int rc; /* Sanity check */ assert ( ! timer_running ( &sandev->timer ) ); - /* Reopen block device if applicable */ - if ( sandev_needs_reopen ( sandev ) && - ( ( rc = sandev_reopen ( sandev ) ) != 0 ) ) { - goto err_reopen; - } + /* (Re)try command */ + for ( retries = 0 ; retries < SAN_COMMAND_MAX_RETRIES ; retries++ ) { - /* Start expiry timer */ - start_timer_fixed ( &sandev->timer, SAN_COMMAND_TIMEOUT ); + /* Reopen block device if applicable */ + if ( sandev_needs_reopen ( sandev ) && + ( ( rc = sandev_reopen ( sandev ) ) != 0 ) ) { + continue; + } - /* Initiate command */ - if ( ( rc = command ( sandev, params ) ) != 0 ) - goto err_op; + /* Start expiry timer */ + start_timer_fixed ( &sandev->timer, SAN_COMMAND_TIMEOUT ); - /* Wait for command to complete */ - while ( timer_running ( &sandev->timer ) ) - step(); + /* Initiate command */ + if ( ( rc = command ( sandev, params ) ) != 0 ) { + stop_timer ( &sandev->timer ); + continue; + } - /* Collect return status */ - rc = sandev->command_rc; + /* Wait for command to complete */ + while ( timer_running ( &sandev->timer ) ) + step(); - return rc; + /* Exit on success */ + if ( ( rc = sandev->command_rc ) == 0 ) + return 0; + } + + /* Sanity check */ + assert ( ! timer_running ( &sandev->timer ) ); - err_op: - stop_timer ( &sandev->timer ); - err_reopen: return rc; } -- cgit v1.2.3-55-g7522