summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/interface/pcbios/int13.c
diff options
context:
space:
mode:
authorMichael Brown2011-03-02 16:33:39 +0100
committerMichael Brown2011-03-02 16:52:25 +0100
commit560cc637f9381f43557bcf6094a9e12c95278615 (patch)
tree28680ba0fce1525acd7ecc92dfadcf684d7ce1c8 /src/arch/i386/interface/pcbios/int13.c
parent[prefix] Set the "size" bit in the GDT entry for the flat data segment (diff)
downloadipxe-560cc637f9381f43557bcf6094a9e12c95278615.tar.gz
ipxe-560cc637f9381f43557bcf6094a9e12c95278615.tar.xz
ipxe-560cc637f9381f43557bcf6094a9e12c95278615.zip
[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>
Diffstat (limited to 'src/arch/i386/interface/pcbios/int13.c')
-rw-r--r--src/arch/i386/interface/pcbios/int13.c84
1 files changed, 50 insertions, 34 deletions
diff --git a/src/arch/i386/interface/pcbios/int13.c b/src/arch/i386/interface/pcbios/int13.c
index c02d7cdf..392dbd5f 100644
--- a/src/arch/i386/interface/pcbios/int13.c
+++ b/src/arch/i386/interface/pcbios/int13.c
@@ -203,6 +203,32 @@ 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
*
* @v command 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;
@@ -407,36 +439,6 @@ static int int13_guess_geometry ( struct int13_drive *int13 ) {
}
/**
- * 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
*/
static void int13_set_num_drives ( void ) {
@@ -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 ) );