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