ps3disk.c revision 223316
1/*- 2 * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) 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 ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/powerpc/ps3/ps3disk.c 223316 2011-06-20 01:43:18Z nwhitehorn $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/sysctl.h> 33#include <sys/disk.h> 34#include <sys/bio.h> 35#include <sys/bus.h> 36#include <sys/conf.h> 37#include <sys/kernel.h> 38#include <sys/kthread.h> 39#include <sys/lock.h> 40#include <sys/malloc.h> 41#include <sys/module.h> 42#include <sys/mutex.h> 43 44#include <vm/vm.h> 45#include <vm/pmap.h> 46 47#include <machine/pio.h> 48#include <machine/bus.h> 49#include <machine/platform.h> 50#include <machine/pmap.h> 51#include <machine/resource.h> 52#include <sys/bus.h> 53#include <sys/rman.h> 54 55#include <geom/geom_disk.h> 56 57#include "ps3bus.h" 58#include "ps3-hvcall.h" 59 60#define PS3DISK_LOCK_INIT(_sc) \ 61 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3disk", MTX_DEF) 62#define PS3DISK_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 63#define PS3DISK_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 64#define PS3DISK_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 65#define PS3DISK_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 66#define PS3DISK_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 67 68#define LV1_STORAGE_ATA_HDDOUT 0x23 69 70SYSCTL_NODE(_hw, OID_AUTO, ps3disk, CTLFLAG_RD, 0, "PS3 Disk driver parameters"); 71 72#ifdef PS3DISK_DEBUG 73static int ps3disk_debug = 0; 74SYSCTL_INT(_hw_ps3disk, OID_AUTO, debug, CTLFLAG_RW, &ps3disk_debug, 75 0, "control debugging printfs"); 76TUNABLE_INT("hw.ps3disk.debug", &ps3disk_debug); 77enum { 78 PS3DISK_DEBUG_INTR = 0x00000001, 79 PS3DISK_DEBUG_TASK = 0x00000002, 80 PS3DISK_DEBUG_READ = 0x00000004, 81 PS3DISK_DEBUG_WRITE = 0x00000008, 82 PS3DISK_DEBUG_FLUSH = 0x00000010, 83 PS3DISK_DEBUG_ANY = 0xffffffff 84}; 85#define DPRINTF(sc, m, fmt, ...) \ 86do { \ 87 if (sc->sc_debug & (m)) \ 88 printf(fmt, __VA_ARGS__); \ 89} while (0) 90#else 91#define DPRINTF(sc, m, fmt, ...) 92#endif 93 94struct ps3disk_region { 95 uint64_t r_id; 96 uint64_t r_start; 97 uint64_t r_size; 98 uint64_t r_flags; 99}; 100 101struct ps3disk_softc { 102 device_t sc_dev; 103 104 struct mtx sc_mtx; 105 106 uint64_t sc_blksize; 107 uint64_t sc_nblocks; 108 109 uint64_t sc_nregs; 110 struct ps3disk_region *sc_reg; 111 112 int sc_irqid; 113 struct resource *sc_irq; 114 void *sc_irqctx; 115 116 struct disk **sc_disk; 117 118 struct bio_queue_head sc_bioq; 119 120 struct proc *sc_task; 121 122 int sc_bounce_maxblocks; 123 bus_dma_tag_t sc_bounce_dmatag; 124 bus_dmamap_t sc_bounce_dmamap; 125 bus_addr_t sc_bounce_dmaphys; 126 char *sc_bounce; 127 uint64_t sc_bounce_lpar; 128 int sc_bounce_busy; 129 uint64_t sc_bounce_tag; 130 uint64_t sc_bounce_status; 131 132 int sc_running; 133 134 int sc_debug; 135}; 136 137static int ps3disk_open(struct disk *dp); 138static int ps3disk_close(struct disk *dp); 139static void ps3disk_strategy(struct bio *bp); 140static void ps3disk_task(void *arg); 141 142static int ps3disk_intr_filter(void *arg); 143static void ps3disk_intr(void *arg); 144static void ps3disk_getphys(void *arg, bus_dma_segment_t *segs, int nsegs, int error); 145static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc); 146static int ps3disk_enum_regions(struct ps3disk_softc *sc); 147static int ps3disk_read(struct ps3disk_softc *sc, int regidx, 148 uint64_t start_sector, uint64_t sector_count, char *data); 149static int ps3disk_write(struct ps3disk_softc *sc, int regidx, 150 uint64_t start_sector, uint64_t sector_count, char *data); 151static int ps3disk_flush(struct ps3disk_softc *sc); 152 153static void ps3disk_sysctlattach(struct ps3disk_softc *sc); 154 155static MALLOC_DEFINE(M_PS3DISK, "ps3disk", "PS3 Disk"); 156 157static int 158ps3disk_probe(device_t dev) 159{ 160 if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE || 161 ps3bus_get_devtype(dev) != PS3_DEVTYPE_DISK) 162 return (ENXIO); 163 164 device_set_desc(dev, "Playstation 3 Disk"); 165 166 return (BUS_PROBE_SPECIFIC); 167} 168 169static int 170ps3disk_attach(device_t dev) 171{ 172 struct ps3disk_softc *sc; 173 struct disk *d; 174 intmax_t mb; 175 char unit; 176 int i, err; 177 178 sc = device_get_softc(dev); 179 sc->sc_dev = dev; 180 181 PS3DISK_LOCK_INIT(sc); 182 183 err = ps3disk_get_disk_geometry(sc); 184 if (err) { 185 device_printf(dev, "Could not get disk geometry\n"); 186 err = ENXIO; 187 goto fail_destroy_lock; 188 } 189 190 device_printf(dev, "block size %lu total blocks %lu\n", 191 sc->sc_blksize, sc->sc_nblocks); 192 193 err = ps3disk_enum_regions(sc); 194 if (err) { 195 device_printf(dev, "Could not enumerate disk regions\n"); 196 err = ENXIO; 197 goto fail_destroy_lock; 198 } 199 200 device_printf(dev, "Found %lu regions\n", sc->sc_nregs); 201 202 if (!sc->sc_nregs) { 203 err = ENXIO; 204 goto fail_destroy_lock; 205 } 206 207 /* Setup interrupt handler */ 208 209 sc->sc_irqid = 0; 210 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid, 211 RF_ACTIVE); 212 if (!sc->sc_irq) { 213 device_printf(dev, "Could not allocate IRQ\n"); 214 err = ENXIO; 215 goto fail_free_regions; 216 } 217 218 err = bus_setup_intr(dev, sc->sc_irq, 219 INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY, 220 ps3disk_intr_filter, ps3disk_intr, sc, &sc->sc_irqctx); 221 if (err) { 222 device_printf(dev, "Could not setup IRQ\n"); 223 err = ENXIO; 224 goto fail_release_intr; 225 } 226 227 /* Setup DMA bounce buffer */ 228 229 sc->sc_bounce_maxblocks = DFLTPHYS / sc->sc_blksize; 230 231 err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0, 232 BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 233 sc->sc_bounce_maxblocks * sc->sc_blksize, 1, 234 sc->sc_bounce_maxblocks * sc->sc_blksize, 235 0, NULL, NULL, &sc->sc_bounce_dmatag); 236 if (err) { 237 device_printf(dev, "Could not create DMA tag for bounce buffer\n"); 238 err = ENXIO; 239 goto fail_teardown_intr; 240 } 241 242 err = bus_dmamem_alloc(sc->sc_bounce_dmatag, (void **) &sc->sc_bounce, 243 BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 244 &sc->sc_bounce_dmamap); 245 if (err) { 246 device_printf(dev, "Could not allocate DMA memory for bounce buffer\n"); 247 err = ENXIO; 248 goto fail_destroy_dmatag; 249 } 250 251 err = bus_dmamap_load(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap, 252 sc->sc_bounce, sc->sc_bounce_maxblocks * sc->sc_blksize, 253 ps3disk_getphys, &sc->sc_bounce_dmaphys, 0); 254 if (err) { 255 device_printf(dev, "Could not load DMA map for bounce buffer\n"); 256 err = ENXIO; 257 goto fail_free_dmamem; 258 } 259 260 sc->sc_bounce_lpar = vtophys(sc->sc_bounce); 261 262 if (bootverbose) 263 device_printf(dev, "bounce buffer lpar address 0x%016lx\n", 264 sc->sc_bounce_lpar); 265 266 /* Setup disks */ 267 268 sc->sc_disk = malloc(sc->sc_nregs * sizeof(struct disk *), 269 M_PS3DISK, M_ZERO | M_WAITOK); 270 if (!sc->sc_disk) { 271 device_printf(dev, "Could not allocate disk(s)\n"); 272 err = ENOMEM; 273 goto fail_unload_dmamem; 274 } 275 276 for (i = 0; i < sc->sc_nregs; i++) { 277 struct ps3disk_region *rp = &sc->sc_reg[i]; 278 279 d = sc->sc_disk[i] = disk_alloc(); 280 d->d_open = ps3disk_open; 281 d->d_close = ps3disk_close; 282 d->d_strategy = ps3disk_strategy; 283 d->d_name = "ps3disk"; 284 d->d_drv1 = sc; 285 d->d_maxsize = DFLTPHYS; 286 d->d_sectorsize = sc->sc_blksize; 287 d->d_unit = i; 288 d->d_mediasize = sc->sc_reg[i].r_size * sc->sc_blksize; 289 d->d_flags |= DISKFLAG_CANFLUSHCACHE; 290 291 mb = d->d_mediasize >> 20; 292 unit = 'M'; 293 if (mb >= 10240) { 294 unit = 'G'; 295 mb /= 1024; 296 } 297 298 /* Test to see if we can read this region */ 299 err = lv1_storage_read(ps3bus_get_device(dev), d->d_unit, 300 0, 1, rp->r_flags, sc->sc_bounce_lpar, &sc->sc_bounce_tag); 301 device_printf(dev, "region %d %ju%cB%s\n", i, mb, unit, 302 (err == 0) ? "" : " (hypervisor protected)"); 303 304 if (err == 0) 305 disk_create(d, DISK_VERSION); 306 } 307 err = 0; 308 309 bioq_init(&sc->sc_bioq); 310 311 ps3disk_sysctlattach(sc); 312 313 sc->sc_running = 1; 314 315 kproc_create(&ps3disk_task, sc, &sc->sc_task, 0, 0, "task: ps3disk"); 316 317 return (0); 318 319fail_unload_dmamem: 320 321 bus_dmamap_unload(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap); 322 323fail_free_dmamem: 324 325 bus_dmamem_free(sc->sc_bounce_dmatag, sc->sc_bounce, sc->sc_bounce_dmamap); 326 327fail_destroy_dmatag: 328 329 bus_dma_tag_destroy(sc->sc_bounce_dmatag); 330 331fail_teardown_intr: 332 333 bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx); 334 335fail_release_intr: 336 337 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq); 338 339fail_free_regions: 340 341 free(sc->sc_reg, M_PS3DISK); 342 343fail_destroy_lock: 344 345 PS3DISK_LOCK_DESTROY(sc); 346 347 return (err); 348} 349 350static int 351ps3disk_detach(device_t dev) 352{ 353 struct ps3disk_softc *sc = device_get_softc(dev); 354 int i; 355 356 PS3DISK_LOCK(sc); 357 sc->sc_running = 0; 358 wakeup(sc); 359 PS3DISK_UNLOCK(sc); 360 361 PS3DISK_LOCK(sc); 362 while (sc->sc_running != -1) 363 msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0); 364 PS3DISK_UNLOCK(sc); 365 366 for (i = 0; i < sc->sc_nregs; i++) 367 disk_destroy(sc->sc_disk[i]); 368 369 bus_dmamap_unload(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap); 370 bus_dmamem_free(sc->sc_bounce_dmatag, sc->sc_bounce, sc->sc_bounce_dmamap); 371 bus_dma_tag_destroy(sc->sc_bounce_dmatag); 372 373 bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx); 374 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq); 375 376 free(sc->sc_disk, M_PS3DISK); 377 378 free(sc->sc_reg, M_PS3DISK); 379 380 PS3DISK_LOCK_DESTROY(sc); 381 382 return (0); 383} 384 385static int 386ps3disk_open(struct disk *dp) 387{ 388 return (0); 389} 390 391static int 392ps3disk_close(struct disk *dp) 393{ 394 return (0); 395} 396 397static void 398ps3disk_strategy(struct bio *bp) 399{ 400 struct ps3disk_softc *sc = (struct ps3disk_softc *) bp->bio_disk->d_drv1; 401 402 if (!sc) { 403 bp->bio_flags |= BIO_ERROR; 404 bp->bio_error = EINVAL; 405 biodone(bp); 406 return; 407 } 408 409 PS3DISK_LOCK(sc); 410 bioq_disksort(&sc->sc_bioq, bp); 411 if (!sc->sc_bounce_busy) 412 wakeup(sc); 413 PS3DISK_UNLOCK(sc); 414} 415 416static void 417ps3disk_task(void *arg) 418{ 419 struct ps3disk_softc *sc = (struct ps3disk_softc *) arg; 420 struct bio *bp; 421 daddr_t block, end; 422 u_long nblocks; 423 char *data; 424 int err; 425 426 while (sc->sc_running) { 427 PS3DISK_LOCK(sc); 428 do { 429 bp = bioq_first(&sc->sc_bioq); 430 if (bp == NULL) 431 msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); 432 } while (bp == NULL && sc->sc_running); 433 if (bp) 434 bioq_remove(&sc->sc_bioq, bp); 435 PS3DISK_UNLOCK(sc); 436 437 if (!sc->sc_running) 438 break; 439 440 DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_cmd 0x%02x\n", 441 __func__, bp->bio_cmd); 442 443 if (bp->bio_cmd == BIO_FLUSH) { 444 err = ps3disk_flush(sc); 445 446 if (err) { 447 bp->bio_error = EIO; 448 bp->bio_flags |= BIO_ERROR; 449 } else { 450 bp->bio_error = 0; 451 bp->bio_flags |= BIO_DONE; 452 } 453 } else if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { 454 end = bp->bio_pblkno + (bp->bio_bcount / sc->sc_blksize); 455 456 DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_pblkno %ld bio_bcount %ld\n", 457 __func__, bp->bio_pblkno, bp->bio_bcount); 458 459 for (block = bp->bio_pblkno; block < end;) { 460 data = bp->bio_data + 461 (block - bp->bio_pblkno) * sc->sc_blksize; 462 463 nblocks = end - block; 464 if (nblocks > sc->sc_bounce_maxblocks) 465 nblocks = sc->sc_bounce_maxblocks; 466 467 DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: nblocks %lu\n", 468 __func__, nblocks); 469 470 if (bp->bio_cmd == BIO_READ) { 471 err = ps3disk_read(sc, bp->bio_disk->d_unit, 472 block, nblocks, data); 473 } else { 474 err = ps3disk_write(sc, bp->bio_disk->d_unit, 475 block, nblocks, data); 476 } 477 478 if (err) 479 break; 480 481 block += nblocks; 482 } 483 484 bp->bio_resid = (end - block) * sc->sc_blksize; 485 if (bp->bio_resid) { 486 bp->bio_error = EIO; 487 bp->bio_flags |= BIO_ERROR; 488 } else { 489 bp->bio_error = 0; 490 bp->bio_flags |= BIO_DONE; 491 } 492 493 DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_resid %ld\n", 494 __func__, bp->bio_resid); 495 } else { 496 bp->bio_error = EINVAL; 497 bp->bio_flags |= BIO_ERROR; 498 } 499 500 if (bp->bio_flags & BIO_ERROR) 501 disk_err(bp, "hard error", -1, 1); 502 503 biodone(bp); 504 } 505 506 PS3DISK_LOCK(sc); 507 sc->sc_running = -1; 508 wakeup(sc); 509 PS3DISK_UNLOCK(sc); 510 511 kproc_exit(0); 512} 513 514static int 515ps3disk_intr_filter(void *arg) 516{ 517 return (FILTER_SCHEDULE_THREAD); 518} 519 520static void 521ps3disk_intr(void *arg) 522{ 523 struct ps3disk_softc *sc = (struct ps3disk_softc *) arg; 524 device_t dev = sc->sc_dev; 525 uint64_t devid = ps3bus_get_device(dev); 526 uint64_t tag, status; 527 int err; 528 529 PS3DISK_LOCK(sc); 530 531 err = lv1_storage_get_async_status(devid, &tag, &status); 532 533 DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: err %d tag 0x%016lx status 0x%016lx\n", 534 __func__, err, tag, status); 535 536 if (err) 537 goto out; 538 539 if (!sc->sc_bounce_busy) { 540 device_printf(dev, "Got interrupt while no request pending\n"); 541 goto out; 542 } 543 544 if (tag != sc->sc_bounce_tag) 545 device_printf(dev, "Tag mismatch, got 0x%016lx expected 0x%016lx\n", 546 tag, sc->sc_bounce_tag); 547 548 if (status) 549 device_printf(dev, "Request completed with status 0x%016lx\n", status); 550 551 sc->sc_bounce_status = status; 552 sc->sc_bounce_busy = 0; 553 554 wakeup(sc); 555 556out: 557 558 PS3DISK_UNLOCK(sc); 559} 560 561static void 562ps3disk_getphys(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 563{ 564 if (error != 0) 565 return; 566 567 *(bus_addr_t *) arg = segs[0].ds_addr; 568} 569 570static int 571ps3disk_get_disk_geometry(struct ps3disk_softc *sc) 572{ 573 device_t dev = sc->sc_dev; 574 uint64_t bus_index = ps3bus_get_busidx(dev); 575 uint64_t dev_index = ps3bus_get_devidx(dev); 576 uint64_t junk; 577 int err; 578 579 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 580 (lv1_repository_string("bus") >> 32) | bus_index, 581 lv1_repository_string("dev") | dev_index, 582 lv1_repository_string("blk_size"), 0, &sc->sc_blksize, &junk); 583 if (err) { 584 device_printf(dev, "Could not get block size (0x%08x)\n", err); 585 err = ENXIO; 586 goto out; 587 } 588 589 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 590 (lv1_repository_string("bus") >> 32) | bus_index, 591 lv1_repository_string("dev") | dev_index, 592 lv1_repository_string("n_blocks"), 0, &sc->sc_nblocks, &junk); 593 if (err) { 594 device_printf(dev, "Could not get total number of blocks (0x%08x)\n", 595 err); 596 err = ENXIO; 597 goto out; 598 } 599 600 err = 0; 601 602out: 603 604 return (err); 605} 606 607static int 608ps3disk_enum_regions(struct ps3disk_softc *sc) 609{ 610 device_t dev = sc->sc_dev; 611 uint64_t bus_index = ps3bus_get_busidx(dev); 612 uint64_t dev_index = ps3bus_get_devidx(dev); 613 uint64_t junk; 614 int i, err; 615 616 /* Read number of regions */ 617 618 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 619 (lv1_repository_string("bus") >> 32) | bus_index, 620 lv1_repository_string("dev") | dev_index, 621 lv1_repository_string("n_regs"), 0, &sc->sc_nregs, &junk); 622 if (err) { 623 device_printf(dev, "Could not get number of regions (0x%08x)\n", 624 err); 625 err = ENXIO; 626 goto fail; 627 } 628 629 if (!sc->sc_nregs) 630 return 0; 631 632 sc->sc_reg = malloc(sc->sc_nregs * sizeof(struct ps3disk_region), 633 M_PS3DISK, M_ZERO | M_WAITOK); 634 if (!sc->sc_reg) { 635 err = ENOMEM; 636 goto fail; 637 } 638 639 /* Setup regions */ 640 641 for (i = 0; i < sc->sc_nregs; i++) { 642 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 643 (lv1_repository_string("bus") >> 32) | bus_index, 644 lv1_repository_string("dev") | dev_index, 645 lv1_repository_string("region") | i, 646 lv1_repository_string("id"), &sc->sc_reg[i].r_id, &junk); 647 if (err) { 648 device_printf(dev, "Could not get region id (0x%08x)\n", 649 err); 650 err = ENXIO; 651 goto fail; 652 } 653 654 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 655 (lv1_repository_string("bus") >> 32) | bus_index, 656 lv1_repository_string("dev") | dev_index, 657 lv1_repository_string("region") | i, 658 lv1_repository_string("start"), &sc->sc_reg[i].r_start, &junk); 659 if (err) { 660 device_printf(dev, "Could not get region start (0x%08x)\n", 661 err); 662 err = ENXIO; 663 goto fail; 664 } 665 666 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 667 (lv1_repository_string("bus") >> 32) | bus_index, 668 lv1_repository_string("dev") | dev_index, 669 lv1_repository_string("region") | i, 670 lv1_repository_string("size"), &sc->sc_reg[i].r_size, &junk); 671 if (err) { 672 device_printf(dev, "Could not get region size (0x%08x)\n", 673 err); 674 err = ENXIO; 675 goto fail; 676 } 677 678 if (i == 0) 679 /* disables HV access control and grants access to whole disk */ 680 sc->sc_reg[i].r_flags = 0x2; 681 else 682 sc->sc_reg[i].r_flags = 0; 683 } 684 685 return (0); 686 687fail: 688 689 sc->sc_nregs = 0; 690 if (sc->sc_reg) 691 free(sc->sc_reg, M_PS3DISK); 692 693 return (err); 694} 695 696static int 697ps3disk_read(struct ps3disk_softc *sc, int regidx, 698 uint64_t start_sector, uint64_t sector_count, char *data) 699{ 700 device_t dev = sc->sc_dev; 701 struct ps3disk_region *rp = &sc->sc_reg[regidx]; 702 uint64_t devid = ps3bus_get_device(dev); 703 int err; 704 705 PS3DISK_LOCK(sc); 706 707 if (sc->sc_bounce_busy) { 708 device_printf(dev, "busy\n"); 709 PS3DISK_UNLOCK(sc); 710 return EIO; 711 } 712 713 sc->sc_bounce_busy = 1; 714 715 err = lv1_storage_read(devid, rp->r_id, 716 start_sector, sector_count, rp->r_flags, 717 sc->sc_bounce_lpar, &sc->sc_bounce_tag); 718 if (err) { 719 device_printf(dev, "Could not read sectors (0x%08x)\n", err); 720 err = EIO; 721 goto out; 722 } 723 724 DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n", 725 __func__, sc->sc_bounce_tag); 726 727 err = msleep(sc, &sc->sc_mtx, PRIBIO, "read", hz); 728 if (err) { 729 device_printf(dev, "Read request timed out\n"); 730 err = EIO; 731 goto out; 732 } 733 734 if (sc->sc_bounce_busy || sc->sc_bounce_status) { 735 err = EIO; 736 } else { 737 bus_dmamap_sync(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap, 738 BUS_DMASYNC_POSTREAD); 739 memcpy(data, sc->sc_bounce, sector_count * sc->sc_blksize); 740 err = 0; 741 } 742 743out: 744 745 sc->sc_bounce_busy = 0; 746 747 PS3DISK_UNLOCK(sc); 748 749 return (err); 750} 751 752static int 753ps3disk_write(struct ps3disk_softc *sc, int regidx, 754 uint64_t start_sector, uint64_t sector_count, char *data) 755{ 756 device_t dev = sc->sc_dev; 757 struct ps3disk_region *rp = &sc->sc_reg[regidx]; 758 uint64_t devid = ps3bus_get_device(dev); 759 int err; 760 761 PS3DISK_LOCK(sc); 762 763 if (sc->sc_bounce_busy) { 764 device_printf(dev, "busy\n"); 765 PS3DISK_UNLOCK(sc); 766 return EIO; 767 } 768 769 memcpy(sc->sc_bounce, data, sector_count * sc->sc_blksize); 770 771 bus_dmamap_sync(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap, 772 BUS_DMASYNC_PREWRITE); 773 774 sc->sc_bounce_busy = 1; 775 776 err = lv1_storage_write(devid, rp->r_id, 777 start_sector, sector_count, rp->r_flags, 778 sc->sc_bounce_lpar, &sc->sc_bounce_tag); 779 if (err) { 780 device_printf(dev, "Could not write sectors (0x%08x)\n", err); 781 err = EIO; 782 goto out; 783 } 784 785 DPRINTF(sc, PS3DISK_DEBUG_WRITE, "%s: tag 0x%016lx\n", 786 __func__, sc->sc_bounce_tag); 787 788 err = msleep(sc, &sc->sc_mtx, PRIBIO, "write", hz); 789 if (err) { 790 device_printf(dev, "Write request timed out\n"); 791 err = EIO; 792 goto out; 793 } 794 795 err = (sc->sc_bounce_busy || sc->sc_bounce_status) ? EIO : 0; 796 797out: 798 799 sc->sc_bounce_busy = 0; 800 801 PS3DISK_UNLOCK(sc); 802 803 return (err); 804} 805 806static int 807ps3disk_flush(struct ps3disk_softc *sc) 808{ 809 device_t dev = sc->sc_dev; 810 uint64_t devid = ps3bus_get_device(dev); 811 int err; 812 813 PS3DISK_LOCK(sc); 814 815 if (sc->sc_bounce_busy) { 816 device_printf(dev, "busy\n"); 817 PS3DISK_UNLOCK(sc); 818 return EIO; 819 } 820 821 sc->sc_bounce_busy = 1; 822 823 err = lv1_storage_send_device_command(devid, LV1_STORAGE_ATA_HDDOUT, 824 0, 0, 0, 0, &sc->sc_bounce_tag); 825 if (err) { 826 device_printf(dev, "Could not flush (0x%08x)\n", err); 827 err = EIO; 828 goto out; 829 } 830 831 DPRINTF(sc, PS3DISK_DEBUG_FLUSH, "%s: tag 0x%016lx\n", 832 __func__, sc->sc_bounce_tag); 833 834 err = msleep(sc, &sc->sc_mtx, PRIBIO, "flush", hz); 835 if (err) { 836 device_printf(dev, "Flush request timed out\n"); 837 err = EIO; 838 goto out; 839 } 840 841 err = (sc->sc_bounce_busy || sc->sc_bounce_status) ? EIO : 0; 842 843out: 844 845 sc->sc_bounce_busy = 0; 846 847 PS3DISK_UNLOCK(sc); 848 849 return (err); 850} 851 852#ifdef PS3DISK_DEBUG 853static int 854ps3disk_sysctl_debug(SYSCTL_HANDLER_ARGS) 855{ 856 struct ps3disk_softc *sc = arg1; 857 int debug, error; 858 859 debug = sc->sc_debug; 860 861 error = sysctl_handle_int(oidp, &debug, 0, req); 862 if (error || !req->newptr) 863 return error; 864 865 sc->sc_debug = debug; 866 867 return 0; 868} 869#endif 870 871static void 872ps3disk_sysctlattach(struct ps3disk_softc *sc) 873{ 874#ifdef PS3DISK_DEBUG 875 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 876 struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 877 878 sc->sc_debug = ps3disk_debug; 879 880 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 881 "debug", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 882 ps3disk_sysctl_debug, "I", "control debugging printfs"); 883#endif 884} 885 886static device_method_t ps3disk_methods[] = { 887 DEVMETHOD(device_probe, ps3disk_probe), 888 DEVMETHOD(device_attach, ps3disk_attach), 889 DEVMETHOD(device_detach, ps3disk_detach), 890 {0, 0}, 891}; 892 893static driver_t ps3disk_driver = { 894 "ps3disk", 895 ps3disk_methods, 896 sizeof(struct ps3disk_softc), 897}; 898 899static devclass_t ps3disk_devclass; 900 901DRIVER_MODULE(ps3disk, ps3bus, ps3disk_driver, ps3disk_devclass, 0, 0); 902