Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 14 Oct 2019 19:17:00 +0000 (UTC)
From:      Toomas Soome <tsoome@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r353501 - in stable/12/stand: efi/boot1 efi/include efi/libefi efi/loader efi/loader/arch/i386 libsa
Message-ID:  <201910141917.x9EJH0vQ029327@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tsoome
Date: Mon Oct 14 19:17:00 2019
New Revision: 353501
URL: https://svnweb.freebsd.org/changeset/base/353501

Log:
  loader.efi: Block IO should honor align_io
  
  MFC: r347195, r350654, r350655, r350656, r351274, r351630, r351637
  r352421, r352439, r352443, r352444, r352445, r352446, r352451
  
  We need to bring in a bit more than just align_io change.

Modified:
  stable/12/stand/efi/boot1/boot1.c
  stable/12/stand/efi/include/efilib.h
  stable/12/stand/efi/libefi/devpath.c
  stable/12/stand/efi/libefi/efinet.c
  stable/12/stand/efi/libefi/efipart.c
  stable/12/stand/efi/libefi/libefi.c
  stable/12/stand/efi/loader/arch/i386/efimd.c
  stable/12/stand/efi/loader/efi_main.c
  stable/12/stand/efi/loader/framebuffer.c
  stable/12/stand/efi/loader/main.c
  stable/12/stand/libsa/stand.h
  stable/12/stand/libsa/zalloc.c
  stable/12/stand/libsa/zalloc_defs.h
  stable/12/stand/libsa/zalloc_malloc.c
  stable/12/stand/libsa/zalloc_mem.h
  stable/12/stand/libsa/zalloc_protos.h
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/stand/efi/boot1/boot1.c
==============================================================================
--- stable/12/stand/efi/boot1/boot1.c	Mon Oct 14 19:06:17 2019	(r353500)
+++ stable/12/stand/efi/boot1/boot1.c	Mon Oct 14 19:17:00 2019	(r353501)
@@ -246,8 +246,9 @@ try_boot(void)
 		goto errout;
 	}
 
-	if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
-	    (VOID**)&loaded_image)) != EFI_SUCCESS) {
+	status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID,
+	    (void **)&loaded_image);
+	if (status != EFI_SUCCESS) {
 		printf("Failed to query LoadedImage provided by %s (%lu)\n",
 		    mod->name, EFI_ERROR_CODE(status));
 		goto errout;
@@ -306,7 +307,7 @@ probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, B
 	UINTN i;
 
 	/* Figure out if we're dealing with an actual partition. */
-	status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
+	status = OpenProtocolByHandle(h, &DevicePathGUID, (void **)&devpath);
 	if (status == EFI_UNSUPPORTED)
 		return (status);
 
@@ -322,7 +323,7 @@ probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, B
 		efi_free_devpath_name(text);
 	}
 #endif
-	status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
+	status = OpenProtocolByHandle(h, &BlockIoProtocolGUID, (void **)&blkio);
 	if (status == EFI_UNSUPPORTED)
 		return (status);
 
@@ -445,7 +446,7 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
 	putchar('\n');
 
 	/* Determine the devpath of our image so we can prefer it. */
-	status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img);
+	status = OpenProtocolByHandle(IH, &LoadedImageGUID, (void **)&img);
 	imgpath = NULL;
 	if (status == EFI_SUCCESS) {
 		text = efi_devpath_name(img->FilePath);
@@ -455,8 +456,8 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
 			efi_free_devpath_name(text);
 		}
 
-		status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
-		    (void **)&imgpath);
+		status = OpenProtocolByHandle(img->DeviceHandle,
+		    &DevicePathGUID, (void **)&imgpath);
 		if (status != EFI_SUCCESS) {
 			DPRINTF("Failed to get image DevicePath (%lu)\n",
 			    EFI_ERROR_CODE(status));

Modified: stable/12/stand/efi/include/efilib.h
==============================================================================
--- stable/12/stand/efi/include/efilib.h	Mon Oct 14 19:06:17 2019	(r353500)
+++ stable/12/stand/efi/include/efilib.h	Mon Oct 14 19:17:00 2019	(r353501)
@@ -69,6 +69,7 @@ pdinfo_t *efiblk_get_pdinfo_by_handle(EFI_HANDLE h);
 pdinfo_t *efiblk_get_pdinfo_by_device_path(EFI_DEVICE_PATH *path);
 
 void *efi_get_table(EFI_GUID *tbl);
+EFI_STATUS OpenProtocolByHandle(EFI_HANDLE, EFI_GUID *, void **);
 
 int efi_getdev(void **vdev, const char *devspec, const char **path);
 char *efi_fmtdev(void *vdev);
@@ -92,6 +93,7 @@ CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *);
 void efi_free_devpath_name(CHAR16 *);
 EFI_DEVICE_PATH *efi_devpath_to_media_path(EFI_DEVICE_PATH *);
 UINTN efi_devpath_length(EFI_DEVICE_PATH *);
