diff options
Diffstat (limited to 'src/core/sanboot.c')
-rw-r--r-- | src/core/sanboot.c | 101 |
1 files changed, 97 insertions, 4 deletions
diff --git a/src/core/sanboot.c b/src/core/sanboot.c index 03beae79..f134f76a 100644 --- a/src/core/sanboot.c +++ b/src/core/sanboot.c @@ -119,8 +119,10 @@ static void sandev_free ( struct refcnt *refcnt ) { assert ( ! timer_running ( &sandev->timer ) ); assert ( ! sandev->active ); assert ( list_empty ( &sandev->opened ) ); - for ( i = 0 ; i < sandev->paths ; i++ ) + for ( i = 0 ; i < sandev->paths ; i++ ) { uri_put ( sandev->path[i].uri ); + assert ( sandev->path[i].desc == NULL ); + } free ( sandev ); } @@ -199,6 +201,15 @@ static int sanpath_open ( struct san_path *sanpath ) { return rc; } + /* Update ACPI descriptor, if applicable */ + if ( ! ( sandev->flags & SAN_NO_DESCRIBE ) ) { + if ( sanpath->desc ) + acpi_del ( sanpath->desc ); + sanpath->desc = acpi_describe ( &sanpath->block ); + if ( sanpath->desc ) + acpi_add ( sanpath->desc ); + } + /* Start process */ process_add ( &sanpath->process ); @@ -607,6 +618,72 @@ int sandev_rw ( struct san_device *sandev, uint64_t lba, } /** + * Describe SAN device + * + * @v sandev SAN device + * @ret rc Return status code + * + * Allow connections to progress until all existent path descriptors + * are complete. + */ +static int sandev_describe ( struct san_device *sandev ) { + struct san_path *sanpath; + struct acpi_descriptor *desc; + int rc; + + /* Wait for all paths to be either described or closed */ + while ( 1 ) { + + /* Allow connections to progress */ + step(); + + /* Fail if any closed path has an incomplete descriptor */ + list_for_each_entry ( sanpath, &sandev->closed, list ) { + desc = sanpath->desc; + if ( ! desc ) + continue; + if ( ( rc = desc->model->complete ( desc ) ) != 0 ) { + DBGC ( sandev, "SAN %#02x.%d could not be " + "described: %s\n", sandev->drive, + sanpath->index, strerror ( rc ) ); + return rc; + } + } + + /* Succeed if no paths have an incomplete descriptor */ + rc = 0; + list_for_each_entry ( sanpath, &sandev->opened, list ) { + desc = sanpath->desc; + if ( ! desc ) + continue; + if ( ( rc = desc->model->complete ( desc ) ) != 0 ) + break; + } + if ( rc == 0 ) + return 0; + } +} + +/** + * Remove SAN device descriptors + * + * @v sandev SAN device + */ +static void sandev_undescribe ( struct san_device *sandev ) { + struct san_path *sanpath; + unsigned int i; + + /* Remove all ACPI descriptors */ + for ( i = 0 ; i < sandev->paths ; i++ ) { + sanpath = &sandev->path[i]; + if ( sanpath->desc ) { + acpi_del ( sanpath->desc ); + sanpath->desc = NULL; + } + } +} + +/** * Configure SAN device as a CD-ROM, if applicable * * @v sandev SAN device @@ -729,18 +806,25 @@ struct san_device * alloc_sandev ( struct uri **uris, unsigned int count, * Register SAN device * * @v sandev SAN device + * @v drive Drive number + * @v flags Flags * @ret rc Return status code */ -int register_sandev ( struct san_device *sandev ) { +int register_sandev ( struct san_device *sandev, unsigned int drive, + unsigned int flags ) { int rc; /* Check that drive number is not in use */ - if ( sandev_find ( sandev->drive ) != NULL ) { - DBGC ( sandev, "SAN %#02x is already in use\n", sandev->drive ); + if ( sandev_find ( drive ) != NULL ) { + DBGC ( sandev, "SAN %#02x is already in use\n", drive ); rc = -EADDRINUSE; goto err_in_use; } + /* Record drive number and flags */ + sandev->drive = drive; + sandev->flags = flags; + /* Check that device is capable of being opened (i.e. that all * URIs are well-formed and that at least one path is * working). @@ -748,6 +832,10 @@ int register_sandev ( struct san_device *sandev ) { if ( ( rc = sandev_reopen ( sandev ) ) != 0 ) goto err_reopen; + /* Describe device */ + if ( ( rc = sandev_describe ( sandev ) ) != 0 ) + goto err_describe; + /* Read device capacity */ if ( ( rc = sandev_command ( sandev, sandev_command_read_capacity, NULL ) ) != 0 ) @@ -766,8 +854,10 @@ int register_sandev ( struct san_device *sandev ) { list_del ( &sandev->list ); err_iso9660: err_capacity: + err_describe: err_reopen: sandev_restart ( sandev, rc ); + sandev_undescribe ( sandev ); err_in_use: return rc; } @@ -788,6 +878,9 @@ void unregister_sandev ( struct san_device *sandev ) { /* Shut down interfaces */ sandev_restart ( sandev, 0 ); + /* Remove ACPI descriptors */ + sandev_undescribe ( sandev ); + DBGC ( sandev, "SAN %#02x unregistered\n", sandev->drive ); } |