diff options
author | Toomas Soome <tsoome@me.com> | 2016-11-17 17:02:22 +0200 |
---|---|---|
committer | Dan McDonald <danmcd@joyent.com> | 2017-09-25 14:37:10 -0400 |
commit | dbacaf56963d687dced1eddb2d3beb695f5ebc7e (patch) | |
tree | 3b4c38e49c376eb341dda5152e545e5f33c68e9d | |
parent | e984c70bc7d741cd0663924c95c15fed9f645565 (diff) | |
download | illumos-joyent-dbacaf56963d687dced1eddb2d3beb695f5ebc7e.tar.gz |
8646 loader: replace EFI part devices.
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Igor Kozhukhov <igor@dilos.org>
Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r-- | usr/src/boot/lib/libstand/stand.h | 1 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/include/efilib.h | 24 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/libefi/devpath.c | 28 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/libefi/efipart.c | 837 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/conf.c | 4 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/devicename.c | 78 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/efi/loader/main.c | 188 | ||||
-rw-r--r-- | usr/src/boot/sys/boot/zfs/zfs.c | 5 |
8 files changed, 966 insertions, 199 deletions
diff --git a/usr/src/boot/lib/libstand/stand.h b/usr/src/boot/lib/libstand/stand.h index 9a7e070bdc..00b4ac210c 100644 --- a/usr/src/boot/lib/libstand/stand.h +++ b/usr/src/boot/lib/libstand/stand.h @@ -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; }; diff --git a/usr/src/boot/sys/boot/efi/include/efilib.h b/usr/src/boot/sys/boot/efi/include/efilib.h index 6a94fd172a..e5eadf6a5d 100644 --- a/usr/src/boot/sys/boot/efi/include/efilib.h +++ b/usr/src/boot/sys/boot/efi/include/efilib.h @@ -30,16 +30,37 @@ #include <stand.h> #include <stdbool.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; /* list of partitions */ + EFI_HANDLE pd_handle; + EFI_HANDLE pd_alias; + EFI_DEVICE_PATH *pd_devpath; + EFI_BLOCK_IO *pd_blkio; + uint32_t pd_unit; /* unit number */ + uint32_t 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); @@ -52,6 +73,7 @@ EFI_DEVICE_PATH *efi_lookup_devpath(EFI_HANDLE); 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 *); +bool efi_devpath_match(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *); CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *); void efi_free_devpath_name(CHAR16 *); diff --git a/usr/src/boot/sys/boot/efi/libefi/devpath.c b/usr/src/boot/sys/boot/efi/libefi/devpath.c index dbf55f5059..ab56d97a9a 100644 --- a/usr/src/boot/sys/boot/efi/libefi/devpath.c +++ b/usr/src/boot/sys/boot/efi/libefi/devpath.c @@ -137,3 +137,31 @@ efi_devpath_handle(EFI_DEVICE_PATH *devpath) return (NULL); return (h); } + +bool +efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2) +{ + size_t len; + + if (devpath1 == NULL || devpath2 == NULL) + return (false); + + while (true) { + if (DevicePathType(devpath1) != DevicePathType(devpath2) || + DevicePathSubType(devpath1) != DevicePathSubType(devpath2)) + return (false); + + len = DevicePathNodeLength(devpath1); + if (len != DevicePathNodeLength(devpath2)) + return (false); + + if (memcmp(devpath1, devpath2, len) != 0) + return (false); + + if (IsDevicePathEnd(devpath1)) + break; + devpath1 = NextDevicePathNode(devpath1); + devpath2 = NextDevicePathNode(devpath2); + } + return (true); +} diff --git a/usr/src/boot/sys/boot/efi/libefi/efipart.c b/usr/src/boot/sys/boot/efi/libefi/efipart.c index fb65fe82cc..b72f273337 100644 --- a/usr/src/boot/sys/boot/efi/libefi/efipart.c +++ b/usr/src/boot/sys/boot/efi/libefi/efipart.c @@ -29,6 +29,7 @@ #include <sys/disk.h> #include <sys/param.h> #include <sys/time.h> +#include <sys/queue.h> #include <stddef.h> #include <stdarg.h> @@ -37,59 +38,115 @@ #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_ioctl(struct open_file *, u_long, void *); -static int efipart_print(int); -struct devsw efipart_dev = { - .dv_name = "part", +static int efipart_printfd(int); +static int efipart_printcd(int); +static int efipart_printhd(int); + +/* EISA PNP ID's for floppy controllers */ +#define PNP0604 0x604 +#define PNP0700 0x700 +#define PNP0701 0x701 + +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 = efipart_ioctl, + .dv_print = efipart_printfd, + .dv_cleanup = NULL +}; + +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_init, + .dv_init = efipart_inithd, .dv_strategy = efipart_strategy, .dv_open = efipart_open, .dv_close = efipart_close, .dv_ioctl = efipart_ioctl, - .dv_print = efipart_print, + .dv_print = efipart_printhd, .dv_cleanup = NULL }; -/* - * info structure to support bcache - */ -struct pdinfo +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) { - int pd_unit; /* unit number */ - int pd_open; /* reference counter */ - void *pd_bcache; /* buffer cache data */ -}; -static struct pdinfo *pdinfo; -static int npdinfo = 0; + pdinfo_t *pd; -#define PD(dev) (pdinfo[(dev)->d_unit]) + 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; - 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,30 +155,148 @@ efipart_init(void) if (EFI_ERROR(status)) return (efi_status_to_errno(status)); - /* Filter handles to only include illumos partitions. */ - nin = sz / sizeof(EFI_HANDLE); - hout = hin + nin; - aliases = hout + nin; - nout = 0; + efipart_handles = hin; + efipart_nhandles = sz; + return (0); +} + +static ACPI_HID_DEVICE_PATH * +efipart_floppy(EFI_DEVICE_PATH *node) +{ + ACPI_HID_DEVICE_PATH *acpi; + + if (DevicePathType(node) == ACPI_DEVICE_PATH && + DevicePathSubType(node) == ACPI_DP) { + acpi = (ACPI_HID_DEVICE_PATH *) node; + if (acpi->HID == EISA_PNP_ID(PNP0604) || + acpi->HID == EISA_PNP_ID(PNP0700) || + acpi->HID == EISA_PNP_ID(PNP0701)) { + return (acpi); + } + } + return (NULL); +} + +/* + * Add or update entries with new handle data. + */ +static int +efipart_fdinfo_add(EFI_HANDLE handle, uint32_t uid, EFI_DEVICE_PATH *devpath) +{ + pdinfo_t *fd; - bzero(aliases, nin * sizeof(EFI_HANDLE)); - pdinfo = malloc(nin * sizeof(*pdinfo)); - if (pdinfo == NULL) + fd = calloc(1, sizeof(pdinfo_t)); + if (fd == NULL) { + printf("Failed to register floppy %d, out of memory\n", uid); return (ENOMEM); + } + STAILQ_INIT(&fd->pd_part); + + fd->pd_unit = uid; + fd->pd_handle = handle; + fd->pd_devpath = devpath; + STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link); + return (0); +} - for (n = 0; n < nin; n++) { - devpath = efi_lookup_devpath(hin[n]); - if (devpath == NULL) { +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 ((node = efi_devpath_last_node(devpath)) == NULL) continue; + 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)) +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) == true) { + pd->pd_handle = handle; + pd->pd_alias = alias; + return (0); + } + unit++; + } + + cd = calloc(1, sizeof(pdinfo_t)); + if (cd == NULL) { + printf("Failed to add cd %d, out of memory\n", unit); + return (ENOMEM); + } + STAILQ_INIT(&cd->pd_part); + + 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 (!blkio->Media->LogicalPartition) + 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 @@ -129,8 +304,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); @@ -142,124 +315,500 @@ 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++; - } - - bcache_add_dev(npdinfo); - err = efi_register_handles(&efipart_dev, hout, aliases, nout); - free(hin); - return (err); + 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); + } + } } static int -efipart_print(int verbose) +efipart_initcd(void) { - char line[80]; + int rv; + + rv = efipart_inithandles(); + if (rv != 0) + return (rv); + STAILQ_INIT(&cdinfo); + + efipart_updatecd(); + + bcache_add_dev(efiblk_pdinfo_count(&cdinfo)); + return (0); +} + +static int +efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle) +{ + 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); + } + node = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(part_devpath); + if (node == NULL) + return (ENOENT); /* This should not happen. */ + + pd = calloc(1, sizeof(pdinfo_t)); + if (pd == NULL) { + printf("Failed to add disk, out of memory\n"); + return (ENOMEM); + } + STAILQ_INIT(&pd->pd_part); + + STAILQ_FOREACH(hd, &hdinfo, pd_link) { + if (efi_devpath_match(hd->pd_devpath, disk_devpath) == true) { + /* 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 = calloc(1, sizeof(pdinfo_t)); + if (pd == NULL) { + printf("Failed to add partition, out of memory\n"); + return (ENOMEM); + } + STAILQ_INIT(&pd->pd_part); + + /* Add the partition. */ + pd->pd_handle = part_handle; + pd->pd_unit = node->PartitionNumber; + pd->pd_devpath = part_devpath; + STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link); + + return (0); +} + +/* + * The MEDIA_FILEPATH_DP has device name. + * From U-Boot sources it looks like names are in the form + * of typeN:M, where type is interface type, N is disk id + * and M is partition id. + */ +static int +efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle) +{ + EFI_DEVICE_PATH *devpath; + FILEPATH_DEVICE_PATH *node; + char *pathname, *p; + int unit, len; + pdinfo_t *pd, *last; + + /* First collect and verify all the data */ + if ((devpath = efi_lookup_devpath(disk_handle)) == NULL) + return (ENOENT); + node = (FILEPATH_DEVICE_PATH *)efi_devpath_last_node(devpath); + if (node == NULL) + return (ENOENT); /* This should not happen. */ + + pd = calloc(1, sizeof(pdinfo_t)); + if (pd == NULL) { + printf("Failed to add disk, out of memory\n"); + return (ENOMEM); + } + STAILQ_INIT(&pd->pd_part); + last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); + if (last != NULL) + unit = last->pd_unit + 1; + else + unit = 0; + + /* FILEPATH_DEVICE_PATH has 0 terminated string */ + for (len = 0; node->PathName[len] != 0; len++) + ; + if ((pathname = malloc(len + 1)) == NULL) { + printf("Failed to add disk, out of memory\n"); + free(pd); + return (ENOMEM); + } + cpy16to8(node->PathName, pathname, len + 1); + p = strchr(pathname, ':'); + + /* + * Assume we are receiving handles in order, first disk handle, + * then partitions for this disk. If this assumption proves + * false, this code would need update. + */ + if (p == NULL) { /* no colon, add the disk */ + pd->pd_handle = disk_handle; + pd->pd_unit = unit; + pd->pd_devpath = devpath; + STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link); + free(pathname); + return (0); + } + p++; /* skip the colon */ + errno = 0; + unit = (int)strtol(p, NULL, 0); + if (errno != 0) { + printf("Bad unit number for partition \"%s\"\n", pathname); + free(pathname); + free(pd); + return (EUNIT); + } + + /* + * We should have disk registered, if not, we are receiving + * handles out of order, and this code should be reworked + * to create "blank" disk for partition, and to find the + * disk based on PathName compares. + */ + if (last == NULL) { + printf("BUG: No disk for partition \"%s\"\n", pathname); + free(pathname); + free(pd); + return (EINVAL); + } + /* Add the partition. */ + pd->pd_handle = disk_handle; + pd->pd_unit = unit; + pd->pd_devpath = devpath; + STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link); + free(pathname); + 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; + } + + if (DevicePathType(node) == MEDIA_DEVICE_PATH && + DevicePathSubType(node) == MEDIA_FILEPATH_DP) { + efipart_hdinfo_add_filepath(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]; + + if (STAILQ_EMPTY(pdlist)) + return (0); - printf("%s devices:", efipart_dev.dv_name); + 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)) { - sprintf(line, " %s%d:", efipart_dev.dv_name, unit); - ret = pager_output(line); - + 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)) { - sprintf(line, " %llu blocks", - (unsigned long long)(blkio->Media->LastBlock + 1)); - ret = pager_output(line); - if (blkio->Media->RemovableMedia) - ret = pager_output(" (removable)"); + 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); + 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; } - ret = pager_output("\n"); - if (ret != 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) { + int rc; + + rc = disk_open(dev, + blkio->Media->BlockSize * (blkio->Media->LastBlock + 1), + blkio->Media->BlockSize); + if (rc != 0) { + pd->pd_open--; + if (pd->pd_open == 0) { + pd->pd_blkio = NULL; + bcache_free(pd->pd_bcache); + pd->pd_bcache = NULL; + } + } + return (rc); + } 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); + + pd = efiblk_get_pdinfo(pdi, dev->d_unit); + if (pd == 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->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 devdesc *dev; - EFI_BLOCK_IO *blkio; + struct disk_devdesc *dev; + pdinfo_list_t *pdi; + pdinfo_t *pd; + int rc; - dev = (struct devdesc *)(f->f_devdata); - if (dev->d_opendata == NULL) + dev = (struct disk_devdesc *)(f->f_devdata); + if (dev == NULL) 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); + + 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 = blkio->Media->BlockSize; + *(u_int *)data = pd->pd_blkio->Media->BlockSize; break; case DIOCGMEDIASIZE: - *(uint64_t *)data = blkio->Media->BlockSize * - (blkio->Media->LastBlock + 1); + *(uint64_t *)data = pd->pd_blkio->Media->BlockSize * + (pd->pd_blkio->Media->LastBlock + 1); break; default: return (ENOTTY); @@ -303,8 +852,10 @@ efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks, return (ENOSYS); } - if (EFI_ERROR(status)) - printf("%s: rw=%d, status=%lu\n", __func__, rw, (u_long)status); + if (EFI_ERROR(status)) { + printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw, + blk, nblks, EFI_ERROR_CODE(status)); + } return (efi_status_to_errno(status)); } @@ -313,12 +864,33 @@ efipart_strategy(void *devdata, int rw, daddr_t blk, 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); + + if (pd->pd_blkio->Media->RemovableMedia && + !pd->pd_blkio->Media->MediaPresent) + return (ENXIO); - 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)); } @@ -326,17 +898,28 @@ 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; - uint64_t off; + uint64_t off, disk_blocks, d_offset = 0; char *blkbuf; size_t blkoff, blksz; int error; + uint64_t diskend, readstart; 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); @@ -344,11 +927,33 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size, return (EIO); off = blk * 512; + /* + * Get disk blocks, this value is either for whole disk or for + * partition. + */ + disk_blocks = 0; + if (dev->d_dev->dv_type == DEVT_DISK) { + if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { + /* DIOCGMEDIASIZE does return bytes. */ + disk_blocks /= blkio->Media->BlockSize; + } + d_offset = dev->d_offset; + } + if (disk_blocks == 0) + disk_blocks = blkio->Media->LastBlock + 1 - d_offset; + /* make sure we don't read past disk end */ - if ((off + size) / blkio->Media->BlockSize - 1 > - blkio->Media->LastBlock) { - size = blkio->Media->LastBlock + 1 - - off / blkio->Media->BlockSize; + if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) { + diskend = d_offset + disk_blocks; + readstart = off / blkio->Media->BlockSize; + + if (diskend <= readstart) { + if (rsize != NULL) + *rsize = 0; + + return (EIO); + } + size = diskend - readstart; size = size * blkio->Media->BlockSize; } diff --git a/usr/src/boot/sys/boot/efi/loader/conf.c b/usr/src/boot/sys/boot/efi/loader/conf.c index 7da0afc6ca..6b24517c98 100644 --- a/usr/src/boot/sys/boot/efi/loader/conf.c +++ b/usr/src/boot/sys/boot/efi/loader/conf.c @@ -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, diff --git a/usr/src/boot/sys/boot/efi/loader/devicename.c b/usr/src/boot/sys/boot/efi/loader/devicename.c index 72588b08f5..1e499c0b1b 100644 --- a/usr/src/boot/sys/boot/efi/loader/devicename.c +++ b/usr/src/boot/sys/boot/efi/loader/devicename.c @@ -32,6 +32,7 @@ #include <sys/disklabel.h> #include <sys/param.h> #include <bootstrap.h> +#include <disk.h> #include <libzfs.h> #include <efi.h> @@ -85,9 +86,9 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path) { struct devdesc *idev; struct devsw *dv; + int i, unit, err; char *cp; const char *np; - int i; /* minimum length check */ if (strlen(devspec) < 2) @@ -103,50 +104,73 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path) return (ENOENT); np = devspec + strlen(dv->dv_name); + idev = NULL; + err = 0; - 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) + goto fail; + break; + case DEVT_ZFS: idev = malloc(sizeof (struct zfs_devdesc)); if (idev == NULL) return (ENOMEM); err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); - if (err != 0) { - free(idev); - return (err); - } - cp = strchr(np + 1, ':'); - } else { + if (err != 0) + goto fail; + break; + + 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; + unit = 0; + 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); + /* get unit number if present */ + errno = 0; + unit = strtol(np, &cp, 0); + if (errno != 0 || cp == np) { + err = EUNIT; + goto fail; } } - } + if (*cp != '\0' && *cp != ':') { + err = EINVAL; + goto fail; + } - if (*cp != '\0' && *cp != ':') { - free(idev); - return (EINVAL); + idev->d_unit = unit; + 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 free(idev); return (0); + +fail: + free(idev); + return (err); } char * @@ -156,12 +180,16 @@ efi_fmtdev(void *vdev) static char buf[SPECNAMELEN + 1]; switch (dev->d_type) { - case DEVT_ZFS: - return (zfs_fmtdev(dev)); case DEVT_NONE: strlcpy(buf, "(no device)", sizeof (buf)); break; + case DEVT_DISK: + return (disk_fmtdev(vdev)); + + case DEVT_ZFS: + return (zfs_fmtdev(dev)); + default: snprintf(buf, sizeof (buf), "%s%d:", dev->d_dev->dv_name, dev->d_unit); diff --git a/usr/src/boot/sys/boot/efi/loader/main.c b/usr/src/boot/sys/boot/efi/loader/main.c index 3ef635fd91..7db2db1f64 100644 --- a/usr/src/boot/sys/boot/efi/loader/main.c +++ b/usr/src/boot/sys/boot/efi/loader/main.c @@ -35,6 +35,7 @@ #include <inttypes.h> #include <string.h> #include <setjmp.h> +#include <disk.h> #include <efi.h> #include <efilib.h> @@ -65,6 +66,7 @@ extern void acpi_detect(void); extern void efi_getsmap(void); #ifdef EFI_ZFS_BOOT static void efi_zfs_probe(void); +static uint64_t pool_guid; #endif static int @@ -149,12 +151,107 @@ out: 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 @@ -162,8 +259,10 @@ find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit, * 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); @@ -175,8 +274,10 @@ find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit, free(copy); copy = NULL; - if (efi_handle_lookup(h, dev, unit, extra) == 0) + if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) { + set_devdesc_currdev(dev, unit); return (0); + } devpath = efi_lookup_devpath(h); if (devpath != NULL) { @@ -195,9 +296,7 @@ main(int argc, CHAR16 *argv[]) 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; void *ptr; UINTN k; int has_kbd; @@ -365,45 +464,9 @@ main(int argc, CHAR16 *argv[]) */ 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); -#ifdef __FreeBSD__ - init_zfs_bootenv(zfs_fmtdev(&currdev)); -#endif - 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; - } - } - efi_init_environment(); setenv("ISADIR", "amd64", 1); /* we only build 64bit */ acpi_detect(); @@ -842,18 +905,31 @@ COMMAND_SET(chain, "chain", "chain load file", command_chain); static void efi_zfs_probe(void) { - EFI_HANDLE h; - u_int unit; - int i; - char dname[SPECNAMELEN + 1]; - uint64_t guid; - - 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); + pdinfo_list_t *hdi; + pdinfo_t *hd, *pd = NULL; + EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; + EFI_LOADED_IMAGE *img; + char devname[SPECNAMELEN + 1]; + + BS->HandleProtocol(IH, &imgid, (VOID**)&img); + hdi = efiblk_get_pdinfo_list(&efipart_hddev); + + /* + * Find the handle for the boot device. The boot1 did find the + * device with loader binary, now we need to search for the + * same device and if it is part of the zfs pool, we record the + * pool GUID for currdev setup. + */ + STAILQ_FOREACH(hd, hdi, pd_link) { + STAILQ_FOREACH(pd, &hd->pd_part, pd_link) { + + snprintf(devname, sizeof(devname), "%s%dp%d:", + efipart_hddev.dv_name, hd->pd_unit, pd->pd_unit); + if (pd->pd_handle == img->DeviceHandle) + (void) zfs_probe_dev(devname, &pool_guid); + else + (void) zfs_probe_dev(devname, NULL); + } } } diff --git a/usr/src/boot/sys/boot/zfs/zfs.c b/usr/src/boot/sys/boot/zfs/zfs.c index d4b7e8ef40..adfa9caf5a 100644 --- a/usr/src/boot/sys/boot/zfs/zfs.c +++ b/usr/src/boot/sys/boot/zfs/zfs.c @@ -490,6 +490,8 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid) uint64_t mediasz; int ret; + if (pool_guid) + *pool_guid = 0; pa.fd = open(devname, O_RDONLY); if (pa.fd == -1) return (ENXIO); @@ -497,6 +499,7 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid) ret = zfs_probe(pa.fd, pool_guid); if (ret == 0) return (0); + /* Probe each partition */ ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz); if (ret == 0) @@ -512,6 +515,8 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid) } } close(pa.fd); + if (pool_guid && *pool_guid == 0) + ret = ENXIO; return (ret); } |