+EFI_HANDLE efi_devpath_to_handle(EFI_DEVICE_PATH *path, EFI_HANDLE *handles, unsigned nhandles);
 
 int efi_status_to_errno(EFI_STATUS);
 EFI_STATUS errno_to_efi_status(int errno);

Modified: stable/12/stand/efi/libefi/devpath.c
==============================================================================
--- stable/12/stand/efi/libefi/devpath.c	Mon Oct 14 19:06:17 2019	(r353500)
+++ stable/12/stand/efi/libefi/devpath.c	Mon Oct 14 19:17:00 2019	(r353501)
@@ -42,8 +42,8 @@ efi_lookup_image_devpath(EFI_HANDLE handle)
 	EFI_DEVICE_PATH *devpath;
 	EFI_STATUS status;
 
-	status = BS->HandleProtocol(handle, &ImageDevicePathGUID,
-	    (VOID **)&devpath);
+	status = OpenProtocolByHandle(handle, &ImageDevicePathGUID,
+	    (void **)&devpath);
 	if (EFI_ERROR(status))
 		devpath = NULL;
 	return (devpath);
@@ -55,7 +55,8 @@ efi_lookup_devpath(EFI_HANDLE handle)
 	EFI_DEVICE_PATH *devpath;
 	EFI_STATUS status;
 
-	status = BS->HandleProtocol(handle, &DevicePathGUID, (VOID **)&devpath);
+	status = OpenProtocolByHandle(handle, &DevicePathGUID,
+	    (void **)&devpath);
 	if (EFI_ERROR(status))
 		devpath = NULL;
 	return (devpath);
@@ -228,4 +229,26 @@ efi_devpath_length(EFI_DEVICE_PATH  *path)
 	while (!IsDevicePathEnd(path))
 		path = NextDevicePathNode(path);
 	return ((UINTN)path - (UINTN)start) + DevicePathNodeLength(path);
+}
+
+EFI_HANDLE
+efi_devpath_to_handle(EFI_DEVICE_PATH *path, EFI_HANDLE *handles, unsigned nhandles)
+{
+	unsigned i;
+	EFI_DEVICE_PATH *media, *devpath;
+	EFI_HANDLE h;
+
+	media = efi_devpath_to_media_path(path);
+	if (media == NULL)
+		return (NULL);
+	for (i = 0; i < nhandles; i++) {
+		h = handles[i];
+		devpath = efi_lookup_devpath(h);
+		if (devpath == NULL)
+			continue;
+		if (!efi_devpath_match_node(media, efi_devpath_to_media_path(devpath)))
+			continue;
+		return (h);
+	}
+	return (NULL);
 }

Modified: stable/12/stand/efi/libefi/efinet.c
==============================================================================
--- stable/12/stand/efi/libefi/efinet.c	Mon Oct 14 19:06:17 2019	(r353500)
+++ stable/12/stand/efi/libefi/efinet.c	Mon Oct 14 19:17:00 2019	(r353501)
@@ -195,7 +195,7 @@ efinet_init(struct iodesc *desc, void *machdep_hint)
 	}
 
 	h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
-	status = BS->HandleProtocol(h, &sn_guid, (VOID **)&nif->nif_devdata);
+	status = OpenProtocolByHandle(h, &sn_guid, (void **)&nif->nif_devdata);
 	if (status != EFI_SUCCESS) {
 		printf("net%d: cannot fetch interface data (status=%lu)\n",
 		    nif->nif_unit, EFI_ERROR_CODE(status));

Modified: stable/12/stand/efi/libefi/efipart.c
==============================================================================
--- stable/12/stand/efi/libefi/efipart.c	Mon Oct 14 19:06:17 2019	(r353500)
+++ stable/12/stand/efi/libefi/efipart.c	Mon Oct 14 19:17:00 2019	(r353501)
@@ -64,6 +64,9 @@ static int efipart_printhd(int);
 #define	PNP0700	0x700
 #define	PNP0701	0x701
 
+/* Bounce buffer max size */
+#define	BIO_BUFFER_SIZE	0x4000
+
 struct devsw efipart_fddev = {
 	.dv_name = "fd",
 	.dv_type = DEVT_FD,
@@ -100,12 +103,18 @@ struct devsw efipart_hddev = {
 	.dv_cleanup = NULL
 };
 
-static pdinfo_list_t fdinfo;
-static pdinfo_list_t cdinfo;
-static pdinfo_list_t hdinfo;
+static pdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo);
+static pdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo);
+static pdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo);
 
