2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/sysctl.h>
39 #include <sys/kernel.h>
40 #include <sys/kthread.h>
42 #include <sys/malloc.h>
43 #include <sys/module.h>
44 #include <sys/mutex.h>
49 #include <machine/pio.h>
50 #include <machine/bus.h>
51 #include <machine/platform.h>
52 #include <machine/resource.h>
56 #include <geom/geom_disk.h>
59 #include "ps3-hvcall.h"
61 #define PS3DISK_LOCK_INIT(_sc) \
62 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3disk", MTX_DEF)
63 #define PS3DISK_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
64 #define PS3DISK_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
65 #define PS3DISK_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
66 #define PS3DISK_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
67 #define PS3DISK_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
69 #define LV1_STORAGE_ATA_HDDOUT 0x23
71 static SYSCTL_NODE(_hw, OID_AUTO, ps3disk, CTLFLAG_RD, 0,
72 "PS3 Disk driver parameters");
75 static int ps3disk_debug = 0;
76 SYSCTL_INT(_hw_ps3disk, OID_AUTO, debug, CTLFLAG_RW, &ps3disk_debug,
77 0, "control debugging printfs");
78 TUNABLE_INT("hw.ps3disk.debug", &ps3disk_debug);
80 PS3DISK_DEBUG_INTR = 0x00000001,
81 PS3DISK_DEBUG_TASK = 0x00000002,
82 PS3DISK_DEBUG_READ = 0x00000004,
83 PS3DISK_DEBUG_WRITE = 0x00000008,
84 PS3DISK_DEBUG_FLUSH = 0x00000010,
85 PS3DISK_DEBUG_ANY = 0xffffffff
87 #define DPRINTF(sc, m, fmt, ...) \
89 if (sc->sc_debug & (m)) \
90 printf(fmt, __VA_ARGS__); \
93 #define DPRINTF(sc, m, fmt, ...)
96 struct ps3disk_region {
103 struct ps3disk_softc {
112 struct ps3disk_region *sc_reg;
115 struct resource *sc_irq;
118 struct disk **sc_disk;
120 struct bio_queue_head sc_bioq;
121 struct bio_queue_head sc_deferredq;
122 struct proc *sc_task;
124 bus_dma_tag_t sc_dmatag;
130 static int ps3disk_open(struct disk *dp);
131 static int ps3disk_close(struct disk *dp);
132 static void ps3disk_strategy(struct bio *bp);
134 static void ps3disk_task(void *arg);
135 static void ps3disk_intr(void *arg);
136 static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc);
137 static int ps3disk_enum_regions(struct ps3disk_softc *sc);
138 static void ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
141 static void ps3disk_sysctlattach(struct ps3disk_softc *sc);
143 static MALLOC_DEFINE(M_PS3DISK, "ps3disk", "PS3 Disk");
146 ps3disk_probe(device_t dev)
148 if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
149 ps3bus_get_devtype(dev) != PS3_DEVTYPE_DISK)
152 device_set_desc(dev, "Playstation 3 Disk");
154 return (BUS_PROBE_SPECIFIC);
158 ps3disk_attach(device_t dev)
160 struct ps3disk_softc *sc;
167 sc = device_get_softc(dev);
170 PS3DISK_LOCK_INIT(sc);
172 err = ps3disk_get_disk_geometry(sc);
174 device_printf(dev, "Could not get disk geometry\n");
176 goto fail_destroy_lock;
179 device_printf(dev, "block size %lu total blocks %lu\n",
180 sc->sc_blksize, sc->sc_nblocks);
182 err = ps3disk_enum_regions(sc);
184 device_printf(dev, "Could not enumerate disk regions\n");
186 goto fail_destroy_lock;
189 device_printf(dev, "Found %lu regions\n", sc->sc_nregs);
193 goto fail_destroy_lock;
196 /* Setup interrupt handler */
198 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
201 device_printf(dev, "Could not allocate IRQ\n");
203 goto fail_free_regions;
206 err = bus_setup_intr(dev, sc->sc_irq,
207 INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
208 NULL, ps3disk_intr, sc, &sc->sc_irqctx);
210 device_printf(dev, "Could not setup IRQ\n");
212 goto fail_release_intr;
216 err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
217 BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
218 BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0,
219 busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag);
221 device_printf(dev, "Could not create DMA tag\n");
223 goto fail_teardown_intr;
228 sc->sc_disk = malloc(sc->sc_nregs * sizeof(struct disk *),
229 M_PS3DISK, M_ZERO | M_WAITOK);
231 device_printf(dev, "Could not allocate disk(s)\n");
233 goto fail_teardown_intr;
236 for (i = 0; i < sc->sc_nregs; i++) {
237 struct ps3disk_region *rp = &sc->sc_reg[i];
239 d = sc->sc_disk[i] = disk_alloc();
240 d->d_open = ps3disk_open;
241 d->d_close = ps3disk_close;
242 d->d_strategy = ps3disk_strategy;
243 d->d_name = "ps3disk";
245 d->d_maxsize = PAGE_SIZE;
246 d->d_sectorsize = sc->sc_blksize;
248 d->d_mediasize = sc->sc_reg[i].r_size * sc->sc_blksize;
249 d->d_flags |= DISKFLAG_CANFLUSHCACHE;
251 mb = d->d_mediasize >> 20;
258 /* Test to see if we can read this region */
259 err = lv1_storage_read(ps3bus_get_device(dev), d->d_unit,
260 0, 0, rp->r_flags, 0, &junk);
261 device_printf(dev, "region %d %ju%cB%s\n", i, mb, unit,
262 (err == LV1_DENIED_BY_POLICY) ? " (hypervisor protected)"
265 if (err != LV1_DENIED_BY_POLICY)
266 disk_create(d, DISK_VERSION);
270 bioq_init(&sc->sc_bioq);
271 bioq_init(&sc->sc_deferredq);
272 kproc_create(&ps3disk_task, sc, &sc->sc_task, 0, 0, "ps3disk");
274 ps3disk_sysctlattach(sc);
279 bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
281 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
283 free(sc->sc_reg, M_PS3DISK);
285 PS3DISK_LOCK_DESTROY(sc);
290 ps3disk_detach(device_t dev)
292 struct ps3disk_softc *sc = device_get_softc(dev);
295 for (i = 0; i < sc->sc_nregs; i++)
296 disk_destroy(sc->sc_disk[i]);
298 bus_dma_tag_destroy(sc->sc_dmatag);
300 bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
301 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
303 free(sc->sc_disk, M_PS3DISK);
304 free(sc->sc_reg, M_PS3DISK);
306 PS3DISK_LOCK_DESTROY(sc);
312 ps3disk_open(struct disk *dp)
318 ps3disk_close(struct disk *dp)
323 /* Process deferred blocks */
325 ps3disk_task(void *arg)
327 struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
332 kproc_suspend_check(sc->sc_task);
333 tsleep(&sc->sc_deferredq, PRIBIO, "ps3disk", 10);
336 bp = bioq_takefirst(&sc->sc_deferredq);
342 if (bp->bio_driver1 != NULL) {
343 bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
345 bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
349 ps3disk_strategy(bp);
356 ps3disk_strategy(struct bio *bp)
358 struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
362 bp->bio_flags |= BIO_ERROR;
363 bp->bio_error = EINVAL;
369 bp->bio_resid = bp->bio_bcount;
370 bioq_insert_tail(&sc->sc_bioq, bp);
372 DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_cmd 0x%02x\n",
373 __func__, bp->bio_cmd);
376 if (bp->bio_cmd == BIO_FLUSH) {
378 err = lv1_storage_send_device_command(
379 ps3bus_get_device(sc->sc_dev), LV1_STORAGE_ATA_HDDOUT,
380 0, 0, 0, 0, (uint64_t *)&bp->bio_driver2);
383 } else if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
384 if (bp->bio_bcount % sc->sc_blksize != 0) {
387 bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT,
388 (bus_dmamap_t *)(&bp->bio_driver1));
389 err = bus_dmamap_load(sc->sc_dmatag,
390 (bus_dmamap_t)(bp->bio_driver1), bp->bio_data,
391 bp->bio_bcount, ps3disk_transfer, bp, 0);
392 if (err == EINPROGRESS)
400 bioq_remove(&sc->sc_bioq, bp);
401 bioq_insert_tail(&sc->sc_deferredq, bp);
402 } else if (err != 0) {
404 bp->bio_flags |= BIO_ERROR;
405 bioq_remove(&sc->sc_bioq, bp);
406 disk_err(bp, "hard error", -1, 1);
414 ps3disk_intr(void *arg)
416 struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
417 device_t dev = sc->sc_dev;
418 uint64_t devid = ps3bus_get_device(dev);
420 uint64_t tag, status;
422 if (lv1_storage_get_async_status(devid, &tag, &status) != 0)
427 DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: tag 0x%016lx "
428 "status 0x%016lx\n", __func__, tag, status);
430 /* Locate the matching request */
431 TAILQ_FOREACH(bp, &sc->sc_bioq.queue, bio_queue) {
432 if ((uint64_t)bp->bio_driver2 != tag)
436 device_printf(sc->sc_dev, "%s error (%#lx)\n",
437 (bp->bio_cmd == BIO_READ) ? "Read" : "Write",
440 bp->bio_flags |= BIO_ERROR;
444 bp->bio_flags |= BIO_DONE;
447 if (bp->bio_driver1 != NULL) {
448 if (bp->bio_cmd == BIO_READ)
449 bus_dmamap_sync(sc->sc_dmatag, (bus_dmamap_t)
450 bp->bio_driver1, BUS_DMASYNC_POSTREAD);
451 bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
453 bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
457 bioq_remove(&sc->sc_bioq, bp);
462 if (bioq_first(&sc->sc_deferredq) != NULL)
463 wakeup(&sc->sc_deferredq);
469 ps3disk_get_disk_geometry(struct ps3disk_softc *sc)
471 device_t dev = sc->sc_dev;
472 uint64_t bus_index = ps3bus_get_busidx(dev);
473 uint64_t dev_index = ps3bus_get_devidx(dev);
477 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
478 (lv1_repository_string("bus") >> 32) | bus_index,
479 lv1_repository_string("dev") | dev_index,
480 lv1_repository_string("blk_size"), 0, &sc->sc_blksize, &junk);
482 device_printf(dev, "Could not get block size (0x%08x)\n", err);
486 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
487 (lv1_repository_string("bus") >> 32) | bus_index,
488 lv1_repository_string("dev") | dev_index,
489 lv1_repository_string("n_blocks"), 0, &sc->sc_nblocks, &junk);
491 device_printf(dev, "Could not get total number of blocks "
500 ps3disk_enum_regions(struct ps3disk_softc *sc)
502 device_t dev = sc->sc_dev;
503 uint64_t bus_index = ps3bus_get_busidx(dev);
504 uint64_t dev_index = ps3bus_get_devidx(dev);
508 /* Read number of regions */
510 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
511 (lv1_repository_string("bus") >> 32) | bus_index,
512 lv1_repository_string("dev") | dev_index,
513 lv1_repository_string("n_regs"), 0, &sc->sc_nregs, &junk);
515 device_printf(dev, "Could not get number of regions (0x%08x)\n",
524 sc->sc_reg = malloc(sc->sc_nregs * sizeof(struct ps3disk_region),
525 M_PS3DISK, M_ZERO | M_WAITOK);
533 for (i = 0; i < sc->sc_nregs; i++) {
534 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
535 (lv1_repository_string("bus") >> 32) | bus_index,
536 lv1_repository_string("dev") | dev_index,
537 lv1_repository_string("region") | i,
538 lv1_repository_string("id"), &sc->sc_reg[i].r_id, &junk);
540 device_printf(dev, "Could not get region id (0x%08x)\n",
546 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
547 (lv1_repository_string("bus") >> 32) | bus_index,
548 lv1_repository_string("dev") | dev_index,
549 lv1_repository_string("region") | i,
550 lv1_repository_string("start"), &sc->sc_reg[i].r_start,
553 device_printf(dev, "Could not get region start "
559 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
560 (lv1_repository_string("bus") >> 32) | bus_index,
561 lv1_repository_string("dev") | dev_index,
562 lv1_repository_string("region") | i,
563 lv1_repository_string("size"), &sc->sc_reg[i].r_size,
566 device_printf(dev, "Could not get region size "
573 sc->sc_reg[i].r_flags = 0x2;
575 sc->sc_reg[i].r_flags = 0;
584 free(sc->sc_reg, M_PS3DISK);
590 ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
592 struct bio *bp = (struct bio *)(arg);
593 struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
594 struct ps3disk_region *rp = &sc->sc_reg[bp->bio_disk->d_unit];
595 uint64_t devid = ps3bus_get_device(sc->sc_dev);
599 /* Locks already held by busdma */
600 PS3DISK_ASSERT_LOCKED(sc);
603 bp->bio_error = error;
604 bp->bio_flags |= BIO_ERROR;
605 bioq_remove(&sc->sc_bioq, bp);
610 block = bp->bio_pblkno;
611 for (i = 0; i < nsegs; i++) {
612 KASSERT((segs[i].ds_len % sc->sc_blksize) == 0,
613 ("DMA fragments not blocksize multiples"));
615 if (bp->bio_cmd == BIO_READ) {
616 err = lv1_storage_read(devid, rp->r_id,
617 block, segs[i].ds_len/sc->sc_blksize,
618 rp->r_flags, segs[i].ds_addr,
619 (uint64_t *)&bp->bio_driver2);
621 bus_dmamap_sync(sc->sc_dmatag,
622 (bus_dmamap_t)bp->bio_driver1,
623 BUS_DMASYNC_PREWRITE);
624 err = lv1_storage_write(devid, rp->r_id,
625 block, segs[i].ds_len/sc->sc_blksize,
626 rp->r_flags, segs[i].ds_addr,
627 (uint64_t *)&bp->bio_driver2);
631 if (err == LV1_BUSY) {
632 bioq_remove(&sc->sc_bioq, bp);
633 bioq_insert_tail(&sc->sc_deferredq, bp);
635 bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
637 bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
639 device_printf(sc->sc_dev, "Could not read "
640 "sectors (0x%08x)\n", err);
641 bp->bio_error = EINVAL;
642 bp->bio_flags |= BIO_ERROR;
643 bioq_remove(&sc->sc_bioq, bp);
650 DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n",
651 __func__, sc->sc_bounce_tag);
657 ps3disk_sysctl_debug(SYSCTL_HANDLER_ARGS)
659 struct ps3disk_softc *sc = arg1;
662 debug = sc->sc_debug;
664 error = sysctl_handle_int(oidp, &debug, 0, req);
665 if (error || !req->newptr)
668 sc->sc_debug = debug;
675 ps3disk_sysctlattach(struct ps3disk_softc *sc)
678 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
679 struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
681 sc->sc_debug = ps3disk_debug;
683 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
684 "debug", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
685 ps3disk_sysctl_debug, "I", "control debugging printfs");
689 static device_method_t ps3disk_methods[] = {
690 DEVMETHOD(device_probe, ps3disk_probe),
691 DEVMETHOD(device_attach, ps3disk_attach),
692 DEVMETHOD(device_detach, ps3disk_detach),
696 static driver_t ps3disk_driver = {
699 sizeof(struct ps3disk_softc),
702 static devclass_t ps3disk_devclass;
704 DRIVER_MODULE(ps3disk, ps3bus, ps3disk_driver, ps3disk_devclass, 0, 0);