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