-static EFI_HANDLE *efipart_handles = NULL;
-static UINTN efipart_nhandles = 0;
+/*
+ * efipart_inithandles() is used to build up the pdinfo list from
+ * block device handles. Then each devsw init callback is used to
+ * pick items from pdinfo and move to proper device list.
+ * In ideal world, we should end up with empty pdinfo once all
+ * devsw initializers are called.
+ */
+static pdinfo_list_t pdinfo = STAILQ_HEAD_INITIALIZER(pdinfo);
 
 pdinfo_list_t *
 efiblk_get_pdinfo_list(struct devsw *dev)
@@ -140,23 +149,14 @@ efiblk_get_pdinfo(struct devdesc *dev)
 pdinfo_t *
 efiblk_get_pdinfo_by_device_path(EFI_DEVICE_PATH *path)
 {
-	unsigned i;
-	EFI_DEVICE_PATH *media, *devpath;
 	EFI_HANDLE h;
+	EFI_STATUS status;
+	EFI_DEVICE_PATH *devp = path;
 
-	media = efi_devpath_to_media_path(path);
-	if (media == NULL)
+	status = BS->LocateDevicePath(&blkio_guid, &devp, &h);
+	if (EFI_ERROR(status))
 		return (NULL);
-	for (i = 0; i < efipart_nhandles; i++) {
-		h = efipart_handles[i];
-		devpath = efi_lookup_devpath(h);
-		if (devpath == NULL)
-			continue;
-		if (!efi_devpath_match_node(media, efi_devpath_to_media_path(devpath)))
-			continue;
-		return (efiblk_get_pdinfo_by_handle(h));
-	}
-	return (NULL);
+	return (efiblk_get_pdinfo_by_handle(h));
 }
 
 static bool
@@ -185,6 +185,10 @@ efiblk_get_pdinfo_by_handle(EFI_HANDLE h)
 	STAILQ_FOREACH(dp, &cdinfo, pd_link) {
 		if (same_handle(dp, h))
 			return (dp);
+		STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
+			if (same_handle(pp, h))
+				return (pp);
+		}
 	}
 	STAILQ_FOREACH(dp, &fdinfo, pd_link) {
 		if (same_handle(dp, h))
@@ -208,15 +212,16 @@ efiblk_pdinfo_count(pdinfo_list_t *pdi)
 int
 efipart_inithandles(void)
 {
+	unsigned i, nin;
 	UINTN sz;
 	EFI_HANDLE *hin;
+	EFI_DEVICE_PATH *devpath;
+	EFI_BLOCK_IO *blkio;
 	EFI_STATUS status;
+	pdinfo_t *pd;
 
-	if (efipart_nhandles != 0) {
-		free(efipart_handles);
-		efipart_handles = NULL;
-		efipart_nhandles = 0;
-	}
+	if (!STAILQ_EMPTY(&pdinfo))
+		return (0);
 
 	sz = 0;
 	hin = NULL;
@@ -231,12 +236,60 @@ efipart_inithandles(void)
 	if (EFI_ERROR(status))
 		return (efi_status_to_errno(status));
 
-	efipart_handles = hin;
-	efipart_nhandles = sz / sizeof(*hin);
+	nin = sz / sizeof(*hin);
 #ifdef EFIPART_DEBUG
-	printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__,
-	    efipart_nhandles);
+	printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__, nin);
 #endif
+
+	for (i = 0; i < nin; i++) {
+		/*
+		 * Get devpath and open protocol.
+		 * We should not get errors here
+		 */
+		if ((devpath = efi_lookup_devpath(hin[i])) == NULL)
+			continue;
+
+		status = OpenProtocolByHandle(hin[i], &blkio_guid,
+		    (void **)&blkio);
+		if (EFI_ERROR(status)) {
+			printf("error %lu\n", EFI_ERROR_CODE(status));
+			continue;
+		}
+
+		/*
+		 * We assume the block size 512 or greater power of 2.
+		 * Also skip devices with block size > 64k (16 is max
+		 * ashift supported by zfs).
+		 * iPXE is known to insert stub BLOCK IO device with
+		 * BlockSize 1.
+		 */
+		if (blkio->Media->BlockSize < 512 ||
+		    blkio->Media->BlockSize > (1 << 16) ||
+		    !powerof2(blkio->Media->BlockSize)) {
+			continue;
+		}
+
+		/* Allowed values are 0, 1 and power of 2. */
+		if (blkio->Media->IoAlign > 1 &&
+		    !powerof2(blkio->Media->IoAlign)) {
+			continue;
+		}
+
+		/* This is bad. */
+		if ((pd = calloc(1, sizeof(*pd))) == NULL) {
+			printf("efipart_inithandles: Out of memory.\n");
+			free(hin);
+			return (ENOMEM);
+		}
+		STAILQ_INIT(&pd->pd_part);
+
+		pd->pd_handle = hin[i];
+		pd->pd_devpath = devpath;
+		pd->pd_blkio = blkio;
+		STAILQ_INSERT_TAIL(&pdinfo, pd, pd_link);
+	}
+
+	free(hin);
 	return (0);
 }
 
