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 if (dev->dd.d_dev->dv_type != DEVT_DISK) { 931 bcache_free(pd->pd_bcache); 932 pd->pd_bcache = NULL; 933 } 934 } 935 if (dev->dd.d_dev->dv_type == DEVT_DISK) 936 return (disk_close(dev)); 937 return (0); 938 } 939 940 static int 941 efipart_ioctl(struct open_file *f, unsigned long cmd, void *data) 942 { 943 struct disk_devdesc *dev; 944 pdinfo_t *pd; 945 int rc; 946 947 dev = (struct disk_devdesc *)(f->f_devdata); 948 if (dev == NULL) 949 return (EINVAL); 950 951 pd = efiblk_get_pdinfo((struct devdesc *)dev); 952 if (pd == NULL) 953 return (EINVAL); 954 955 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 956 rc = disk_ioctl(dev, cmd, data); 957 if (rc != ENOTTY) 958 return (rc); 959 } 960 961 switch (cmd) { 962 case DIOCGSECTORSIZE: 963 *(uint_t *)data = pd->pd_blkio->Media->BlockSize; 964 break; 965 case DIOCGMEDIASIZE: 966 *(uint64_t *)data = pd->pd_blkio->Media->BlockSize * 967 (pd->pd_blkio->Media->LastBlock + 1); 968 break; 969 default: 970 return (ENOTTY); 971 } 972 973 return (0); 974 } 975 976 /* 977 * efipart_readwrite() 978 * Internal equivalent of efipart_strategy(), which operates on the 979 * media-native block size. This function expects all I/O requests 980 * to be within the media size and returns an error if such is not 981 * the case. 982 */ 983 static int 984 efipart_readwrite(pdinfo_t *pd, int rw, daddr_t blk, daddr_t nblks, 985 char *buf) 986 { 987 EFI_STATUS status; 988 EFI_BLOCK_IO *blkio = pd->pd_blkio; 989 990 if (blkio == NULL) 991 return (ENXIO); 992 if (blk < 0 || blk > blkio->Media->LastBlock) 993 return (EIO); 994 if ((blk + nblks - 1) > blkio->Media->LastBlock) 995 return (EIO); 996 997 switch (rw & F_MASK) { 998 case F_READ: 999 status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk, 1000 nblks * blkio->Media->BlockSize, buf); 1001 break; 1002 case F_WRITE: 1003 if (blkio->Media->ReadOnly) 1004 return (EROFS); 1005 status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk, 1006 nblks * blkio->Media->BlockSize, buf); 1007 break; 1008 default: 1009 return (ENOSYS); 1010 } 1011 1012 if (EFI_ERROR(status)) { 1013 CHAR16 *pathname; 1014 1015 pathname = efi_devpath_name(pd->pd_devpath); 1016 if (pathname != NULL) { 1017 printf("%S: ", pathname); 1018 efi_free_devpath_name(pathname); 1019 } 1020 printf("%s error: blk=%ju size=%ju status=%lu\n", 1021 (rw & F_MASK) == F_READ ? "read" : "write", 1022 blk, nblks, DECODE_ERROR(status)); 1023 } 1024 return (efi_status_to_errno(status)); 1025 } 1026 1027 static int 1028 efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, 1029 char *buf, size_t *rsize) 1030 { 1031 struct bcache_devdata bcd; 1032 struct disk_devdesc *dev; 1033 pdinfo_t *pd; 1034 1035 dev = (struct disk_devdesc *)devdata; 1036 if (dev == NULL) 1037 return (EINVAL); 1038 1039 pd = efiblk_get_pdinfo((struct devdesc *)dev); 1040 if (pd == NULL) 1041 return (EINVAL); 1042 1043 if (pd->pd_blkio->Media->RemovableMedia && 1044 !pd->pd_blkio->Media->MediaPresent) 1045 return (ENXIO); 1046 1047 bcd.dv_strategy = efipart_realstrategy; 1048 bcd.dv_devdata = devdata; 1049 bcd.dv_cache = pd->pd_bcache; 1050 1051 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 1052 daddr_t offset; 1053 1054 offset = dev->d_offset * pd->pd_blkio->Media->BlockSize; 1055 offset /= 512; 1056 return (bcache_strategy(&bcd, rw, blk + offset, 1057 size, buf, rsize)); 1058 } 1059 return (bcache_strategy(&bcd, rw, blk, size, buf, rsize)); 1060 } 1061 1062 static int 1063 efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size, 1064 char *buf, size_t *rsize) 1065 { 1066 struct disk_devdesc *dev = (struct disk_devdesc *)devdata; 1067 pdinfo_t *pd; 1068 EFI_BLOCK_IO *blkio; 1069 uint64_t off, disk_blocks, d_offset = 0; 1070 char *blkbuf; 1071 size_t blkoff, blksz, bio_size; 1072 unsigned ioalign; 1073 bool need_buf; 1074 int rc; 1075 uint64_t diskend, readstart; 1076 1077 if (dev == NULL || blk < 0) 1078 return (EINVAL); 1079 1080 pd = efiblk_get_pdinfo((struct devdesc *)dev); 1081 if (pd == NULL) 1082 return (EINVAL); 1083 1084 blkio = pd->pd_blkio; 1085 if (blkio == NULL) 1086 return (ENXIO); 1087 1088 if (size == 0 || (size % 512) != 0) 1089 return (EIO); 1090 1091 off = blk * 512; 1092 /* 1093 * Get disk blocks, this value is either for whole disk or for 1094 * partition. 1095 */ 1096 disk_blocks = 0; 1097 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 1098 if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { 1099 /* DIOCGMEDIASIZE does return bytes. */ 1100 disk_blocks /= blkio->Media->BlockSize; 1101 } 1102 d_offset = dev->d_offset; 1103 } 1104 if (disk_blocks == 0) 1105 disk_blocks = blkio->Media->LastBlock + 1 - d_offset; 1106 1107 /* make sure we don't read past disk end */ 1108 if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) { 1109 diskend = d_offset + disk_blocks; 1110 readstart = off / blkio->Media->BlockSize; 1111 1112 if (diskend <= readstart) { 1113 if (rsize != NULL) 1114 *rsize = 0; 1115 1116 return (EIO); 1117 } 1118 size = diskend - readstart; 1119 size = size * blkio->Media->BlockSize; 1120 } 1121 1122 need_buf = true; 1123 /* Do we need bounce buffer? */ 1124 if ((size % blkio->Media->BlockSize == 0) && 1125 (off % blkio->Media->BlockSize == 0)) 1126 need_buf = false; 1127 1128 /* Do we have IO alignment requirement? */ 1129 ioalign = blkio->Media->IoAlign; 1130 if (ioalign == 0) 1131 ioalign++; 1132 1133 if (ioalign > 1 && (uintptr_t)buf != roundup2((uintptr_t)buf, ioalign)) 1134 need_buf = true; 1135 1136 if (need_buf) { 1137 for (bio_size = BIO_BUFFER_SIZE; bio_size > 0; 1138 bio_size -= blkio->Media->BlockSize) { 1139 blkbuf = memalign(ioalign, bio_size); 1140 if (blkbuf != NULL) 1141 break; 1142 } 1143 } else { 1144 blkbuf = buf; 1145 bio_size = size; 1146 } 1147 1148 if (blkbuf == NULL) 1149 return (ENOMEM); 1150 1151 if (rsize != NULL) 1152 *rsize = size; 1153 1154 rc = 0; 1155 blk = off / blkio->Media->BlockSize; 1156 blkoff = off % blkio->Media->BlockSize; 1157 1158 while (size > 0) { 1159 size_t x = min(size, bio_size); 1160 1161 if (x < blkio->Media->BlockSize) 1162 x = 1; 1163 else 1164 x /= blkio->Media->BlockSize; 1165 1166 switch (rw & F_MASK) { 1167 case F_READ: 1168 blksz = blkio->Media->BlockSize * x - blkoff; 1169 if (size < blksz) 1170 blksz = size; 1171 1172 rc = efipart_readwrite(pd, rw, blk, x, blkbuf); 1173 if (rc != 0) 1174 goto error; 1175 1176 if (need_buf) 1177 bcopy(blkbuf + blkoff, buf, blksz); 1178 break; 1179 case F_WRITE: 1180 rc = 0; 1181 if (blkoff != 0) { 1182 /* 1183 * We got offset to sector, read 1 sector to 1184 * blkbuf. 1185 */ 1186 x = 1; 1187 blksz = blkio->Media->BlockSize - blkoff; 1188 blksz = min(blksz, size); 1189 rc = efipart_readwrite(pd, F_READ, blk, x, 1190 blkbuf); 1191 } else if (size < blkio->Media->BlockSize) { 1192 /* 1193 * The remaining block is not full 1194 * sector. Read 1 sector to blkbuf. 1195 */ 1196 x = 1; 1197 blksz = size; 1198 rc = efipart_readwrite(pd, F_READ, blk, x, 1199 blkbuf); 1200 } else { 1201 /* We can write full sector(s). */ 1202 blksz = blkio->Media->BlockSize * x; 1203 } 1204 1205 if (rc != 0) 1206 goto error; 1207 /* 1208 * Put your Data In, Put your Data out, 1209 * Put your Data In, and shake it all about 1210 */ 1211 if (need_buf) 1212 bcopy(buf, blkbuf + blkoff, blksz); 1213 rc = efipart_readwrite(pd, F_WRITE, blk, x, blkbuf); 1214 if (rc != 0) 1215 goto error; 1216 break; 1217 default: 1218 /* DO NOTHING */ 1219 rc = EROFS; 1220 goto error; 1221 } 1222 1223 blkoff = 0; 1224 buf += blksz; 1225 size -= blksz; 1226 blk += x; 1227 } 1228 1229 error: 1230 if (rsize != NULL) 1231 *rsize -= size; 1232 1233 if (need_buf) 1234 free(blkbuf); 1235 return (rc); 1236 } 1237