diff options
author | Michael Brown | 2010-09-22 01:44:27 +0200 |
---|---|---|
committer | Michael Brown | 2010-09-22 18:12:48 +0200 |
commit | a5a4dcd0c702d73a61b796e9a5d84433f162693c (patch) | |
tree | 7fdb684997c1531e21df87a2c15d0bac49082809 /src/net/fcp.c | |
parent | [ata] Add support for describing an ATA device using EDD (diff) | |
download | ipxe-a5a4dcd0c702d73a61b796e9a5d84433f162693c.tar.gz ipxe-a5a4dcd0c702d73a61b796e9a5d84433f162693c.tar.xz ipxe-a5a4dcd0c702d73a61b796e9a5d84433f162693c.zip |
[fcp] Add support for describing an FCP device using EDD
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net/fcp.c')
-rw-r--r-- | src/net/fcp.c | 72 |
1 files changed, 68 insertions, 4 deletions
diff --git a/src/net/fcp.c b/src/net/fcp.c index 42f6528e..ae70fe38 100644 --- a/src/net/fcp.c +++ b/src/net/fcp.c @@ -36,6 +36,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/uri.h> #include <ipxe/acpi.h> #include <ipxe/scsi.h> +#include <ipxe/device.h> +#include <ipxe/edd.h> #include <ipxe/fc.h> #include <ipxe/fcels.h> #include <ipxe/fcp.h> @@ -152,6 +154,11 @@ struct fcp_device { struct interface scsi; /** List of active commands */ struct list_head fcpcmds; + + /** Fibre Channel WWN (for boot firmware table) */ + struct fc_name wwn; + /** SCSI LUN (for boot firmware table) */ + struct scsi_lun lun; }; /** An FCP command */ @@ -840,9 +847,9 @@ static size_t fcpdev_window ( struct fcp_device *fcpdev ) { * @v len Length of ACPI table * @ret rc Return status code */ -static int fcpdev_describe ( struct fcp_device *fcpdev, - struct acpi_description_header *acpi, - size_t len ) { +static int fcpdev_acpi_describe ( struct fcp_device *fcpdev, + struct acpi_description_header *acpi, + size_t len ) { DBGC ( fcpdev, "FCP %p cannot yet describe device in an ACPI table\n", fcpdev ); @@ -851,12 +858,65 @@ static int fcpdev_describe ( struct fcp_device *fcpdev, return 0; } +/** + * Describe FCP device using EDD + * + * @v fcpdev FCP device + * @v type EDD interface type + * @v path EDD device path + * @ret rc Return status code + */ +static int fcpdev_edd_describe ( struct fcp_device *fcpdev, + struct edd_interface_type *type, + union edd_device_path *path ) { + union { + struct fc_name fc; + uint64_t u64; + } wwn; + union { + struct scsi_lun scsi; + uint64_t u64; + } lun; + + type->type = cpu_to_le64 ( EDD_INTF_TYPE_FIBRE ); + memcpy ( &wwn.fc, &fcpdev->wwn, sizeof ( wwn.fc ) ); + path->fibre.wwn = be64_to_cpu ( wwn.u64 ); + memcpy ( &lun.scsi, &fcpdev->lun, sizeof ( lun.scsi ) ); + path->fibre.lun = be64_to_cpu ( lun.u64 ); + return 0; +} + +/** + * Identify device underlying FCP device + * + * @v fcpdev FCP device + * @ret device Underlying device + */ +static struct device * fcpdev_identify_device ( struct fcp_device *fcpdev ) { + + /* We know the underlying device only if the link is up; + * otherwise we don't have a port to examine. + */ + if ( ! fc_link_ok ( &fcpdev->ulp->link ) ) { + DBGC ( fcpdev, "FCP %p doesn't know underlying device " + "until link is up\n", fcpdev ); + return NULL; + } + + /* Hand off to port's transport interface */ + assert ( fcpdev->ulp->peer->port != NULL ); + return identify_device ( &fcpdev->ulp->peer->port->transport ); +} + /** FCP device SCSI interface operations */ static struct interface_operation fcpdev_scsi_op[] = { INTF_OP ( scsi_command, struct fcp_device *, fcpdev_scsi_command ), INTF_OP ( xfer_window, struct fcp_device *, fcpdev_window ), INTF_OP ( intf_close, struct fcp_device *, fcpdev_close ), - INTF_OP ( acpi_describe, struct fcp_device *, fcpdev_describe ), + INTF_OP ( acpi_describe, struct fcp_device *, fcpdev_acpi_describe ), + INTF_OP ( edd_describe, struct fcp_device *, fcpdev_edd_describe ), + INTF_OP ( identify_device, struct fcp_device *, + fcpdev_identify_device ), }; /** FCP device SCSI interface descriptor */ @@ -898,6 +958,10 @@ static int fcpdev_open ( struct interface *parent, struct fc_name *wwn, DBGC ( fcpdev, "FCP %p opened for %s\n", fcpdev, fc_ntoa ( wwn ) ); + /* Preserve parameters required for boot firmware table */ + memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) ); + memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) ); + /* Attach SCSI device to parent interface */ if ( ( rc = scsi_open ( parent, &fcpdev->scsi, lun ) ) != 0 ) { DBGC ( fcpdev, "FCP %p could not create SCSI device: %s\n", |