@@ -257,134 +310,49 @@ efipart_floppy(EFI_DEVICE_PATH *node)
 	return (NULL);
 }
 
-/*
- * Determine if the provided device path is hdd.
- *
- * There really is no simple fool proof way to classify the devices.
- * Since we do build three lists of devices - floppy, cd and hdd, we
- * will try to see  if the device is floppy or cd, and list anything else
- * as hdd.
- */
-static bool
-efipart_hdd(EFI_DEVICE_PATH *dp)
+static pdinfo_t *
+efipart_find_parent(pdinfo_list_t *pdi, EFI_DEVICE_PATH *devpath)
 {
-	unsigned i;
-	EFI_DEVICE_PATH *devpath, *node;
-	EFI_BLOCK_IO *blkio;
-	EFI_STATUS status;
+	pdinfo_t *pd;
 
-	if (dp == NULL)
-		return (false);
-
-	if ((node = efi_devpath_last_node(dp)) == NULL)
-		return (false);
-
-	if (efipart_floppy(node) != NULL)
-		return (false);
-
-	/*
-	 * Test every EFI BLOCK IO handle to make sure dp is not device path
-	 * for CD/DVD.
-	 */
-	for (i = 0; i < efipart_nhandles; i++) {
-		devpath = efi_lookup_devpath(efipart_handles[i]);
-		if (devpath == NULL)
-			return (false);
-
-		/* Only continue testing when dp is prefix in devpath. */
-		if (!efi_devpath_is_prefix(dp, devpath))
-			continue;
-
-		/*
-		 * The device path has to have last node describing the
-		 *  device, or we can not test the type.
-		 */
-		if ((node = efi_devpath_last_node(devpath)) == NULL)
-			return (false);
-
-		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
-		    DevicePathSubType(node) == MEDIA_CDROM_DP) {
-			return (false);
-		}
-
-		/* Make sure we do have the media. */
-		status = BS->HandleProtocol(efipart_handles[i],
-		    &blkio_guid, (void **)&blkio);
-		if (EFI_ERROR(status))
-			return (false);
-
-		/* USB or SATA cd without the media. */
-		if (blkio->Media->RemovableMedia &&
-		    !blkio->Media->MediaPresent) {
-			return (false);
-		}
-
-		/*
-		 * We assume the block size 512 or greater power of 2. 
-		 * iPXE is known to insert stub BLOCK IO device with
-		 * BlockSize 1.
-		 */
-		if (blkio->Media->BlockSize < 512 ||
-		    !powerof2(blkio->Media->BlockSize)) {
-			return (false);
-		}
+	STAILQ_FOREACH(pd, pdi, pd_link) {
+		if (efi_devpath_is_prefix(pd->pd_devpath, devpath))
+			return (pd);
 	}
-	return (true);
+	return (NULL);
 }
 
-/*
- * Add or update entries with new handle data.
- */
 static int
