Author: tsoome
Date: Mon Feb  6 09:18:47 2017
New Revision: 313333
URL: https://svnweb.freebsd.org/changeset/base/313333

Log:
  loader: Replace EFI part devices.
  
  Rewrite EFI part device interface to present disk devices in more
  user friendly way.
  
  We keep list of three types of devices: floppy, cd and disk, the
  visible names: fdX: cdX: and diskX:
  
  Use common/disk.c and common/part.c interfaces to manage the
  partitioning.
  
  The lsdev -l will additionally list the device path.
  
  Reviewed by:  imp, allanjude
  Approved by:  imp (mentor), allanjude (mentor)
  Differential Revision:        https://reviews.freebsd.org/D8581

Modified:
  head/lib/libstand/stand.h
  head/sys/boot/efi/include/efilib.h
  head/sys/boot/efi/libefi/devpath.c
  head/sys/boot/efi/libefi/efipart.c
  head/sys/boot/efi/loader/conf.c
  head/sys/boot/efi/loader/devicename.c
  head/sys/boot/efi/loader/main.c
  head/sys/boot/zfs/zfs.c

Modified: head/lib/libstand/stand.h
==============================================================================
--- head/lib/libstand/stand.h   Mon Feb  6 08:58:40 2017        (r313332)
+++ head/lib/libstand/stand.h   Mon Feb  6 09:18:47 2017        (r313333)
@@ -168,6 +168,7 @@ struct devdesc
 #define DEVT_NET       2
 #define DEVT_CD                3
 #define DEVT_ZFS       4
+#define DEVT_FD                5
     int                        d_unit;
     void               *d_opendata;
 };

Modified: head/sys/boot/efi/include/efilib.h
==============================================================================
--- head/sys/boot/efi/include/efilib.h  Mon Feb  6 08:58:40 2017        
(r313332)
+++ head/sys/boot/efi/include/efilib.h  Mon Feb  6 09:18:47 2017        
(r313333)
@@ -31,16 +31,37 @@
 #define        _LOADER_EFILIB_H
 
 #include <stand.h>
+#include <sys/queue.h>
 
 extern EFI_HANDLE              IH;
 extern EFI_SYSTEM_TABLE                *ST;
 extern EFI_BOOT_SERVICES       *BS;
 extern EFI_RUNTIME_SERVICES    *RS;
 
-extern struct devsw efipart_dev;
+extern struct devsw efipart_fddev;
+extern struct devsw efipart_cddev;
+extern struct devsw efipart_hddev;
 extern struct devsw efinet_dev;
 extern struct netif_driver efinetif;
 
+/* EFI block device data, included here to help efi_zfs_probe() */
+typedef STAILQ_HEAD(pdinfo_list, pdinfo) pdinfo_list_t;
+
+typedef struct pdinfo
+{
+       STAILQ_ENTRY(pdinfo)    pd_link;        /* link in device list */
+       pdinfo_list_t           pd_part;        /* link of partitions */
+       EFI_HANDLE              pd_handle;
+       EFI_HANDLE              pd_alias;
+       EFI_DEVICE_PATH         *pd_devpath;
+       EFI_BLOCK_IO            *pd_blkio;
+       int                     pd_unit;        /* unit number */
+       int                     pd_open;        /* reference counter */
+       void                    *pd_bcache;     /* buffer cache data */
+} pdinfo_t;
+
+pdinfo_list_t *efiblk_get_pdinfo_list(struct devsw *dev);
+
 void *efi_get_table(EFI_GUID *tbl);
 
 int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int);
@@ -53,6 +74,7 @@ EFI_DEVICE_PATH *efi_lookup_devpath(EFI_
 EFI_HANDLE efi_devpath_handle(EFI_DEVICE_PATH *);
 EFI_DEVICE_PATH *efi_devpath_last_node(EFI_DEVICE_PATH *);
 EFI_DEVICE_PATH *efi_devpath_trim(EFI_DEVICE_PATH *);
+int efi_devpath_match(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *);
 CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *);
 void efi_free_devpath_name(CHAR16 *);
 

Modified: head/sys/boot/efi/libefi/devpath.c
==============================================================================
--- head/sys/boot/efi/libefi/devpath.c  Mon Feb  6 08:58:40 2017        
(r313332)
+++ head/sys/boot/efi/libefi/devpath.c  Mon Feb  6 09:18:47 2017        
(r313333)
@@ -138,3 +138,31 @@ efi_devpath_handle(EFI_DEVICE_PATH *devp
                return (NULL);
        return (h);
 }
