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