-efipart_fdinfo_add(EFI_HANDLE handle, uint32_t uid, EFI_DEVICE_PATH *devpath)
+efipart_initfd(void)
 {
-	pdinfo_t *fd;
-
-	fd = calloc(1, sizeof(pdinfo_t));
-	if (fd == NULL) {
-		printf("Failed to register floppy %d, out of memory\n", uid);
-		return (ENOMEM);
-	}
-	STAILQ_INIT(&fd->pd_part);
-
-	fd->pd_unit = uid;
-	fd->pd_handle = handle;
-	fd->pd_devpath = devpath;
-	fd->pd_parent = NULL;
-	fd->pd_devsw = &efipart_fddev;
-	STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
-	return (0);
-}
-
-static void
-efipart_updatefd(void)
-{
-	EFI_DEVICE_PATH *devpath, *node;
+	EFI_DEVICE_PATH *node;
 	ACPI_HID_DEVICE_PATH *acpi;
-	int i;
+	pdinfo_t *parent, *fd;
 
-	for (i = 0; i < efipart_nhandles; i++) {
-		devpath = efi_lookup_devpath(efipart_handles[i]);
-		if (devpath == NULL)
+restart:
+	STAILQ_FOREACH(fd, &pdinfo, pd_link) {
+		if ((node = efi_devpath_last_node(fd->pd_devpath)) == NULL)
 			continue;
 
-		if ((node = efi_devpath_last_node(devpath)) == NULL)
+		if ((acpi = efipart_floppy(node)) == NULL)
 			continue;
-		if ((acpi = efipart_floppy(node)) != NULL) {
-			efipart_fdinfo_add(efipart_handles[i], acpi->UID,
-			    devpath);
+
+		STAILQ_REMOVE(&pdinfo, fd, pdinfo, pd_link);
+		parent = efipart_find_parent(&pdinfo, fd->pd_devpath);
+		if (parent != NULL) {
+			STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
+			parent->pd_alias = fd->pd_handle;
+			parent->pd_unit = acpi->UID;
+			free(fd);
+			fd = parent;
+		} else {
+			fd->pd_unit = acpi->UID;
 		}
+		fd->pd_devsw = &efipart_fddev;
+		STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
+		goto restart;
 	}
-}
 
-static int
-efipart_initfd(void)
-{
-
-	STAILQ_INIT(&fdinfo);
-
-	efipart_updatefd();
-
 	bcache_add_dev(efiblk_pdinfo_count(&fdinfo));
 	return (0);
 }
@@ -392,68 +360,90 @@ efipart_initfd(void)
 /*
  * Add or update entries with new handle data.
  */
-static int
-efipart_cdinfo_add(EFI_HANDLE handle, EFI_HANDLE alias,
-    EFI_DEVICE_PATH *devpath)
+static void
+efipart_cdinfo_add(pdinfo_t *cd)
 {
-	int unit;
-	pdinfo_t *cd;
-	pdinfo_t *pd;
+	pdinfo_t *pd, *last;
 
-	unit = 0;
 	STAILQ_FOREACH(pd, &cdinfo, pd_link) {
-		if (efi_devpath_match(pd->pd_devpath, devpath) == true) {
-			pd->pd_handle = handle;
-			pd->pd_alias = alias;
-			return (0);
+		if (efi_devpath_is_prefix(pd->pd_devpath, cd->pd_devpath)) {
+			last = STAILQ_LAST(&pd->pd_part, pdinfo, pd_link);
+			if (last != NULL)
+				cd->pd_unit = last->pd_unit + 1;
+			else
+				cd->pd_unit = 0;
+			cd->pd_parent = pd;
+			cd->pd_devsw = &efipart_cddev;
+			STAILQ_INSERT_TAIL(&pd->pd_part, cd, pd_link);
+			return;
 		}
-		unit++;
 	}
 
-	cd = calloc(1, sizeof(pdinfo_t));
-	if (cd == NULL) {
-		printf("Failed to add cd %d, out of memory\n", unit);
-		return (ENOMEM);
-	}
-	STAILQ_INIT(&cd->pd_part);
+	last = STAILQ_LAST(&cdinfo, pdinfo, pd_link);
+	if (last != NULL)
+		cd->pd_unit = last->pd_unit + 1;
+	else
+		cd->pd_unit = 0;
 
-	cd->pd_handle = handle;
-	cd->pd_unit = unit;
-	cd->pd_alias = alias;
-	cd->pd_devpath = devpath;
 	cd->pd_parent = NULL;
 	cd->pd_devsw = &efipart_cddev;
 	STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link);
-	return (0);
 }
 
+static bool
+efipart_testcd(EFI_DEVICE_PATH *node, EFI_BLOCK_IO *blkio)
+{
+	if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
+	    DevicePathSubType(node) == MEDIA_CDROM_DP) {
+		return (true);
+	}
+
+	/* cd drive without the media. */
+	if (blkio->Media->RemovableMedia &&
+	    !blkio->Media->MediaPresent) {
+		return (true);
+	}
+
+	return (false);
+}
+
 static void
 efipart_updatecd(void)
 {
-	int i;
-	EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
-	EFI_HANDLE handle;
-	EFI_BLOCK_IO *blkio;
+	EFI_DEVICE_PATH *devpath, *node;
 	EFI_STATUS status;
+	pdinfo_t *parent, *cd;
 
-	for (i = 0; i < efipart_nhandles; i++) {
-		devpath = efi_lookup_devpath(efipart_handles[i]);
-		if (devpath == NULL)
+restart:
+	STAILQ_FOREACH(cd, &pdinfo, pd_link) {
+		if ((node = efi_devpath_last_node(cd->pd_devpath)) == NULL)
 			continue;
 
-		if ((node = efi_devpath_last_node(devpath)) == NULL)
-			continue;
-
 		if (efipart_floppy(node) != NULL)
 			continue;
 
-		if (efipart_hdd(devpath))
-			continue;
+		/* Is parent of this device already registered? */
+		parent = efipart_find_parent(&cdinfo, cd->pd_devpath);
+		if (parent != NULL) {
+			STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link);
+			efipart_cdinfo_add(cd);
+			goto restart;
+		}
 
-		status = BS->HandleProtocol(efipart_handles[i],
-		    &blkio_guid, (void **)&blkio);
-		if (EFI_ERROR(status))
+		if (!efipart_testcd(node, cd->pd_blkio))
 			continue;
+
+		/* Find parent and unlink both parent and cd from pdinfo */
+		STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link);
+		parent = efipart_find_parent(&pdinfo, cd->pd_devpath);
+		if (parent != NULL) {
+			STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
+			efipart_cdinfo_add(parent);
+		}
+
+		if (parent == NULL)
+			parent = efipart_find_parent(&cdinfo, cd->pd_devpath);
+
 		/*
 		 * If we come across a logical partition of subtype CDROM
 		 * it doesn't refer to the CD filesystem itself, but rather
@@ -462,132 +452,79 @@ efipart_updatecd(void)
 		 * that will be the CD filesystem.
 		 */
 		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
-		    DevicePathSubType(node) == MEDIA_CDROM_DP) {
-			devpathcpy = efi_devpath_trim(devpath);
-			if (devpathcpy == NULL)
-				continue;
-			tmpdevpath = devpathcpy;
-			status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
-			    &handle);
-			free(devpathcpy);
-			if (EFI_ERROR(status))
-				continue;
-			devpath = efi_lookup_devpath(handle);
-			efipart_cdinfo_add(handle, efipart_handles[i],
-			    devpath);
-			continue;
-		}
+		    DevicePathSubType(node) == MEDIA_CDROM_DP &&
+		    parent == NULL) {
+			parent = calloc(1, sizeof(*parent));
+			if (parent == NULL) {
+				printf("efipart_updatecd: out of memory\n");
+				/* this device is lost but try again. */
+				free(cd);
+				goto restart;
+			}
 
-		if (DevicePathType(node) == MESSAGING_DEVICE_PATH &&
-		    DevicePathSubType(node) == MSG_ATAPI_DP) {
-			efipart_cdinfo_add(efipart_handles[i], NULL,
-			    devpath);
-			continue;
+			devpath = efi_devpath_trim(cd->pd_devpath);
+			if (devpath == NULL) {
+				printf("efipart_updatecd: out of memory\n");
+				/* this device is lost but try again. */
+				free(parent);
+				free(cd);
+				goto restart;
+			}
+			parent->pd_devpath = devpath;
+			status = BS->LocateDevicePath(&blkio_guid,
+			    &parent->pd_devpath, &parent->pd_handle);
+			free(devpath);
+			if (EFI_ERROR(status)) {
+				printf("efipart_updatecd: error %lu\n",
+				    EFI_ERROR_CODE(status));
+				free(parent);
+				free(cd);
+				goto restart;
+			}
+			parent->pd_devpath =
+			    efi_lookup_devpath(parent->pd_handle);
+			efipart_cdinfo_add(parent);
 		}
 
-		/* USB or SATA cd without the media. */
-		if (blkio->Media->RemovableMedia &&
-		    !blkio->Media->MediaPresent) {
-			efipart_cdinfo_add(efipart_handles[i], NULL,
-			    devpath);
-		}
+		efipart_cdinfo_add(cd);
+		goto restart;
 	}
 }
 
 static int
 efipart_initcd(void)
 {
-
-	STAILQ_INIT(&cdinfo);
-
 	efipart_updatecd();
 
 	bcache_add_dev(efiblk_pdinfo_count(&cdinfo));
 	return (0);
 }
 
