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