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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to