[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 <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2017-03-07 16:11:22 +00:00
parent 23d388418e
commit d9886f1961
2 changed files with 39 additions and 46 deletions

View File

@@ -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++ ) {
/* 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 );
continue;
}
/* Wait for command to complete */
while ( timer_running ( &sandev->timer ) )
step();
/* Exit on success */
if ( ( rc = sandev->command_rc ) == 0 )
return 0;
}
/* Start expiry timer */
start_timer_fixed ( &sandev->timer, SAN_COMMAND_TIMEOUT );
/* Sanity check */
assert ( ! timer_running ( &sandev->timer ) );
/* Initiate command */
if ( ( rc = command ( sandev, params ) ) != 0 )
goto err_op;
/* Wait for command to complete */
while ( timer_running ( &sandev->timer ) )
step();
/* Collect return status */
rc = sandev->command_rc;
return rc;
err_op:
stop_timer ( &sandev->timer );
err_reopen:
return rc;
}