-static int
-efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle)
+static void
+efipart_hdinfo_add(pdinfo_t *hd, HARDDRIVE_DEVICE_PATH *node)
 {
-	EFI_DEVICE_PATH *disk_devpath, *part_devpath;
-	HARDDRIVE_DEVICE_PATH *node;
-	int unit;
-	pdinfo_t *hd, *pd, *last;
+	pdinfo_t *pd, *last;
 
-	disk_devpath = efi_lookup_devpath(disk_handle);
-	if (disk_devpath == NULL)
-		return (ENOENT);
-
-	if (part_handle != NULL) {
-		part_devpath = efi_lookup_devpath(part_handle);
-		if (part_devpath == NULL)
-			return (ENOENT);
-		node = (HARDDRIVE_DEVICE_PATH *)
-		    efi_devpath_last_node(part_devpath);
-		if (node == NULL)
-			return (ENOENT);	/* This should not happen. */
-	} else {
-		part_devpath = NULL;
-		node = NULL;
-	}
-
-	pd = calloc(1, sizeof(pdinfo_t));
-	if (pd == NULL) {
-		printf("Failed to add disk, out of memory\n");
-		return (ENOMEM);
-	}
-	STAILQ_INIT(&pd->pd_part);
-
-	STAILQ_FOREACH(hd, &hdinfo, pd_link) {
-		if (efi_devpath_match(hd->pd_devpath, disk_devpath) == true) {
-			if (part_devpath == NULL)
-				return (0);
-
+	STAILQ_FOREACH(pd, &hdinfo, pd_link) {
+		if (efi_devpath_is_prefix(pd->pd_devpath, hd->pd_devpath)) {
 			/* Add the partition. */
-			pd->pd_handle = part_handle;
-			pd->pd_unit = node->PartitionNumber;
-			pd->pd_devpath = part_devpath;
-			pd->pd_parent = hd;
-			pd->pd_devsw = &efipart_hddev;
-			STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
-			return (0);
+			hd->pd_unit = node->PartitionNumber;
+			hd->pd_parent = pd;
+			hd->pd_devsw = &efipart_hddev;
+			STAILQ_INSERT_TAIL(&pd->pd_part, hd, pd_link);
+			return;
 		}
 	}
 
 	last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
 	if (last != NULL)
-		unit = last->pd_unit + 1;
+		hd->pd_unit = last->pd_unit + 1;
 	else
-		unit = 0;
+		hd->pd_unit = 0;
 
 	/* Add the disk. */
-	hd = pd;
-	hd->pd_handle = disk_handle;
-	hd->pd_unit = unit;
-	hd->pd_devpath = disk_devpath;
-	hd->pd_parent = NULL;
 	hd->pd_devsw = &efipart_hddev;
 	STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
-
-	if (part_devpath == NULL)
-		return (0);
-
-	pd = calloc(1, sizeof(pdinfo_t));
-	if (pd == NULL) {
-		printf("Failed to add partition, out of memory\n");
-		return (ENOMEM);
-	}
-	STAILQ_INIT(&pd->pd_part);
-
-	/* Add the partition. */
-	pd->pd_handle = part_handle;
-	pd->pd_unit = node->PartitionNumber;
-	pd->pd_devpath = part_devpath;
-	pd->pd_parent = hd;
-	pd->pd_devsw = &efipart_hddev;
-	STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
-
-	return (0);
 }
 
 /*
@@ -596,40 +533,25 @@ efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE 
  * of typeN:M, where type is interface type, N is disk id
  * and M is partition id.
  */
-static int
-efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle)
+static void
+efipart_hdinfo_add_filepath(pdinfo_t *hd, FILEPATH_DEVICE_PATH *node)
 {
-	EFI_DEVICE_PATH *devpath;
-	FILEPATH_DEVICE_PATH *node;
 	char *pathname, *p;
-	int unit, len;
-	pdinfo_t *pd, *last;
+	int len;
+	pdinfo_t *last;
 
-	/* First collect and verify all the data */
-	if ((devpath = efi_lookup_devpath(disk_handle)) == NULL)
-		return (ENOENT);
-	node = (FILEPATH_DEVICE_PATH *)efi_devpath_last_node(devpath);
-	if (node == NULL)
-		return (ENOENT);	/* This should not happen. */
-
-	pd = calloc(1, sizeof(pdinfo_t));
-	if (pd == NULL) {
-		printf("Failed to add disk, out of memory\n");
-		return (ENOMEM);
-	}
-	STAILQ_INIT(&pd->pd_part);
 	last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
 	if (last != NULL)
-		unit = last->pd_unit + 1;
+		hd->pd_unit = last->pd_unit + 1;
 	else
-		unit = 0;
+		hd->pd_unit = 0;
 
 	/* FILEPATH_DEVICE_PATH has 0 terminated string */
 	len = ucs2len(node->PathName);
 	if ((pathname = malloc(len + 1)) == NULL) {
 		printf("Failed to add disk, out of memory\n");
-		free(pd);
-		return (ENOMEM);
+		free(hd);
+		return;
 	}
 	cpy16to8(node->PathName, pathname, len + 1);
 	p = strchr(pathname, ':');
@@ -640,23 +562,19 @@ efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle)
 	 * false, this code would need update.
 	 */
 	if (p == NULL) {	/* no colon, add the disk */
-		pd->pd_handle = disk_handle;
-		pd->pd_unit = unit;
-		pd->pd_devpath = devpath;
-		pd->pd_parent = NULL;
-		pd->pd_devsw = &efipart_hddev;
-		STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link);
+		hd->pd_devsw = &efipart_hddev;
+		STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
 		free(pathname);
-		return (0);
+		return;
 	}
 	p++;	/* skip the colon */
 	errno = 0;
