david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[int13] Automatically reopen underlying block device as needed

We currently use INT 13,00 as an opportunity to reopen the underlying
block device, which works well for callers such as DOS that will use
INT 13,00 in response to any disk errors.  However, some callers (such
as Windows Server 2008) do not attempt to reset the disk, and so any
failures become effectively permanent.

Fix this by automatically reopening the underlying block device
whenever we might want to access it.

This makes direct installation of Windows to an iSCSI target much more
reliable.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2011-03-02 15:33:39 +00:00
parent 90563f69be
commit 560cc637f9
1 changed files with 50 additions and 34 deletions

View File

@ -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 ) );