2 * Copyright (c) 2010 Marcel Moolenaar
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
33 #include <sys/queue.h>
37 #include <bootstrap.h>
45 static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
47 static int efipart_initfd(void);
48 static int efipart_initcd(void);
49 static int efipart_inithd(void);
51 static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *);
52 static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *);
54 static int efipart_open(struct open_file *, ...);
55 static int efipart_close(struct open_file *);
56 static int efipart_ioctl(struct open_file *, u_long, void *);
58 static int efipart_printfd(int);
59 static int efipart_printcd(int);
60 static int efipart_printhd(int);
62 /* EISA PNP ID's for floppy controllers */
67 /* Bounce buffer max size */
68 #define BIO_BUFFER_SIZE 0x4000
70 struct devsw efipart_fddev = {
73 .dv_init = efipart_initfd,
74 .dv_strategy = efipart_strategy,
75 .dv_open = efipart_open,
76 .dv_close = efipart_close,
77 .dv_ioctl = efipart_ioctl,
78 .dv_print = efipart_printfd,
82 struct devsw efipart_cddev = {
85 .dv_init = efipart_initcd,
86 .dv_strategy = efipart_strategy,
87 .dv_open = efipart_open,
88 .dv_close = efipart_close,
89 .dv_ioctl = efipart_ioctl,
90 .dv_print = efipart_printcd,
94 struct devsw efipart_hddev = {
97 .dv_init = efipart_inithd,
98 .dv_strategy = efipart_strategy,
99 .dv_open = efipart_open,
100 .dv_close = efipart_close,
101 .dv_ioctl = efipart_ioctl,
102 .dv_print = efipart_printhd,
106 static pdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo);
107 static pdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo);
108 static pdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo);
111 * efipart_inithandles() is used to build up the pdinfo list from
112 * block device handles. Then each devsw init callback is used to
113 * pick items from pdinfo and move to proper device list.
114 * In ideal world, we should end up with empty pdinfo once all
115 * devsw initializers are called.
117 static pdinfo_list_t pdinfo = STAILQ_HEAD_INITIALIZER(pdinfo);
120 efiblk_get_pdinfo_list(struct devsw *dev)
122 if (dev->dv_type == DEVT_DISK)
124 if (dev->dv_type == DEVT_CD)
126 if (dev->dv_type == DEVT_FD)
131 /* XXX this gets called way way too often, investigate */
133 efiblk_get_pdinfo(struct devdesc *dev)
138 pdi = efiblk_get_pdinfo_list(dev->d_dev);
142 STAILQ_FOREACH(pd, pdi, pd_link) {
143 if (pd->pd_unit == dev->d_unit)
150 efiblk_get_pdinfo_by_device_path(EFI_DEVICE_PATH *path)
154 EFI_DEVICE_PATH *devp = path;
156 status = BS->LocateDevicePath(&blkio_guid, &devp, &h);
157 if (EFI_ERROR(status))
159 return (efiblk_get_pdinfo_by_handle(h));
163 same_handle(pdinfo_t *pd, EFI_HANDLE h)
166 return (pd->pd_handle == h || pd->pd_alias == h);
170 efiblk_get_pdinfo_by_handle(EFI_HANDLE h)
175 * Check hard disks, then cd, then floppy
177 STAILQ_FOREACH(dp, &hdinfo, pd_link) {
178 if (same_handle(dp, h))
180 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
181 if (same_handle(pp, h))
185 STAILQ_FOREACH(dp, &cdinfo, pd_link) {
186 if (same_handle(dp, h))
188 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
189 if (same_handle(pp, h))
193 STAILQ_FOREACH(dp, &fdinfo, pd_link) {
194 if (same_handle(dp, h))
201 efiblk_pdinfo_count(pdinfo_list_t *pdi)
206 STAILQ_FOREACH(pd, pdi, pd_link) {
213 efipart_inithandles(void)
218 EFI_DEVICE_PATH *devpath;
223 if (!STAILQ_EMPTY(&pdinfo))
228 status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin);
229 if (status == EFI_BUFFER_TOO_SMALL) {
231 status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
233 if (EFI_ERROR(status))
236 if (EFI_ERROR(status))
237 return (efi_status_to_errno(status));
239 nin = sz / sizeof(*hin);
241 printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__, nin);
244 for (i = 0; i < nin; i++) {
246 * Get devpath and open protocol.
247 * We should not get errors here
249 if ((devpath = efi_lookup_devpath(hin[i])) == NULL)
252 status = OpenProtocolByHandle(hin[i], &blkio_guid,
254 if (EFI_ERROR(status)) {
255 printf("error %lu\n", EFI_ERROR_CODE(status));
260 * We assume the block size 512 or greater power of 2.
261 * Also skip devices with block size > 64k (16 is max
262 * ashift supported by zfs).
263 * iPXE is known to insert stub BLOCK IO device with
266 if (blkio->Media->BlockSize < 512 ||
267 blkio->Media->BlockSize > (1 << 16) ||
268 !powerof2(blkio->Media->BlockSize)) {
272 /* Allowed values are 0, 1 and power of 2. */
273 if (blkio->Media->IoAlign > 1 &&
274 !powerof2(blkio->Media->IoAlign)) {
279 if ((pd = calloc(1, sizeof(*pd))) == NULL) {
280 printf("efipart_inithandles: Out of memory.\n");
284 STAILQ_INIT(&pd->pd_part);
286 pd->pd_handle = hin[i];
287 pd->pd_devpath = devpath;
288 pd->pd_blkio = blkio;
289 STAILQ_INSERT_TAIL(&pdinfo, pd, pd_link);
296 static ACPI_HID_DEVICE_PATH *
297 efipart_floppy(EFI_DEVICE_PATH *node)
299 ACPI_HID_DEVICE_PATH *acpi;
301 if (DevicePathType(node) == ACPI_DEVICE_PATH &&
302 DevicePathSubType(node) == ACPI_DP) {
303 acpi = (ACPI_HID_DEVICE_PATH *) node;
304 if (acpi->HID == EISA_PNP_ID(PNP0604) ||
305 acpi->HID == EISA_PNP_ID(PNP0700) ||
306 acpi->HID == EISA_PNP_ID(PNP0701)) {
314 efipart_find_parent(pdinfo_list_t *pdi, EFI_DEVICE_PATH *devpath)
318 STAILQ_FOREACH(pd, pdi, pd_link) {
319 if (efi_devpath_is_prefix(pd->pd_devpath, devpath))
321 part = efipart_find_parent(&pd->pd_part, devpath);
331 EFI_DEVICE_PATH *node;
332 ACPI_HID_DEVICE_PATH *acpi;
333 pdinfo_t *parent, *fd;
336 STAILQ_FOREACH(fd, &pdinfo, pd_link) {
337 if ((node = efi_devpath_last_node(fd->pd_devpath)) == NULL)
340 if ((acpi = efipart_floppy(node)) == NULL)
343 STAILQ_REMOVE(&pdinfo, fd, pdinfo, pd_link);
344 parent = efipart_find_parent(&pdinfo, fd->pd_devpath);
345 if (parent != NULL) {
346 STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
347 parent->pd_alias = fd->pd_handle;
348 parent->pd_unit = acpi->UID;
352 fd->pd_unit = acpi->UID;
354 fd->pd_devsw = &efipart_fddev;
355 STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
359 bcache_add_dev(efiblk_pdinfo_count(&fdinfo));
364 * Add or update entries with new handle data.
367 efipart_cdinfo_add(pdinfo_t *cd)
371 STAILQ_FOREACH(pd, &cdinfo, pd_link) {
372 if (efi_devpath_is_prefix(pd->pd_devpath, cd->pd_devpath)) {
373 last = STAILQ_LAST(&pd->pd_part, pdinfo, pd_link);
375 cd->pd_unit = last->pd_unit + 1;
379 cd->pd_devsw = &efipart_cddev;
380 STAILQ_INSERT_TAIL(&pd->pd_part, cd, pd_link);
385 last = STAILQ_LAST(&cdinfo, pdinfo, pd_link);
387 cd->pd_unit = last->pd_unit + 1;
391 cd->pd_parent = NULL;
392 cd->pd_devsw = &efipart_cddev;
393 STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link);
397 efipart_testcd(EFI_DEVICE_PATH *node, EFI_BLOCK_IO *blkio)
399 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
400 DevicePathSubType(node) == MEDIA_CDROM_DP) {
404 /* cd drive without the media. */
405 if (blkio->Media->RemovableMedia &&
406 !blkio->Media->MediaPresent) {
414 efipart_updatecd(void)
416 EFI_DEVICE_PATH *devpath, *node;
418 pdinfo_t *parent, *cd;
421 STAILQ_FOREACH(cd, &pdinfo, pd_link) {
422 if ((node = efi_devpath_last_node(cd->pd_devpath)) == NULL)
425 if (efipart_floppy(node) != NULL)
428 /* Is parent of this device already registered? */
429 parent = efipart_find_parent(&cdinfo, cd->pd_devpath);
430 if (parent != NULL) {
431 STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link);
432 efipart_cdinfo_add(cd);
436 if (!efipart_testcd(node, cd->pd_blkio))
439 /* Find parent and unlink both parent and cd from pdinfo */
440 STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link);
441 parent = efipart_find_parent(&pdinfo, cd->pd_devpath);
442 if (parent != NULL) {
443 STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
444 efipart_cdinfo_add(parent);
448 parent = efipart_find_parent(&cdinfo, cd->pd_devpath);
451 * If we come across a logical partition of subtype CDROM
452 * it doesn't refer to the CD filesystem itself, but rather
453 * to any usable El Torito boot image on it. In this case
454 * we try to find the parent device and add that instead as
455 * that will be the CD filesystem.
457 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
458 DevicePathSubType(node) == MEDIA_CDROM_DP &&
460 parent = calloc(1, sizeof(*parent));
461 if (parent == NULL) {
462 printf("efipart_updatecd: out of memory\n");
463 /* this device is lost but try again. */
468 devpath = efi_devpath_trim(cd->pd_devpath);
469 if (devpath == NULL) {
470 printf("efipart_updatecd: out of memory\n");
471 /* this device is lost but try again. */
476 parent->pd_devpath = devpath;
477 status = BS->LocateDevicePath(&blkio_guid,
478 &parent->pd_devpath, &parent->pd_handle);
480 if (EFI_ERROR(status)) {
481 printf("efipart_updatecd: error %lu\n",
482 EFI_ERROR_CODE(status));
488 efi_lookup_devpath(parent->pd_handle);
489 efipart_cdinfo_add(parent);
492 efipart_cdinfo_add(cd);
502 bcache_add_dev(efiblk_pdinfo_count(&cdinfo));
507 efipart_hdinfo_add_node(pdinfo_t *hd, EFI_DEVICE_PATH *node)
514 /* Find our disk device. */
515 STAILQ_FOREACH(pd, &hdinfo, pd_link) {
516 if (efi_devpath_is_prefix(pd->pd_devpath, hd->pd_devpath))
522 /* If the node is not MEDIA_HARDDRIVE_DP, it is sub-partition. */
523 if (DevicePathSubType(node) != MEDIA_HARDDRIVE_DP) {
524 STAILQ_FOREACH(ptr, &pd->pd_part, pd_link) {
525 if (efi_devpath_is_prefix(ptr->pd_devpath,
530 * ptr == NULL means we have handles in unexpected order
531 * and we would need to re-order the partitions later.
537 /* Add the partition. */
538 if (DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) {
539 hd->pd_unit = ((HARDDRIVE_DEVICE_PATH *)node)->PartitionNumber;
541 ptr = STAILQ_LAST(&pd->pd_part, pdinfo, pd_link);
543 hd->pd_unit = ptr->pd_unit + 1;
548 hd->pd_devsw = &efipart_hddev;
550 STAILQ_INSERT_TAIL(&pd->pd_part, hd, pd_link);
555 efipart_hdinfo_add(pdinfo_t *hd, EFI_DEVICE_PATH *node)
559 if (efipart_hdinfo_add_node(hd, node))
562 last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
564 hd->pd_unit = last->pd_unit + 1;
569 hd->pd_devsw = &efipart_hddev;
570 STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
574 * The MEDIA_FILEPATH_DP has device name.
575 * From U-Boot sources it looks like names are in the form
576 * of typeN:M, where type is interface type, N is disk id
577 * and M is partition id.
580 efipart_hdinfo_add_filepath(pdinfo_t *hd, FILEPATH_DEVICE_PATH *node)
586 last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
588 hd->pd_unit = last->pd_unit + 1;
592 /* FILEPATH_DEVICE_PATH has 0 terminated string */
593 len = ucs2len(node->PathName);
594 if ((pathname = malloc(len + 1)) == NULL) {
595 printf("Failed to add disk, out of memory\n");
599 cpy16to8(node->PathName, pathname, len + 1);
600 p = strchr(pathname, ':');
603 * Assume we are receiving handles in order, first disk handle,
604 * then partitions for this disk. If this assumption proves
605 * false, this code would need update.
607 if (p == NULL) { /* no colon, add the disk */
608 hd->pd_devsw = &efipart_hddev;
609 STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
613 p++; /* skip the colon */
615 hd->pd_unit = (int)strtol(p, NULL, 0);
617 printf("Bad unit number for partition \"%s\"\n", pathname);
624 * We should have disk registered, if not, we are receiving
625 * handles out of order, and this code should be reworked
626 * to create "blank" disk for partition, and to find the
627 * disk based on PathName compares.
630 printf("BUG: No disk for partition \"%s\"\n", pathname);
635 /* Add the partition. */
636 hd->pd_parent = last;
637 hd->pd_devsw = &efipart_hddev;
638 STAILQ_INSERT_TAIL(&last->pd_part, hd, pd_link);
643 efipart_updatehd(void)
645 EFI_DEVICE_PATH *devpath, *node;
647 pdinfo_t *parent, *hd;
650 STAILQ_FOREACH(hd, &pdinfo, pd_link) {
651 if ((node = efi_devpath_last_node(hd->pd_devpath)) == NULL)
654 if (efipart_floppy(node) != NULL)
657 if (efipart_testcd(node, hd->pd_blkio))
660 if (DevicePathType(node) == HARDWARE_DEVICE_PATH &&
661 (DevicePathSubType(node) == HW_PCI_DP ||
662 DevicePathSubType(node) == HW_VENDOR_DP)) {
663 STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
664 efipart_hdinfo_add(hd, NULL);
668 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
669 DevicePathSubType(node) == MEDIA_FILEPATH_DP) {
670 STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
671 efipart_hdinfo_add_filepath(hd,
672 (FILEPATH_DEVICE_PATH *)node);
676 STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
677 parent = efipart_find_parent(&pdinfo, hd->pd_devpath);
678 if (parent != NULL) {
679 STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
680 efipart_hdinfo_add(parent, NULL);
682 parent = efipart_find_parent(&hdinfo, hd->pd_devpath);
685 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
686 DevicePathSubType(node) == MEDIA_HARDDRIVE_DP &&
688 parent = calloc(1, sizeof(*parent));
689 if (parent == NULL) {
690 printf("efipart_updatehd: out of memory\n");
691 /* this device is lost but try again. */
696 devpath = efi_devpath_trim(hd->pd_devpath);
697 if (devpath == NULL) {
698 printf("efipart_updatehd: out of memory\n");
699 /* this device is lost but try again. */
705 parent->pd_devpath = devpath;
706 status = BS->LocateDevicePath(&blkio_guid,
707 &parent->pd_devpath, &parent->pd_handle);
709 if (EFI_ERROR(status)) {
710 printf("efipart_updatehd: error %lu\n",
711 EFI_ERROR_CODE(status));
718 efi_lookup_devpath(&parent->pd_handle);
720 efipart_hdinfo_add(parent, NULL);
723 efipart_hdinfo_add(hd, node);
734 bcache_add_dev(efiblk_pdinfo_count(&hdinfo));
739 efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose)
747 struct disk_devdesc pd_dev;
750 if (STAILQ_EMPTY(pdlist))
753 printf("%s devices:", dev->dv_name);
754 if ((ret = pager_output("\n")) != 0)
757 STAILQ_FOREACH(pd, pdlist, pd_link) {
759 if (verbose) { /* Output the device path. */
760 text = efi_devpath_name(efi_lookup_devpath(h));
763 efi_free_devpath_name(text);
764 if ((ret = pager_output("\n")) != 0)
768 snprintf(line, sizeof(line),
769 " %s%d", dev->dv_name, pd->pd_unit);
771 status = OpenProtocolByHandle(h, &blkio_guid, (void **)&blkio);
772 if (!EFI_ERROR(status)) {
774 blkio->Media->LastBlock == 0? 0:
775 (unsigned long long) (blkio->Media->LastBlock + 1));
776 if (blkio->Media->LastBlock != 0) {
777 printf(" X %u", blkio->Media->BlockSize);
780 if (blkio->Media->MediaPresent) {
781 if (blkio->Media->RemovableMedia)
782 printf(" (removable)");
784 printf(" (no media)");
786 if ((ret = pager_output("\n")) != 0)
788 if (!blkio->Media->MediaPresent)
791 pd->pd_blkio = blkio;
792 pd_dev.dd.d_dev = dev;
793 pd_dev.dd.d_unit = pd->pd_unit;
794 pd_dev.d_slice = D_SLICENONE;
795 pd_dev.d_partition = D_PARTNONE;
796 ret = disk_open(&pd_dev, blkio->Media->BlockSize *
797 (blkio->Media->LastBlock + 1),
798 blkio->Media->BlockSize);
800 ret = disk_print(&pd_dev, line, verbose);
805 /* Do not fail from disk_open() */
809 if ((ret = pager_output("\n")) != 0)
817 efipart_printfd(int verbose)
819 return (efipart_print_common(&efipart_fddev, &fdinfo, verbose));
823 efipart_printcd(int verbose)
825 return (efipart_print_common(&efipart_cddev, &cdinfo, verbose));
829 efipart_printhd(int verbose)
831 return (efipart_print_common(&efipart_hddev, &hdinfo, verbose));
835 efipart_open(struct open_file *f, ...)
838 struct disk_devdesc *dev;
844 dev = va_arg(args, struct disk_devdesc *);
849 pd = efiblk_get_pdinfo((struct devdesc *)dev);
853 if (pd->pd_blkio == NULL) {
854 status = OpenProtocolByHandle(pd->pd_handle, &blkio_guid,
855 (void **)&pd->pd_blkio);
856 if (EFI_ERROR(status))
857 return (efi_status_to_errno(status));
860 blkio = pd->pd_blkio;
861 if (!blkio->Media->MediaPresent)
865 if (pd->pd_bcache == NULL)
866 pd->pd_bcache = bcache_allocate();
868 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
872 blkio->Media->BlockSize * (blkio->Media->LastBlock + 1),
873 blkio->Media->BlockSize);
876 if (pd->pd_open == 0) {
878 bcache_free(pd->pd_bcache);
879 pd->pd_bcache = NULL;
888 efipart_close(struct open_file *f)
890 struct disk_devdesc *dev;
893 dev = (struct disk_devdesc *)(f->f_devdata);
897 pd = efiblk_get_pdinfo((struct devdesc *)dev);
902 if (pd->pd_open == 0) {
904 bcache_free(pd->pd_bcache);
905 pd->pd_bcache = NULL;
907 if (dev->dd.d_dev->dv_type == DEVT_DISK)
908 return (disk_close(dev));
913 efipart_ioctl(struct open_file *f, u_long cmd, void *data)
915 struct disk_devdesc *dev;
919 dev = (struct disk_devdesc *)(f->f_devdata);
923 pd = efiblk_get_pdinfo((struct devdesc *)dev);
927 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
928 rc = disk_ioctl(dev, cmd, data);
934 case DIOCGSECTORSIZE:
935 *(u_int *)data = pd->pd_blkio->Media->BlockSize;
938 *(uint64_t *)data = pd->pd_blkio->Media->BlockSize *
939 (pd->pd_blkio->Media->LastBlock + 1);
949 * efipart_readwrite()
950 * Internal equivalent of efipart_strategy(), which operates on the
951 * media-native block size. This function expects all I/O requests
952 * to be within the media size and returns an error if such is not
956 efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks,
963 if (blk < 0 || blk > blkio->Media->LastBlock)
965 if ((blk + nblks - 1) > blkio->Media->LastBlock)
968 switch (rw & F_MASK) {
970 status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk,
971 nblks * blkio->Media->BlockSize, buf);
974 if (blkio->Media->ReadOnly)
976 status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk,
977 nblks * blkio->Media->BlockSize, buf);
983 if (EFI_ERROR(status)) {
984 printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw,
985 blk, nblks, EFI_ERROR_CODE(status));
987 return (efi_status_to_errno(status));
991 efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size,
992 char *buf, size_t *rsize)
994 struct bcache_devdata bcd;
995 struct disk_devdesc *dev;
998 dev = (struct disk_devdesc *)devdata;
1002 pd = efiblk_get_pdinfo((struct devdesc *)dev);
1006 if (pd->pd_blkio->Media->RemovableMedia &&
1007 !pd->pd_blkio->Media->MediaPresent)
1010 bcd.dv_strategy = efipart_realstrategy;
1011 bcd.dv_devdata = devdata;
1012 bcd.dv_cache = pd->pd_bcache;
1014 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
1017 offset = dev->d_offset * pd->pd_blkio->Media->BlockSize;
1019 return (bcache_strategy(&bcd, rw, blk + offset,
1022 return (bcache_strategy(&bcd, rw, blk, size, buf, rsize));
1026 efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
1027 char *buf, size_t *rsize)
1029 struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
1031 EFI_BLOCK_IO *blkio;
1032 uint64_t off, disk_blocks, d_offset = 0;
1034 size_t blkoff, blksz, bio_size;
1038 uint64_t diskend, readstart;
1040 if (dev == NULL || blk < 0)
1043 pd = efiblk_get_pdinfo((struct devdesc *)dev);
1047 blkio = pd->pd_blkio;
1051 if (size == 0 || (size % 512) != 0)
1056 * Get disk blocks, this value is either for whole disk or for
1060 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
1061 if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
1062 /* DIOCGMEDIASIZE does return bytes. */
1063 disk_blocks /= blkio->Media->BlockSize;
1065 d_offset = dev->d_offset;
1067 if (disk_blocks == 0)
1068 disk_blocks = blkio->Media->LastBlock + 1 - d_offset;
1070 /* make sure we don't read past disk end */
1071 if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) {
1072 diskend = d_offset + disk_blocks;
1073 readstart = off / blkio->Media->BlockSize;
1075 if (diskend <= readstart) {
1081 size = diskend - readstart;
1082 size = size * blkio->Media->BlockSize;
1086 /* Do we need bounce buffer? */
1087 if ((size % blkio->Media->BlockSize == 0) &&
1088 (off % blkio->Media->BlockSize == 0))
1091 /* Do we have IO alignment requirement? */
1092 ioalign = blkio->Media->IoAlign;
1096 if (ioalign > 1 && (uintptr_t)buf != roundup2((uintptr_t)buf, ioalign))
1100 for (bio_size = BIO_BUFFER_SIZE; bio_size > 0;
1101 bio_size -= blkio->Media->BlockSize) {
1102 blkbuf = memalign(ioalign, bio_size);
1118 blk = off / blkio->Media->BlockSize;
1119 blkoff = off % blkio->Media->BlockSize;
1122 size_t x = min(size, bio_size);
1124 if (x < blkio->Media->BlockSize)
1127 x /= blkio->Media->BlockSize;
1129 switch (rw & F_MASK) {
1131 blksz = blkio->Media->BlockSize * x - blkoff;
1135 rc = efipart_readwrite(blkio, rw, blk, x, blkbuf);
1140 bcopy(blkbuf + blkoff, buf, blksz);
1146 * We got offset to sector, read 1 sector to
1150 blksz = blkio->Media->BlockSize - blkoff;
1151 blksz = min(blksz, size);
1152 rc = efipart_readwrite(blkio, F_READ, blk, x,
1154 } else if (size < blkio->Media->BlockSize) {
1156 * The remaining block is not full
1157 * sector. Read 1 sector to blkbuf.
1161 rc = efipart_readwrite(blkio, F_READ, blk, x,
1164 /* We can write full sector(s). */
1165 blksz = blkio->Media->BlockSize * x;
1171 * Put your Data In, Put your Data out,
1172 * Put your Data In, and shake it all about
1175 bcopy(buf, blkbuf + blkoff, blksz);
1176 rc = efipart_readwrite(blkio, F_WRITE, blk, x, blkbuf);