-	unit = (int)strtol(p, NULL, 0);
+	hd->pd_unit = (int)strtol(p, NULL, 0);
 	if (errno != 0) {
 		printf("Bad unit number for partition \"%s\"\n", pathname);
 		free(pathname);
-		free(pd);
-		return (EUNIT);
+		free(hd);
+		return;
 	}
 
 	/*
@@ -668,80 +586,99 @@ efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle)
 	if (last == NULL) {
 		printf("BUG: No disk for partition \"%s\"\n", pathname);
 		free(pathname);
-		free(pd);
-		return (EINVAL);
+		free(hd);
+		return;
 	}
 	/* Add the partition. */
-	pd->pd_handle = disk_handle;
-	pd->pd_unit = unit;
-	pd->pd_devpath = devpath;
-	pd->pd_parent = last;
-	pd->pd_devsw = &efipart_hddev;
-	STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link);
+	hd->pd_parent = last;
+	hd->pd_devsw = &efipart_hddev;
+	STAILQ_INSERT_TAIL(&last->pd_part, hd, pd_link);
 	free(pathname);
-	return (0);
 }
 
 static void
 efipart_updatehd(void)
 {
-	int i;
-	EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
-	EFI_HANDLE handle;
-	EFI_BLOCK_IO *blkio;
+	EFI_DEVICE_PATH *devpath, *node;
 	EFI_STATUS status;
+	pdinfo_t *parent, *hd;
 
-	for (i = 0; i < efipart_nhandles; i++) {
-		devpath = efi_lookup_devpath(efipart_handles[i]);
-		if (devpath == NULL)
+restart:
+	STAILQ_FOREACH(hd, &pdinfo, pd_link) {
+		if ((node = efi_devpath_last_node(hd->pd_devpath)) == NULL)
 			continue;
 
-		if ((node = efi_devpath_last_node(devpath)) == NULL)
+		if (efipart_floppy(node) != NULL)
 			continue;
 
-		if (!efipart_hdd(devpath))
+		if (efipart_testcd(node, hd->pd_blkio))
 			continue;
 
-		status = BS->HandleProtocol(efipart_handles[i],
-		    &blkio_guid, (void **)&blkio);
-		if (EFI_ERROR(status))
-			continue;
+		if (DevicePathType(node) == HARDWARE_DEVICE_PATH &&
+		    (DevicePathSubType(node) == HW_PCI_DP ||
+		     DevicePathSubType(node) == HW_VENDOR_DP)) {
+			STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
+			efipart_hdinfo_add(hd, NULL);
+			goto restart;
+		}
 
 		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
 		    DevicePathSubType(node) == MEDIA_FILEPATH_DP) {
-			efipart_hdinfo_add_filepath(efipart_handles[i]);
-			continue;
+			STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
+			efipart_hdinfo_add_filepath(hd,
+			    (FILEPATH_DEVICE_PATH *)node);
+			goto restart;
 		}
 
+		STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
+		parent = efipart_find_parent(&pdinfo, hd->pd_devpath);
+		if (parent != NULL) {
+			STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
+			efipart_hdinfo_add(parent, NULL);
+		} else {
+			parent = efipart_find_parent(&hdinfo, hd->pd_devpath);
+		}
+
 		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
-		    DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) {
-			devpathcpy = efi_devpath_trim(devpath);
-			if (devpathcpy == NULL)
-				continue;
-			tmpdevpath = devpathcpy;
-			status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
-			    &handle);
-			free(devpathcpy);
-			if (EFI_ERROR(status))
-				continue;
-			/*
-			 * We do not support nested partitions.
-			 */
-			devpathcpy = efi_lookup_devpath(handle);
-			if (devpathcpy == NULL)
-				continue;
-			if ((node = efi_devpath_last_node(devpathcpy)) == NULL)
-				continue;
+		    DevicePathSubType(node) == MEDIA_HARDDRIVE_DP &&
+		    parent == NULL) {
+			parent = calloc(1, sizeof(*parent));
+			if (parent == NULL) {
+				printf("efipart_updatehd: out of memory\n");
+				/* this device is lost but try again. */
+				free(hd);
+				goto restart;
+			}
 
-			if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
-			    DevicePathSubType(node) == MEDIA_HARDDRIVE_DP)
-				continue;
+			devpath = efi_devpath_trim(hd->pd_devpath);
+			if (devpath == NULL) {
+				printf("efipart_updatehd: out of memory\n");
+				/* this device is lost but try again. */
+				free(parent);
+				free(hd);
+				goto restart;
+			}
 
-			efipart_hdinfo_add(handle, efipart_handles[i]);
-			continue;
+			parent->pd_devpath = devpath;
+			status = BS->LocateDevicePath(&blkio_guid,
+			    &parent->pd_devpath, &parent->pd_handle);
+			free(devpath);
+			if (EFI_ERROR(status)) {
+				printf("efipart_updatehd: error %lu\n",
+				    EFI_ERROR_CODE(status));
+				free(parent);
+				free(hd);
+				goto restart;
+			}
+
+			parent->pd_devpath =
+			    efi_lookup_devpath(&parent->pd_handle);
+
+			efipart_hdinfo_add(parent, NULL);
 		}
 
-		efipart_hdinfo_add(efipart_handles[i], NULL);
+		efipart_hdinfo_add(hd, (HARDDRIVE_DEVICE_PATH *)node);
+		goto restart;
 	}
 }
 
@@ -749,8 +686,6 @@ static int
 efipart_inithd(void)
 {
 
-	STAILQ_INIT(&hdinfo);
-
 	efipart_updatehd();
 
 	bcache_add_dev(efiblk_pdinfo_count(&hdinfo));

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201910141917.x9EJH0vQ029327>