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