+
+int
+efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
+{
+       int len;
+
+       if (devpath1 == NULL || devpath2 == NULL)
+               return (0);
+
+       while (1) {
+               if (DevicePathType(devpath1) != DevicePathType(devpath2) ||
+                   DevicePathSubType(devpath1) != DevicePathSubType(devpath2))
+                       return (0);
+
+               len = DevicePathNodeLength(devpath1);
+               if (len != DevicePathNodeLength(devpath2))
+                       return (0);
+
+               if (memcmp(devpath1, devpath2, (size_t)len) != 0)
+                       return (0);
+
+               if (IsDevicePathEnd(devpath1))
+                       break;
+               devpath1 = NextDevicePathNode(devpath1);
+               devpath2 = NextDevicePathNode(devpath2);
+       }
+       return (1);
+}

Modified: head/sys/boot/efi/libefi/efipart.c
==============================================================================
--- head/sys/boot/efi/libefi/efipart.c  Mon Feb  6 08:58:40 2017        
(r313332)
+++ head/sys/boot/efi/libefi/efipart.c  Mon Feb  6 09:18:47 2017        
(r313333)
@@ -27,8 +27,10 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/disk.h>
 #include <sys/param.h>
 #include <sys/time.h>
+#include <sys/queue.h>
 #include <stddef.h>
 #include <stdarg.h>
 
@@ -37,57 +39,110 @@ __FBSDID("$FreeBSD$");
 #include <efi.h>
 #include <efilib.h>
 #include <efiprot.h>
+#include <disk.h>
 
 static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
 
-static int efipart_init(void);
+static int efipart_initfd(void);
+static int efipart_initcd(void);
+static int efipart_inithd(void);
+
 static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *);
 static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t 
*);
+
 static int efipart_open(struct open_file *, ...);
 static int efipart_close(struct open_file *);
-static int efipart_print(int);
+static int efipart_ioctl(struct open_file *, u_long, void *);
 
-struct devsw efipart_dev = {
-       .dv_name = "part",
-       .dv_type = DEVT_DISK,
-       .dv_init = efipart_init,
+static int efipart_printfd(int);
+static int efipart_printcd(int);
+static int efipart_printhd(int);
+
+struct devsw efipart_fddev = {
+       .dv_name = "fd",
+       .dv_type = DEVT_FD,
+       .dv_init = efipart_initfd,
        .dv_strategy = efipart_strategy,
        .dv_open = efipart_open,
        .dv_close = efipart_close,
-       .dv_ioctl = noioctl,
-       .dv_print = efipart_print,
+       .dv_ioctl = efipart_ioctl,
+       .dv_print = efipart_printfd,
        .dv_cleanup = NULL
 };
 
-/*
- * info structure to support bcache
- */
-struct pdinfo {
-       int     pd_unit;        /* unit number */
-       int     pd_open;        /* reference counter */
-       void    *pd_bcache;     /* buffer cache data */
+struct devsw efipart_cddev = {
+       .dv_name = "cd",
+       .dv_type = DEVT_CD,
+       .dv_init = efipart_initcd,
+       .dv_strategy = efipart_strategy,
+       .dv_open = efipart_open,
+       .dv_close = efipart_close,
+       .dv_ioctl = efipart_ioctl,
+       .dv_print = efipart_printcd,
+       .dv_cleanup = NULL
 };
-static struct pdinfo *pdinfo;
-static int npdinfo = 0;
 
-#define PD(dev)         (pdinfo[(dev)->d_unit])
+struct devsw efipart_hddev = {
+       .dv_name = "disk",
+       .dv_type = DEVT_DISK,
+       .dv_init = efipart_inithd,
+       .dv_strategy = efipart_strategy,
+       .dv_open = efipart_open,
+       .dv_close = efipart_close,
+       .dv_ioctl = efipart_ioctl,
+       .dv_print = efipart_printhd,
+       .dv_cleanup = NULL
+};
+
+static pdinfo_list_t fdinfo;
+static pdinfo_list_t cdinfo;
+static pdinfo_list_t hdinfo;
+
+static EFI_HANDLE *efipart_handles = NULL;
+static UINTN efipart_nhandles = 0;
+
+static pdinfo_t *
+efiblk_get_pdinfo(pdinfo_list_t *pdi, int unit)
+{
+       pdinfo_t *pd;
+
+       STAILQ_FOREACH(pd, pdi, pd_link) {
+               if (pd->pd_unit == unit)
+                       return (pd);
+       }
+       return (NULL);
+}
 
 static int
-efipart_init(void) 
+efiblk_pdinfo_count(pdinfo_list_t *pdi)
+{
+       pdinfo_t *pd;
+       int i = 0;
+
+       STAILQ_FOREACH(pd, pdi, pd_link) {
+               i++;
+       }
+       return (i);
+}
+
+static int
+efipart_inithandles(void)
 {
-       EFI_BLOCK_IO *blkio;
-       EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
-       EFI_HANDLE *hin, *hout, *aliases, handle;
-       EFI_STATUS status;
        UINTN sz;
-       u_int n, nin, nout, nrdisk;
-       int err;
+       EFI_HANDLE *hin;
+       EFI_STATUS status;
+
+       if (efipart_nhandles != 0) {
+               free(efipart_handles);
+               efipart_handles = NULL;
+               efipart_nhandles = 0;
+       }
 
        sz = 0;
        hin = NULL;
-       status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0);
+       status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin);
        if (status == EFI_BUFFER_TOO_SMALL) {
-               hin = (EFI_HANDLE *)malloc(sz * 3);
+               hin = malloc(sz);
                status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
                    hin);
                if (EFI_ERROR(status))
@@ -96,33 +151,150 @@ efipart_init(void) 
        if (EFI_ERROR(status))
                return (efi_status_to_errno(status));
 
-       /* Filter handles to only include FreeBSD partitions. */
-       nin = sz / sizeof(EFI_HANDLE);
-       hout = hin + nin;
-       aliases = hout + nin;
-       nout = 0;
-       nrdisk = 0;
-
-       bzero(aliases, nin * sizeof(EFI_HANDLE));
-       pdinfo = malloc(nin * sizeof(*pdinfo));
-       if (pdinfo == NULL)
-               return (ENOMEM);
+       efipart_handles = hin;
+       efipart_nhandles = sz;
+       return (0);
+}
 
