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))
328 EFI_DEVICE_PATH *node;
329 ACPI_HID_DEVICE_PATH *acpi;
330 pdinfo_t *parent, *fd;
333 STAILQ_FOREACH(fd, &pdinfo, pd_link) {
334 if ((node = efi_devpath_last_node(fd->pd_devpath)) == NULL)
337 if ((acpi = efipart_floppy(node)) == NULL)
340 STAILQ_REMOVE(&pdinfo, fd, pdinfo, pd_link);
341 parent = efipart_find_parent(&pdinfo, fd->pd_devpath);
342 if (parent != NULL) {
343 STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
344 parent->pd_alias = fd->pd_handle;
345 parent->pd_unit = acpi->UID;
349 fd->pd_unit = acpi->UID;
351 fd->pd_devsw = &efipart_fddev;
352 STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
356 bcache_add_dev(efiblk_pdinfo_count(&fdinfo));
361 * Add or update entries with new handle data.
364 efipart_cdinfo_add(pdinfo_t *cd)
368 STAILQ_FOREACH(pd, &cdinfo, pd_link) {
369 if (efi_devpath_is_prefix(pd->pd_devpath, cd->pd_devpath)) {
370 last = STAILQ_LAST(&pd->pd_part, pdinfo, pd_link);
372 cd->pd_unit = last->pd_unit + 1;
376 cd->pd_devsw = &efipart_cddev;
377 STAILQ_INSERT_TAIL(&pd->pd_part, cd, pd_link);
382 last = STAILQ_LAST(&cdinfo, pdinfo, pd_link);
384 cd->pd_unit = last->pd_unit + 1;
388 cd->pd_parent = NULL;
389 cd->pd_devsw = &efipart_cddev;
390 STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link);
394 efipart_testcd(EFI_DEVICE_PATH *node, EFI_BLOCK_IO *blkio)
396 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
397 DevicePathSubType(node) == MEDIA_CDROM_DP) {
401 /* cd drive without the media. */
402 if (blkio->Media->RemovableMedia &&
403 !blkio->Media->MediaPresent) {
411 efipart_updatecd(void)
413 EFI_DEVICE_PATH *devpath, *node;
415 pdinfo_t *parent, *cd;
418 STAILQ_FOREACH(cd, &pdinfo, pd_link) {
419 if ((node = efi_devpath_last_node(cd->pd_devpath)) == NULL)
422 if (efipart_floppy(node) != NULL)
425 /* Is parent of this device already registered? */
426 parent = efipart_find_parent(&cdinfo, cd->pd_devpath);
427 if (parent != NULL) {
428 STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link);
429 efipart_cdinfo_add(cd);
433 if (!efipart_testcd(node, cd->pd_blkio))
436 /* Find parent and unlink both parent and cd from pdinfo */
437 STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link);
438 parent = efipart_find_parent(&pdinfo, cd->pd_devpath);
439 if (parent != NULL) {
440 STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
441 efipart_cdinfo_add(parent);
445 parent = efipart_find_parent(&cdinfo, cd->pd_devpath);
448 * If we come across a logical partition of subtype CDROM
449 * it doesn't refer to the CD filesystem itself, but rather
450 * to any usable El Torito boot image on it. In this case
451 * we try to find the parent device and add that instead as
452 * that will be the CD filesystem.
454 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
455 DevicePathSubType(node) == MEDIA_CDROM_DP &&
457 parent = calloc(1, sizeof(*parent));
458 if (parent == NULL) {
459 printf("efipart_updatecd: out of memory\n");
460 /* this device is lost but try again. */
465 devpath = efi_devpath_trim(cd->pd_devpath);
466 if (devpath == NULL) {
467 printf("efipart_updatecd: out of memory\n");
468 /* this device is lost but try again. */
473 parent->pd_devpath = devpath;
474 status = BS->LocateDevicePath(&blkio_guid,
475 &parent->pd_devpath, &parent->pd_handle);
477 if (EFI_ERROR(status)) {
478 printf("efipart_updatecd: error %lu\n",
479 EFI_ERROR_CODE(status));
485 efi_lookup_devpath(parent->pd_handle);
486 efipart_cdinfo_add(parent);
489 efipart_cdinfo_add(cd);
499 bcache_add_dev(efiblk_pdinfo_count(&cdinfo));
504 efipart_hdinfo_add(pdinfo_t *hd, HARDDRIVE_DEVICE_PATH *node)
508 STAILQ_FOREACH(pd, &hdinfo, pd_link) {
509 if (efi_devpath_is_prefix(pd->pd_devpath, hd->pd_devpath)) {
510 /* Add the partition. */
511 hd->pd_unit = node->PartitionNumber;
513 hd->pd_devsw = &efipart_hddev;
514 STAILQ_INSERT_TAIL(&pd->pd_part, hd, pd_link);
519 last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
521 hd->pd_unit = last->pd_unit + 1;
526 hd->pd_devsw = &efipart_hddev;
527 STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
531 * The MEDIA_FILEPATH_DP has device name.
532 * From U-Boot sources it looks like names are in the form
533 * of typeN:M, where type is interface type, N is disk id
534 * and M is partition id.
537 efipart_hdinfo_add_filepath(pdinfo_t *hd, FILEPATH_DEVICE_PATH *node)
543 last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
545 hd->pd_unit = last->pd_unit + 1;
549 /* FILEPATH_DEVICE_PATH has 0 terminated string */
550 len = ucs2len(node->PathName);
551 if ((pathname = malloc(len + 1)) == NULL) {
552 printf("Failed to add disk, out of memory\n");
556 cpy16to8(node->PathName, pathname, len + 1);
557 p = strchr(pathname, ':');
560 * Assume we are receiving handles in order, first disk handle,
561 * then partitions for this disk. If this assumption proves
562 * false, this code would need update.
564 if (p == NULL) { /* no colon, add the disk */
565 hd->pd_devsw = &efipart_hddev;
566 STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
570 p++; /* skip the colon */
572 hd->pd_unit = (int)strtol(p, NULL, 0);
574 printf("Bad unit number for partition \"%s\"\n", pathname);
581 * We should have disk registered, if not, we are receiving
582 * handles out of order, and this code should be reworked
583 * to create "blank" disk for partition, and to find the
584 * disk based on PathName compares.
587 printf("BUG: No disk for partition \"%s\"\n", pathname);
592 /* Add the partition. */
593 hd->pd_parent = last;
594 hd->pd_devsw = &efipart_hddev;
595 STAILQ_INSERT_TAIL(&last->pd_part, hd, pd_link);
600 efipart_updatehd(void)
602 EFI_DEVICE_PATH *devpath, *node;
604 pdinfo_t *parent, *hd;
607 STAILQ_FOREACH(hd, &pdinfo, pd_link) {
608 if ((node = efi_devpath_last_node(hd->pd_devpath)) == NULL)
611 if (efipart_floppy(node) != NULL)
614 if (efipart_testcd(node, hd->pd_blkio))
617 if (DevicePathType(node) == HARDWARE_DEVICE_PATH &&
618 (DevicePathSubType(node) == HW_PCI_DP ||
619 DevicePathSubType(node) == HW_VENDOR_DP)) {
620 STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
621 efipart_hdinfo_add(hd, NULL);
625 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
626 DevicePathSubType(node) == MEDIA_FILEPATH_DP) {
627 STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
628 efipart_hdinfo_add_filepath(hd,
629 (FILEPATH_DEVICE_PATH *)node);
633 STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
634 parent = efipart_find_parent(&pdinfo, hd->pd_devpath);
635 if (parent != NULL) {
636 STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
637 efipart_hdinfo_add(parent, NULL);
639 parent = efipart_find_parent(&hdinfo, hd->pd_devpath);
642 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
643 DevicePathSubType(node) == MEDIA_HARDDRIVE_DP &&
645 parent = calloc(1, sizeof(*parent));
646 if (parent == NULL) {
647 printf("efipart_updatehd: out of memory\n");
648 /* this device is lost but try again. */
653 devpath = efi_devpath_trim(hd->pd_devpath);
654 if (devpath == NULL) {
655 printf("efipart_updatehd: out of memory\n");
656 /* this device is lost but try again. */
662 parent->pd_devpath = devpath;
663 status = BS->LocateDevicePath(&blkio_guid,
664 &parent->pd_devpath, &parent->pd_handle);
666 if (EFI_ERROR(status)) {
667 printf("efipart_updatehd: error %lu\n",
668 EFI_ERROR_CODE(status));
675 efi_lookup_devpath(&parent->pd_handle);
677 efipart_hdinfo_add(parent, NULL);
680 efipart_hdinfo_add(hd, (HARDDRIVE_DEVICE_PATH *)node);
691 bcache_add_dev(efiblk_pdinfo_count(&hdinfo));
696 efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose)
704 struct disk_devdesc pd_dev;
707 if (STAILQ_EMPTY(pdlist))
710 printf("%s devices:", dev->dv_name);
711 if ((ret = pager_output("\n")) != 0)
714 STAILQ_FOREACH(pd, pdlist, pd_link) {
716 if (verbose) { /* Output the device path. */
717 text = efi_devpath_name(efi_lookup_devpath(h));
720 efi_free_devpath_name(text);
721 if ((ret = pager_output("\n")) != 0)
725 snprintf(line, sizeof(line),
726 " %s%d", dev->dv_name, pd->pd_unit);
728 status = OpenProtocolByHandle(h, &blkio_guid, (void **)&blkio);
729 if (!EFI_ERROR(status)) {
731 blkio->Media->LastBlock == 0? 0:
732 (unsigned long long) (blkio->Media->LastBlock + 1));
733 if (blkio->Media->LastBlock != 0) {
734 printf(" X %u", blkio->Media->BlockSize);
737 if (blkio->Media->MediaPresent) {
738 if (blkio->Media->RemovableMedia)
739 printf(" (removable)");
741 printf(" (no media)");
743 if ((ret = pager_output("\n")) != 0)
745 if (!blkio->Media->MediaPresent)
748 pd->pd_blkio = blkio;
749 pd_dev.dd.d_dev = dev;
750 pd_dev.dd.d_unit = pd->pd_unit;
752 pd_dev.d_partition = -1;
753 ret = disk_open(&pd_dev, blkio->Media->BlockSize *
754 (blkio->Media->LastBlock + 1),
755 blkio->Media->BlockSize);
757 ret = disk_print(&pd_dev, line, verbose);
762 /* Do not fail from disk_open() */
766 if ((ret = pager_output("\n")) != 0)
774 efipart_printfd(int verbose)
776 return (efipart_print_common(&efipart_fddev, &fdinfo, verbose));
780 efipart_printcd(int verbose)
782 return (efipart_print_common(&efipart_cddev, &cdinfo, verbose));
786 efipart_printhd(int verbose)
788 return (efipart_print_common(&efipart_hddev, &hdinfo, verbose));
792 efipart_open(struct open_file *f, ...)
795 struct disk_devdesc *dev;
801 dev = va_arg(args, struct disk_devdesc *);
806 pd = efiblk_get_pdinfo((struct devdesc *)dev);
810 if (pd->pd_blkio == NULL) {
811 status = OpenProtocolByHandle(pd->pd_handle, &blkio_guid,
812 (void **)&pd->pd_blkio);
813 if (EFI_ERROR(status))
814 return (efi_status_to_errno(status));
817 blkio = pd->pd_blkio;
818 if (!blkio->Media->MediaPresent)
822 if (pd->pd_bcache == NULL)
823 pd->pd_bcache = bcache_allocate();
825 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
829 blkio->Media->BlockSize * (blkio->Media->LastBlock + 1),
830 blkio->Media->BlockSize);
833 if (pd->pd_open == 0) {
835 bcache_free(pd->pd_bcache);
836 pd->pd_bcache = NULL;
845 efipart_close(struct open_file *f)
847 struct disk_devdesc *dev;
850 dev = (struct disk_devdesc *)(f->f_devdata);
854 pd = efiblk_get_pdinfo((struct devdesc *)dev);
859 if (pd->pd_open == 0) {
861 bcache_free(pd->pd_bcache);
862 pd->pd_bcache = NULL;
864 if (dev->dd.d_dev->dv_type == DEVT_DISK)
865 return (disk_close(dev));
870 efipart_ioctl(struct open_file *f, u_long cmd, void *data)
872 struct disk_devdesc *dev;
876 dev = (struct disk_devdesc *)(f->f_devdata);
880 pd = efiblk_get_pdinfo((struct devdesc *)dev);
884 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
885 rc = disk_ioctl(dev, cmd, data);
891 case DIOCGSECTORSIZE:
892 *(u_int *)data = pd->pd_blkio->Media->BlockSize;
895 *(uint64_t *)data = pd->pd_blkio->Media->BlockSize *
896 (pd->pd_blkio->Media->LastBlock + 1);
906 * efipart_readwrite()
907 * Internal equivalent of efipart_strategy(), which operates on the
908 * media-native block size. This function expects all I/O requests
909 * to be within the media size and returns an error if such is not
913 efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks,
920 if (blk < 0 || blk > blkio->Media->LastBlock)
922 if ((blk + nblks - 1) > blkio->Media->LastBlock)
925 switch (rw & F_MASK) {
927 status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk,
928 nblks * blkio->Media->BlockSize, buf);
931 if (blkio->Media->ReadOnly)
933 status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk,
934 nblks * blkio->Media->BlockSize, buf);
940 if (EFI_ERROR(status)) {
941 printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw,
942 blk, nblks, EFI_ERROR_CODE(status));
944 return (efi_status_to_errno(status));
948 efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size,
949 char *buf, size_t *rsize)
951 struct bcache_devdata bcd;
952 struct disk_devdesc *dev;
955 dev = (struct disk_devdesc *)devdata;
959 pd = efiblk_get_pdinfo((struct devdesc *)dev);
963 if (pd->pd_blkio->Media->RemovableMedia &&
964 !pd->pd_blkio->Media->MediaPresent)
967 bcd.dv_strategy = efipart_realstrategy;
968 bcd.dv_devdata = devdata;
969 bcd.dv_cache = pd->pd_bcache;
971 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
974 offset = dev->d_offset * pd->pd_blkio->Media->BlockSize;
976 return (bcache_strategy(&bcd, rw, blk + offset,
979 return (bcache_strategy(&bcd, rw, blk, size, buf, rsize));
983 efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
984 char *buf, size_t *rsize)
986 struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
989 uint64_t off, disk_blocks, d_offset = 0;
991 size_t blkoff, blksz, bio_size;
995 uint64_t diskend, readstart;
997 if (dev == NULL || blk < 0)
1000 pd = efiblk_get_pdinfo((struct devdesc *)dev);
1004 blkio = pd->pd_blkio;
1008 if (size == 0 || (size % 512) != 0)
1013 * Get disk blocks, this value is either for whole disk or for
1017 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
1018 if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
1019 /* DIOCGMEDIASIZE does return bytes. */
1020 disk_blocks /= blkio->Media->BlockSize;
1022 d_offset = dev->d_offset;
1024 if (disk_blocks == 0)
1025 disk_blocks = blkio->Media->LastBlock + 1 - d_offset;
1027 /* make sure we don't read past disk end */
1028 if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) {
1029 diskend = d_offset + disk_blocks;
1030 readstart = off / blkio->Media->BlockSize;
1032 if (diskend <= readstart) {
1038 size = diskend - readstart;
1039 size = size * blkio->Media->BlockSize;
1043 /* Do we need bounce buffer? */
1044 if ((size % blkio->Media->BlockSize == 0) &&
1045 (off % blkio->Media->BlockSize == 0))
1048 /* Do we have IO alignment requirement? */
1049 ioalign = blkio->Media->IoAlign;
1053 if (ioalign > 1 && (uintptr_t)buf != roundup2((uintptr_t)buf, ioalign))
1057 for (bio_size = BIO_BUFFER_SIZE; bio_size > 0;
1058 bio_size -= blkio->Media->BlockSize) {
1059 blkbuf = memalign(ioalign, bio_size);
1075 blk = off / blkio->Media->BlockSize;
1076 blkoff = off % blkio->Media->BlockSize;
1079 size_t x = min(size, bio_size);
1081 if (x < blkio->Media->BlockSize)
1084 x /= blkio->Media->BlockSize;
1086 switch (rw & F_MASK) {
1088 blksz = blkio->Media->BlockSize * x - blkoff;
1092 rc = efipart_readwrite(blkio, rw, blk, x, blkbuf);
1097 bcopy(blkbuf + blkoff, buf, blksz);
1103 * We got offset to sector, read 1 sector to
1107 blksz = blkio->Media->BlockSize - blkoff;
1108 blksz = min(blksz, size);
1109 rc = efipart_readwrite(blkio, F_READ, blk, x,
1111 } else if (size < blkio->Media->BlockSize) {
1113 * The remaining block is not full
1114 * sector. Read 1 sector to blkbuf.
1118 rc = efipart_readwrite(blkio, F_READ, blk, x,
1121 /* We can write full sector(s). */
1122 blksz = blkio->Media->BlockSize * x;
1128 * Put your Data In, Put your Data out,
1129 * Put your Data In, and shake it all about
1132 bcopy(buf, blkbuf + blkoff, blksz);
1133 rc = efipart_readwrite(blkio, F_WRITE, blk, x, blkbuf);