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