-       for (n = 0; n < nin; n++) {
-               devpath = efi_lookup_devpath(hin[n]);
-               if (devpath == NULL) {
-                       continue;
+static ACPI_HID_DEVICE_PATH *
+efipart_floppy(EFI_DEVICE_PATH *node)
+{
+       ACPI_HID_DEVICE_PATH *acpi = NULL;
+
+       if (DevicePathType(node) == ACPI_DEVICE_PATH &&
+           DevicePathSubType(node) == ACPI_DP) {
+               acpi = (ACPI_HID_DEVICE_PATH *) node;
+               if (acpi->HID == EISA_PNP_ID(0x604) ||
+                   acpi->HID == EISA_PNP_ID(0x700) ||
+                   acpi->HID == EISA_ID(0x41d1, 0x701)) {
+                       return (acpi);
                }
+       }
+       return (acpi);
+}
 
-               status = BS->HandleProtocol(hin[n], &blkio_guid,
-                   (void**)&blkio);
-               if (EFI_ERROR(status))
+/*
+ * Add or update entries with new handle data.
+ */
+static int
+efipart_fdinfo_add(EFI_HANDLE handle, uint32_t uid, EFI_DEVICE_PATH *devpath)
+{
+       pdinfo_t *fd;
+
+       fd = malloc(sizeof(pdinfo_t));
+       if (fd == NULL) {
+               printf("Failed to register floppy %d, out of memory\n", uid);
+               return (ENOMEM);
+       }
+       memset(fd, 0, sizeof(pdinfo_t));
+       STAILQ_INIT(&fd->pd_part);
+
+       fd->pd_unit = uid;
+       fd->pd_handle = handle;
+       fd->pd_devpath = devpath;
+       STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
+       return (0);
+}
+
+static void
+efipart_updatefd(void)
+{
+       EFI_DEVICE_PATH *devpath, *node;
+       ACPI_HID_DEVICE_PATH *acpi;
+       int i, nin;
+
+       nin = efipart_nhandles / sizeof (*efipart_handles);
+       for (i = 0; i < nin; i++) {
+               devpath = efi_lookup_devpath(efipart_handles[i]);
+               if (devpath == NULL)
                        continue;
-               if (!blkio->Media->LogicalPartition) {
-                       nrdisk++;
+
+               if ((node = efi_devpath_last_node(devpath)) == NULL)
                        continue;
+               if ((acpi = efipart_floppy(node)) != NULL) {
+                       efipart_fdinfo_add(efipart_handles[i], acpi->UID,
+                           devpath);
+               }
+       }
+}
+
+static int
+efipart_initfd(void)
+{
+       int rv;
+
+       rv = efipart_inithandles();
+       if (rv != 0)
+               return (rv);
+       STAILQ_INIT(&fdinfo);
+
+       efipart_updatefd();
+
+       bcache_add_dev(efiblk_pdinfo_count(&fdinfo));
+       return (0);
+}
+
+/*
+ * Add or update entries with new handle data.
+ */
+static int
+efipart_cdinfo_add(EFI_HANDLE handle, EFI_HANDLE alias,
+    EFI_DEVICE_PATH *devpath)
+{
+       int unit;
+       pdinfo_t *cd;
+       pdinfo_t *pd;
+
+       unit = 0;
+       STAILQ_FOREACH(pd, &cdinfo, pd_link) {
+               if (efi_devpath_match(pd->pd_devpath, devpath) != 0) {
+                       pd->pd_handle = handle;
+                       pd->pd_alias = alias;
+                       return (0);
                }
+               unit++;
+       }
+ 
+       cd = malloc(sizeof(pdinfo_t));
+       if (cd == NULL) {
+               printf("Failed to add cd %d, out of memory\n", unit);
+               return (ENOMEM);
+       }
+       memset(cd, 0, sizeof(pdinfo_t));
+       STAILQ_INIT(&cd->pd_part);
+
+       cd->pd_handle = handle;
+       cd->pd_unit = unit;
+       cd->pd_alias = alias;
+       cd->pd_devpath = devpath;
+       STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link);
+       return (0);
+}
+
+static void
+efipart_updatecd(void)
+{
+       int i, nin;
+       EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
+       EFI_HANDLE handle;
+       EFI_BLOCK_IO *blkio;
+       EFI_STATUS status;
 
+       nin = efipart_nhandles / sizeof (*efipart_handles);
+       for (i = 0; i < nin; i++) {
+               devpath = efi_lookup_devpath(efipart_handles[i]);
+               if (devpath == NULL)
+                       continue;
+
+               if ((node = efi_devpath_last_node(devpath)) == NULL)
+                       continue;
+               if (efipart_floppy(node) != NULL)
+                       continue;
+ 
+               status = BS->HandleProtocol(efipart_handles[i],
+                   &blkio_guid, (void **)&blkio);
+               if (EFI_ERROR(status))
+                       continue;
                /*
                 * If we come across a logical partition of subtype CDROM
                 * it doesn't refer to the CD filesystem itself, but rather
@@ -130,8 +302,6 @@ efipart_init(void) 
                 * we try to find the parent device and add that instead as
                 * that will be the CD filesystem.
                 */
-               if ((node = efi_devpath_last_node(devpath)) == NULL)
-                       continue;
                if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
                    DevicePathSubType(node) == MEDIA_CDROM_DP) {
                        devpathcpy = efi_devpath_trim(devpath);
@@ -143,109 +313,400 @@ efipart_init(void) 
                        free(devpathcpy);
                        if (EFI_ERROR(status))
                                continue;
-                       hout[nout] = handle;
-                       aliases[nout] = hin[n];
-               } else
-                       hout[nout] = hin[n];
-               nout++;
-               pdinfo[npdinfo].pd_open = 0;
-               pdinfo[npdinfo].pd_bcache = NULL;
-               pdinfo[npdinfo].pd_unit = npdinfo;
-               npdinfo++;
+                       devpath = efi_lookup_devpath(handle);
+                       efipart_cdinfo_add(handle, efipart_handles[i],
+                           devpath);
+                       continue;
+               }
+
+               if (DevicePathType(node) == MESSAGING_DEVICE_PATH &&
+                   DevicePathSubType(node) == MSG_ATAPI_DP) {
+                       efipart_cdinfo_add(efipart_handles[i], NULL,
+                           devpath);
+                       continue;
+               }
+
+               /* USB or SATA cd without the media. */
+               if (blkio->Media->RemovableMedia &&
+                   !blkio->Media->MediaPresent) {
+                       efipart_cdinfo_add(efipart_handles[i], NULL,
+                           devpath);
+               }
        }
+}
 
