svn commit: r313333 - in head: lib/libstand sys/boot/efi/include sys/boot/efi/libefi sys/boot/efi/loader sys/boot/zfs

Toomas Soome tsoome at FreeBSD.org
Mon Feb 6 09:18:49 UTC 2017


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 ***


More information about the svn-src-all mailing list