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