Page MenuHomeFreeBSD

D8581.id22355.diff
No OneTemporary

D8581.id22355.diff

Index: lib/libstand/stand.h
===================================================================
--- lib/libstand/stand.h
+++ lib/libstand/stand.h
@@ -168,6 +168,7 @@
#define DEVT_NET 2
#define DEVT_CD 3
#define DEVT_ZFS 4
+#define DEVT_FD 5
int d_unit;
void *d_opendata;
};
Index: sys/boot/common/disk.c
===================================================================
--- sys/boot/common/disk.c
+++ sys/boot/common/disk.c
@@ -46,6 +46,7 @@
struct open_disk {
struct ptable *table;
off_t mediasize;
+ off_t entrysize;
u_int sectorsize;
u_int flags;
int rcnt;
@@ -264,13 +265,25 @@
}
int
-disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *buf)
+disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *data)
{
+ struct open_disk *od = dev->d_opendata;
- if (dev->d_dev->dv_ioctl)
- return ((*dev->d_dev->dv_ioctl)(dev->d_opendata, cmd, buf));
+ switch (cmd) {
+ case DIOCGSECTORSIZE:
+ *(u_int *)data = od->sectorsize;
+ break;
+ case DIOCGMEDIASIZE:
+ if (dev->d_offset == 0)
+ *(off_t *)data = od->mediasize;
+ else
+ *(off_t *)data = od->entrysize * od->sectorsize;
+ break;
+ default:
+ return (ENOTTY);
+ }
- return (ENXIO);
+ return (0);
}
int
@@ -315,6 +328,7 @@
}
dev->d_opendata = od;
od->rcnt = 0;
+ od->entrysize = 0;
}
od->mediasize = mediasize;
od->sectorsize = sectorsize;
@@ -336,8 +350,10 @@
partition >= 0) {
/* It doesn't matter what value has d_slice */
rc = ptable_getpart(od->table, &part, partition);
- if (rc == 0)
+ if (rc == 0) {
dev->d_offset = part.start;
+ od->entrysize = part.end - part.start + 1;
+ }
} else if (slice >= 0) {
/* Try to get information about partition */
if (slice == 0)
@@ -347,6 +363,7 @@
if (rc != 0) /* Partition doesn't exist */
goto out;
dev->d_offset = part.start;
+ od->entrysize = part.end - part.start + 1;
slice = part.index;
if (ptable_gettype(od->table) == PTABLE_GPT) {
partition = 255;
@@ -389,6 +406,7 @@
if (rc != 0)
goto out;
dev->d_offset += part.start;
+ od->entrysize = part.end - part.start + 1;
}
out:
if (table != NULL)
Index: sys/boot/efi/include/efilib.h
===================================================================
--- sys/boot/efi/include/efilib.h
+++ sys/boot/efi/include/efilib.h
@@ -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_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 *);
Index: sys/boot/efi/libefi/devpath.c
===================================================================
--- sys/boot/efi/libefi/devpath.c
+++ sys/boot/efi/libefi/devpath.c
@@ -165,3 +165,31 @@
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);
+}
Index: sys/boot/efi/libefi/efipart.c
===================================================================
--- sys/boot/efi/libefi/efipart.c
+++ sys/boot/efi/libefi/efipart.c
@@ -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,59 +39,112 @@
#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, size_t, char *,
size_t *);
static int efipart_realstrategy(void *, int, daddr_t, size_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
+};
+
+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 struct pdinfo *pdinfo;
-static int npdinfo = 0;
-#define PD(dev) (pdinfo[(dev)->d_unit])
+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))
@@ -98,33 +153,148 @@
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)
+ efipart_handles = hin;
+ efipart_nhandles = sz;
+ return (0);
+}
+
+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);
+}
+
+/*
+ * 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);
- for (n = 0; n < nin; n++) {
- devpath = efi_lookup_devpath(hin[n]);
- if (devpath == NULL) {
+ 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;
+
+ node = efi_devpath_last_node(devpath);
+ if ((acpi = efipart_floppy(node)) != NULL) {
+ efipart_fdinfo_add(efipart_handles[i], acpi->UID,
+ devpath);
}
+ }
+}
- status = BS->HandleProtocol(hin[n], &blkio_guid,
- (void**)&blkio);
- if (EFI_ERROR(status))
- continue;
- if (!blkio->Media->LogicalPartition) {
- nrdisk++;
- continue;
+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;
+
+ node = efi_devpath_last_node(devpath);
+ 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
@@ -142,109 +312,386 @@
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);
+
+ efipart_updatecd();
- if (nout == 0 && nrdisk > 0)
- printf("Found %d disk(s) but no logical partition\n", nrdisk);
- return (err);
+ 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;
+
+ node = efi_devpath_last_node(devpath);
+ 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);
+ tmpdevpath = devpathcpy;
+ status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
+ &handle);
+ free(devpathcpy);
+ if (EFI_ERROR(status))
+ 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);
}
@@ -293,21 +740,39 @@
size_t size, 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;
- return (bcache_strategy(&bcd, rw, blk, offset, size,
- buf, rsize));
+ bcd.dv_cache = pd->pd_bcache;
+
+ if (dev->d_dev->dv_type == DEVT_DISK) {
+ return (bcache_strategy(&bcd, rw, blk + dev->d_offset, offset,
+ size, buf, rsize));
+ }
+ return (bcache_strategy(&bcd, rw, blk, offset, size, buf, rsize));
}
static int
efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t offset,
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 +782,15 @@
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);
Index: sys/boot/efi/loader/conf.c
===================================================================
--- sys/boot/efi/loader/conf.c
+++ sys/boot/efi/loader/conf.c
@@ -36,7 +36,9 @@
#endif
struct devsw *devsw[] = {
- &efipart_dev,
+ &efipart_fddev,
+ &efipart_cddev,
+ &efipart_hddev,
&efinet_dev,
#ifdef EFI_ZFS_BOOT
&zfs_dev,
Index: sys/boot/efi/loader/devicename.c
===================================================================
--- sys/boot/efi/loader/devicename.c
+++ sys/boot/efi/loader/devicename.c
@@ -33,6 +33,7 @@
#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 @@
struct devsw *dv;
char *cp;
const char *np;
- int i;
+ int i, err;
/* minimum length check */
if (strlen(devspec) < 2)
@@ -106,11 +107,26 @@
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:
idev = malloc(sizeof(struct zfs_devdesc));
if (idev == NULL)
return (ENOMEM);
@@ -120,34 +136,35 @@
free(idev);
return (err);
}
- cp = strchr(np + 1, ':');
- } else
+ break;
#endif
- {
+ default:
idev = malloc(sizeof(struct devdesc));
if (idev == NULL)
return (ENOMEM);
- idev->d_dev = dv;
- idev->d_type = dv->dv_type;
idev->d_unit = -1;
+ cp = (char *)np;
if (*np != '\0' && *np != ':') {
idev->d_unit = strtol(np, &cp, 0);
if (cp == np) {
- idev->d_unit = -1;
free(idev);
return (EUNIT);
}
}
- }
+ if (*cp != '\0' && *cp != ':') {
+ free(idev);
+ return (EINVAL);
+ }
- if (*cp != '\0' && *cp != ':') {
- free(idev);
- return (EINVAL);
+ if (path != NULL)
+ *path = (*cp == 0) ? cp : cp + 1;
+ break;
}
- if (path != NULL)
- *path = (*cp == 0) ? cp : cp + 1;
+ idev->d_dev = dv;
+ idev->d_type = dv->dv_type;
+
if (dev != NULL)
*dev = idev;
else
@@ -162,14 +179,17 @@
static char buf[SPECNAMELEN + 1];
switch(dev->d_type) {
-#ifdef EFI_ZFS_BOOT
- case DEVT_ZFS:
- return (zfs_fmtdev(dev));
-#endif
case DEVT_NONE:
strcpy(buf, "(no device)");
break;
+ case DEVT_DISK:
+ return (disk_fmtdev(vdev));
+
+#ifdef EFI_ZFS_BOOT
+ case DEVT_ZFS:
+ return (zfs_fmtdev(dev));
+#endif
default:
sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
break;
Index: sys/boot/efi/loader/main.c
===================================================================
--- sys/boot/efi/loader/main.c
+++ sys/boot/efi/loader/main.c
@@ -35,6 +35,7 @@
#include <stand.h>
#include <string.h>
#include <setjmp.h>
+#include <disk.h>
#include <efi.h>
#include <efilib.h>
@@ -89,6 +90,7 @@
#ifdef EFI_ZFS_BOOT
static void efi_zfs_probe(void);
+static uint64_t pool_guid;
#endif
/*
@@ -199,12 +201,107 @@
return retval;
}
+static void
+set_devdesc_currdev(struct devsw *dev, int unit)
+{
+ struct devdesc currdev;
+ char *devname;
+
+ currdev.d_dev = dev;
+ currdev.d_type = currdev.d_dev->dv_type;
+ currdev.d_unit = unit;
+ currdev.d_opendata = NULL;
+ devname = efi_fmtdev(&currdev);
+
+ env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
+ env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, devname, env_noset, env_nounset);
+}
+
static int
-find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit,
- uint64_t *extra)
+find_currdev(EFI_LOADED_IMAGE *img)
{
+ pdinfo_list_t *pdi_list;
+ pdinfo_t *dp, *pp;
EFI_DEVICE_PATH *devpath, *copy;
EFI_HANDLE h;
+ char *devname;
+ struct devsw *dev;
+ int unit;
+ uint64_t extra;
+
+ /* Did efi_zfs_probe() detect the boot pool? */
+ if (pool_guid != 0) {
+ struct zfs_devdesc currdev;
+
+ currdev.d_dev = &zfs_dev;
+ currdev.d_unit = 0;
+ currdev.d_type = currdev.d_dev->dv_type;
+ currdev.d_opendata = NULL;
+ currdev.pool_guid = pool_guid;
+ currdev.root_guid = 0;
+ devname = efi_fmtdev(&currdev);
+
+ env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
+ env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, devname, env_noset,
+ env_nounset);
+ return (0);
+ }
+
+ /* We have device lists for hd, cd, fd, walk them all. */
+ pdi_list = efiblk_get_pdinfo_list(&efipart_hddev);
+ STAILQ_FOREACH(dp, pdi_list, pd_link) {
+ struct disk_devdesc currdev;
+
+ currdev.d_dev = &efipart_hddev;
+ currdev.d_type = currdev.d_dev->dv_type;
+ currdev.d_unit = dp->pd_unit;
+ currdev.d_opendata = NULL;
+ currdev.d_slice = -1;
+ currdev.d_partition = -1;
+
+ if (dp->pd_handle == img->DeviceHandle) {
+ devname = efi_fmtdev(&currdev);
+
+ env_setenv("currdev", EV_VOLATILE, devname,
+ efi_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, devname,
+ env_noset, env_nounset);
+ return (0);
+ }
+ /* Assuming GPT partitioning. */
+ STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
+ if (pp->pd_handle == img->DeviceHandle) {
+ currdev.d_slice = pp->pd_unit;
+ currdev.d_partition = 255;
+ devname = efi_fmtdev(&currdev);
+
+ env_setenv("currdev", EV_VOLATILE, devname,
+ efi_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, devname,
+ env_noset, env_nounset);
+ return (0);
+ }
+ }
+ }
+
+ pdi_list = efiblk_get_pdinfo_list(&efipart_cddev);
+ STAILQ_FOREACH(dp, pdi_list, pd_link) {
+ if (dp->pd_handle == img->DeviceHandle ||
+ dp->pd_alias == img->DeviceHandle) {
+ set_devdesc_currdev(&efipart_cddev, dp->pd_unit);
+ return (0);
+ }
+ }
+
+ pdi_list = efiblk_get_pdinfo_list(&efipart_fddev);
+ STAILQ_FOREACH(dp, pdi_list, pd_link) {
+ if (dp->pd_handle == img->DeviceHandle) {
+ set_devdesc_currdev(&efipart_fddev, dp->pd_unit);
+ return (0);
+ }
+ }
/*
* Try the device handle from our loaded image first. If that
@@ -212,8 +309,10 @@
* any of the nodes in that path match one of the enumerated
* handles.
*/
- if (efi_handle_lookup(img->DeviceHandle, dev, unit, extra) == 0)
+ if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) {
+ set_devdesc_currdev(dev, unit);
return (0);
+ }
copy = NULL;
devpath = efi_lookup_image_devpath(IH);
@@ -222,7 +321,8 @@
if (h == NULL)
break;
- if (efi_handle_lookup(h, dev, unit, extra) == 0) {
+ if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) {
+ set_devdesc_currdev(dev, unit);
if (copy != NULL)
free(copy);
return (0);
@@ -237,11 +337,6 @@
}
}
- /* Try to fallback on first device */
- if (devsw[0] != NULL) {
- *dev = devsw[0];
- return (0);
- }
return (ENOENT);
}
@@ -251,9 +346,7 @@
char var[128];
EFI_LOADED_IMAGE *img;
EFI_GUID *guid;
- int i, j, vargood, unit, howto;
- struct devsw *dev;
- uint64_t pool_guid;
+ int i, j, vargood, howto;
UINTN k;
int has_kbd;
char buf[40];
@@ -424,43 +517,9 @@
*/
BS->SetWatchdogTimer(0, 0, 0, NULL);
- if (find_currdev(img, &dev, &unit, &pool_guid) != 0)
+ if (find_currdev(img) != 0)
return (EFI_NOT_FOUND);
- switch (dev->dv_type) {
-#ifdef EFI_ZFS_BOOT
- case DEVT_ZFS: {
- struct zfs_devdesc currdev;
-
- currdev.d_dev = dev;
- currdev.d_unit = unit;
- currdev.d_type = currdev.d_dev->dv_type;
- currdev.d_opendata = NULL;
- currdev.pool_guid = pool_guid;
- currdev.root_guid = 0;
- env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
- efi_setcurrdev, env_nounset);
- env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
- env_nounset);
- init_zfs_bootenv(zfs_fmtdev(&currdev));
- break;
- }
-#endif
- default: {
- struct devdesc currdev;
-
- currdev.d_dev = dev;
- currdev.d_unit = unit;
- currdev.d_opendata = NULL;
- currdev.d_type = currdev.d_dev->dv_type;
- env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
- efi_setcurrdev, env_nounset);
- env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
- env_nounset);
- break;
- }
- }
-
snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16,
ST->Hdr.Revision & 0xffff);
env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset);
@@ -1096,20 +1155,66 @@
#ifdef EFI_ZFS_BOOT
static void
+efipart_probe_img(pdinfo_list_t *hdi)
+{
+ EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
+ EFI_LOADED_IMAGE *img;
+ pdinfo_t *hd, *pd = NULL;
+ char devname[SPECNAMELEN + 1];
+
+ BS->HandleProtocol(IH, &imgid, (VOID**)&img);
+
+ /*
+ * Search for the booted image device handle from hard disk list.
+ * Note, this does also include usb sticks, and we assume there is no
+ * ZFS on floppies nor cd.
+ * However, we might have booted from floppy (unlikely) or CD,
+ * so we should not surprised if we can not find the handle.
+ */
+ STAILQ_FOREACH(hd, hdi, pd_link) {
+ if (hd->pd_handle == img->DeviceHandle)
+ break;
+ STAILQ_FOREACH(pd, &hd->pd_part, pd_link) {
+ if (pd->pd_handle == img->DeviceHandle)
+ break;
+ }
+ if (pd != NULL)
+ break;
+ }
+ if (hd != NULL) {
+ if (pd != NULL) {
+ snprintf(devname, sizeof(devname), "%s%dp%d:",
+ efipart_hddev.dv_name, hd->pd_unit, pd->pd_unit);
+ } else {
+ snprintf(devname, sizeof(devname), "%s%d:",
+ efipart_hddev.dv_name, hd->pd_unit);
+ }
+ (void) zfs_probe_dev(devname, &pool_guid);
+ }
+}
+
+static void
efi_zfs_probe(void)
{
- EFI_HANDLE h;
- u_int unit;
- int i;
- char dname[SPECNAMELEN + 1];
- uint64_t guid;
+ pdinfo_list_t *hdi;
+ pdinfo_t *hd;
+ char devname[SPECNAMELEN + 1];
+
+ hdi = efiblk_get_pdinfo_list(&efipart_hddev);
+ /*
+ * First probe the boot device (from where loader.efi was read),
+ * and set pool_guid global variable if we are booting from zfs.
+ * Since loader is running, we do have an access to the device,
+ * however, it might not be zfs.
+ */
+
+ if (pool_guid == 0)
+ efipart_probe_img(hdi);
- unit = 0;
- h = efi_find_handle(&efipart_dev, 0);
- for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) {
- snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i);
- if (zfs_probe_dev(dname, &guid) == 0)
- (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid);
+ STAILQ_FOREACH(hd, hdi, pd_link) {
+ snprintf(devname, sizeof(devname), "%s%d:",
+ efipart_hddev.dv_name, hd->pd_unit);
+ (void) zfs_probe_dev(devname, NULL);
}
}
#endif
Index: sys/boot/zfs/zfs.c
===================================================================
--- sys/boot/zfs/zfs.c
+++ sys/boot/zfs/zfs.c
@@ -486,6 +486,8 @@
off_t mediasz;
int ret;
+ if (pool_guid)
+ *pool_guid = 0;
pa.fd = open(devname, O_RDONLY);
if (pa.fd == -1)
return (ENXIO);
@@ -493,6 +495,7 @@
ret = zfs_probe(pa.fd, pool_guid);
if (ret == 0)
return (0);
+
/* Probe each partition */
ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz);
if (ret == 0)
@@ -508,6 +511,8 @@
}
}
close(pa.fd);
+ if (pool_guid && *pool_guid == 0)
+ ret = ENXIO;
return (ret);
}

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 7, 2:18 AM (15 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29349016
Default Alt Text
D8581.id22355.diff (34 KB)

Event Timeline