1 /*- 2 * Copyright (c) 2010 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 13 * 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 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/disk.h> 31 #include <sys/param.h> 32 #include <sys/time.h> 33 #include <sys/queue.h> 34 #include <stddef.h> 35 #include <stdarg.h> 36 37 #include <bootstrap.h> 38 39 #include <efi.h> 40 #include <efilib.h> 41 #include <efiprot.h> 42 #include <efichar.h> 43 #include <disk.h> 44 45 static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; 46 47 static int efipart_initfd(void); 48 static int efipart_initcd(void); 49 static int efipart_inithd(void); 50 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 *); 53 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 *); 57 58 static int efipart_printfd(int); 59 static int efipart_printcd(int); 60 static int efipart_printhd(int); 61 62 /* EISA PNP ID's for floppy controllers */ 63 #define PNP0604 0x604 64 #define PNP0700 0x700 65 #define PNP0701 0x701 66 67 /* Bounce buffer max size */ 68 #define BIO_BUFFER_SIZE 0x4000 69 70 struct devsw efipart_fddev = { 71 .dv_name = "fd", 72 .dv_type = DEVT_FD, 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, 79 .dv_cleanup = NULL 80 }; 81 82 struct devsw efipart_cddev = { 83 .dv_name = "cd", 84 .dv_type = DEVT_CD, 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, 91 .dv_cleanup = NULL 92 }; 93 94 struct devsw efipart_hddev = { 95 .dv_name = "disk", 96 .dv_type = DEVT_DISK, 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, 103 .dv_cleanup = NULL 104 }; 105 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); 109 110 /* 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. 116 */ 117 static pdinfo_list_t pdinfo = STAILQ_HEAD_INITIALIZER(pdinfo); 118 119 pdinfo_list_t * 120 efiblk_get_pdinfo_list(struct devsw *dev) 121 { 122 if (dev->dv_type == DEVT_DISK) 123 return (&hdinfo); 124 if (dev->dv_type == DEVT_CD) 125 return (&cdinfo); 126 if (dev->dv_type == DEVT_FD) 127 return (&fdinfo); 128 return (NULL); 129 } 130 131 /* XXX this gets called way way too often, investigate */ 132 pdinfo_t * 133 efiblk_get_pdinfo(struct devdesc *dev) 134 { 135 pdinfo_list_t *pdi; 136 pdinfo_t *pd = NULL; 137 138 pdi = efiblk_get_pdinfo_list(dev->d_dev); 139 if (pdi == NULL) 140 return (pd); 141 142 STAILQ_FOREACH(pd, pdi, pd_link) { 143 if (pd->pd_unit == dev->d_unit) 144 return (pd); 145 } 146 return (pd); 147 } 148 149 pdinfo_t * 150 efiblk_get_pdinfo_by_device_path(EFI_DEVICE_PATH *path) 151 { 152 EFI_HANDLE h; 153 EFI_STATUS status; 154 EFI_DEVICE_PATH *devp = path; 155 156 status = BS->LocateDevicePath(&blkio_guid, &devp, &h); 157 if (EFI_ERROR(status)) 158 return (NULL); 159 return (efiblk_get_pdinfo_by_handle(h)); 160 } 161 162 static bool 163 same_handle(pdinfo_t *pd, EFI_HANDLE h) 164 { 165 166 return (pd->pd_handle == h || pd->pd_alias == h); 167 } 168 169 pdinfo_t * 170 efiblk_get_pdinfo_by_handle(EFI_HANDLE h) 171 { 172 pdinfo_t *dp, *pp; 173 174 /* 175 * Check hard disks, then cd, then floppy 176 */ 177 STAILQ_FOREACH(dp, &hdinfo, pd_link) { 178 if (same_handle(dp, h)) 179 return (dp); 180 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { 181 if (same_handle(pp, h)) 182 return (pp); 183 } 184 } 185 STAILQ_FOREACH(dp, &cdinfo, pd_link) { 186 if (same_handle(dp, h)) 187 return (dp); 188 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { 189 if (same_handle(pp, h)) 190 return (pp); 191 } 192 } 193 STAILQ_FOREACH(dp, &fdinfo, pd_link) { 194 if (same_handle(dp, h)) 195 return (dp); 196 } 197 return (NULL); 198 } 199 200 static int 201 efiblk_pdinfo_count(pdinfo_list_t *pdi) 202 { 203 pdinfo_t *pd; 204 int i = 0; 205 206 STAILQ_FOREACH(pd, pdi, pd_link) { 207 i++; 208 } 209 return (i); 210 } 211 212 int 213 efipart_inithandles(void) 214 { 215 unsigned i, nin; 216 UINTN sz; 217 EFI_HANDLE *hin; 218 EFI_DEVICE_PATH *devpath; 219 EFI_BLOCK_IO *blkio; 220 EFI_STATUS status; 221 pdinfo_t *pd; 222 223 if (!STAILQ_EMPTY(&pdinfo)) 224 return (0); 225 226 sz = 0; 227 hin = NULL; 228 status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin); 229 if (status == EFI_BUFFER_TOO_SMALL) { 230 hin = malloc(sz); 231 status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 232 hin); 233 if (EFI_ERROR(status)) 234 free(hin); 235 } 236 if (EFI_ERROR(status)) 237 return (efi_status_to_errno(status)); 238 239 nin = sz / sizeof(*hin); 240 #ifdef EFIPART_DEBUG 241 printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__, nin); 242 #endif 243 244 for (i = 0; i < nin; i++) { 245 /* 246 * Get devpath and open protocol. 247 * We should not get errors here 248 */ 249 if ((devpath = efi_lookup_devpath(hin[i])) == NULL) 250 continue; 251 252 status = OpenProtocolByHandle(hin[i], &blkio_guid, 253 (void **)&blkio); 254 if (EFI_ERROR(status)) { 255 printf("error %lu\n", EFI_ERROR_CODE(status)); 256 continue; 257 } 258 259 /* 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 264 * BlockSize 1. 265 */ 266 if (blkio->Media->BlockSize < 512 || 267 blkio->Media->BlockSize > (1 << 16) || 268 !powerof2(blkio->Media->BlockSize)) { 269 continue; 270 } 271 272 /* Allowed values are 0, 1 and power of 2. */ 273 if (blkio->Media->IoAlign > 1 && 274 !powerof2(blkio->Media->IoAlign)) { 275 continue; 276 } 277 278 /* This is bad. */ 279 if ((pd = calloc(1, sizeof(*pd))) == NULL) { 280 printf("efipart_inithandles: Out of memory.\n"); 281 free(hin); 282 return (ENOMEM); 283 } 284 STAILQ_INIT(&pd->pd_part); 285 286 pd->pd_handle = hin[i]; 287 pd->pd_devpath = devpath; 288 pd->pd_blkio = blkio; 289 STAILQ_INSERT_TAIL(&pdinfo, pd, pd_link); 290 } 291 292 free(hin); 293 return (0); 294 } 295 296 static ACPI_HID_DEVICE_PATH * 297 efipart_floppy(EFI_DEVICE_PATH *node) 298 { 299 ACPI_HID_DEVICE_PATH *acpi; 300 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)) { 307 return (acpi); 308 } 309 } 310 return (NULL); 311 } 312 313 static pdinfo_t * 314 efipart_find_parent(pdinfo_list_t *pdi, EFI_DEVICE_PATH *devpath) 315 { 316 pdinfo_t *pd, *part; 317 318 STAILQ_FOREACH(pd, pdi, pd_link) { 319 if (efi_devpath_is_prefix(pd->pd_devpath, devpath)) 320 return (pd); 321 part = efipart_find_parent(&pd->pd_part, devpath); 322 if (part != NULL) 323 return (part); 324 } 325 return (NULL); 326 } 327 328 static int 329 efipart_initfd(void) 330 { 331 EFI_DEVICE_PATH *node; 332 ACPI_HID_DEVICE_PATH *acpi; 333 pdinfo_t *parent, *fd; 334 335 restart: 336 STAILQ_FOREACH(fd, &pdinfo, pd_link) { 337 if ((node = efi_devpath_last_node(fd->pd_devpath)) == NULL) 338 continue; 339 340 if ((acpi = efipart_floppy(node)) == NULL) 341 continue; 342 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; 349 free(fd); 350 fd = parent; 351 } else { 352 fd->pd_unit = acpi->UID; 353 } 354 fd->pd_devsw = &efipart_fddev; 355 STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link); 356 goto restart; 357 } 358 359 bcache_add_dev(efiblk_pdinfo_count(&fdinfo)); 360 return (0); 361 } 362 363 /* 364 * Add or update entries with new handle data. 365 */ 366 static void 367 efipart_cdinfo_add(pdinfo_t *cd) 368 { 369 pdinfo_t *pd, *last; 370 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); 374 if (last != NULL) 375 cd->pd_unit = last->pd_unit + 1; 376 else 377 cd->pd_unit = 0; 378 cd->pd_parent = pd; 379 cd->pd_devsw = &efipart_cddev; 380 STAILQ_INSERT_TAIL(&pd->pd_part, cd, pd_link); 381 return; 382 } 383 } 384 385 last = STAILQ_LAST(&cdinfo, pdinfo, pd_link); 386 if (last != NULL) 387 cd->pd_unit = last->pd_unit + 1; 388 else 389 cd->pd_unit = 0; 390 391 cd->pd_parent = NULL; 392 cd->pd_devsw = &efipart_cddev; 393 STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link); 394 } 395 396 static bool 397 efipart_testcd(EFI_DEVICE_PATH *node, EFI_BLOCK_IO *blkio) 398 { 399 if (DevicePathType(node) == MEDIA_DEVICE_PATH && 400 DevicePathSubType(node) == MEDIA_CDROM_DP) { 401 return (true); 402 } 403 404 /* cd drive without the media. */ 405 if (blkio->Media->RemovableMedia && 406 !blkio->Media->MediaPresent) { 407 return (true); 408 } 409 410 return (false); 411 } 412 413 static void 414 efipart_updatecd(void) 415 { 416 EFI_DEVICE_PATH *devpath, *node; 417 EFI_STATUS status; 418 pdinfo_t *parent, *cd; 419 420 restart: 421 STAILQ_FOREACH(cd, &pdinfo, pd_link) { 422 if ((node = efi_devpath_last_node(cd->pd_devpath)) == NULL) 423 continue; 424 425 if (efipart_floppy(node) != NULL) 426 continue; 427 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); 433 goto restart; 434 } 435 436 if (!efipart_testcd(node, cd->pd_blkio)) 437 continue; 438 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); 445 } 446 447 if (parent == NULL) 448 parent = efipart_find_parent(&cdinfo, cd->pd_devpath); 449 450 /* 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. 456 */ 457 if (DevicePathType(node) == MEDIA_DEVICE_PATH && 458 DevicePathSubType(node) == MEDIA_CDROM_DP && 459 parent == NULL) { 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. */ 464 free(cd); 465 goto restart; 466 } 467 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. */ 472 free(parent); 473 free(cd); 474 goto restart; 475 } 476 parent->pd_devpath = devpath; 477 status = BS->LocateDevicePath(&blkio_guid, 478 &parent->pd_devpath, &parent->pd_handle); 479 free(devpath); 480 if (EFI_ERROR(status)) { 481 printf("efipart_updatecd: error %lu\n", 482 EFI_ERROR_CODE(status)); 483 free(parent); 484 free(cd); 485 goto restart; 486 } 487 parent->pd_devpath = 488 efi_lookup_devpath(parent->pd_handle); 489 efipart_cdinfo_add(parent); 490 } 491 492 efipart_cdinfo_add(cd); 493 goto restart; 494 } 495 } 496 497 static int 498 efipart_initcd(void) 499 { 500 efipart_updatecd(); 501 502 bcache_add_dev(efiblk_pdinfo_count(&cdinfo)); 503 return (0); 504 } 505 506 static bool 507 efipart_hdinfo_add_node(pdinfo_t *hd, EFI_DEVICE_PATH *node) 508 { 509 pdinfo_t *pd, *last; 510 VENDOR_DEVICE_PATH *ven_node; 511 512 STAILQ_FOREACH(pd, &hdinfo, pd_link) { 513 if (efi_devpath_is_prefix(pd->pd_devpath, hd->pd_devpath)) 514 break; 515 } 516 if (pd == NULL) 517 return (false); 518 519 /* Add the partition. */ 520 if (DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) { 521 hd->pd_unit = ((HARDDRIVE_DEVICE_PATH *)node)->PartitionNumber; 522 } else { 523 last = STAILQ_LAST(&pd->pd_part, pdinfo, pd_link); 524 if (last != NULL) 525 hd->pd_unit = last->pd_unit + 1; 526 else 527 hd->pd_unit = 0; 528 } 529 hd->pd_parent = pd; 530 hd->pd_devsw = &efipart_hddev; 531 532 STAILQ_INSERT_TAIL(&pd->pd_part, hd, pd_link); 533 return (true); 534 } 535 536 static void 537 efipart_hdinfo_add(pdinfo_t *hd, EFI_DEVICE_PATH *node) 538 { 539 pdinfo_t *pd, *last; 540 541 if (efipart_hdinfo_add_node(hd, node)) 542 return; 543 544 last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); 545 if (last != NULL) 546 hd->pd_unit = last->pd_unit + 1; 547 else 548 hd->pd_unit = 0; 549 550 /* Add the disk. */ 551 hd->pd_devsw = &efipart_hddev; 552 STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); 553 } 554 555 /* 556 * The MEDIA_FILEPATH_DP has device name. 557 * From U-Boot sources it looks like names are in the form 558 * of typeN:M, where type is interface type, N is disk id 559 * and M is partition id. 560 */ 561 static void 562 efipart_hdinfo_add_filepath(pdinfo_t *hd, FILEPATH_DEVICE_PATH *node) 563 { 564 char *pathname, *p; 565 int len; 566 pdinfo_t *last; 567 568 last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); 569 if (last != NULL) 570 hd->pd_unit = last->pd_unit + 1; 571 else 572 hd->pd_unit = 0; 573 574 /* FILEPATH_DEVICE_PATH has 0 terminated string */ 575 len = ucs2len(node->PathName); 576 if ((pathname = malloc(len + 1)) == NULL) { 577 printf("Failed to add disk, out of memory\n"); 578 free(hd); 579 return; 580 } 581 cpy16to8(node->PathName, pathname, len + 1); 582 p = strchr(pathname, ':'); 583 584 /* 585 * Assume we are receiving handles in order, first disk handle, 586 * then partitions for this disk. If this assumption proves 587 * false, this code would need update. 588 */ 589 if (p == NULL) { /* no colon, add the disk */ 590 hd->pd_devsw = &efipart_hddev; 591 STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); 592 free(pathname); 593 return; 594 } 595 p++; /* skip the colon */ 596 errno = 0; 597 hd->pd_unit = (int)strtol(p, NULL, 0); 598 if (errno != 0) { 599 printf("Bad unit number for partition \"%s\"\n", pathname); 600 free(pathname); 601 free(hd); 602 return; 603 } 604 605 /* 606 * We should have disk registered, if not, we are receiving 607 * handles out of order, and this code should be reworked 608 * to create "blank" disk for partition, and to find the 609 * disk based on PathName compares. 610 */ 611 if (last == NULL) { 612 printf("BUG: No disk for partition \"%s\"\n", pathname); 613 free(pathname); 614 free(hd); 615 return; 616 } 617 /* Add the partition. */ 618 hd->pd_parent = last; 619 hd->pd_devsw = &efipart_hddev; 620 STAILQ_INSERT_TAIL(&last->pd_part, hd, pd_link); 621 free(pathname); 622 } 623 624 static void 625 efipart_updatehd(void) 626 { 627 EFI_DEVICE_PATH *devpath, *node; 628 EFI_STATUS status; 629 pdinfo_t *parent, *hd; 630 631 restart: 632 STAILQ_FOREACH(hd, &pdinfo, pd_link) { 633 if ((node = efi_devpath_last_node(hd->pd_devpath)) == NULL) 634 continue; 635 636 if (efipart_floppy(node) != NULL) 637 continue; 638 639 if (efipart_testcd(node, hd->pd_blkio)) 640 continue; 641 642 if (DevicePathType(node) == HARDWARE_DEVICE_PATH && 643 (DevicePathSubType(node) == HW_PCI_DP || 644 DevicePathSubType(node) == HW_VENDOR_DP)) { 645 STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link); 646 efipart_hdinfo_add(hd, NULL); 647 goto restart; 648 } 649 650 if (DevicePathType(node) == MEDIA_DEVICE_PATH && 651 DevicePathSubType(node) == MEDIA_FILEPATH_DP) { 652 STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link); 653 efipart_hdinfo_add_filepath(hd, 654 (FILEPATH_DEVICE_PATH *)node); 655 goto restart; 656 } 657 658 STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link); 659 parent = efipart_find_parent(&pdinfo, hd->pd_devpath); 660 if (parent != NULL) { 661 STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link); 662 efipart_hdinfo_add(parent, NULL); 663 } else { 664 parent = efipart_find_parent(&hdinfo, hd->pd_devpath); 665 } 666 667 if (DevicePathType(node) == MEDIA_DEVICE_PATH && 668 DevicePathSubType(node) == MEDIA_HARDDRIVE_DP && 669 parent == NULL) { 670 parent = calloc(1, sizeof(*parent)); 671 if (parent == NULL) { 672 printf("efipart_updatehd: out of memory\n"); 673 /* this device is lost but try again. */ 674 free(hd); 675 goto restart; 676 } 677 678 devpath = efi_devpath_trim(hd->pd_devpath); 679 if (devpath == NULL) { 680 printf("efipart_updatehd: out of memory\n"); 681 /* this device is lost but try again. */ 682 free(parent); 683 free(hd); 684 goto restart; 685 } 686 687 parent->pd_devpath = devpath; 688 status = BS->LocateDevicePath(&blkio_guid, 689 &parent->pd_devpath, &parent->pd_handle); 690 free(devpath); 691 if (EFI_ERROR(status)) { 692 printf("efipart_updatehd: error %lu\n", 693 EFI_ERROR_CODE(status)); 694 free(parent); 695 free(hd); 696 goto restart; 697 } 698 699 parent->pd_devpath = 700 efi_lookup_devpath(&parent->pd_handle); 701 702 efipart_hdinfo_add(parent, NULL); 703 } 704 705 efipart_hdinfo_add(hd, node); 706 goto restart; 707 } 708 } 709 710 static int 711 efipart_inithd(void) 712 { 713 714 efipart_updatehd(); 715 716 bcache_add_dev(efiblk_pdinfo_count(&hdinfo)); 717 return (0); 718 } 719 720 static int 721 efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose) 722 { 723 int ret = 0; 724 EFI_BLOCK_IO *blkio; 725 EFI_STATUS status; 726 EFI_HANDLE h; 727 pdinfo_t *pd; 728 CHAR16 *text; 729 struct disk_devdesc pd_dev; 730 char line[80]; 731 732 if (STAILQ_EMPTY(pdlist)) 733 return (0); 734 735 printf("%s devices:", dev->dv_name); 736 if ((ret = pager_output("\n")) != 0) 737 return (ret); 738 739 STAILQ_FOREACH(pd, pdlist, pd_link) { 740 h = pd->pd_handle; 741 if (verbose) { /* Output the device path. */ 742 text = efi_devpath_name(efi_lookup_devpath(h)); 743 if (text != NULL) { 744 printf(" %S", text); 745 efi_free_devpath_name(text); 746 if ((ret = pager_output("\n")) != 0) 747 break; 748 } 749 } 750 snprintf(line, sizeof(line), 751 " %s%d", dev->dv_name, pd->pd_unit); 752 printf("%s:", line); 753 status = OpenProtocolByHandle(h, &blkio_guid, (void **)&blkio); 754 if (!EFI_ERROR(status)) { 755 printf(" %llu", 756 blkio->Media->LastBlock == 0? 0: 757 (unsigned long long) (blkio->Media->LastBlock + 1)); 758 if (blkio->Media->LastBlock != 0) { 759 printf(" X %u", blkio->Media->BlockSize); 760 } 761 printf(" blocks"); 762 if (blkio->Media->MediaPresent) { 763 if (blkio->Media->RemovableMedia) 764 printf(" (removable)"); 765 } else { 766 printf(" (no media)"); 767 } 768 if ((ret = pager_output("\n")) != 0) 769 break; 770 if (!blkio->Media->MediaPresent) 771 continue; 772 773 pd->pd_blkio = blkio; 774 pd_dev.dd.d_dev = dev; 775 pd_dev.dd.d_unit = pd->pd_unit; 776 pd_dev.d_slice = D_SLICENONE; 777 pd_dev.d_partition = D_PARTNONE; 778 ret = disk_open(&pd_dev, blkio->Media->BlockSize * 779 (blkio->Media->LastBlock + 1), 780 blkio->Media->BlockSize); 781 if (ret == 0) { 782 ret = disk_print(&pd_dev, line, verbose); 783 disk_close(&pd_dev); 784 if (ret != 0) 785 return (ret); 786 } else { 787 /* Do not fail from disk_open() */ 788 ret = 0; 789 } 790 } else { 791 if ((ret = pager_output("\n")) != 0) 792 break; 793 } 794 } 795 return (ret); 796 } 797 798 static int 799 efipart_printfd(int verbose) 800 { 801 return (efipart_print_common(&efipart_fddev, &fdinfo, verbose)); 802 } 803 804 static int 805 efipart_printcd(int verbose) 806 { 807 return (efipart_print_common(&efipart_cddev, &cdinfo, verbose)); 808 } 809 810 static int 811 efipart_printhd(int verbose) 812 { 813 return (efipart_print_common(&efipart_hddev, &hdinfo, verbose)); 814 } 815 816 static int 817 efipart_open(struct open_file *f, ...) 818 { 819 va_list args; 820 struct disk_devdesc *dev; 821 pdinfo_t *pd; 822 EFI_BLOCK_IO *blkio; 823 EFI_STATUS status; 824 825 va_start(args, f); 826 dev = va_arg(args, struct disk_devdesc *); 827 va_end(args); 828 if (dev == NULL) 829 return (EINVAL); 830 831 pd = efiblk_get_pdinfo((struct devdesc *)dev); 832 if (pd == NULL) 833 return (EIO); 834 835 if (pd->pd_blkio == NULL) { 836 status = OpenProtocolByHandle(pd->pd_handle, &blkio_guid, 837 (void **)&pd->pd_blkio); 838 if (EFI_ERROR(status)) 839 return (efi_status_to_errno(status)); 840 } 841 842 blkio = pd->pd_blkio; 843 if (!blkio->Media->MediaPresent) 844 return (EAGAIN); 845 846 pd->pd_open++; 847 if (pd->pd_bcache == NULL) 848 pd->pd_bcache = bcache_allocate(); 849 850 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 851 int rc; 852 853 rc = disk_open(dev, 854 blkio->Media->BlockSize * (blkio->Media->LastBlock + 1), 855 blkio->Media->BlockSize); 856 if (rc != 0) { 857 pd->pd_open--; 858 if (pd->pd_open == 0) { 859 pd->pd_blkio = NULL; 860 bcache_free(pd->pd_bcache); 861 pd->pd_bcache = NULL; 862 } 863 } 864 return (rc); 865 } 866 return (0); 867 } 868 869 static int 870 efipart_close(struct open_file *f) 871 { 872 struct disk_devdesc *dev; 873 pdinfo_t *pd; 874 875 dev = (struct disk_devdesc *)(f->f_devdata); 876 if (dev == NULL) 877 return (EINVAL); 878 879 pd = efiblk_get_pdinfo((struct devdesc *)dev); 880 if (pd == NULL) 881 return (EINVAL); 882 883 pd->pd_open--; 884 if (pd->pd_open == 0) { 885 pd->pd_blkio = NULL; 886 bcache_free(pd->pd_bcache); 887 pd->pd_bcache = NULL; 888 } 889 if (dev->dd.d_dev->dv_type == DEVT_DISK) 890 return (disk_close(dev)); 891 return (0); 892 } 893 894 static int 895 efipart_ioctl(struct open_file *f, u_long cmd, void *data) 896 { 897 struct disk_devdesc *dev; 898 pdinfo_t *pd; 899 int rc; 900 901 dev = (struct disk_devdesc *)(f->f_devdata); 902 if (dev == NULL) 903 return (EINVAL); 904 905 pd = efiblk_get_pdinfo((struct devdesc *)dev); 906 if (pd == NULL) 907 return (EINVAL); 908 909 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 910 rc = disk_ioctl(dev, cmd, data); 911 if (rc != ENOTTY) 912 return (rc); 913 } 914 915 switch (cmd) { 916 case DIOCGSECTORSIZE: 917 *(u_int *)data = pd->pd_blkio->Media->BlockSize; 918 break; 919 case DIOCGMEDIASIZE: 920 *(uint64_t *)data = pd->pd_blkio->Media->BlockSize * 921 (pd->pd_blkio->Media->LastBlock + 1); 922 break; 923 default: 924 return (ENOTTY); 925 } 926 927 return (0); 928 } 929 930 /* 931 * efipart_readwrite() 932 * Internal equivalent of efipart_strategy(), which operates on the 933 * media-native block size. This function expects all I/O requests 934 * to be within the media size and returns an error if such is not 935 * the case. 936 */ 937 static int 938 efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks, 939 char *buf) 940 { 941 EFI_STATUS status; 942 943 if (blkio == NULL) 944 return (ENXIO); 945 if (blk < 0 || blk > blkio->Media->LastBlock) 946 return (EIO); 947 if ((blk + nblks - 1) > blkio->Media->LastBlock) 948 return (EIO); 949 950 switch (rw & F_MASK) { 951 case F_READ: 952 status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk, 953 nblks * blkio->Media->BlockSize, buf); 954 break; 955 case F_WRITE: 956 if (blkio->Media->ReadOnly) 957 return (EROFS); 958 status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk, 959 nblks * blkio->Media->BlockSize, buf); 960 break; 961 default: 962 return (ENOSYS); 963 } 964 965 if (EFI_ERROR(status)) { 966 printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw, 967 blk, nblks, EFI_ERROR_CODE(status)); 968 } 969 return (efi_status_to_errno(status)); 970 } 971 972 static int 973 efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, 974 char *buf, size_t *rsize) 975 { 976 struct bcache_devdata bcd; 977 struct disk_devdesc *dev; 978 pdinfo_t *pd; 979 980 dev = (struct disk_devdesc *)devdata; 981 if (dev == NULL) 982 return (EINVAL); 983 984 pd = efiblk_get_pdinfo((struct devdesc *)dev); 985 if (pd == NULL) 986 return (EINVAL); 987 988 if (pd->pd_blkio->Media->RemovableMedia && 989 !pd->pd_blkio->Media->MediaPresent) 990 return (ENXIO); 991 992 bcd.dv_strategy = efipart_realstrategy; 993 bcd.dv_devdata = devdata; 994 bcd.dv_cache = pd->pd_bcache; 995 996 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 997 daddr_t offset; 998 999 offset = dev->d_offset * pd->pd_blkio->Media->BlockSize; 1000 offset /= 512; 1001 return (bcache_strategy(&bcd, rw, blk + offset, 1002 size, buf, rsize)); 1003 } 1004 return (bcache_strategy(&bcd, rw, blk, size, buf, rsize)); 1005 } 1006 1007 static int 1008 efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size, 1009 char *buf, size_t *rsize) 1010 { 1011 struct disk_devdesc *dev = (struct disk_devdesc *)devdata; 1012 pdinfo_t *pd; 1013 EFI_BLOCK_IO *blkio; 1014 uint64_t off, disk_blocks, d_offset = 0; 1015 char *blkbuf; 1016 size_t blkoff, blksz, bio_size; 1017 unsigned ioalign; 1018 bool need_buf; 1019 int rc; 1020 uint64_t diskend, readstart; 1021 1022 if (dev == NULL || blk < 0) 1023 return (EINVAL); 1024 1025 pd = efiblk_get_pdinfo((struct devdesc *)dev); 1026 if (pd == NULL) 1027 return (EINVAL); 1028 1029 blkio = pd->pd_blkio; 1030 if (blkio == NULL) 1031 return (ENXIO); 1032 1033 if (size == 0 || (size % 512) != 0) 1034 return (EIO); 1035 1036 off = blk * 512; 1037 /* 1038 * Get disk blocks, this value is either for whole disk or for 1039 * partition. 1040 */ 1041 disk_blocks = 0; 1042 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 1043 if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { 1044 /* DIOCGMEDIASIZE does return bytes. */ 1045 disk_blocks /= blkio->Media->BlockSize; 1046 } 1047 d_offset = dev->d_offset; 1048 } 1049 if (disk_blocks == 0) 1050 disk_blocks = blkio->Media->LastBlock + 1 - d_offset; 1051 1052 /* make sure we don't read past disk end */ 1053 if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) { 1054 diskend = d_offset + disk_blocks; 1055 readstart = off / blkio->Media->BlockSize; 1056 1057 if (diskend <= readstart) { 1058 if (rsize != NULL) 1059 *rsize = 0; 1060 1061 return (EIO); 1062 } 1063 size = diskend - readstart; 1064 size = size * blkio->Media->BlockSize; 1065 } 1066 1067 need_buf = true; 1068 /* Do we need bounce buffer? */ 1069 if ((size % blkio->Media->BlockSize == 0) && 1070 (off % blkio->Media->BlockSize == 0)) 1071 need_buf = false; 1072 1073 /* Do we have IO alignment requirement? */ 1074 ioalign = blkio->Media->IoAlign; 1075 if (ioalign == 0) 1076 ioalign++; 1077 1078 if (ioalign > 1 && (uintptr_t)buf != roundup2((uintptr_t)buf, ioalign)) 1079 need_buf = true; 1080 1081 if (need_buf) { 1082 for (bio_size = BIO_BUFFER_SIZE; bio_size > 0; 1083 bio_size -= blkio->Media->BlockSize) { 1084 blkbuf = memalign(ioalign, bio_size); 1085 if (blkbuf != NULL) 1086 break; 1087 } 1088 } else { 1089 blkbuf = buf; 1090 bio_size = size; 1091 } 1092 1093 if (blkbuf == NULL) 1094 return (ENOMEM); 1095 1096 if (rsize != NULL) 1097 *rsize = size; 1098 1099 rc = 0; 1100 blk = off / blkio->Media->BlockSize; 1101 blkoff = off % blkio->Media->BlockSize; 1102 1103 while (size > 0) { 1104 size_t x = min(size, bio_size); 1105 1106 if (x < blkio->Media->BlockSize) 1107 x = 1; 1108 else 1109 x /= blkio->Media->BlockSize; 1110 1111 switch (rw & F_MASK) { 1112 case F_READ: 1113 blksz = blkio->Media->BlockSize * x - blkoff; 1114 if (size < blksz) 1115 blksz = size; 1116 1117 rc = efipart_readwrite(blkio, rw, blk, x, blkbuf); 1118 if (rc != 0) 1119 goto error; 1120 1121 if (need_buf) 1122 bcopy(blkbuf + blkoff, buf, blksz); 1123 break; 1124 case F_WRITE: 1125 rc = 0; 1126 if (blkoff != 0) { 1127 /* 1128 * We got offset to sector, read 1 sector to 1129 * blkbuf. 1130 */ 1131 x = 1; 1132 blksz = blkio->Media->BlockSize - blkoff; 1133 blksz = min(blksz, size); 1134 rc = efipart_readwrite(blkio, F_READ, blk, x, 1135 blkbuf); 1136 } else if (size < blkio->Media->BlockSize) { 1137 /* 1138 * The remaining block is not full 1139 * sector. Read 1 sector to blkbuf. 1140 */ 1141 x = 1; 1142 blksz = size; 1143 rc = efipart_readwrite(blkio, F_READ, blk, x, 1144 blkbuf); 1145 } else { 1146 /* We can write full sector(s). */ 1147 blksz = blkio->Media->BlockSize * x; 1148 } 1149 1150 if (rc != 0) 1151 goto error; 1152 /* 1153 * Put your Data In, Put your Data out, 1154 * Put your Data In, and shake it all about 1155 */ 1156 if (need_buf) 1157 bcopy(buf, blkbuf + blkoff, blksz); 1158 rc = efipart_readwrite(blkio, F_WRITE, blk, x, blkbuf); 1159 if (rc != 0) 1160 goto error; 1161 break; 1162 default: 1163 /* DO NOTHING */ 1164 rc = EROFS; 1165 goto error; 1166 } 1167 1168 blkoff = 0; 1169 buf += blksz; 1170 size -= blksz; 1171 blk += x; 1172 } 1173 1174 error: 1175 if (rsize != NULL) 1176 *rsize -= size; 1177 1178 if (need_buf) 1179 free(blkbuf); 1180 return (rc); 1181 } 1182