-       bcache_add_dev(npdinfo);
-       err = efi_register_handles(&efipart_dev, hout, aliases, nout);
-       free(hin);
+static int
+efipart_initcd(void)
+{
+       int rv;
+
+       rv = efipart_inithandles();
+       if (rv != 0)
+               return (rv);
+       STAILQ_INIT(&cdinfo);
 
-       if (nout == 0 && nrdisk > 0)
-               printf("Found %d disk(s) but no logical partition\n", nrdisk);
-       return (err);
+       efipart_updatecd();
+
+       bcache_add_dev(efiblk_pdinfo_count(&cdinfo));
+       return (0);
 }
 
 static int
-efipart_print(int verbose)
+efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle)
 {
-       char line[80];
+       EFI_DEVICE_PATH *disk_devpath, *part_devpath;
+       HARDDRIVE_DEVICE_PATH *node;
+       int unit;
+       pdinfo_t *hd, *pd, *last;
+
+       disk_devpath = efi_lookup_devpath(disk_handle);
+       part_devpath = efi_lookup_devpath(part_handle);
+       if (disk_devpath == NULL || part_devpath == NULL) {
+               return (ENOENT);
+       }
+
+       pd = malloc(sizeof(pdinfo_t));
+       if (pd == NULL) {
+               printf("Failed to add disk, out of memory\n");
+               return (ENOMEM);
+       }
+       memset(pd, 0, sizeof(pdinfo_t));
+       STAILQ_INIT(&pd->pd_part);
+       node = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(part_devpath);
+
+       STAILQ_FOREACH(hd, &hdinfo, pd_link) {
+               if (efi_devpath_match(hd->pd_devpath, disk_devpath) != 0) {
+                       /* Add the partition. */
+                       pd->pd_handle = part_handle;
+                       pd->pd_unit = node->PartitionNumber;
+                       pd->pd_devpath = part_devpath;
+                       STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
+                       return (0);
+               }
+       }
+
+       last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
+       if (last != NULL)
+               unit = last->pd_unit + 1;
+       else
+               unit = 0;
+
+       /* Add the disk. */
+       hd = pd;
+       hd->pd_handle = disk_handle;
+       hd->pd_unit = unit;
+       hd->pd_devpath = disk_devpath;
+       STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
+
+       pd = malloc(sizeof(pdinfo_t));
+       if (pd == NULL) {
+               printf("Failed to add partition, out of memory\n");
+               return (ENOMEM);
+       }
+       memset(pd, 0, sizeof(pdinfo_t));
+       STAILQ_INIT(&pd->pd_part);
+
+       /* Add the partition. */
+       pd->pd_handle = part_handle;
+       pd->pd_unit = node->PartitionNumber;
+       pd->pd_devpath = part_devpath;
+       STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
+
+       return (0);
+}
+
+static void
+efipart_updatehd(void)
+{
+       int i, nin;
+       EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
+       EFI_HANDLE handle;
        EFI_BLOCK_IO *blkio;
-       EFI_HANDLE h;
        EFI_STATUS status;
-       u_int unit;
+
+       nin = efipart_nhandles / sizeof (*efipart_handles);
+       for (i = 0; i < nin; i++) {
+               devpath = efi_lookup_devpath(efipart_handles[i]);
+               if (devpath == NULL)
+                       continue;
+
+               if ((node = efi_devpath_last_node(devpath)) == NULL)
+                       continue;
+               if (efipart_floppy(node) != NULL)
+                       continue;
+
+               status = BS->HandleProtocol(efipart_handles[i],
+                   &blkio_guid, (void **)&blkio);
+               if (EFI_ERROR(status))
+                       continue;
+
+               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;
+                       if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
+                           DevicePathSubType(node) == MEDIA_HARDDRIVE_DP)
+                               continue;
+                       efipart_hdinfo_add(handle, efipart_handles[i]);
+                       continue;
+               }
+       }
+}
+
+static int
+efipart_inithd(void)
+{
+       int rv;
+
+       rv = efipart_inithandles();
+       if (rv != 0)
+               return (rv);
+       STAILQ_INIT(&hdinfo);
+
+       efipart_updatehd();
+
+       bcache_add_dev(efiblk_pdinfo_count(&hdinfo));
+       return (0);
+}
+
+static int
+efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose)
+{
        int ret = 0;
+       EFI_BLOCK_IO *blkio;
+       EFI_STATUS status;
+       EFI_HANDLE h;
+       pdinfo_t *pd;
+       CHAR16 *text;
+       struct disk_devdesc pd_dev;
+       char line[80];
 
-       printf("%s devices:", efipart_dev.dv_name);
+       if (STAILQ_EMPTY(pdlist))
+               return (0);
+ 
+       printf("%s devices:", dev->dv_name);
        if ((ret = pager_output("\n")) != 0)
                return (ret);
 
-       for (unit = 0, h = efi_find_handle(&efipart_dev, 0);
-           h != NULL; h = efi_find_handle(&efipart_dev, ++unit)) {
-               snprintf(line, sizeof(line), "    %s%d:",
-                   efipart_dev.dv_name, unit);
-               if ((ret = pager_output(line)) != 0)
-                       break;
-
+       STAILQ_FOREACH(pd, pdlist, pd_link) {
+               h = pd->pd_handle;
+               if (verbose) {  /* Output the device path. */
+                       text = efi_devpath_name(efi_lookup_devpath(h));
+                       if (text != NULL) {
+                               printf("  %S", text);
+                               efi_free_devpath_name(text);
+                               if ((ret = pager_output("\n")) != 0)
+                                       break;
+                       }
+               }
+               snprintf(line, sizeof(line),
+                   "    %s%d", dev->dv_name, pd->pd_unit);
+               printf("%s:", line);
                status = BS->HandleProtocol(h, &blkio_guid, (void **)&blkio);
                if (!EFI_ERROR(status)) {
-                       snprintf(line, sizeof(line), "    %llu blocks",
-                           (unsigned long long)(blkio->Media->LastBlock + 1));
-                       if ((ret = pager_output(line)) != 0)
+                       printf("    %llu",
+                           blkio->Media->LastBlock == 0? 0:
+                           (unsigned long long) (blkio->Media->LastBlock + 1));
+                       if (blkio->Media->LastBlock != 0) {
+                               printf(" X %u", blkio->Media->BlockSize);
+                       }
+                       printf(" blocks");
+                       if (blkio->Media->MediaPresent) {
+                               if (blkio->Media->RemovableMedia)
+                                       printf(" (removable)");
+                       } else
+                               printf(" (no media)");
+                       if ((ret = pager_output("\n")) != 0)
+                               break;
+                       if (!blkio->Media->MediaPresent)
+                               continue;
+
+                       pd->pd_blkio = blkio;
+                       pd_dev.d_dev = dev;
+                       pd_dev.d_unit = pd->pd_unit;
+                       pd_dev.d_slice = -1;
+                       pd_dev.d_partition = -1;
+                       pd_dev.d_opendata = blkio;
+                       ret = disk_open(&pd_dev, blkio->Media->BlockSize *
+                           (blkio->Media->LastBlock + 1),
+                           blkio->Media->BlockSize,
+                           blkio->Media->RemovableMedia? DISK_F_NOCACHE: 0);
+                       if (ret == 0) {
+                               ret = disk_print(&pd_dev, line, verbose);
+                               disk_close(&pd_dev);
+                               if (ret != 0)
+                                       return (ret);
+                       } else {
+                               /* Do not fail from disk_open() */
+                               ret = 0;
+                       }
+               } else {
+                       if ((ret = pager_output("\n")) != 0)
                                break;
-                       if (blkio->Media->RemovableMedia)
-                               if ((ret = pager_output(" (removable)")) != 0)
-                                       break;
                }
-               if ((ret = pager_output("\n")) != 0)
-                       break;
        }
        return (ret);
 }
 
 static int
+efipart_printfd(int verbose)
+{
+       return (efipart_print_common(&efipart_fddev, &fdinfo, verbose));
+}
+
+static int
+efipart_printcd(int verbose)
+{
+       return (efipart_print_common(&efipart_cddev, &cdinfo, verbose));
+}
+
+static int
+efipart_printhd(int verbose)
+{
+       return (efipart_print_common(&efipart_hddev, &hdinfo, verbose));
+}
+
+pdinfo_list_t *
+efiblk_get_pdinfo_list(struct devsw *dev)
+{
+       if (dev->dv_type == DEVT_DISK)
+               return (&hdinfo);
+       if (dev->dv_type == DEVT_CD)
+               return (&cdinfo);
+       if (dev->dv_type == DEVT_FD)
+               return (&fdinfo);
+       return (NULL);
+}
+
+static int
 efipart_open(struct open_file *f, ...)
 {
        va_list args;
-       struct devdesc *dev;
+       struct disk_devdesc *dev;
+       pdinfo_list_t *pdi;
+       pdinfo_t *pd;
        EFI_BLOCK_IO *blkio;
-       EFI_HANDLE h;
        EFI_STATUS status;
 
        va_start(args, f);
-       dev = va_arg(args, struct devdesc*);
+       dev = va_arg(args, struct disk_devdesc*);
        va_end(args);
+       if (dev == NULL)
+               return (EINVAL);
 
-       h = efi_find_handle(&efipart_dev, dev->d_unit);
-       if (h == NULL)
+       pdi = efiblk_get_pdinfo_list(dev->d_dev);
+       if (pdi == NULL)
                return (EINVAL);
 
-       status = BS->HandleProtocol(h, &blkio_guid, (void **)&blkio);
-       if (EFI_ERROR(status))
-               return (efi_status_to_errno(status));
+       pd = efiblk_get_pdinfo(pdi, dev->d_unit);
+       if (pd == NULL)
+               return (EIO);
+ 
+       if (pd->pd_blkio == NULL) {
+               status = BS->HandleProtocol(pd->pd_handle, &blkio_guid,
+                   (void **)&pd->pd_blkio);
+               if (EFI_ERROR(status))
+                       return (efi_status_to_errno(status));
+       }
 
+       blkio = pd->pd_blkio;
        if (!blkio->Media->MediaPresent)
                return (EAGAIN);
 
-       dev->d_opendata = blkio;
-       PD(dev).pd_open++;
-       if (PD(dev).pd_bcache == NULL)
-               PD(dev).pd_bcache = bcache_allocate();
+       pd->pd_open++;
+       if (pd->pd_bcache == NULL)
+               pd->pd_bcache = bcache_allocate();
+
+       if (dev->d_dev->dv_type == DEVT_DISK) {
+               return (disk_open(dev,
+                   blkio->Media->BlockSize * (blkio->Media->LastBlock + 1),
+                   blkio->Media->BlockSize,
+                   blkio->Media->RemovableMedia? DISK_F_NOCACHE: 0));
+       }
        return (0);
 }
 
 static int
 efipart_close(struct open_file *f)
 {
-       struct devdesc *dev;
+       struct disk_devdesc *dev;
+       pdinfo_list_t *pdi;
+       pdinfo_t *pd;
 
-       dev = (struct devdesc *)(f->f_devdata);
-       if (dev->d_opendata == NULL)
+       dev = (struct disk_devdesc *)(f->f_devdata);
+       if (dev == NULL)
+               return (EINVAL);
+       pdi = efiblk_get_pdinfo_list(dev->d_dev);
+       if (pdi == NULL)
                return (EINVAL);
 
-       dev->d_opendata = NULL;
-       PD(dev).pd_open--;
-       if (PD(dev).pd_open == 0) {
-               bcache_free(PD(dev).pd_bcache);
-               PD(dev).pd_bcache = NULL;
+       pd = efiblk_get_pdinfo(pdi, dev->d_unit);
+       if (pd == NULL)
+               return (EINVAL);
+
+       pd->pd_open--;
+       if (pd->pd_open == 0) {
+               pd->pd_blkio = NULL;
+               bcache_free(pd->pd_bcache);
+               pd->pd_bcache = NULL;
        }
+       if (dev->d_dev->dv_type == DEVT_DISK)
+               return (disk_close(dev));
+       return (0);
+}
+
+static int
+efipart_ioctl(struct open_file *f, u_long cmd, void *data)
+{
+       struct disk_devdesc *dev;
+       pdinfo_list_t *pdi;
+       pdinfo_t *pd;
+       int rc;
+
+       dev = (struct disk_devdesc *)(f->f_devdata);
+       if (dev == NULL)
+               return (EINVAL);
+       pdi = efiblk_get_pdinfo_list(dev->d_dev);
+       if (pdi == NULL)
+               return (EINVAL);
+
+       pd = efiblk_get_pdinfo(pdi, dev->d_unit);
+       if (pd == NULL)
+               return (EINVAL);
+
+       if (dev->d_dev->dv_type == DEVT_DISK) {
+               rc = disk_ioctl(dev, cmd, data);
+               if (rc != ENOTTY)
+                       return (rc);
+       }
+
+       switch (cmd) {
+       case DIOCGSECTORSIZE:
+               *(u_int *)data = pd->pd_blkio->Media->BlockSize;
+               break;
+       case DIOCGMEDIASIZE:
+               *(off_t *)data = pd->pd_blkio->Media->BlockSize *
+                   (pd->pd_blkio->Media->LastBlock + 1);
+               break;
+       default:
+               return (ENOTTY);
+       }
+
        return (0);
 }
 
@@ -294,12 +755,29 @@ efipart_strategy(void *devdata, int rw, 
     char *buf, size_t *rsize)
 {
        struct bcache_devdata bcd;
-       struct devdesc *dev;
+       struct disk_devdesc *dev;
+       pdinfo_list_t *pdi;
+       pdinfo_t *pd;
+
+       dev = (struct disk_devdesc *)devdata;
+       if (dev == NULL)
+               return (EINVAL);
+       pdi = efiblk_get_pdinfo_list(dev->d_dev);
+       if (pdi == NULL)
+               return (EINVAL);
+
+       pd = efiblk_get_pdinfo(pdi, dev->d_unit);
+       if (pd == NULL)
+               return (EINVAL);
 
-       dev = (struct devdesc *)devdata;
        bcd.dv_strategy = efipart_realstrategy;
        bcd.dv_devdata = devdata;
-       bcd.dv_cache = PD(dev).pd_bcache;
+       bcd.dv_cache = pd->pd_bcache;
+
+       if (dev->d_dev->dv_type == DEVT_DISK) {
+               return (bcache_strategy(&bcd, rw, blk + dev->d_offset,
+                   size, buf, rsize));
+       }
        return (bcache_strategy(&bcd, rw, blk, size, buf, rsize));
 }
 
@@ -307,7 +785,9 @@ static int
 efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
     char *buf, size_t *rsize)
 {
-       struct devdesc *dev = (struct devdesc *)devdata;
+       struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
+       pdinfo_list_t *pdi;
+       pdinfo_t *pd;
        EFI_BLOCK_IO *blkio;
        off_t off;
        char *blkbuf;
@@ -317,7 +797,15 @@ efipart_realstrategy(void *devdata, int 
        if (dev == NULL || blk < 0)
                return (EINVAL);
 
-       blkio = dev->d_opendata;
+       pdi = efiblk_get_pdinfo_list(dev->d_dev);
+       if (pdi == NULL)
+               return (EINVAL);
+
+       pd = efiblk_get_pdinfo(pdi, dev->d_unit);
+       if (pd == NULL)
+               return (EINVAL);
+
+       blkio = pd->pd_blkio;
        if (blkio == NULL)
                return (ENXIO);
 

Modified: head/sys/boot/efi/loader/conf.c
==============================================================================
--- head/sys/boot/efi/loader/conf.c     Mon Feb  6 08:58:40 2017        
(r313332)
+++ head/sys/boot/efi/loader/conf.c     Mon Feb  6 09:18:47 2017        
(r313333)
@@ -36,7 +36,9 @@ __FBSDID("$FreeBSD$");
 #endif
 
 struct devsw *devsw[] = {
-       &efipart_dev,
+       &efipart_fddev,
+       &efipart_cddev,
+       &efipart_hddev,
        &efinet_dev,
 #ifdef EFI_ZFS_BOOT
        &zfs_dev,

Modified: head/sys/boot/efi/loader/devicename.c
==============================================================================
--- head/sys/boot/efi/loader/devicename.c       Mon Feb  6 08:58:40 2017        
(r313332)
+++ head/sys/boot/efi/loader/devicename.c       Mon Feb  6 09:18:47 2017        
(r313333)
@@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/disklabel.h>
 #include <sys/param.h>
 #include <bootstrap.h>
+#include <disk.h>
 #ifdef EFI_ZFS_BOOT
 #include <libzfs.h>
 #endif
@@ -90,7 +91,7 @@ efi_parsedev(struct devdesc **dev, const
        struct devsw *dv;
        char *cp;
        const char *np;
-       int i;
+       int i, err;
 
        /* minimum length check */
        if (strlen(devspec) < 2)
@@ -106,11 +107,26 @@ efi_parsedev(struct devdesc **dev, const
                return (ENOENT);
 
        np = devspec + strlen(dv->dv_name);
+       err = 0;
 
-#ifdef EFI_ZFS_BOOT
-       if (dv->dv_type == DEVT_ZFS) {
-               int err;
+       switch (dv->dv_type) {
+       case DEVT_NONE:
+               break;
+
+       case DEVT_DISK:
+               idev = malloc(sizeof(struct disk_devdesc));
+               if (idev == NULL)
+                       return (ENOMEM);
+
+               err = disk_parsedev((struct disk_devdesc *)idev, np, path);
+               if (err != 0) {
+                       free(idev);
+                       return (err);
+               }
+               break;
 
+#ifdef EFI_ZFS_BOOT
+       case DEVT_ZFS:

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to