diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/acpi.c | 85 | ||||
-rw-r--r-- | src/core/dummy_sanboot.c | 25 | ||||
-rw-r--r-- | src/core/null_sanboot.c | 5 | ||||
-rw-r--r-- | src/core/sanboot.c | 101 |
4 files changed, 173 insertions, 43 deletions
diff --git a/src/core/acpi.c b/src/core/acpi.c index 955637e0..8ebe4b19 100644 --- a/src/core/acpi.c +++ b/src/core/acpi.c @@ -43,27 +43,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ /** - * Transcribe ACPI table signature (for debugging) - * - * @v signature ACPI table signature - * @ret name ACPI table signature name - */ -static const char * acpi_name ( uint32_t signature ) { - static union { - uint32_t signature; - char name[5]; - } u; - - u.signature = cpu_to_le32 ( signature ); - return u.name; -} - -/** * Fix up ACPI table checksum * * @v acpi ACPI table header */ -void acpi_fix_checksum ( struct acpi_description_header *acpi ) { +void acpi_fix_checksum ( struct acpi_header *acpi ) { unsigned int i = 0; uint8_t sum = 0; @@ -147,7 +131,7 @@ userptr_t acpi_find_rsdt ( userptr_t ebda ) { * @ret table Table, or UNULL if not found */ userptr_t acpi_find ( userptr_t rsdt, uint32_t signature, unsigned int index ) { - struct acpi_description_header acpi; + struct acpi_header acpi; struct acpi_rsdt *rsdtab; typeof ( rsdtab->entry[0] ) entry; userptr_t table; @@ -227,7 +211,7 @@ userptr_t acpi_find ( userptr_t rsdt, uint32_t signature, unsigned int index ) { * the ACPI specification itself. */ static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) { - struct acpi_description_header acpi; + struct acpi_header acpi; union { uint32_t dword; uint8_t byte[4]; @@ -331,34 +315,73 @@ int acpi_sx ( userptr_t rsdt, uint32_t signature ) { /****************************************************************************** * - * Interface methods + * Descriptors * ****************************************************************************** */ /** - * Describe object in an ACPI table + * Add ACPI descriptor + * + * @v desc ACPI descriptor + */ +void acpi_add ( struct acpi_descriptor *desc ) { + + /* Add to list of descriptors */ + ref_get ( desc->refcnt ); + list_add_tail ( &desc->list, &desc->model->descs ); +} + +/** + * Remove ACPI descriptor + * + * @v desc ACPI descriptor + */ +void acpi_del ( struct acpi_descriptor *desc ) { + + /* Remove from list of descriptors */ + list_check_contains_entry ( desc, &desc->model->descs, list ); + list_del ( &desc->list ); + ref_put ( desc->refcnt ); +} + +/** + * Get object's ACPI descriptor * * @v intf Interface - * @v acpi ACPI table - * @v len Length of ACPI table - * @ret rc Return status code + * @ret desc ACPI descriptor, or NULL */ -int acpi_describe ( struct interface *intf, - struct acpi_description_header *acpi, size_t len ) { +struct acpi_descriptor * acpi_describe ( struct interface *intf ) { struct interface *dest; acpi_describe_TYPE ( void * ) *op = intf_get_dest_op ( intf, acpi_describe, &dest ); void *object = intf_object ( dest ); - int rc; + struct acpi_descriptor *desc; if ( op ) { - rc = op ( object, acpi, len ); + desc = op ( object ); } else { - /* Default is to fail to describe */ - rc = -EOPNOTSUPP; + desc = NULL; } intf_put ( dest ); - return rc; + return desc; +} + +/** + * Install ACPI tables + * + * @v install Table installation method + * @ret rc Return status code + */ +int acpi_install ( int ( * install ) ( struct acpi_header *acpi ) ){ + struct acpi_model *model; + int rc; + + for_each_table_entry ( model, ACPI_MODELS ) { + if ( ( rc = model->install ( install ) ) != 0 ) + return rc; + } + + return 0; } diff --git a/src/core/dummy_sanboot.c b/src/core/dummy_sanboot.c index 64d5206f..08180852 100644 --- a/src/core/dummy_sanboot.c +++ b/src/core/dummy_sanboot.c @@ -38,10 +38,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v drive Drive number * @v uris List of URIs * @v count Number of URIs + * @v flags Flags * @ret drive Drive number, or negative error */ static int dummy_san_hook ( unsigned int drive, struct uri **uris, - unsigned int count ) { + unsigned int count, unsigned int flags ) { struct san_device *sandev; int rc; @@ -51,10 +52,9 @@ static int dummy_san_hook ( unsigned int drive, struct uri **uris, rc = -ENOMEM; goto err_alloc; } - sandev->drive = drive; /* Register SAN device */ - if ( ( rc = register_sandev ( sandev ) ) != 0 ) { + if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) { DBGC ( sandev, "SAN %#02x could not register: %s\n", sandev->drive, strerror ( rc ) ); goto err_register; @@ -102,15 +102,28 @@ static int dummy_san_boot ( unsigned int drive __unused ) { } /** - * Describe dummy SAN device + * Install ACPI table * - * @v drive Drive number + * @v acpi ACPI description header + * @ret rc Return status code */ -static int dummy_san_describe ( unsigned int drive __unused ) { +static int dummy_install ( struct acpi_header *acpi ) { + DBGC ( acpi, "ACPI table %s:\n", acpi_name ( acpi->signature ) ); + DBGC_HDA ( acpi, 0, acpi, le32_to_cpu ( acpi->length ) ); return 0; } +/** + * Describe dummy SAN device + * + * @ret rc Return status code + */ +static int dummy_san_describe ( void ) { + + return acpi_install ( dummy_install ); +} + PROVIDE_SANBOOT ( dummy, san_hook, dummy_san_hook ); PROVIDE_SANBOOT ( dummy, san_unhook, dummy_san_unhook ); PROVIDE_SANBOOT ( dummy, san_boot, dummy_san_boot ); diff --git a/src/core/null_sanboot.c b/src/core/null_sanboot.c index 42fb0682..b09562e2 100644 --- a/src/core/null_sanboot.c +++ b/src/core/null_sanboot.c @@ -28,7 +28,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); static int null_san_hook ( unsigned int drive __unused, struct uri **uris __unused, - unsigned int count __unused ) { + unsigned int count __unused, + unsigned int flags __unused ) { return -EOPNOTSUPP; } @@ -40,7 +41,7 @@ static int null_san_boot ( unsigned int drive __unused ) { return -EOPNOTSUPP; } -static int null_san_describe ( unsigned int drive __unused ) { +static int null_san_describe ( void ) { return -EOPNOTSUPP; } 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 ); } |