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