xref: /freebsd/sys/powerpc/ps3/ps3disk.c (revision dfcd47a78deb04107f316d96ea6ddd8a6e8d504b)
10d317057SNathan Whitehorn /*-
20d317057SNathan Whitehorn  * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru)
30d317057SNathan Whitehorn  * All rights reserved.
40d317057SNathan Whitehorn  *
50d317057SNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
60d317057SNathan Whitehorn  * modification, are permitted provided that the following conditions
70d317057SNathan Whitehorn  * are met:
80d317057SNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
90d317057SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
100d317057SNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
110d317057SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
120d317057SNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
130d317057SNathan Whitehorn  *
140d317057SNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
150d317057SNathan Whitehorn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
160d317057SNathan Whitehorn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
170d317057SNathan Whitehorn  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
180d317057SNathan Whitehorn  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
190d317057SNathan Whitehorn  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
200d317057SNathan Whitehorn  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
210d317057SNathan Whitehorn  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
220d317057SNathan Whitehorn  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
230d317057SNathan Whitehorn  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
240d317057SNathan Whitehorn  *
250d317057SNathan Whitehorn  */
260d317057SNathan Whitehorn 
270d317057SNathan Whitehorn #include <sys/cdefs.h>
280d317057SNathan Whitehorn __FBSDID("$FreeBSD$");
290d317057SNathan Whitehorn 
300d317057SNathan Whitehorn #include <sys/param.h>
310d317057SNathan Whitehorn #include <sys/systm.h>
320d317057SNathan Whitehorn #include <sys/sysctl.h>
330d317057SNathan Whitehorn #include <sys/disk.h>
340d317057SNathan Whitehorn #include <sys/bio.h>
350d317057SNathan Whitehorn #include <sys/bus.h>
360d317057SNathan Whitehorn #include <sys/conf.h>
370d317057SNathan Whitehorn #include <sys/kernel.h>
380d317057SNathan Whitehorn #include <sys/kthread.h>
390d317057SNathan Whitehorn #include <sys/lock.h>
400d317057SNathan Whitehorn #include <sys/malloc.h>
410d317057SNathan Whitehorn #include <sys/module.h>
420d317057SNathan Whitehorn #include <sys/mutex.h>
430d317057SNathan Whitehorn 
440d317057SNathan Whitehorn #include <vm/vm.h>
450d317057SNathan Whitehorn #include <vm/pmap.h>
460d317057SNathan Whitehorn 
470d317057SNathan Whitehorn #include <machine/pio.h>
480d317057SNathan Whitehorn #include <machine/bus.h>
490d317057SNathan Whitehorn #include <machine/platform.h>
500d317057SNathan Whitehorn #include <machine/pmap.h>
510d317057SNathan Whitehorn #include <machine/resource.h>
520d317057SNathan Whitehorn #include <sys/bus.h>
530d317057SNathan Whitehorn #include <sys/rman.h>
540d317057SNathan Whitehorn 
550d317057SNathan Whitehorn #include <geom/geom_disk.h>
560d317057SNathan Whitehorn 
570d317057SNathan Whitehorn #include "ps3bus.h"
580d317057SNathan Whitehorn #include "ps3-hvcall.h"
590d317057SNathan Whitehorn 
600d317057SNathan Whitehorn #define PS3DISK_LOCK_INIT(_sc)		\
610d317057SNathan Whitehorn 	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3disk", MTX_DEF)
620d317057SNathan Whitehorn #define PS3DISK_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
630d317057SNathan Whitehorn #define PS3DISK_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
640d317057SNathan Whitehorn #define	PS3DISK_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
650d317057SNathan Whitehorn #define PS3DISK_ASSERT_LOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_OWNED);
660d317057SNathan Whitehorn #define PS3DISK_ASSERT_UNLOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
670d317057SNathan Whitehorn 
680d317057SNathan Whitehorn #define LV1_STORAGE_ATA_HDDOUT 		0x23
690d317057SNathan Whitehorn 
700d317057SNathan Whitehorn SYSCTL_NODE(_hw, OID_AUTO, ps3disk, CTLFLAG_RD, 0, "PS3 Disk driver parameters");
710d317057SNathan Whitehorn 
720d317057SNathan Whitehorn #ifdef PS3DISK_DEBUG
730d317057SNathan Whitehorn static int ps3disk_debug = 0;
740d317057SNathan Whitehorn SYSCTL_INT(_hw_ps3disk, OID_AUTO, debug, CTLFLAG_RW, &ps3disk_debug,
750d317057SNathan Whitehorn 	0, "control debugging printfs");
760d317057SNathan Whitehorn TUNABLE_INT("hw.ps3disk.debug", &ps3disk_debug);
770d317057SNathan Whitehorn enum {
780d317057SNathan Whitehorn 	PS3DISK_DEBUG_INTR	= 0x00000001,
790d317057SNathan Whitehorn 	PS3DISK_DEBUG_TASK	= 0x00000002,
800d317057SNathan Whitehorn 	PS3DISK_DEBUG_READ	= 0x00000004,
810d317057SNathan Whitehorn 	PS3DISK_DEBUG_WRITE	= 0x00000008,
820d317057SNathan Whitehorn 	PS3DISK_DEBUG_FLUSH	= 0x00000010,
830d317057SNathan Whitehorn 	PS3DISK_DEBUG_ANY	= 0xffffffff
840d317057SNathan Whitehorn };
850d317057SNathan Whitehorn #define	DPRINTF(sc, m, fmt, ...)				\
860d317057SNathan Whitehorn do {								\
870d317057SNathan Whitehorn 	if (sc->sc_debug & (m))					\
880d317057SNathan Whitehorn 		printf(fmt, __VA_ARGS__);			\
890d317057SNathan Whitehorn } while (0)
900d317057SNathan Whitehorn #else
910d317057SNathan Whitehorn #define	DPRINTF(sc, m, fmt, ...)
920d317057SNathan Whitehorn #endif
930d317057SNathan Whitehorn 
940d317057SNathan Whitehorn struct ps3disk_region {
950d317057SNathan Whitehorn 	uint64_t r_id;
960d317057SNathan Whitehorn 	uint64_t r_start;
970d317057SNathan Whitehorn 	uint64_t r_size;
980d317057SNathan Whitehorn 	uint64_t r_flags;
990d317057SNathan Whitehorn };
1000d317057SNathan Whitehorn 
1010d317057SNathan Whitehorn struct ps3disk_softc {
1020d317057SNathan Whitehorn 	device_t sc_dev;
1030d317057SNathan Whitehorn 
1040d317057SNathan Whitehorn 	struct mtx sc_mtx;
1050d317057SNathan Whitehorn 
1060d317057SNathan Whitehorn 	uint64_t sc_blksize;
1070d317057SNathan Whitehorn 	uint64_t sc_nblocks;
1080d317057SNathan Whitehorn 
1090d317057SNathan Whitehorn 	uint64_t sc_nregs;
1100d317057SNathan Whitehorn 	struct ps3disk_region *sc_reg;
1110d317057SNathan Whitehorn 
1120d317057SNathan Whitehorn 	int sc_irqid;
1130d317057SNathan Whitehorn 	struct resource	*sc_irq;
1140d317057SNathan Whitehorn 	void *sc_irqctx;
1150d317057SNathan Whitehorn 
1160d317057SNathan Whitehorn 	struct disk **sc_disk;
1170d317057SNathan Whitehorn 
1180d317057SNathan Whitehorn 	struct bio_queue_head sc_bioq;
1190d317057SNathan Whitehorn 
1200d317057SNathan Whitehorn 	struct proc *sc_task;
1210d317057SNathan Whitehorn 
1220d317057SNathan Whitehorn 	int sc_bounce_maxblocks;
1230d317057SNathan Whitehorn 	bus_dma_tag_t sc_bounce_dmatag;
1240d317057SNathan Whitehorn 	bus_dmamap_t sc_bounce_dmamap;
1250d317057SNathan Whitehorn 	bus_addr_t sc_bounce_dmaphys;
1260d317057SNathan Whitehorn 	char *sc_bounce;
1270d317057SNathan Whitehorn 	uint64_t sc_bounce_lpar;
1280d317057SNathan Whitehorn 	int sc_bounce_busy;
1290d317057SNathan Whitehorn 	uint64_t sc_bounce_tag;
1300d317057SNathan Whitehorn 	uint64_t sc_bounce_status;
1310d317057SNathan Whitehorn 
1320d317057SNathan Whitehorn 	int sc_running;
1330d317057SNathan Whitehorn 
1340d317057SNathan Whitehorn 	int sc_debug;
1350d317057SNathan Whitehorn };
1360d317057SNathan Whitehorn 
1370d317057SNathan Whitehorn static int ps3disk_open(struct disk *dp);
1380d317057SNathan Whitehorn static int ps3disk_close(struct disk *dp);
1390d317057SNathan Whitehorn static void ps3disk_strategy(struct bio *bp);
1400d317057SNathan Whitehorn static void ps3disk_task(void *arg);
1410d317057SNathan Whitehorn 
1420d317057SNathan Whitehorn static int ps3disk_intr_filter(void *arg);
1430d317057SNathan Whitehorn static void ps3disk_intr(void *arg);
1440d317057SNathan Whitehorn static void ps3disk_getphys(void *arg, bus_dma_segment_t *segs, int nsegs, int error);
1450d317057SNathan Whitehorn static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc);
1460d317057SNathan Whitehorn static int ps3disk_enum_regions(struct ps3disk_softc *sc);
1470d317057SNathan Whitehorn static int ps3disk_read(struct ps3disk_softc *sc, int regidx,
1480d317057SNathan Whitehorn 	uint64_t start_sector, uint64_t sector_count, char *data);
1490d317057SNathan Whitehorn static int ps3disk_write(struct ps3disk_softc *sc, int regidx,
1500d317057SNathan Whitehorn 	uint64_t start_sector, uint64_t sector_count, char *data);
1510d317057SNathan Whitehorn static int ps3disk_flush(struct ps3disk_softc *sc);
1520d317057SNathan Whitehorn 
1530d317057SNathan Whitehorn static void ps3disk_sysctlattach(struct ps3disk_softc *sc);
1540d317057SNathan Whitehorn 
1550d317057SNathan Whitehorn static MALLOC_DEFINE(M_PS3DISK, "ps3disk", "PS3 Disk");
1560d317057SNathan Whitehorn 
1570d317057SNathan Whitehorn static int
1580d317057SNathan Whitehorn ps3disk_probe(device_t dev)
1590d317057SNathan Whitehorn {
1600d317057SNathan Whitehorn 	if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
1610d317057SNathan Whitehorn 	    ps3bus_get_devtype(dev) != PS3_DEVTYPE_DISK)
1620d317057SNathan Whitehorn 		return (ENXIO);
1630d317057SNathan Whitehorn 
1640d317057SNathan Whitehorn 	device_set_desc(dev, "Playstation 3 Disk");
1650d317057SNathan Whitehorn 
1660d317057SNathan Whitehorn 	return (BUS_PROBE_SPECIFIC);
1670d317057SNathan Whitehorn }
1680d317057SNathan Whitehorn 
1690d317057SNathan Whitehorn static int
1700d317057SNathan Whitehorn ps3disk_attach(device_t dev)
1710d317057SNathan Whitehorn {
1720d317057SNathan Whitehorn 	struct ps3disk_softc *sc;
1730d317057SNathan Whitehorn 	struct disk *d;
1740d317057SNathan Whitehorn 	intmax_t mb;
1750d317057SNathan Whitehorn 	char unit;
1760d317057SNathan Whitehorn 	int i, err;
1770d317057SNathan Whitehorn 
1780d317057SNathan Whitehorn 	sc = device_get_softc(dev);
1790d317057SNathan Whitehorn 	sc->sc_dev = dev;
1800d317057SNathan Whitehorn 
1810d317057SNathan Whitehorn 	PS3DISK_LOCK_INIT(sc);
1820d317057SNathan Whitehorn 
1830d317057SNathan Whitehorn 	err = ps3disk_get_disk_geometry(sc);
1840d317057SNathan Whitehorn 	if (err) {
1850d317057SNathan Whitehorn 		device_printf(dev, "Could not get disk geometry\n");
1860d317057SNathan Whitehorn 		err = ENXIO;
1870d317057SNathan Whitehorn 		goto fail_destroy_lock;
1880d317057SNathan Whitehorn 	}
1890d317057SNathan Whitehorn 
1900d317057SNathan Whitehorn 	device_printf(dev, "block size %lu total blocks %lu\n",
1910d317057SNathan Whitehorn 	    sc->sc_blksize, sc->sc_nblocks);
1920d317057SNathan Whitehorn 
1930d317057SNathan Whitehorn 	err = ps3disk_enum_regions(sc);
1940d317057SNathan Whitehorn 	if (err) {
1950d317057SNathan Whitehorn 		device_printf(dev, "Could not enumerate disk regions\n");
1960d317057SNathan Whitehorn 		err = ENXIO;
1970d317057SNathan Whitehorn 		goto fail_destroy_lock;
1980d317057SNathan Whitehorn 	}
1990d317057SNathan Whitehorn 
2000d317057SNathan Whitehorn 	device_printf(dev, "Found %lu regions\n", sc->sc_nregs);
2010d317057SNathan Whitehorn 
2020d317057SNathan Whitehorn 	if (!sc->sc_nregs) {
2030d317057SNathan Whitehorn 		err = ENXIO;
2040d317057SNathan Whitehorn 		goto fail_destroy_lock;
2050d317057SNathan Whitehorn 	}
2060d317057SNathan Whitehorn 
2070d317057SNathan Whitehorn 	/* Setup interrupt handler */
2080d317057SNathan Whitehorn 
2090d317057SNathan Whitehorn 	sc->sc_irqid = 0;
2100d317057SNathan Whitehorn 	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
2110d317057SNathan Whitehorn 	    RF_ACTIVE);
2120d317057SNathan Whitehorn 	if (!sc->sc_irq) {
2130d317057SNathan Whitehorn 		device_printf(dev, "Could not allocate IRQ\n");
2140d317057SNathan Whitehorn 		err = ENXIO;
2150d317057SNathan Whitehorn 		goto fail_free_regions;
2160d317057SNathan Whitehorn 	}
2170d317057SNathan Whitehorn 
2180d317057SNathan Whitehorn 	err = bus_setup_intr(dev, sc->sc_irq,
2190d317057SNathan Whitehorn 	    INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
2200d317057SNathan Whitehorn 	    ps3disk_intr_filter, ps3disk_intr, sc, &sc->sc_irqctx);
2210d317057SNathan Whitehorn 	if (err) {
2220d317057SNathan Whitehorn 		device_printf(dev, "Could not setup IRQ\n");
2230d317057SNathan Whitehorn 		err = ENXIO;
2240d317057SNathan Whitehorn 		goto fail_release_intr;
2250d317057SNathan Whitehorn 	}
2260d317057SNathan Whitehorn 
2270d317057SNathan Whitehorn 	/* Setup DMA bounce buffer */
2280d317057SNathan Whitehorn 
2290d317057SNathan Whitehorn 	sc->sc_bounce_maxblocks = DFLTPHYS / sc->sc_blksize;
2300d317057SNathan Whitehorn 
2310d317057SNathan Whitehorn 	err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
2320d317057SNathan Whitehorn 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
2330d317057SNathan Whitehorn 	    sc->sc_bounce_maxblocks * sc->sc_blksize, 1,
2340d317057SNathan Whitehorn 	    sc->sc_bounce_maxblocks * sc->sc_blksize,
2350d317057SNathan Whitehorn 	    0, NULL, NULL, &sc->sc_bounce_dmatag);
2360d317057SNathan Whitehorn 	if (err) {
2370d317057SNathan Whitehorn 		device_printf(dev, "Could not create DMA tag for bounce buffer\n");
2380d317057SNathan Whitehorn 		err = ENXIO;
2390d317057SNathan Whitehorn 		goto fail_teardown_intr;
2400d317057SNathan Whitehorn 	}
2410d317057SNathan Whitehorn 
2420d317057SNathan Whitehorn 	err = bus_dmamem_alloc(sc->sc_bounce_dmatag, (void **) &sc->sc_bounce,
2430d317057SNathan Whitehorn 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
2440d317057SNathan Whitehorn 	    &sc->sc_bounce_dmamap);
2450d317057SNathan Whitehorn 	if (err) {
2460d317057SNathan Whitehorn 		device_printf(dev, "Could not allocate DMA memory for bounce buffer\n");
2470d317057SNathan Whitehorn 		err = ENXIO;
2480d317057SNathan Whitehorn 		goto fail_destroy_dmatag;
2490d317057SNathan Whitehorn 	}
2500d317057SNathan Whitehorn 
2510d317057SNathan Whitehorn 	err = bus_dmamap_load(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap,
2520d317057SNathan Whitehorn 	    sc->sc_bounce, sc->sc_bounce_maxblocks * sc->sc_blksize,
2530d317057SNathan Whitehorn 	    ps3disk_getphys, &sc->sc_bounce_dmaphys, 0);
2540d317057SNathan Whitehorn 	if (err) {
2550d317057SNathan Whitehorn 		device_printf(dev, "Could not load DMA map for bounce buffer\n");
2560d317057SNathan Whitehorn 		err = ENXIO;
2570d317057SNathan Whitehorn 		goto fail_free_dmamem;
2580d317057SNathan Whitehorn 	}
2590d317057SNathan Whitehorn 
2600d317057SNathan Whitehorn 	sc->sc_bounce_lpar = vtophys(sc->sc_bounce);
2610d317057SNathan Whitehorn 
2620d317057SNathan Whitehorn 	if (bootverbose)
2630d317057SNathan Whitehorn 		device_printf(dev, "bounce buffer lpar address 0x%016lx\n",
2640d317057SNathan Whitehorn 		    sc->sc_bounce_lpar);
2650d317057SNathan Whitehorn 
2660d317057SNathan Whitehorn 	/* Setup disks */
2670d317057SNathan Whitehorn 
2680d317057SNathan Whitehorn 	sc->sc_disk = malloc(sc->sc_nregs * sizeof(struct disk *),
2690d317057SNathan Whitehorn 	    M_PS3DISK, M_ZERO | M_WAITOK);
2700d317057SNathan Whitehorn 	if (!sc->sc_disk) {
2710d317057SNathan Whitehorn 		device_printf(dev, "Could not allocate disk(s)\n");
2720d317057SNathan Whitehorn 		err = ENOMEM;
2730d317057SNathan Whitehorn 		goto fail_unload_dmamem;
2740d317057SNathan Whitehorn 	}
2750d317057SNathan Whitehorn 
2760d317057SNathan Whitehorn 	for (i = 0; i < sc->sc_nregs; i++) {
277*dfcd47a7SNathan Whitehorn 		struct ps3disk_region *rp = &sc->sc_reg[i];
278*dfcd47a7SNathan Whitehorn 
2790d317057SNathan Whitehorn 		d = sc->sc_disk[i] = disk_alloc();
2800d317057SNathan Whitehorn 		d->d_open = ps3disk_open;
2810d317057SNathan Whitehorn 		d->d_close = ps3disk_close;
2820d317057SNathan Whitehorn 		d->d_strategy = ps3disk_strategy;
2830d317057SNathan Whitehorn 		d->d_name = "ps3disk";
2840d317057SNathan Whitehorn 		d->d_drv1 = sc;
2850d317057SNathan Whitehorn 		d->d_maxsize = DFLTPHYS;
2860d317057SNathan Whitehorn 		d->d_sectorsize = sc->sc_blksize;
2870d317057SNathan Whitehorn 		d->d_unit = i;
2880d317057SNathan Whitehorn 		d->d_mediasize = sc->sc_reg[i].r_size * sc->sc_blksize;
2890d317057SNathan Whitehorn 		d->d_flags |= DISKFLAG_CANFLUSHCACHE;
2900d317057SNathan Whitehorn 
2910d317057SNathan Whitehorn 		mb = d->d_mediasize >> 20;
2920d317057SNathan Whitehorn 		unit = 'M';
2930d317057SNathan Whitehorn 		if (mb >= 10240) {
2940d317057SNathan Whitehorn 			unit = 'G';
2950d317057SNathan Whitehorn 			mb /= 1024;
2960d317057SNathan Whitehorn 		}
2970d317057SNathan Whitehorn 
298*dfcd47a7SNathan Whitehorn 		/* Test to see if we can read this region */
299*dfcd47a7SNathan Whitehorn 		err = lv1_storage_read(ps3bus_get_device(dev), d->d_unit,
300*dfcd47a7SNathan Whitehorn 		    0, 1, rp->r_flags, sc->sc_bounce_lpar, &sc->sc_bounce_tag);
301*dfcd47a7SNathan Whitehorn 		device_printf(dev, "region %d %ju%cB%s\n", i, mb, unit,
302*dfcd47a7SNathan Whitehorn 		     (err == 0) ? "" : " (hypervisor protected)");
3030d317057SNathan Whitehorn 
304*dfcd47a7SNathan Whitehorn 		if (err == 0)
3050d317057SNathan Whitehorn 			disk_create(d, DISK_VERSION);
3060d317057SNathan Whitehorn 	}
307*dfcd47a7SNathan Whitehorn 	err = 0;
3080d317057SNathan Whitehorn 
3090d317057SNathan Whitehorn 	bioq_init(&sc->sc_bioq);
3100d317057SNathan Whitehorn 
3110d317057SNathan Whitehorn 	ps3disk_sysctlattach(sc);
3120d317057SNathan Whitehorn 
3130d317057SNathan Whitehorn 	sc->sc_running = 1;
3140d317057SNathan Whitehorn 
3150d317057SNathan Whitehorn 	kproc_create(&ps3disk_task, sc, &sc->sc_task, 0, 0, "task: ps3disk");
3160d317057SNathan Whitehorn 
3170d317057SNathan Whitehorn 	return (0);
3180d317057SNathan Whitehorn 
3190d317057SNathan Whitehorn fail_unload_dmamem:
3200d317057SNathan Whitehorn 
3210d317057SNathan Whitehorn 	bus_dmamap_unload(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap);
3220d317057SNathan Whitehorn 
3230d317057SNathan Whitehorn fail_free_dmamem:
3240d317057SNathan Whitehorn 
3250d317057SNathan Whitehorn 	bus_dmamem_free(sc->sc_bounce_dmatag, sc->sc_bounce, sc->sc_bounce_dmamap);
3260d317057SNathan Whitehorn 
3270d317057SNathan Whitehorn fail_destroy_dmatag:
3280d317057SNathan Whitehorn 
3290d317057SNathan Whitehorn 	bus_dma_tag_destroy(sc->sc_bounce_dmatag);
3300d317057SNathan Whitehorn 
3310d317057SNathan Whitehorn fail_teardown_intr:
3320d317057SNathan Whitehorn 
3330d317057SNathan Whitehorn 	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
3340d317057SNathan Whitehorn 
3350d317057SNathan Whitehorn fail_release_intr:
3360d317057SNathan Whitehorn 
3370d317057SNathan Whitehorn 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
3380d317057SNathan Whitehorn 
3390d317057SNathan Whitehorn fail_free_regions:
3400d317057SNathan Whitehorn 
3410d317057SNathan Whitehorn 	free(sc->sc_reg, M_PS3DISK);
3420d317057SNathan Whitehorn 
3430d317057SNathan Whitehorn fail_destroy_lock:
3440d317057SNathan Whitehorn 
3450d317057SNathan Whitehorn 	PS3DISK_LOCK_DESTROY(sc);
3460d317057SNathan Whitehorn 
3470d317057SNathan Whitehorn 	return (err);
3480d317057SNathan Whitehorn }
3490d317057SNathan Whitehorn 
3500d317057SNathan Whitehorn static int
3510d317057SNathan Whitehorn ps3disk_detach(device_t dev)
3520d317057SNathan Whitehorn {
3530d317057SNathan Whitehorn 	struct ps3disk_softc *sc = device_get_softc(dev);
3540d317057SNathan Whitehorn 	int i;
3550d317057SNathan Whitehorn 
3560d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
3570d317057SNathan Whitehorn 	sc->sc_running = 0;
3580d317057SNathan Whitehorn 	wakeup(sc);
3590d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
3600d317057SNathan Whitehorn 
3610d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
3620d317057SNathan Whitehorn 	while (sc->sc_running != -1)
3630d317057SNathan Whitehorn 		msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0);
3640d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
3650d317057SNathan Whitehorn 
3660d317057SNathan Whitehorn 	for (i = 0; i < sc->sc_nregs; i++)
3670d317057SNathan Whitehorn 		disk_destroy(sc->sc_disk[i]);
3680d317057SNathan Whitehorn 
3690d317057SNathan Whitehorn 	bus_dmamap_unload(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap);
3700d317057SNathan Whitehorn 	bus_dmamem_free(sc->sc_bounce_dmatag, sc->sc_bounce, sc->sc_bounce_dmamap);
3710d317057SNathan Whitehorn 	bus_dma_tag_destroy(sc->sc_bounce_dmatag);
3720d317057SNathan Whitehorn 
3730d317057SNathan Whitehorn 	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
3740d317057SNathan Whitehorn 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
3750d317057SNathan Whitehorn 
3760d317057SNathan Whitehorn 	free(sc->sc_disk, M_PS3DISK);
3770d317057SNathan Whitehorn 
3780d317057SNathan Whitehorn 	free(sc->sc_reg, M_PS3DISK);
3790d317057SNathan Whitehorn 
3800d317057SNathan Whitehorn 	PS3DISK_LOCK_DESTROY(sc);
3810d317057SNathan Whitehorn 
3820d317057SNathan Whitehorn 	return (0);
3830d317057SNathan Whitehorn }
3840d317057SNathan Whitehorn 
3850d317057SNathan Whitehorn static int
3860d317057SNathan Whitehorn ps3disk_open(struct disk *dp)
3870d317057SNathan Whitehorn {
3880d317057SNathan Whitehorn 	return (0);
3890d317057SNathan Whitehorn }
3900d317057SNathan Whitehorn 
3910d317057SNathan Whitehorn static int
3920d317057SNathan Whitehorn ps3disk_close(struct disk *dp)
3930d317057SNathan Whitehorn {
3940d317057SNathan Whitehorn 	return (0);
3950d317057SNathan Whitehorn }
3960d317057SNathan Whitehorn 
3970d317057SNathan Whitehorn static void
3980d317057SNathan Whitehorn ps3disk_strategy(struct bio *bp)
3990d317057SNathan Whitehorn {
4000d317057SNathan Whitehorn 	struct ps3disk_softc *sc = (struct ps3disk_softc *) bp->bio_disk->d_drv1;
4010d317057SNathan Whitehorn 
4020d317057SNathan Whitehorn 	if (!sc) {
4030d317057SNathan Whitehorn 		bp->bio_flags |= BIO_ERROR;
4040d317057SNathan Whitehorn 		bp->bio_error = EINVAL;
4050d317057SNathan Whitehorn 		biodone(bp);
4060d317057SNathan Whitehorn 		return;
4070d317057SNathan Whitehorn 	}
4080d317057SNathan Whitehorn 
4090d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
4100d317057SNathan Whitehorn 	bioq_disksort(&sc->sc_bioq, bp);
4110d317057SNathan Whitehorn 	if (!sc->sc_bounce_busy)
4120d317057SNathan Whitehorn 		wakeup(sc);
4130d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
4140d317057SNathan Whitehorn }
4150d317057SNathan Whitehorn 
4160d317057SNathan Whitehorn static void
4170d317057SNathan Whitehorn ps3disk_task(void *arg)
4180d317057SNathan Whitehorn {
4190d317057SNathan Whitehorn 	struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
4200d317057SNathan Whitehorn 	struct bio *bp;
4210d317057SNathan Whitehorn 	daddr_t block, end;
4220d317057SNathan Whitehorn 	u_long nblocks;
4230d317057SNathan Whitehorn 	char *data;
4240d317057SNathan Whitehorn 	int err;
4250d317057SNathan Whitehorn 
4260d317057SNathan Whitehorn 	while (sc->sc_running) {
4270d317057SNathan Whitehorn 		PS3DISK_LOCK(sc);
4280d317057SNathan Whitehorn 		do {
4290d317057SNathan Whitehorn 			bp = bioq_first(&sc->sc_bioq);
4300d317057SNathan Whitehorn 			if (bp == NULL)
4310d317057SNathan Whitehorn 				msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0);
4320d317057SNathan Whitehorn 		} while (bp == NULL && sc->sc_running);
4330d317057SNathan Whitehorn 		if (bp)
4340d317057SNathan Whitehorn 			bioq_remove(&sc->sc_bioq, bp);
4350d317057SNathan Whitehorn 		PS3DISK_UNLOCK(sc);
4360d317057SNathan Whitehorn 
4370d317057SNathan Whitehorn 		if (!sc->sc_running)
4380d317057SNathan Whitehorn 			break;
4390d317057SNathan Whitehorn 
4400d317057SNathan Whitehorn 		DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_cmd 0x%02x\n",
4410d317057SNathan Whitehorn 	 	    __func__, bp->bio_cmd);
4420d317057SNathan Whitehorn 
4430d317057SNathan Whitehorn 		if (bp->bio_cmd == BIO_FLUSH) {
4440d317057SNathan Whitehorn 			err = ps3disk_flush(sc);
4450d317057SNathan Whitehorn 
4460d317057SNathan Whitehorn 			if (err) {
4470d317057SNathan Whitehorn 				bp->bio_error = EIO;
4480d317057SNathan Whitehorn 				bp->bio_flags |= BIO_ERROR;
4490d317057SNathan Whitehorn 			} else {
4500d317057SNathan Whitehorn 				bp->bio_error = 0;
4510d317057SNathan Whitehorn 				bp->bio_flags |= BIO_DONE;
4520d317057SNathan Whitehorn 			}
4530d317057SNathan Whitehorn 		} else if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
4540d317057SNathan Whitehorn 			end = bp->bio_pblkno + (bp->bio_bcount / sc->sc_blksize);
4550d317057SNathan Whitehorn 
4560d317057SNathan Whitehorn 			DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_pblkno %ld bio_bcount %ld\n",
4570d317057SNathan Whitehorn 	 		    __func__, bp->bio_pblkno, bp->bio_bcount);
4580d317057SNathan Whitehorn 
4590d317057SNathan Whitehorn 			for (block = bp->bio_pblkno; block < end;) {
4600d317057SNathan Whitehorn 				data = bp->bio_data +
4610d317057SNathan Whitehorn 				    (block - bp->bio_pblkno) * sc->sc_blksize;
4620d317057SNathan Whitehorn 
4630d317057SNathan Whitehorn 				nblocks = end - block;
4640d317057SNathan Whitehorn 				if (nblocks > sc->sc_bounce_maxblocks)
4650d317057SNathan Whitehorn 					nblocks = sc->sc_bounce_maxblocks;
4660d317057SNathan Whitehorn 
4670d317057SNathan Whitehorn 				DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: nblocks %lu\n",
4680d317057SNathan Whitehorn 	 			    __func__, nblocks);
4690d317057SNathan Whitehorn 
4700d317057SNathan Whitehorn 				if (bp->bio_cmd == BIO_READ) {
4710d317057SNathan Whitehorn 					err = ps3disk_read(sc, bp->bio_disk->d_unit,
4720d317057SNathan Whitehorn 					    block, nblocks, data);
4730d317057SNathan Whitehorn 				} else {
4740d317057SNathan Whitehorn 					err = ps3disk_write(sc, bp->bio_disk->d_unit,
4750d317057SNathan Whitehorn 					    block, nblocks, data);
4760d317057SNathan Whitehorn 				}
4770d317057SNathan Whitehorn 
4780d317057SNathan Whitehorn 				if (err)
4790d317057SNathan Whitehorn 					break;
4800d317057SNathan Whitehorn 
4810d317057SNathan Whitehorn 				block += nblocks;
4820d317057SNathan Whitehorn 			}
4830d317057SNathan Whitehorn 
4840d317057SNathan Whitehorn 			bp->bio_resid = (end - block) * sc->sc_blksize;
4850d317057SNathan Whitehorn 			if (bp->bio_resid) {
4860d317057SNathan Whitehorn 				bp->bio_error = EIO;
4870d317057SNathan Whitehorn 				bp->bio_flags |= BIO_ERROR;
4880d317057SNathan Whitehorn 			} else {
4890d317057SNathan Whitehorn 				bp->bio_error = 0;
4900d317057SNathan Whitehorn 				bp->bio_flags |= BIO_DONE;
4910d317057SNathan Whitehorn 			}
4920d317057SNathan Whitehorn 
4930d317057SNathan Whitehorn 			DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_resid %ld\n",
4940d317057SNathan Whitehorn 	 		    __func__, bp->bio_resid);
4950d317057SNathan Whitehorn 		} else {
4960d317057SNathan Whitehorn 			bp->bio_error = EINVAL;
4970d317057SNathan Whitehorn 			bp->bio_flags |= BIO_ERROR;
4980d317057SNathan Whitehorn 		}
4990d317057SNathan Whitehorn 
5000d317057SNathan Whitehorn 		if (bp->bio_flags & BIO_ERROR)
5010d317057SNathan Whitehorn 			disk_err(bp, "hard error", -1, 1);
5020d317057SNathan Whitehorn 
5030d317057SNathan Whitehorn 		biodone(bp);
5040d317057SNathan Whitehorn 	}
5050d317057SNathan Whitehorn 
5060d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
5070d317057SNathan Whitehorn 	sc->sc_running = -1;
5080d317057SNathan Whitehorn 	wakeup(sc);
5090d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
5100d317057SNathan Whitehorn 
5110d317057SNathan Whitehorn 	kproc_exit(0);
5120d317057SNathan Whitehorn }
5130d317057SNathan Whitehorn 
5140d317057SNathan Whitehorn static int
5150d317057SNathan Whitehorn ps3disk_intr_filter(void *arg)
5160d317057SNathan Whitehorn {
5170d317057SNathan Whitehorn 	return (FILTER_SCHEDULE_THREAD);
5180d317057SNathan Whitehorn }
5190d317057SNathan Whitehorn 
5200d317057SNathan Whitehorn static void
5210d317057SNathan Whitehorn ps3disk_intr(void *arg)
5220d317057SNathan Whitehorn {
5230d317057SNathan Whitehorn 	struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
5240d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
5250d317057SNathan Whitehorn 	uint64_t devid = ps3bus_get_device(dev);
5260d317057SNathan Whitehorn 	uint64_t tag, status;
5270d317057SNathan Whitehorn 	int err;
5280d317057SNathan Whitehorn 
5290d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
5300d317057SNathan Whitehorn 
5310d317057SNathan Whitehorn 	err = lv1_storage_get_async_status(devid, &tag, &status);
5320d317057SNathan Whitehorn 
5330d317057SNathan Whitehorn 	DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: err %d tag 0x%016lx status 0x%016lx\n",
5340d317057SNathan Whitehorn 	    __func__, err, tag, status);
5350d317057SNathan Whitehorn 
5360d317057SNathan Whitehorn 	if (err)
5370d317057SNathan Whitehorn 		goto out;
5380d317057SNathan Whitehorn 
5390d317057SNathan Whitehorn 	if (!sc->sc_bounce_busy) {
5400d317057SNathan Whitehorn 		device_printf(dev, "Got interrupt while no request pending\n");
5410d317057SNathan Whitehorn 		goto out;
5420d317057SNathan Whitehorn 	}
5430d317057SNathan Whitehorn 
5440d317057SNathan Whitehorn 	if (tag != sc->sc_bounce_tag)
5450d317057SNathan Whitehorn 		device_printf(dev, "Tag mismatch, got 0x%016lx expected 0x%016lx\n",
5460d317057SNathan Whitehorn 		    tag, sc->sc_bounce_tag);
5470d317057SNathan Whitehorn 
5480d317057SNathan Whitehorn 	if (status)
5490d317057SNathan Whitehorn 		device_printf(dev, "Request completed with status 0x%016lx\n", status);
5500d317057SNathan Whitehorn 
5510d317057SNathan Whitehorn 	sc->sc_bounce_status = status;
5520d317057SNathan Whitehorn 	sc->sc_bounce_busy = 0;
5530d317057SNathan Whitehorn 
5540d317057SNathan Whitehorn 	wakeup(sc);
5550d317057SNathan Whitehorn 
5560d317057SNathan Whitehorn out:
5570d317057SNathan Whitehorn 
5580d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
5590d317057SNathan Whitehorn }
5600d317057SNathan Whitehorn 
5610d317057SNathan Whitehorn static void
5620d317057SNathan Whitehorn ps3disk_getphys(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
5630d317057SNathan Whitehorn {
5640d317057SNathan Whitehorn 	if (error != 0)
5650d317057SNathan Whitehorn 		return;
5660d317057SNathan Whitehorn 
5670d317057SNathan Whitehorn 	*(bus_addr_t *) arg = segs[0].ds_addr;
5680d317057SNathan Whitehorn }
5690d317057SNathan Whitehorn 
5700d317057SNathan Whitehorn static int
5710d317057SNathan Whitehorn ps3disk_get_disk_geometry(struct ps3disk_softc *sc)
5720d317057SNathan Whitehorn {
5730d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
5740d317057SNathan Whitehorn 	uint64_t bus_index = ps3bus_get_busidx(dev);
5750d317057SNathan Whitehorn 	uint64_t dev_index = ps3bus_get_devidx(dev);
5760d317057SNathan Whitehorn 	uint64_t junk;
5770d317057SNathan Whitehorn 	int err;
5780d317057SNathan Whitehorn 
5790d317057SNathan Whitehorn 	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
5800d317057SNathan Whitehorn 	    (lv1_repository_string("bus") >> 32) | bus_index,
5810d317057SNathan Whitehorn 	    lv1_repository_string("dev") | dev_index,
5820d317057SNathan Whitehorn 	    lv1_repository_string("blk_size"), 0, &sc->sc_blksize, &junk);
5830d317057SNathan Whitehorn 	if (err) {
5840d317057SNathan Whitehorn 		device_printf(dev, "Could not get block size (0x%08x)\n", err);
5850d317057SNathan Whitehorn 		err = ENXIO;
5860d317057SNathan Whitehorn 		goto out;
5870d317057SNathan Whitehorn 	}
5880d317057SNathan Whitehorn 
5890d317057SNathan Whitehorn 	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
5900d317057SNathan Whitehorn 	    (lv1_repository_string("bus") >> 32) | bus_index,
5910d317057SNathan Whitehorn 	    lv1_repository_string("dev") | dev_index,
5920d317057SNathan Whitehorn 	    lv1_repository_string("n_blocks"), 0, &sc->sc_nblocks, &junk);
5930d317057SNathan Whitehorn 	if (err) {
5940d317057SNathan Whitehorn 		device_printf(dev, "Could not get total number of blocks (0x%08x)\n",
5950d317057SNathan Whitehorn 		    err);
5960d317057SNathan Whitehorn 		err = ENXIO;
5970d317057SNathan Whitehorn 		goto out;
5980d317057SNathan Whitehorn 	}
5990d317057SNathan Whitehorn 
6000d317057SNathan Whitehorn 	err = 0;
6010d317057SNathan Whitehorn 
6020d317057SNathan Whitehorn out:
6030d317057SNathan Whitehorn 
6040d317057SNathan Whitehorn 	return (err);
6050d317057SNathan Whitehorn }
6060d317057SNathan Whitehorn 
6070d317057SNathan Whitehorn static int
6080d317057SNathan Whitehorn ps3disk_enum_regions(struct ps3disk_softc *sc)
6090d317057SNathan Whitehorn {
6100d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
6110d317057SNathan Whitehorn 	uint64_t bus_index = ps3bus_get_busidx(dev);
6120d317057SNathan Whitehorn 	uint64_t dev_index = ps3bus_get_devidx(dev);
6130d317057SNathan Whitehorn 	uint64_t junk;
6140d317057SNathan Whitehorn 	int i, err;
6150d317057SNathan Whitehorn 
6160d317057SNathan Whitehorn 	/* Read number of regions */
6170d317057SNathan Whitehorn 
6180d317057SNathan Whitehorn 	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
6190d317057SNathan Whitehorn 	    (lv1_repository_string("bus") >> 32) | bus_index,
6200d317057SNathan Whitehorn 	    lv1_repository_string("dev") | dev_index,
6210d317057SNathan Whitehorn 	    lv1_repository_string("n_regs"), 0, &sc->sc_nregs, &junk);
6220d317057SNathan Whitehorn 	if (err) {
6230d317057SNathan Whitehorn 		device_printf(dev, "Could not get number of regions (0x%08x)\n",
6240d317057SNathan Whitehorn 		    err);
6250d317057SNathan Whitehorn 		err = ENXIO;
6260d317057SNathan Whitehorn 		goto fail;
6270d317057SNathan Whitehorn 	}
6280d317057SNathan Whitehorn 
6290d317057SNathan Whitehorn 	if (!sc->sc_nregs)
6300d317057SNathan Whitehorn 		return 0;
6310d317057SNathan Whitehorn 
6320d317057SNathan Whitehorn 	sc->sc_reg = malloc(sc->sc_nregs * sizeof(struct ps3disk_region),
6330d317057SNathan Whitehorn 	    M_PS3DISK, M_ZERO | M_WAITOK);
6340d317057SNathan Whitehorn 	if (!sc->sc_reg) {
6350d317057SNathan Whitehorn 		err = ENOMEM;
6360d317057SNathan Whitehorn 		goto fail;
6370d317057SNathan Whitehorn 	}
6380d317057SNathan Whitehorn 
6390d317057SNathan Whitehorn 	/* Setup regions */
6400d317057SNathan Whitehorn 
6410d317057SNathan Whitehorn 	for (i = 0; i < sc->sc_nregs; i++) {
6420d317057SNathan Whitehorn 		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
6430d317057SNathan Whitehorn 		    (lv1_repository_string("bus") >> 32) | bus_index,
6440d317057SNathan Whitehorn 		    lv1_repository_string("dev") | dev_index,
6450d317057SNathan Whitehorn 		    lv1_repository_string("region") | i,
6460d317057SNathan Whitehorn 		    lv1_repository_string("id"), &sc->sc_reg[i].r_id, &junk);
6470d317057SNathan Whitehorn 		if (err) {
6480d317057SNathan Whitehorn 			device_printf(dev, "Could not get region id (0x%08x)\n",
6490d317057SNathan Whitehorn 			    err);
6500d317057SNathan Whitehorn 			err = ENXIO;
6510d317057SNathan Whitehorn 			goto fail;
6520d317057SNathan Whitehorn 		}
6530d317057SNathan Whitehorn 
6540d317057SNathan Whitehorn 		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
6550d317057SNathan Whitehorn 		    (lv1_repository_string("bus") >> 32) | bus_index,
6560d317057SNathan Whitehorn 		    lv1_repository_string("dev") | dev_index,
6570d317057SNathan Whitehorn 		    lv1_repository_string("region") | i,
6580d317057SNathan Whitehorn 		    lv1_repository_string("start"), &sc->sc_reg[i].r_start, &junk);
6590d317057SNathan Whitehorn 		if (err) {
6600d317057SNathan Whitehorn 			device_printf(dev, "Could not get region start (0x%08x)\n",
6610d317057SNathan Whitehorn 			    err);
6620d317057SNathan Whitehorn 			err = ENXIO;
6630d317057SNathan Whitehorn 			goto fail;
6640d317057SNathan Whitehorn 		}
6650d317057SNathan Whitehorn 
6660d317057SNathan Whitehorn 		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
6670d317057SNathan Whitehorn 		    (lv1_repository_string("bus") >> 32) | bus_index,
6680d317057SNathan Whitehorn 		    lv1_repository_string("dev") | dev_index,
6690d317057SNathan Whitehorn 		    lv1_repository_string("region") | i,
6700d317057SNathan Whitehorn 		    lv1_repository_string("size"), &sc->sc_reg[i].r_size, &junk);
6710d317057SNathan Whitehorn 		if (err) {
6720d317057SNathan Whitehorn 			device_printf(dev, "Could not get region size (0x%08x)\n",
6730d317057SNathan Whitehorn 			    err);
6740d317057SNathan Whitehorn 			err = ENXIO;
6750d317057SNathan Whitehorn 			goto fail;
6760d317057SNathan Whitehorn 		}
6770d317057SNathan Whitehorn 
6780d317057SNathan Whitehorn 		if (i == 0)
6790d317057SNathan Whitehorn 			/* disables HV access control and grants access to whole disk */
6800d317057SNathan Whitehorn 			sc->sc_reg[i].r_flags = 0x2;
6810d317057SNathan Whitehorn 		else
6820d317057SNathan Whitehorn 			sc->sc_reg[i].r_flags = 0;
6830d317057SNathan Whitehorn 	}
6840d317057SNathan Whitehorn 
6850d317057SNathan Whitehorn 	return (0);
6860d317057SNathan Whitehorn 
6870d317057SNathan Whitehorn fail:
6880d317057SNathan Whitehorn 
6890d317057SNathan Whitehorn 	sc->sc_nregs = 0;
6900d317057SNathan Whitehorn 	if (sc->sc_reg)
6910d317057SNathan Whitehorn 		free(sc->sc_reg, M_PS3DISK);
6920d317057SNathan Whitehorn 
6930d317057SNathan Whitehorn 	return (err);
6940d317057SNathan Whitehorn }
6950d317057SNathan Whitehorn 
6960d317057SNathan Whitehorn static int
6970d317057SNathan Whitehorn ps3disk_read(struct ps3disk_softc *sc, int regidx,
6980d317057SNathan Whitehorn 	uint64_t start_sector, uint64_t sector_count, char *data)
6990d317057SNathan Whitehorn {
7000d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
7010d317057SNathan Whitehorn 	struct ps3disk_region *rp = &sc->sc_reg[regidx];
7020d317057SNathan Whitehorn 	uint64_t devid = ps3bus_get_device(dev);
7030d317057SNathan Whitehorn 	int err;
7040d317057SNathan Whitehorn 
7050d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
7060d317057SNathan Whitehorn 
7070d317057SNathan Whitehorn 	if (sc->sc_bounce_busy) {
7080d317057SNathan Whitehorn 		device_printf(dev, "busy\n");
7090d317057SNathan Whitehorn 		PS3DISK_UNLOCK(sc);
7100d317057SNathan Whitehorn 		return EIO;
7110d317057SNathan Whitehorn 	}
7120d317057SNathan Whitehorn 
7130d317057SNathan Whitehorn 	sc->sc_bounce_busy = 1;
7140d317057SNathan Whitehorn 
7150d317057SNathan Whitehorn 	err = lv1_storage_read(devid, rp->r_id,
7160d317057SNathan Whitehorn 	    start_sector, sector_count, rp->r_flags,
7170d317057SNathan Whitehorn 	    sc->sc_bounce_lpar, &sc->sc_bounce_tag);
7180d317057SNathan Whitehorn 	if (err) {
7190d317057SNathan Whitehorn 		device_printf(dev, "Could not read sectors (0x%08x)\n", err);
7200d317057SNathan Whitehorn 		err = EIO;
7210d317057SNathan Whitehorn 		goto out;
7220d317057SNathan Whitehorn 	}
7230d317057SNathan Whitehorn 
7240d317057SNathan Whitehorn 	DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n",
7250d317057SNathan Whitehorn 	    __func__, sc->sc_bounce_tag);
7260d317057SNathan Whitehorn 
7270d317057SNathan Whitehorn 	err = msleep(sc, &sc->sc_mtx, PRIBIO, "read", hz);
7280d317057SNathan Whitehorn 	if (err) {
7290d317057SNathan Whitehorn 		device_printf(dev, "Read request timed out\n");
7300d317057SNathan Whitehorn 		err = EIO;
7310d317057SNathan Whitehorn 		goto out;
7320d317057SNathan Whitehorn 	}
7330d317057SNathan Whitehorn 
7340d317057SNathan Whitehorn 	if (sc->sc_bounce_busy || sc->sc_bounce_status) {
7350d317057SNathan Whitehorn 		err = EIO;
7360d317057SNathan Whitehorn 	} else {
7370d317057SNathan Whitehorn 		bus_dmamap_sync(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap,
7380d317057SNathan Whitehorn 		    BUS_DMASYNC_POSTREAD);
7390d317057SNathan Whitehorn 		memcpy(data, sc->sc_bounce, sector_count * sc->sc_blksize);
7400d317057SNathan Whitehorn 		err = 0;
7410d317057SNathan Whitehorn 	}
7420d317057SNathan Whitehorn 
7430d317057SNathan Whitehorn out:
7440d317057SNathan Whitehorn 
7450d317057SNathan Whitehorn 	sc->sc_bounce_busy = 0;
7460d317057SNathan Whitehorn 
7470d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
7480d317057SNathan Whitehorn 
7490d317057SNathan Whitehorn 	return (err);
7500d317057SNathan Whitehorn }
7510d317057SNathan Whitehorn 
7520d317057SNathan Whitehorn static int
7530d317057SNathan Whitehorn ps3disk_write(struct ps3disk_softc *sc, int regidx,
7540d317057SNathan Whitehorn 	uint64_t start_sector, uint64_t sector_count, char *data)
7550d317057SNathan Whitehorn {
7560d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
7570d317057SNathan Whitehorn 	struct ps3disk_region *rp = &sc->sc_reg[regidx];
7580d317057SNathan Whitehorn 	uint64_t devid = ps3bus_get_device(dev);
7590d317057SNathan Whitehorn 	int err;
7600d317057SNathan Whitehorn 
7610d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
7620d317057SNathan Whitehorn 
7630d317057SNathan Whitehorn 	if (sc->sc_bounce_busy) {
7640d317057SNathan Whitehorn 		device_printf(dev, "busy\n");
7650d317057SNathan Whitehorn 		PS3DISK_UNLOCK(sc);
7660d317057SNathan Whitehorn 		return EIO;
7670d317057SNathan Whitehorn 	}
7680d317057SNathan Whitehorn 
7690d317057SNathan Whitehorn 	memcpy(sc->sc_bounce, data, sector_count * sc->sc_blksize);
7700d317057SNathan Whitehorn 
7710d317057SNathan Whitehorn 	bus_dmamap_sync(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap,
7720d317057SNathan Whitehorn 	    BUS_DMASYNC_PREWRITE);
7730d317057SNathan Whitehorn 
7740d317057SNathan Whitehorn 	sc->sc_bounce_busy = 1;
7750d317057SNathan Whitehorn 
7760d317057SNathan Whitehorn 	err = lv1_storage_write(devid, rp->r_id,
7770d317057SNathan Whitehorn 	    start_sector, sector_count, rp->r_flags,
7780d317057SNathan Whitehorn 	    sc->sc_bounce_lpar, &sc->sc_bounce_tag);
7790d317057SNathan Whitehorn 	if (err) {
7800d317057SNathan Whitehorn 		device_printf(dev, "Could not write sectors (0x%08x)\n", err);
7810d317057SNathan Whitehorn 		err = EIO;
7820d317057SNathan Whitehorn 		goto out;
7830d317057SNathan Whitehorn 	}
7840d317057SNathan Whitehorn 
7850d317057SNathan Whitehorn 	DPRINTF(sc, PS3DISK_DEBUG_WRITE, "%s: tag 0x%016lx\n",
7860d317057SNathan Whitehorn 	    __func__, sc->sc_bounce_tag);
7870d317057SNathan Whitehorn 
7880d317057SNathan Whitehorn 	err = msleep(sc, &sc->sc_mtx, PRIBIO, "write", hz);
7890d317057SNathan Whitehorn 	if (err) {
7900d317057SNathan Whitehorn 		device_printf(dev, "Write request timed out\n");
7910d317057SNathan Whitehorn 		err = EIO;
7920d317057SNathan Whitehorn 		goto out;
7930d317057SNathan Whitehorn 	}
7940d317057SNathan Whitehorn 
7950d317057SNathan Whitehorn 	err = (sc->sc_bounce_busy || sc->sc_bounce_status) ? EIO : 0;
7960d317057SNathan Whitehorn 
7970d317057SNathan Whitehorn out:
7980d317057SNathan Whitehorn 
7990d317057SNathan Whitehorn 	sc->sc_bounce_busy = 0;
8000d317057SNathan Whitehorn 
8010d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
8020d317057SNathan Whitehorn 
8030d317057SNathan Whitehorn 	return (err);
8040d317057SNathan Whitehorn }
8050d317057SNathan Whitehorn 
8060d317057SNathan Whitehorn static int
8070d317057SNathan Whitehorn ps3disk_flush(struct ps3disk_softc *sc)
8080d317057SNathan Whitehorn {
8090d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
8100d317057SNathan Whitehorn 	uint64_t devid = ps3bus_get_device(dev);
8110d317057SNathan Whitehorn 	int err;
8120d317057SNathan Whitehorn 
8130d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
8140d317057SNathan Whitehorn 
8150d317057SNathan Whitehorn 	if (sc->sc_bounce_busy) {
8160d317057SNathan Whitehorn 		device_printf(dev, "busy\n");
8170d317057SNathan Whitehorn 		PS3DISK_UNLOCK(sc);
8180d317057SNathan Whitehorn 		return EIO;
8190d317057SNathan Whitehorn 	}
8200d317057SNathan Whitehorn 
8210d317057SNathan Whitehorn 	sc->sc_bounce_busy = 1;
8220d317057SNathan Whitehorn 
8230d317057SNathan Whitehorn 	err = lv1_storage_send_device_command(devid, LV1_STORAGE_ATA_HDDOUT,
8240d317057SNathan Whitehorn 	    0, 0, 0, 0, &sc->sc_bounce_tag);
8250d317057SNathan Whitehorn 	if (err) {
8260d317057SNathan Whitehorn 		device_printf(dev, "Could not flush (0x%08x)\n", err);
8270d317057SNathan Whitehorn 		err = EIO;
8280d317057SNathan Whitehorn 		goto out;
8290d317057SNathan Whitehorn 	}
8300d317057SNathan Whitehorn 
8310d317057SNathan Whitehorn 	DPRINTF(sc, PS3DISK_DEBUG_FLUSH, "%s: tag 0x%016lx\n",
8320d317057SNathan Whitehorn 	    __func__, sc->sc_bounce_tag);
8330d317057SNathan Whitehorn 
8340d317057SNathan Whitehorn 	err = msleep(sc, &sc->sc_mtx, PRIBIO, "flush", hz);
8350d317057SNathan Whitehorn 	if (err) {
8360d317057SNathan Whitehorn 		device_printf(dev, "Flush request timed out\n");
8370d317057SNathan Whitehorn 		err = EIO;
8380d317057SNathan Whitehorn 		goto out;
8390d317057SNathan Whitehorn 	}
8400d317057SNathan Whitehorn 
8410d317057SNathan Whitehorn 	err = (sc->sc_bounce_busy || sc->sc_bounce_status) ? EIO : 0;
8420d317057SNathan Whitehorn 
8430d317057SNathan Whitehorn out:
8440d317057SNathan Whitehorn 
8450d317057SNathan Whitehorn 	sc->sc_bounce_busy = 0;
8460d317057SNathan Whitehorn 
8470d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
8480d317057SNathan Whitehorn 
8490d317057SNathan Whitehorn 	return (err);
8500d317057SNathan Whitehorn }
8510d317057SNathan Whitehorn 
8520d317057SNathan Whitehorn #ifdef PS3DISK_DEBUG
8530d317057SNathan Whitehorn static int
8540d317057SNathan Whitehorn ps3disk_sysctl_debug(SYSCTL_HANDLER_ARGS)
8550d317057SNathan Whitehorn {
8560d317057SNathan Whitehorn 	struct ps3disk_softc *sc = arg1;
8570d317057SNathan Whitehorn 	int debug, error;
8580d317057SNathan Whitehorn 
8590d317057SNathan Whitehorn 	debug = sc->sc_debug;
8600d317057SNathan Whitehorn 
8610d317057SNathan Whitehorn 	error = sysctl_handle_int(oidp, &debug, 0, req);
8620d317057SNathan Whitehorn 	if (error || !req->newptr)
8630d317057SNathan Whitehorn 		return error;
8640d317057SNathan Whitehorn 
8650d317057SNathan Whitehorn 	sc->sc_debug = debug;
8660d317057SNathan Whitehorn 
8670d317057SNathan Whitehorn 	return 0;
8680d317057SNathan Whitehorn }
8690d317057SNathan Whitehorn #endif
8700d317057SNathan Whitehorn 
8710d317057SNathan Whitehorn static void
8720d317057SNathan Whitehorn ps3disk_sysctlattach(struct ps3disk_softc *sc)
8730d317057SNathan Whitehorn {
8740d317057SNathan Whitehorn #ifdef PS3DISK_DEBUG
8750d317057SNathan Whitehorn 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
8760d317057SNathan Whitehorn 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
8770d317057SNathan Whitehorn 
8780d317057SNathan Whitehorn 	sc->sc_debug = ps3disk_debug;
8790d317057SNathan Whitehorn 
8800d317057SNathan Whitehorn 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
8810d317057SNathan Whitehorn 		"debug", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
8820d317057SNathan Whitehorn 		ps3disk_sysctl_debug, "I", "control debugging printfs");
8830d317057SNathan Whitehorn #endif
8840d317057SNathan Whitehorn }
8850d317057SNathan Whitehorn 
8860d317057SNathan Whitehorn static device_method_t ps3disk_methods[] = {
8870d317057SNathan Whitehorn 	DEVMETHOD(device_probe,		ps3disk_probe),
8880d317057SNathan Whitehorn 	DEVMETHOD(device_attach,	ps3disk_attach),
8890d317057SNathan Whitehorn 	DEVMETHOD(device_detach,	ps3disk_detach),
8900d317057SNathan Whitehorn 	{0, 0},
8910d317057SNathan Whitehorn };
8920d317057SNathan Whitehorn 
8930d317057SNathan Whitehorn static driver_t ps3disk_driver = {
8940d317057SNathan Whitehorn 	"ps3disk",
8950d317057SNathan Whitehorn 	ps3disk_methods,
8960d317057SNathan Whitehorn 	sizeof(struct ps3disk_softc),
8970d317057SNathan Whitehorn };
8980d317057SNathan Whitehorn 
8990d317057SNathan Whitehorn static devclass_t ps3disk_devclass;
9000d317057SNathan Whitehorn 
9010d317057SNathan Whitehorn DRIVER_MODULE(ps3disk, ps3bus, ps3disk_driver, ps3disk_devclass, 0, 0);
902