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