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