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 unsigned i, nin; 337 UINTN sz; 338 EFI_HANDLE *hin; 339 EFI_DEVICE_PATH *devpath; 340 EFI_BLOCK_IO *blkio; 341 EFI_STATUS status; 342 pdinfo_t *pd; 343 344 if (!STAILQ_EMPTY(&pdinfo)) 345 return (0); 346 347 sz = 0; 348 hin = NULL; 349 status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin); 350 if (status == EFI_BUFFER_TOO_SMALL) { 351 hin = malloc(sz); 352 status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 353 hin); 354 if (EFI_ERROR(status)) 355 free(hin); 356 } 357 if (EFI_ERROR(status)) 358 return (efi_status_to_errno(status)); 359 360 nin = sz / sizeof (*hin); 361 #ifdef EFIPART_DEBUG 362 printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__, nin); 363 #endif 364 365 for (i = 0; i < nin; i++) { 366 /* 367 * Get devpath and open protocol. 368 * We should not get errors here 369 */ 370 if ((devpath = efi_lookup_devpath(hin[i])) == NULL) 371 continue; 372 373 status = OpenProtocolByHandle(hin[i], &blkio_guid, 374 (void **)&blkio); 375 if (EFI_ERROR(status)) { 376 printf("error %lu\n", EFI_ERROR_CODE(status)); 377 continue; 378 } 379 380 if (efipart_ignore_device(hin[i], blkio, devpath)) 381 continue; 382 383 /* This is bad. */ 384 if ((pd = calloc(1, sizeof (*pd))) == NULL) { 385 printf("efipart_inithandles: Out of memory.\n"); 386 free(hin); 387 return (ENOMEM); 388 } 389 STAILQ_INIT(&pd->pd_part); 390 391 pd->pd_handle = hin[i]; 392 pd->pd_devpath = devpath; 393 pd->pd_blkio = blkio; 394 STAILQ_INSERT_TAIL(&pdinfo, pd, pd_link); 395 } 396 397 /* 398 * Walk pdinfo and set parents based on device path. 399 */ 400 STAILQ_FOREACH(pd, &pdinfo, pd_link) { 401 pd->pd_parent = efipart_find_parent(&pdinfo, pd->pd_devpath); 402 } 403 free(hin); 404 return (0); 405 } 406 407 /* 408 * Get node identified by pd_test() from plist. 409 */ 410 static pdinfo_t * 411 efipart_get_pd(pdinfo_list_t *plist, pd_test_cb_t pd_test, pdinfo_t *data) 412 { 413 pdinfo_t *pd; 414 415 STAILQ_FOREACH(pd, plist, pd_link) { 416 if (pd_test(pd, data)) 417 break; 418 } 419 420 return (pd); 421 } 422 423 static ACPI_HID_DEVICE_PATH * 424 efipart_floppy(EFI_DEVICE_PATH *node) 425 { 426 ACPI_HID_DEVICE_PATH *acpi; 427 428 if (DevicePathType(node) == ACPI_DEVICE_PATH && 429 DevicePathSubType(node) == ACPI_DP) { 430 acpi = (ACPI_HID_DEVICE_PATH *) node; 431 if (acpi->HID == EISA_PNP_ID(PNP0604) || 432 acpi->HID == EISA_PNP_ID(PNP0700) || 433 acpi->HID == EISA_PNP_ID(PNP0701)) { 434 return (acpi); 435 } 436 } 437 return (NULL); 438 } 439 440 static bool 441 efipart_testfd(pdinfo_t *fd, pdinfo_t *data __unused) 442 { 443 EFI_DEVICE_PATH *node; 444 445 node = efi_devpath_last_node(fd->pd_devpath); 446 if (node == NULL) 447 return (false); 448 449 if (efipart_floppy(node) != NULL) 450 return (true); 451 452 return (false); 453 } 454 455 static int 456 efipart_initfd(void) 457 { 458 EFI_DEVICE_PATH *node; 459 ACPI_HID_DEVICE_PATH *acpi; 460 pdinfo_t *parent, *fd; 461 462 while ((fd = efipart_get_pd(&pdinfo, efipart_testfd, NULL)) != NULL) { 463 if ((node = efi_devpath_last_node(fd->pd_devpath)) == NULL) 464 continue; 465 466 if ((acpi = efipart_floppy(node)) == NULL) 467 continue; 468 469 STAILQ_REMOVE(&pdinfo, fd, pdinfo, pd_link); 470 parent = fd->pd_parent; 471 if (parent != NULL) { 472 STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link); 473 parent->pd_alias = fd->pd_handle; 474 parent->pd_unit = acpi->UID; 475 free(fd); 476 fd = parent; 477 } else { 478 fd->pd_unit = acpi->UID; 479 } 480 fd->pd_devsw = &efipart_fddev; 481 STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link); 482 } 483 484 bcache_add_dev(efiblk_pdinfo_count(&fdinfo)); 485 return (0); 486 } 487 488 /* 489 * Add or update entries with new handle data. 490 */ 491 static void 492 efipart_cdinfo_add(pdinfo_t *cd) 493 { 494 pdinfo_t *parent, *pd, *last; 495 496 if (cd == NULL) 497 return; 498 499 parent = cd->pd_parent; 500 /* Make sure we have parent added */ 501 efipart_cdinfo_add(parent); 502 503 STAILQ_FOREACH(pd, &pdinfo, pd_link) { 504 if (efi_devpath_match(pd->pd_devpath, cd->pd_devpath)) { 505 STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link); 506 break; 507 } 508 } 509 if (pd == NULL) { 510 /* This device is already added. */ 511 return; 512 } 513 514 if (parent != NULL) { 515 last = STAILQ_LAST(&parent->pd_part, pdinfo, pd_link); 516 if (last != NULL) 517 cd->pd_unit = last->pd_unit + 1; 518 else 519 cd->pd_unit = 0; 520 cd->pd_devsw = &efipart_cddev; 521 STAILQ_INSERT_TAIL(&parent->pd_part, cd, pd_link); 522 return; 523 } 524 525 last = STAILQ_LAST(&cdinfo, pdinfo, pd_link); 526 if (last != NULL) 527 cd->pd_unit = last->pd_unit + 1; 528 else 529 cd->pd_unit = 0; 530 531 cd->pd_devsw = &efipart_cddev; 532 STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link); 533 } 534 535 static bool 536 efipart_testcd(pdinfo_t *cd, pdinfo_t *data __unused) 537 { 538 EFI_DEVICE_PATH *node; 539 540 node = efi_devpath_last_node(cd->pd_devpath); 541 if (node == NULL) 542 return (false); 543 544 if (efipart_floppy(node) != NULL) 545 return (false); 546 547 if (DevicePathType(node) == MEDIA_DEVICE_PATH && 548 DevicePathSubType(node) == MEDIA_CDROM_DP) { 549 return (true); 550 } 551 552 /* cd drive without the media. */ 553 if (cd->pd_blkio->Media->RemovableMedia && 554 !cd->pd_blkio->Media->MediaPresent) { 555 return (true); 556 } 557 558 return (false); 559 } 560 561 /* 562 * Test if pd is parent for device. 563 */ 564 static bool 565 efipart_testchild(pdinfo_t *dev, pdinfo_t *pd) 566 { 567 /* device with no parent. */ 568 if (dev->pd_parent == NULL) 569 return (false); 570 571 if (efi_devpath_match(dev->pd_parent->pd_devpath, pd->pd_devpath)) { 572 return (true); 573 } 574 return (false); 575 } 576 577 static int 578 efipart_initcd(void) 579 { 580 pdinfo_t *cd; 581 582 while ((cd = efipart_get_pd(&pdinfo, efipart_testcd, NULL)) != NULL) 583 efipart_cdinfo_add(cd); 584 585 /* Find all children of CD devices we did add above. */ 586 STAILQ_FOREACH(cd, &cdinfo, pd_link) { 587 pdinfo_t *child; 588 589 for (child = efipart_get_pd(&pdinfo, efipart_testchild, cd); 590 child != NULL; 591 child = efipart_get_pd(&pdinfo, efipart_testchild, cd)) 592 efipart_cdinfo_add(child); 593 } 594 bcache_add_dev(efiblk_pdinfo_count(&cdinfo)); 595 return (0); 596 } 597 598 static void 599 efipart_hdinfo_add_node(pdinfo_t *hd, EFI_DEVICE_PATH *node) 600 { 601 pdinfo_t *parent, *ptr; 602 603 if (node == NULL) 604 return; 605 606 parent = hd->pd_parent; 607 /* 608 * If the node is not MEDIA_HARDDRIVE_DP, it is sub-partition. 609 * This can happen with Vendor nodes, and since we do not know 610 * the more about those nodes, we just count them. 611 */ 612 if (DevicePathSubType(node) != MEDIA_HARDDRIVE_DP) { 613 ptr = STAILQ_LAST(&parent->pd_part, pdinfo, pd_link); 614 if (ptr != NULL) 615 hd->pd_unit = ptr->pd_unit + 1; 616 else 617 hd->pd_unit = 0; 618 } else { 619 hd->pd_unit = ((HARDDRIVE_DEVICE_PATH *)node)->PartitionNumber; 620 } 621 622 hd->pd_devsw = &efipart_hddev; 623 STAILQ_INSERT_TAIL(&parent->pd_part, hd, pd_link); 624 } 625 626 /* 627 * The MEDIA_FILEPATH_DP has device name. 628 * From U-Boot sources it looks like names are in the form 629 * of typeN:M, where type is interface type, N is disk id 630 * and M is partition id. 631 */ 632 static void 633 efipart_hdinfo_add_filepath(pdinfo_t *hd, FILEPATH_DEVICE_PATH *node) 634 { 635 char *pathname, *p; 636 int len; 637 pdinfo_t *last; 638 639 last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); 640 if (last != NULL) 641 hd->pd_unit = last->pd_unit + 1; 642 else 643 hd->pd_unit = 0; 644 645 /* FILEPATH_DEVICE_PATH has 0 terminated string */ 646 len = ucs2len(node->PathName); 647 if ((pathname = malloc(len + 1)) == NULL) { 648 printf("Failed to add disk, out of memory\n"); 649 free(hd); 650 return; 651 } 652 cpy16to8(node->PathName, pathname, len + 1); 653 p = strchr(pathname, ':'); 654 655 /* 656 * Assume we are receiving handles in order, first disk handle, 657 * then partitions for this disk. If this assumption proves 658 * false, this code would need update. 659 */ 660 if (p == NULL) { /* no colon, add the disk */ 661 hd->pd_devsw = &efipart_hddev; 662 STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); 663 free(pathname); 664 return; 665 } 666 p++; /* skip the colon */ 667 errno = 0; 668 hd->pd_unit = (int)strtol(p, NULL, 0); 669 if (errno != 0) { 670 printf("Bad unit number for partition \"%s\"\n", pathname); 671 free(pathname); 672 free(hd); 673 return; 674 } 675 676 /* 677 * We should have disk registered, if not, we are receiving 678 * handles out of order, and this code should be reworked 679 * to create "blank" disk for partition, and to find the 680 * disk based on PathName compares. 681 */ 682 if (last == NULL) { 683 printf("BUG: No disk for partition \"%s\"\n", pathname); 684 free(pathname); 685 free(hd); 686 return; 687 } 688 /* Add the partition. */ 689 hd->pd_parent = last; 690 hd->pd_devsw = &efipart_hddev; 691 STAILQ_INSERT_TAIL(&last->pd_part, hd, pd_link); 692 free(pathname); 693 } 694 695 static void 696 efipart_hdinfo_add(pdinfo_t *hd) 697 { 698 pdinfo_t *parent, *pd, *last; 699 EFI_DEVICE_PATH *node; 700 701 if (hd == NULL) 702 return; 703 704 parent = hd->pd_parent; 705 /* Make sure we have parent added */ 706 efipart_hdinfo_add(parent); 707 708 STAILQ_FOREACH(pd, &pdinfo, pd_link) { 709 if (efi_devpath_match(pd->pd_devpath, hd->pd_devpath)) { 710 STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link); 711 break; 712 } 713 } 714 if (pd == NULL) { 715 /* This device is already added. */ 716 return; 717 } 718 719 if ((node = efi_devpath_last_node(hd->pd_devpath)) == NULL) 720 return; 721 722 if (DevicePathType(node) == MEDIA_DEVICE_PATH && 723 DevicePathSubType(node) == MEDIA_FILEPATH_DP) { 724 efipart_hdinfo_add_filepath(hd, 725 (FILEPATH_DEVICE_PATH *)node); 726 return; 727 } 728 729 if (parent != NULL) { 730 efipart_hdinfo_add_node(hd, node); 731 return; 732 } 733 734 last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); 735 if (last != NULL) 736 hd->pd_unit = last->pd_unit + 1; 737 else 738 hd->pd_unit = 0; 739 740 /* Add the disk. */ 741 hd->pd_devsw = &efipart_hddev; 742 STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); 743 } 744 745 static bool 746 efipart_testhd(pdinfo_t *hd, pdinfo_t *data __unused) 747 { 748 if (efipart_testfd(hd, NULL)) 749 return (false); 750 751 if (efipart_testcd(hd, NULL)) 752 return (false); 753 754 /* Anything else must be HD. */ 755 return (true); 756 } 757 758 static int 759 efipart_inithd(void) 760 { 761 pdinfo_t *hd; 762 763 while ((hd = efipart_get_pd(&pdinfo, efipart_testhd, NULL)) != NULL) 764 efipart_hdinfo_add(hd); 765 766 bcache_add_dev(efiblk_pdinfo_count(&hdinfo)); 767 return (0); 768 } 769 770 static int 771 efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose) 772 { 773 int ret = 0; 774 EFI_BLOCK_IO *blkio; 775 EFI_STATUS status; 776 EFI_HANDLE h; 777 pdinfo_t *pd; 778 CHAR16 *text; 779 struct disk_devdesc pd_dev; 780 char line[80]; 781 782 if (STAILQ_EMPTY(pdlist)) 783 return (0); 784 785 printf("%s devices:", dev->dv_name); 786 if ((ret = pager_output("\n")) != 0) 787 return (ret); 788 789 STAILQ_FOREACH(pd, pdlist, pd_link) { 790 h = pd->pd_handle; 791 if (verbose) { /* Output the device path. */ 792 text = efi_devpath_name(efi_lookup_devpath(h)); 793 if (text != NULL) { 794 printf(" %S", text); 795 efi_free_devpath_name(text); 796 if ((ret = pager_output("\n")) != 0) 797 break; 798 } 799 } 800 snprintf(line, sizeof (line), 801 " %s%d", dev->dv_name, pd->pd_unit); 802 printf("%s:", line); 803 status = OpenProtocolByHandle(h, &blkio_guid, (void **)&blkio); 804 if (!EFI_ERROR(status)) { 805 printf(" %llu", 806 blkio->Media->LastBlock == 0? 0: 807 (unsigned long long) (blkio->Media->LastBlock + 1)); 808 if (blkio->Media->LastBlock != 0) { 809 printf(" X %u", blkio->Media->BlockSize); 810 } 811 printf(" blocks"); 812 if (blkio->Media->MediaPresent) { 813 if (blkio->Media->RemovableMedia) 814 printf(" (removable)"); 815 } else { 816 printf(" (no media)"); 817 } 818 if ((ret = pager_output("\n")) != 0) 819 break; 820 if (!blkio->Media->MediaPresent) 821 continue; 822 823 pd->pd_blkio = blkio; 824 pd_dev.dd.d_dev = dev; 825 pd_dev.dd.d_unit = pd->pd_unit; 826 pd_dev.d_slice = D_SLICENONE; 827 pd_dev.d_partition = D_PARTNONE; 828 ret = disk_open(&pd_dev, blkio->Media->BlockSize * 829 (blkio->Media->LastBlock + 1), 830 blkio->Media->BlockSize); 831 if (ret == 0) { 832 ret = disk_print(&pd_dev, line, verbose); 833 disk_close(&pd_dev); 834 if (ret != 0) 835 return (ret); 836 } else { 837 /* Do not fail from disk_open() */ 838 ret = 0; 839 } 840 } else { 841 if ((ret = pager_output("\n")) != 0) 842 break; 843 } 844 } 845 return (ret); 846 } 847 848 static int 849 efipart_printfd(int verbose) 850 { 851 return (efipart_print_common(&efipart_fddev, &fdinfo, verbose)); 852 } 853 854 static int 855 efipart_printcd(int verbose) 856 { 857 return (efipart_print_common(&efipart_cddev, &cdinfo, verbose)); 858 } 859 860 static int 861 efipart_printhd(int verbose) 862 { 863 return (efipart_print_common(&efipart_hddev, &hdinfo, verbose)); 864 } 865 866 static int 867 efipart_open(struct open_file *f, ...) 868 { 869 va_list args; 870 struct disk_devdesc *dev; 871 pdinfo_t *pd; 872 EFI_BLOCK_IO *blkio; 873 EFI_STATUS status; 874 875 va_start(args, f); 876 dev = va_arg(args, struct disk_devdesc *); 877 va_end(args); 878 if (dev == NULL) 879 return (EINVAL); 880 881 pd = efiblk_get_pdinfo((struct devdesc *)dev); 882 if (pd == NULL) 883 return (EIO); 884 885 if (pd->pd_blkio == NULL) { 886 status = OpenProtocolByHandle(pd->pd_handle, &blkio_guid, 887 (void **)&pd->pd_blkio); 888 if (EFI_ERROR(status)) 889 return (efi_status_to_errno(status)); 890 } 891 892 blkio = pd->pd_blkio; 893 if (!blkio->Media->MediaPresent) 894 return (EAGAIN); 895 896 pd->pd_open++; 897 if (pd->pd_bcache == NULL) 898 pd->pd_bcache = bcache_allocate(); 899 900 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 901 int rc; 902 903 rc = disk_open(dev, 904 blkio->Media->BlockSize * (blkio->Media->LastBlock + 1), 905 blkio->Media->BlockSize); 906 if (rc != 0) { 907 pd->pd_open--; 908 if (pd->pd_open == 0) { 909 pd->pd_blkio = NULL; 910 bcache_free(pd->pd_bcache); 911 pd->pd_bcache = NULL; 912 } 913 } 914 return (rc); 915 } 916 return (0); 917 } 918 919 static int 920 efipart_close(struct open_file *f) 921 { 922 struct disk_devdesc *dev; 923 pdinfo_t *pd; 924 925 dev = (struct disk_devdesc *)(f->f_devdata); 926 if (dev == NULL) 927 return (EINVAL); 928 929 pd = efiblk_get_pdinfo((struct devdesc *)dev); 930 if (pd == NULL) 931 return (EINVAL); 932 933 pd->pd_open--; 934 if (pd->pd_open == 0) { 935 pd->pd_blkio = NULL; 936 bcache_free(pd->pd_bcache); 937 pd->pd_bcache = NULL; 938 } 939 if (dev->dd.d_dev->dv_type == DEVT_DISK) 940 return (disk_close(dev)); 941 return (0); 942 } 943 944 static int 945 efipart_ioctl(struct open_file *f, unsigned long cmd, void *data) 946 { 947 struct disk_devdesc *dev; 948 pdinfo_t *pd; 949 int rc; 950 951 dev = (struct disk_devdesc *)(f->f_devdata); 952 if (dev == NULL) 953 return (EINVAL); 954 955 pd = efiblk_get_pdinfo((struct devdesc *)dev); 956 if (pd == NULL) 957 return (EINVAL); 958 959 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 960 rc = disk_ioctl(dev, cmd, data); 961 if (rc != ENOTTY) 962 return (rc); 963 } 964 965 switch (cmd) { 966 case DIOCGSECTORSIZE: 967 *(uint_t *)data = pd->pd_blkio->Media->BlockSize; 968 break; 969 case DIOCGMEDIASIZE: 970 *(uint64_t *)data = pd->pd_blkio->Media->BlockSize * 971 (pd->pd_blkio->Media->LastBlock + 1); 972 break; 973 default: 974 return (ENOTTY); 975 } 976 977 return (0); 978 } 979 980 /* 981 * efipart_readwrite() 982 * Internal equivalent of efipart_strategy(), which operates on the 983 * media-native block size. This function expects all I/O requests 984 * to be within the media size and returns an error if such is not 985 * the case. 986 */ 987 static int 988 efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks, 989 char *buf) 990 { 991 EFI_STATUS status; 992 993 if (blkio == NULL) 994 return (ENXIO); 995 if (blk < 0 || blk > blkio->Media->LastBlock) 996 return (EIO); 997 if ((blk + nblks - 1) > blkio->Media->LastBlock) 998 return (EIO); 999 1000 switch (rw & F_MASK) { 1001 case F_READ: 1002 status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk, 1003 nblks * blkio->Media->BlockSize, buf); 1004 break; 1005 case F_WRITE: 1006 if (blkio->Media->ReadOnly) 1007 return (EROFS); 1008 status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk, 1009 nblks * blkio->Media->BlockSize, buf); 1010 break; 1011 default: 1012 return (ENOSYS); 1013 } 1014 1015 if (EFI_ERROR(status)) { 1016 printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw, 1017 blk, nblks, EFI_ERROR_CODE(status)); 1018 } 1019 return (efi_status_to_errno(status)); 1020 } 1021 1022 static int 1023 efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, 1024 char *buf, size_t *rsize) 1025 { 1026 struct bcache_devdata bcd; 1027 struct disk_devdesc *dev; 1028 pdinfo_t *pd; 1029 1030 dev = (struct disk_devdesc *)devdata; 1031 if (dev == NULL) 1032 return (EINVAL); 1033 1034 pd = efiblk_get_pdinfo((struct devdesc *)dev); 1035 if (pd == NULL) 1036 return (EINVAL); 1037 1038 if (pd->pd_blkio->Media->RemovableMedia && 1039 !pd->pd_blkio->Media->MediaPresent) 1040 return (ENXIO); 1041 1042 bcd.dv_strategy = efipart_realstrategy; 1043 bcd.dv_devdata = devdata; 1044 bcd.dv_cache = pd->pd_bcache; 1045 1046 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 1047 daddr_t offset; 1048 1049 offset = dev->d_offset * pd->pd_blkio->Media->BlockSize; 1050 offset /= 512; 1051 return (bcache_strategy(&bcd, rw, blk + offset, 1052 size, buf, rsize)); 1053 } 1054 return (bcache_strategy(&bcd, rw, blk, size, buf, rsize)); 1055 } 1056 1057 static int 1058 efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size, 1059 char *buf, size_t *rsize) 1060 { 1061 struct disk_devdesc *dev = (struct disk_devdesc *)devdata; 1062 pdinfo_t *pd; 1063 EFI_BLOCK_IO *blkio; 1064 uint64_t off, disk_blocks, d_offset = 0; 1065 char *blkbuf; 1066 size_t blkoff, blksz, bio_size; 1067 unsigned ioalign; 1068 bool need_buf; 1069 int rc; 1070 uint64_t diskend, readstart; 1071 1072 if (dev == NULL || blk < 0) 1073 return (EINVAL); 1074 1075 pd = efiblk_get_pdinfo((struct devdesc *)dev); 1076 if (pd == NULL) 1077 return (EINVAL); 1078 1079 blkio = pd->pd_blkio; 1080 if (blkio == NULL) 1081 return (ENXIO); 1082 1083 if (size == 0 || (size % 512) != 0) 1084 return (EIO); 1085 1086 off = blk * 512; 1087 /* 1088 * Get disk blocks, this value is either for whole disk or for 1089 * partition. 1090 */ 1091 disk_blocks = 0; 1092 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 1093 if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { 1094 /* DIOCGMEDIASIZE does return bytes. */ 1095 disk_blocks /= blkio->Media->BlockSize; 1096 } 1097 d_offset = dev->d_offset; 1098 } 1099 if (disk_blocks == 0) 1100 disk_blocks = blkio->Media->LastBlock + 1 - d_offset; 1101 1102 /* make sure we don't read past disk end */ 1103 if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) { 1104 diskend = d_offset + disk_blocks; 1105 readstart = off / blkio->Media->BlockSize; 1106 1107 if (diskend <= readstart) { 1108 if (rsize != NULL) 1109 *rsize = 0; 1110 1111 return (EIO); 1112 } 1113 size = diskend - readstart; 1114 size = size * blkio->Media->BlockSize; 1115 } 1116 1117 need_buf = true; 1118 /* Do we need bounce buffer? */ 1119 if ((size % blkio->Media->BlockSize == 0) && 1120 (off % blkio->Media->BlockSize == 0)) 1121 need_buf = false; 1122 1123 /* Do we have IO alignment requirement? */ 1124 ioalign = blkio->Media->IoAlign; 1125 if (ioalign == 0) 1126 ioalign++; 1127 1128 if (ioalign > 1 && (uintptr_t)buf != roundup2((uintptr_t)buf, ioalign)) 1129 need_buf = true; 1130 1131 if (need_buf) { 1132 for (bio_size = BIO_BUFFER_SIZE; bio_size > 0; 1133 bio_size -= blkio->Media->BlockSize) { 1134 blkbuf = memalign(ioalign, bio_size); 1135 if (blkbuf != NULL) 1136 break; 1137 } 1138 } else { 1139 blkbuf = buf; 1140 bio_size = size; 1141 } 1142 1143 if (blkbuf == NULL) 1144 return (ENOMEM); 1145 1146 if (rsize != NULL) 1147 *rsize = size; 1148 1149 rc = 0; 1150 blk = off / blkio->Media->BlockSize; 1151 blkoff = off % blkio->Media->BlockSize; 1152 1153 while (size > 0) { 1154 size_t x = min(size, bio_size); 1155 1156 if (x < blkio->Media->BlockSize) 1157 x = 1; 1158 else 1159 x /= blkio->Media->BlockSize; 1160 1161 switch (rw & F_MASK) { 1162 case F_READ: 1163 blksz = blkio->Media->BlockSize * x - blkoff; 1164 if (size < blksz) 1165 blksz = size; 1166 1167 rc = efipart_readwrite(blkio, rw, blk, x, blkbuf); 1168 if (rc != 0) 1169 goto error; 1170 1171 if (need_buf) 1172 bcopy(blkbuf + blkoff, buf, blksz); 1173 break; 1174 case F_WRITE: 1175 rc = 0; 1176 if (blkoff != 0) { 1177 /* 1178 * We got offset to sector, read 1 sector to 1179 * blkbuf. 1180 */ 1181 x = 1; 1182 blksz = blkio->Media->BlockSize - blkoff; 1183 blksz = min(blksz, size); 1184 rc = efipart_readwrite(blkio, F_READ, blk, x, 1185 blkbuf); 1186 } else if (size < blkio->Media->BlockSize) { 1187 /* 1188 * The remaining block is not full 1189 * sector. Read 1 sector to blkbuf. 1190 */ 1191 x = 1; 1192 blksz = size; 1193 rc = efipart_readwrite(blkio, F_READ, blk, x, 1194 blkbuf); 1195 } else { 1196 /* We can write full sector(s). */ 1197 blksz = blkio->Media->BlockSize * x; 1198 } 1199 1200 if (rc != 0) 1201 goto error; 1202 /* 1203 * Put your Data In, Put your Data out, 1204 * Put your Data In, and shake it all about 1205 */ 1206 if (need_buf) 1207 bcopy(buf, blkbuf + blkoff, blksz); 1208 rc = efipart_readwrite(blkio, F_WRITE, blk, x, blkbuf); 1209 if (rc != 0) 1210 goto error; 1211 break; 1212 default: 1213 /* DO NOTHING */ 1214 rc = EROFS; 1215 goto error; 1216 } 1217 1218 blkoff = 0; 1219 buf += blksz; 1220 size -= blksz; 1221 blk += x; 1222 } 1223 1224 error: 1225 if (rsize != NULL) 1226 *rsize -= size; 1227 1228 if (need_buf) 1229 free(blkbuf); 1230 return (rc); 1231 } 1232