diff --git a/src/arch/i386/interface/pcbios/int13.c b/src/arch/i386/interface/pcbios/int13.c index c02d7cdf4..392dbd5fb 100644 --- a/src/arch/i386/interface/pcbios/int13.c +++ b/src/arch/i386/interface/pcbios/int13.c @@ -202,6 +202,32 @@ static struct interface_operation int13_command_op[] = { static struct interface_descriptor int13_command_desc = INTF_DESC ( struct int13_command, block, int13_command_op ); +/** + * Open (or reopen) INT 13 emulated drive underlying block device + * + * @v int13 Emulated drive + * @ret rc Return status code + */ +static int int13_reopen_block ( struct int13_drive *int13 ) { + int rc; + + /* Close any existing block device */ + intf_restart ( &int13->block, -ECONNRESET ); + + /* Open block device */ + if ( ( rc = xfer_open_uri ( &int13->block, int13->uri ) ) != 0 ) { + DBGC ( int13, "INT13 drive %02x could not reopen block " + "device: %s\n", int13->drive, strerror ( rc ) ); + int13->block_rc = rc; + return rc; + } + + /* Clear block device error status */ + int13->block_rc = 0; + + return 0; +} + /** * Prepare to issue INT 13 command * @@ -211,11 +237,17 @@ static struct interface_descriptor int13_command_desc = */ static int int13_command_start ( struct int13_command *command, struct int13_drive *int13 ) { + int rc; /* Sanity check */ assert ( command->int13 == NULL ); assert ( ! timer_running ( &command->timer ) ); + /* Reopen block device if necessary */ + if ( ( int13->block_rc != 0 ) && + ( ( rc = int13_reopen_block ( int13 ) ) != 0 ) ) + return rc; + /* Initialise command */ command->rc = -EINPROGRESS; command->int13 = int13; @@ -406,36 +438,6 @@ static int int13_guess_geometry ( struct int13_drive *int13 ) { return 0; } -/** - * Open (or reopen) INT 13 emulated drive underlying block device - * - * @v int13 Emulated drive - * @ret rc Return status code - */ -static int int13_reopen_block ( struct int13_drive *int13 ) { - int rc; - - /* Close any existing block device */ - intf_restart ( &int13->block, -ECONNRESET ); - - /* Open block device */ - if ( ( rc = xfer_open_uri ( &int13->block, int13->uri ) ) != 0 ) { - DBGC ( int13, "INT13 drive %02x could not reopen block " - "device: %s\n", int13->drive, strerror ( rc ) ); - int13->block_rc = rc; - return rc; - } - - /* Clear block device error status */ - int13->block_rc = 0; - - /* Read device capacity */ - if ( ( rc = int13_read_capacity ( int13 ) ) != 0 ) - return rc; - - return 0; -} - /** * Update BIOS drive count */ @@ -485,6 +487,10 @@ static int int13_reset ( struct int13_drive *int13, if ( ( rc = int13_reopen_block ( int13 ) ) != 0 ) return -INT13_STATUS_RESET_FAILED; + /* Check that block device is functional */ + if ( ( rc = int13_read_capacity ( int13 ) ) != 0 ) + return -INT13_STATUS_RESET_FAILED; + return 0; } @@ -837,6 +843,11 @@ static int int13_device_path_info ( struct int13_drive *int13, uint8_t sum = 0; int rc; + /* Reopen block device if necessary */ + if ( ( int13->block_rc != 0 ) && + ( ( rc = int13_reopen_block ( int13 ) ) != 0 ) ) + return rc; + /* Get underlying hardware device */ device = identify_device ( &int13->block ); if ( ! device ) { @@ -1125,10 +1136,6 @@ static void int13_block_close ( struct int13_drive *int13, int rc ) { /* Shut down interfaces */ intf_restart ( &int13->block, rc ); - - /* Further INT 13 calls will fail immediately. The caller may - * use INT 13,00 to reset the drive. - */ } /** INT 13 drive interface operations */ @@ -1200,6 +1207,10 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) { if ( ( rc = int13_reopen_block ( int13 ) ) != 0 ) goto err_reopen_block; + /* Read device capacity */ + if ( ( rc = int13_read_capacity ( int13 ) ) != 0 ) + return rc; + /* Give drive a default geometry */ if ( ( rc = int13_guess_geometry ( int13 ) ) != 0 ) goto err_guess_geometry; @@ -1383,6 +1394,11 @@ static int int13_describe ( unsigned int drive ) { return -ENODEV; } + /* Reopen block device if necessary */ + if ( ( int13->block_rc != 0 ) && + ( ( rc = int13_reopen_block ( int13 ) ) != 0 ) ) + return rc; + /* Clear table */ memset ( &xbftab, 0, sizeof ( xbftab ) );