summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/acpi.c85
-rw-r--r--src/core/dummy_sanboot.c25
-rw-r--r--src/core/null_sanboot.c5
-rw-r--r--src/core/sanboot.c101
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 );
}