xref: /freebsd/sys/powerpc/ps3/ps3disk.c (revision 7029da5c36f2d3cf6bb6c81bf551229f416399e8)
10d317057SNathan Whitehorn /*-
271e3c308SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
371e3c308SPedro F. Giffuni  *
40d317057SNathan Whitehorn  * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru)
50d317057SNathan Whitehorn  * All rights reserved.
60d317057SNathan Whitehorn  *
70d317057SNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
80d317057SNathan Whitehorn  * modification, are permitted provided that the following conditions
90d317057SNathan Whitehorn  * are met:
100d317057SNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
110d317057SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
120d317057SNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
130d317057SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
140d317057SNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
150d317057SNathan Whitehorn  *
160d317057SNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
170d317057SNathan Whitehorn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
180d317057SNathan Whitehorn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
190d317057SNathan Whitehorn  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
200d317057SNathan Whitehorn  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
210d317057SNathan Whitehorn  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
220d317057SNathan Whitehorn  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
230d317057SNathan Whitehorn  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
240d317057SNathan Whitehorn  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
250d317057SNathan Whitehorn  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
260d317057SNathan Whitehorn  *
270d317057SNathan Whitehorn  */
280d317057SNathan Whitehorn 
290d317057SNathan Whitehorn #include <sys/cdefs.h>
300d317057SNathan Whitehorn __FBSDID("$FreeBSD$");
310d317057SNathan Whitehorn 
320d317057SNathan Whitehorn #include <sys/param.h>
330d317057SNathan Whitehorn #include <sys/systm.h>
340d317057SNathan Whitehorn #include <sys/sysctl.h>
350d317057SNathan Whitehorn #include <sys/disk.h>
360d317057SNathan Whitehorn #include <sys/bio.h>
370d317057SNathan Whitehorn #include <sys/bus.h>
380d317057SNathan Whitehorn #include <sys/conf.h>
390d317057SNathan Whitehorn #include <sys/kernel.h>
400d317057SNathan Whitehorn #include <sys/kthread.h>
410d317057SNathan Whitehorn #include <sys/lock.h>
420d317057SNathan Whitehorn #include <sys/malloc.h>
430d317057SNathan Whitehorn #include <sys/module.h>
440d317057SNathan Whitehorn #include <sys/mutex.h>
450d317057SNathan Whitehorn 
460d317057SNathan Whitehorn #include <vm/vm.h>
470d317057SNathan Whitehorn #include <vm/pmap.h>
480d317057SNathan Whitehorn 
490d317057SNathan Whitehorn #include <machine/pio.h>
500d317057SNathan Whitehorn #include <machine/bus.h>
510d317057SNathan Whitehorn #include <machine/platform.h>
520d317057SNathan Whitehorn #include <machine/resource.h>
530d317057SNathan Whitehorn #include <sys/bus.h>
540d317057SNathan Whitehorn #include <sys/rman.h>
550d317057SNathan Whitehorn 
560d317057SNathan Whitehorn #include <geom/geom_disk.h>
570d317057SNathan Whitehorn 
580d317057SNathan Whitehorn #include "ps3bus.h"
590d317057SNathan Whitehorn #include "ps3-hvcall.h"
600d317057SNathan Whitehorn 
610d317057SNathan Whitehorn #define PS3DISK_LOCK_INIT(_sc)		\
620d317057SNathan Whitehorn 	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3disk", MTX_DEF)
630d317057SNathan Whitehorn #define PS3DISK_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
640d317057SNathan Whitehorn #define PS3DISK_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
650d317057SNathan Whitehorn #define	PS3DISK_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
660d317057SNathan Whitehorn #define PS3DISK_ASSERT_LOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_OWNED);
670d317057SNathan Whitehorn #define PS3DISK_ASSERT_UNLOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
680d317057SNathan Whitehorn 
690d317057SNathan Whitehorn #define LV1_STORAGE_ATA_HDDOUT 		0x23
700d317057SNathan Whitehorn 
71*7029da5cSPawel Biernacki static SYSCTL_NODE(_hw, OID_AUTO, ps3disk, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
726472ac3dSEd Schouten     "PS3 Disk driver parameters");
730d317057SNathan Whitehorn 
740d317057SNathan Whitehorn #ifdef PS3DISK_DEBUG
750d317057SNathan Whitehorn static int ps3disk_debug = 0;
760d317057SNathan Whitehorn SYSCTL_INT(_hw_ps3disk, OID_AUTO, debug, CTLFLAG_RW, &ps3disk_debug,
770d317057SNathan Whitehorn 	0, "control debugging printfs");
780d317057SNathan Whitehorn TUNABLE_INT("hw.ps3disk.debug", &ps3disk_debug);
790d317057SNathan Whitehorn enum {
800d317057SNathan Whitehorn 	PS3DISK_DEBUG_INTR	= 0x00000001,
810d317057SNathan Whitehorn 	PS3DISK_DEBUG_TASK	= 0x00000002,
820d317057SNathan Whitehorn 	PS3DISK_DEBUG_READ	= 0x00000004,
830d317057SNathan Whitehorn 	PS3DISK_DEBUG_WRITE	= 0x00000008,
840d317057SNathan Whitehorn 	PS3DISK_DEBUG_FLUSH	= 0x00000010,
850d317057SNathan Whitehorn 	PS3DISK_DEBUG_ANY	= 0xffffffff
860d317057SNathan Whitehorn };
870d317057SNathan Whitehorn #define	DPRINTF(sc, m, fmt, ...)				\
880d317057SNathan Whitehorn do {								\
890d317057SNathan Whitehorn 	if (sc->sc_debug & (m))					\
900d317057SNathan Whitehorn 		printf(fmt, __VA_ARGS__);			\
910d317057SNathan Whitehorn } while (0)
920d317057SNathan Whitehorn #else
930d317057SNathan Whitehorn #define	DPRINTF(sc, m, fmt, ...)
940d317057SNathan Whitehorn #endif
950d317057SNathan Whitehorn 
960d317057SNathan Whitehorn struct ps3disk_region {
970d317057SNathan Whitehorn 	uint64_t r_id;
980d317057SNathan Whitehorn 	uint64_t r_start;
990d317057SNathan Whitehorn 	uint64_t r_size;
1000d317057SNathan Whitehorn 	uint64_t r_flags;
1010d317057SNathan Whitehorn };
1020d317057SNathan Whitehorn 
1030d317057SNathan Whitehorn struct ps3disk_softc {
1040d317057SNathan Whitehorn 	device_t sc_dev;
1050d317057SNathan Whitehorn 
1060d317057SNathan Whitehorn 	struct mtx sc_mtx;
1070d317057SNathan Whitehorn 
1080d317057SNathan Whitehorn 	uint64_t sc_blksize;
1090d317057SNathan Whitehorn 	uint64_t sc_nblocks;
1100d317057SNathan Whitehorn 
1110d317057SNathan Whitehorn 	uint64_t sc_nregs;
1120d317057SNathan Whitehorn 	struct ps3disk_region *sc_reg;
1130d317057SNathan Whitehorn 
1140d317057SNathan Whitehorn 	int sc_irqid;
1150d317057SNathan Whitehorn 	struct resource	*sc_irq;
1160d317057SNathan Whitehorn 	void *sc_irqctx;
1170d317057SNathan Whitehorn 
1180d317057SNathan Whitehorn 	struct disk **sc_disk;
1190d317057SNathan Whitehorn 
1200d317057SNathan Whitehorn 	struct bio_queue_head sc_bioq;
12198934b1fSNathan Whitehorn 	struct bio_queue_head sc_deferredq;
1220d317057SNathan Whitehorn 	struct proc *sc_task;
1230d317057SNathan Whitehorn 
12498934b1fSNathan Whitehorn 	bus_dma_tag_t sc_dmatag;
1250d317057SNathan Whitehorn 
1260d317057SNathan Whitehorn 	int sc_running;
1270d317057SNathan Whitehorn 	int sc_debug;
1280d317057SNathan Whitehorn };
1290d317057SNathan Whitehorn 
1300d317057SNathan Whitehorn static int ps3disk_open(struct disk *dp);
1310d317057SNathan Whitehorn static int ps3disk_close(struct disk *dp);
1320d317057SNathan Whitehorn static void ps3disk_strategy(struct bio *bp);
1330d317057SNathan Whitehorn 
13498934b1fSNathan Whitehorn static void ps3disk_task(void *arg);
1350d317057SNathan Whitehorn static void ps3disk_intr(void *arg);
1360d317057SNathan Whitehorn static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc);
1370d317057SNathan Whitehorn static int ps3disk_enum_regions(struct ps3disk_softc *sc);
13898934b1fSNathan Whitehorn static void ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
13998934b1fSNathan Whitehorn     int error);
1400d317057SNathan Whitehorn 
1410d317057SNathan Whitehorn static void ps3disk_sysctlattach(struct ps3disk_softc *sc);
1420d317057SNathan Whitehorn 
1430d317057SNathan Whitehorn static MALLOC_DEFINE(M_PS3DISK, "ps3disk", "PS3 Disk");
1440d317057SNathan Whitehorn 
1450d317057SNathan Whitehorn static int
1460d317057SNathan Whitehorn ps3disk_probe(device_t dev)
1470d317057SNathan Whitehorn {
1480d317057SNathan Whitehorn 	if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
1490d317057SNathan Whitehorn 	    ps3bus_get_devtype(dev) != PS3_DEVTYPE_DISK)
1500d317057SNathan Whitehorn 		return (ENXIO);
1510d317057SNathan Whitehorn 
1520d317057SNathan Whitehorn 	device_set_desc(dev, "Playstation 3 Disk");
1530d317057SNathan Whitehorn 
1540d317057SNathan Whitehorn 	return (BUS_PROBE_SPECIFIC);
1550d317057SNathan Whitehorn }
1560d317057SNathan Whitehorn 
1570d317057SNathan Whitehorn static int
1580d317057SNathan Whitehorn ps3disk_attach(device_t dev)
1590d317057SNathan Whitehorn {
1600d317057SNathan Whitehorn 	struct ps3disk_softc *sc;
1610d317057SNathan Whitehorn 	struct disk *d;
1620d317057SNathan Whitehorn 	intmax_t mb;
16398934b1fSNathan Whitehorn 	uint64_t junk;
1640d317057SNathan Whitehorn 	char unit;
1650d317057SNathan Whitehorn 	int i, err;
1660d317057SNathan Whitehorn 
1670d317057SNathan Whitehorn 	sc = device_get_softc(dev);
1680d317057SNathan Whitehorn 	sc->sc_dev = dev;
1690d317057SNathan Whitehorn 
1700d317057SNathan Whitehorn 	PS3DISK_LOCK_INIT(sc);
1710d317057SNathan Whitehorn 
1720d317057SNathan Whitehorn 	err = ps3disk_get_disk_geometry(sc);
1730d317057SNathan Whitehorn 	if (err) {
1740d317057SNathan Whitehorn 		device_printf(dev, "Could not get disk geometry\n");
1750d317057SNathan Whitehorn 		err = ENXIO;
1760d317057SNathan Whitehorn 		goto fail_destroy_lock;
1770d317057SNathan Whitehorn 	}
1780d317057SNathan Whitehorn 
1790d317057SNathan Whitehorn 	device_printf(dev, "block size %lu total blocks %lu\n",
1800d317057SNathan Whitehorn 	    sc->sc_blksize, sc->sc_nblocks);
1810d317057SNathan Whitehorn 
1820d317057SNathan Whitehorn 	err = ps3disk_enum_regions(sc);
1830d317057SNathan Whitehorn 	if (err) {
1840d317057SNathan Whitehorn 		device_printf(dev, "Could not enumerate disk regions\n");
1850d317057SNathan Whitehorn 		err = ENXIO;
1860d317057SNathan Whitehorn 		goto fail_destroy_lock;
1870d317057SNathan Whitehorn 	}
1880d317057SNathan Whitehorn 
1890d317057SNathan Whitehorn 	device_printf(dev, "Found %lu regions\n", sc->sc_nregs);
1900d317057SNathan Whitehorn 
1910d317057SNathan Whitehorn 	if (!sc->sc_nregs) {
1920d317057SNathan Whitehorn 		err = ENXIO;
1930d317057SNathan Whitehorn 		goto fail_destroy_lock;
1940d317057SNathan Whitehorn 	}
1950d317057SNathan Whitehorn 
1960d317057SNathan Whitehorn 	/* Setup interrupt handler */
1970d317057SNathan Whitehorn 	sc->sc_irqid = 0;
1980d317057SNathan Whitehorn 	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
1990d317057SNathan Whitehorn 	    RF_ACTIVE);
2000d317057SNathan Whitehorn 	if (!sc->sc_irq) {
2010d317057SNathan Whitehorn 		device_printf(dev, "Could not allocate IRQ\n");
2020d317057SNathan Whitehorn 		err = ENXIO;
2030d317057SNathan Whitehorn 		goto fail_free_regions;
2040d317057SNathan Whitehorn 	}
2050d317057SNathan Whitehorn 
2060d317057SNathan Whitehorn 	err = bus_setup_intr(dev, sc->sc_irq,
2070d317057SNathan Whitehorn 	    INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
20898934b1fSNathan Whitehorn 	    NULL, ps3disk_intr, sc, &sc->sc_irqctx);
2090d317057SNathan Whitehorn 	if (err) {
2100d317057SNathan Whitehorn 		device_printf(dev, "Could not setup IRQ\n");
2110d317057SNathan Whitehorn 		err = ENXIO;
2120d317057SNathan Whitehorn 		goto fail_release_intr;
2130d317057SNathan Whitehorn 	}
2140d317057SNathan Whitehorn 
21598934b1fSNathan Whitehorn 	/* Setup DMA */
2160d317057SNathan Whitehorn 	err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
2170d317057SNathan Whitehorn 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
21898934b1fSNathan Whitehorn 	    BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0,
21998934b1fSNathan Whitehorn 	    busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag);
2200d317057SNathan Whitehorn 	if (err) {
22198934b1fSNathan Whitehorn 		device_printf(dev, "Could not create DMA tag\n");
2220d317057SNathan Whitehorn 		err = ENXIO;
2230d317057SNathan Whitehorn 		goto fail_teardown_intr;
2240d317057SNathan Whitehorn 	}
2250d317057SNathan Whitehorn 
2260d317057SNathan Whitehorn 	/* Setup disks */
2270d317057SNathan Whitehorn 
2280d317057SNathan Whitehorn 	sc->sc_disk = malloc(sc->sc_nregs * sizeof(struct disk *),
2290d317057SNathan Whitehorn 	    M_PS3DISK, M_ZERO | M_WAITOK);
2300d317057SNathan Whitehorn 	if (!sc->sc_disk) {
2310d317057SNathan Whitehorn 		device_printf(dev, "Could not allocate disk(s)\n");
2320d317057SNathan Whitehorn 		err = ENOMEM;
23398934b1fSNathan Whitehorn 		goto fail_teardown_intr;
2340d317057SNathan Whitehorn 	}
2350d317057SNathan Whitehorn 
2360d317057SNathan Whitehorn 	for (i = 0; i < sc->sc_nregs; i++) {
237dfcd47a7SNathan Whitehorn 		struct ps3disk_region *rp = &sc->sc_reg[i];
238dfcd47a7SNathan Whitehorn 
2390d317057SNathan Whitehorn 		d = sc->sc_disk[i] = disk_alloc();
2400d317057SNathan Whitehorn 		d->d_open = ps3disk_open;
2410d317057SNathan Whitehorn 		d->d_close = ps3disk_close;
2420d317057SNathan Whitehorn 		d->d_strategy = ps3disk_strategy;
2430d317057SNathan Whitehorn 		d->d_name = "ps3disk";
2440d317057SNathan Whitehorn 		d->d_drv1 = sc;
24598934b1fSNathan Whitehorn 		d->d_maxsize = PAGE_SIZE;
2460d317057SNathan Whitehorn 		d->d_sectorsize = sc->sc_blksize;
2470d317057SNathan Whitehorn 		d->d_unit = i;
2480d317057SNathan Whitehorn 		d->d_mediasize = sc->sc_reg[i].r_size * sc->sc_blksize;
2490d317057SNathan Whitehorn 		d->d_flags |= DISKFLAG_CANFLUSHCACHE;
2500d317057SNathan Whitehorn 
2510d317057SNathan Whitehorn 		mb = d->d_mediasize >> 20;
2520d317057SNathan Whitehorn 		unit = 'M';
2530d317057SNathan Whitehorn 		if (mb >= 10240) {
2540d317057SNathan Whitehorn 			unit = 'G';
2550d317057SNathan Whitehorn 			mb /= 1024;
2560d317057SNathan Whitehorn 		}
2570d317057SNathan Whitehorn 
258dfcd47a7SNathan Whitehorn 		/* Test to see if we can read this region */
259dfcd47a7SNathan Whitehorn 		err = lv1_storage_read(ps3bus_get_device(dev), d->d_unit,
26098934b1fSNathan Whitehorn 		    0, 0, rp->r_flags, 0, &junk);
261dfcd47a7SNathan Whitehorn 		device_printf(dev, "region %d %ju%cB%s\n", i, mb, unit,
26298934b1fSNathan Whitehorn 		    (err == LV1_DENIED_BY_POLICY) ?  " (hypervisor protected)"
26398934b1fSNathan Whitehorn 		    : "");
2640d317057SNathan Whitehorn 
26598934b1fSNathan Whitehorn 		if (err != LV1_DENIED_BY_POLICY)
2660d317057SNathan Whitehorn 			disk_create(d, DISK_VERSION);
2670d317057SNathan Whitehorn 	}
268dfcd47a7SNathan Whitehorn 	err = 0;
2690d317057SNathan Whitehorn 
2700d317057SNathan Whitehorn 	bioq_init(&sc->sc_bioq);
27198934b1fSNathan Whitehorn 	bioq_init(&sc->sc_deferredq);
27298934b1fSNathan Whitehorn 	kproc_create(&ps3disk_task, sc, &sc->sc_task, 0, 0, "ps3disk");
2730d317057SNathan Whitehorn 
2740d317057SNathan Whitehorn 	ps3disk_sysctlattach(sc);
2750d317057SNathan Whitehorn 	sc->sc_running = 1;
2760d317057SNathan Whitehorn 	return (0);
2770d317057SNathan Whitehorn 
2780d317057SNathan Whitehorn fail_teardown_intr:
2790d317057SNathan Whitehorn 	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
2800d317057SNathan Whitehorn fail_release_intr:
2810d317057SNathan Whitehorn 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
2820d317057SNathan Whitehorn fail_free_regions:
2830d317057SNathan Whitehorn 	free(sc->sc_reg, M_PS3DISK);
2840d317057SNathan Whitehorn fail_destroy_lock:
2850d317057SNathan Whitehorn 	PS3DISK_LOCK_DESTROY(sc);
2860d317057SNathan Whitehorn 	return (err);
2870d317057SNathan Whitehorn }
2880d317057SNathan Whitehorn 
2890d317057SNathan Whitehorn static int
2900d317057SNathan Whitehorn ps3disk_detach(device_t dev)
2910d317057SNathan Whitehorn {
2920d317057SNathan Whitehorn 	struct ps3disk_softc *sc = device_get_softc(dev);
2930d317057SNathan Whitehorn 	int i;
2940d317057SNathan Whitehorn 
2950d317057SNathan Whitehorn 	for (i = 0; i < sc->sc_nregs; i++)
2960d317057SNathan Whitehorn 		disk_destroy(sc->sc_disk[i]);
2970d317057SNathan Whitehorn 
29898934b1fSNathan Whitehorn 	bus_dma_tag_destroy(sc->sc_dmatag);
2990d317057SNathan Whitehorn 
3000d317057SNathan Whitehorn 	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
3010d317057SNathan Whitehorn 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
3020d317057SNathan Whitehorn 
3030d317057SNathan Whitehorn 	free(sc->sc_disk, M_PS3DISK);
3040d317057SNathan Whitehorn 	free(sc->sc_reg, M_PS3DISK);
3050d317057SNathan Whitehorn 
3060d317057SNathan Whitehorn 	PS3DISK_LOCK_DESTROY(sc);
3070d317057SNathan Whitehorn 
3080d317057SNathan Whitehorn 	return (0);
3090d317057SNathan Whitehorn }
3100d317057SNathan Whitehorn 
3110d317057SNathan Whitehorn static int
3120d317057SNathan Whitehorn ps3disk_open(struct disk *dp)
3130d317057SNathan Whitehorn {
3140d317057SNathan Whitehorn 	return (0);
3150d317057SNathan Whitehorn }
3160d317057SNathan Whitehorn 
3170d317057SNathan Whitehorn static int
3180d317057SNathan Whitehorn ps3disk_close(struct disk *dp)
3190d317057SNathan Whitehorn {
3200d317057SNathan Whitehorn 	return (0);
3210d317057SNathan Whitehorn }
3220d317057SNathan Whitehorn 
32398934b1fSNathan Whitehorn /* Process deferred blocks */
32498934b1fSNathan Whitehorn static void
32598934b1fSNathan Whitehorn ps3disk_task(void *arg)
32698934b1fSNathan Whitehorn {
32798934b1fSNathan Whitehorn 	struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
32898934b1fSNathan Whitehorn 	struct bio *bp;
32998934b1fSNathan Whitehorn 
33098934b1fSNathan Whitehorn 
33198934b1fSNathan Whitehorn 	while (1) {
33298934b1fSNathan Whitehorn 		kproc_suspend_check(sc->sc_task);
33398934b1fSNathan Whitehorn 		tsleep(&sc->sc_deferredq, PRIBIO, "ps3disk", 10);
33498934b1fSNathan Whitehorn 
33598934b1fSNathan Whitehorn 		PS3DISK_LOCK(sc);
33698934b1fSNathan Whitehorn 		bp = bioq_takefirst(&sc->sc_deferredq);
33798934b1fSNathan Whitehorn 		PS3DISK_UNLOCK(sc);
33898934b1fSNathan Whitehorn 
33998934b1fSNathan Whitehorn 		if (bp == NULL)
34098934b1fSNathan Whitehorn 			continue;
34198934b1fSNathan Whitehorn 
34298934b1fSNathan Whitehorn 		if (bp->bio_driver1 != NULL) {
34398934b1fSNathan Whitehorn 			bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
34498934b1fSNathan Whitehorn 			    bp->bio_driver1);
34598934b1fSNathan Whitehorn 			bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
34698934b1fSNathan Whitehorn 			    bp->bio_driver1);
34798934b1fSNathan Whitehorn 		}
34898934b1fSNathan Whitehorn 
34998934b1fSNathan Whitehorn 		ps3disk_strategy(bp);
35098934b1fSNathan Whitehorn 	}
35198934b1fSNathan Whitehorn 
35298934b1fSNathan Whitehorn 	kproc_exit(0);
35398934b1fSNathan Whitehorn }
35498934b1fSNathan Whitehorn 
3550d317057SNathan Whitehorn static void
3560d317057SNathan Whitehorn ps3disk_strategy(struct bio *bp)
3570d317057SNathan Whitehorn {
3580d317057SNathan Whitehorn 	struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
35998934b1fSNathan Whitehorn 	int err;
3600d317057SNathan Whitehorn 
36198934b1fSNathan Whitehorn 	if (sc == NULL) {
3620d317057SNathan Whitehorn 		bp->bio_flags |= BIO_ERROR;
3630d317057SNathan Whitehorn 		bp->bio_error = EINVAL;
3640d317057SNathan Whitehorn 		biodone(bp);
3650d317057SNathan Whitehorn 		return;
3660d317057SNathan Whitehorn 	}
3670d317057SNathan Whitehorn 
3680d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
36998934b1fSNathan Whitehorn 	bp->bio_resid = bp->bio_bcount;
37098934b1fSNathan Whitehorn 	bioq_insert_tail(&sc->sc_bioq, bp);
3710d317057SNathan Whitehorn 
3720d317057SNathan Whitehorn 	DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_cmd 0x%02x\n",
3730d317057SNathan Whitehorn 	    __func__, bp->bio_cmd);
3740d317057SNathan Whitehorn 
37598934b1fSNathan Whitehorn 	err = 0;
3760d317057SNathan Whitehorn 	if (bp->bio_cmd == BIO_FLUSH) {
37798934b1fSNathan Whitehorn 		bp->bio_driver1 = 0;
37898934b1fSNathan Whitehorn 		err = lv1_storage_send_device_command(
37998934b1fSNathan Whitehorn 		    ps3bus_get_device(sc->sc_dev), LV1_STORAGE_ATA_HDDOUT,
38098934b1fSNathan Whitehorn 		    0, 0, 0, 0, (uint64_t *)&bp->bio_driver2);
38198934b1fSNathan Whitehorn 		if (err == LV1_BUSY)
38298934b1fSNathan Whitehorn 			err = EAGAIN;
3830d317057SNathan Whitehorn 	} else if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
38498934b1fSNathan Whitehorn 		if (bp->bio_bcount % sc->sc_blksize != 0) {
38598934b1fSNathan Whitehorn 			err = EINVAL;
3860d317057SNathan Whitehorn 		} else {
38798934b1fSNathan Whitehorn 			bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT,
38898934b1fSNathan Whitehorn 			    (bus_dmamap_t *)(&bp->bio_driver1));
38998934b1fSNathan Whitehorn 			err = bus_dmamap_load(sc->sc_dmatag,
39098934b1fSNathan Whitehorn 			    (bus_dmamap_t)(bp->bio_driver1), bp->bio_data,
39198934b1fSNathan Whitehorn 			    bp->bio_bcount, ps3disk_transfer, bp, 0);
39298934b1fSNathan Whitehorn 			if (err == EINPROGRESS)
39398934b1fSNathan Whitehorn 				err = 0;
39498934b1fSNathan Whitehorn 		}
39598934b1fSNathan Whitehorn 	} else {
39698934b1fSNathan Whitehorn 		err = EINVAL;
3970d317057SNathan Whitehorn 	}
3980d317057SNathan Whitehorn 
39998934b1fSNathan Whitehorn 	if (err == EAGAIN) {
40098934b1fSNathan Whitehorn 		bioq_remove(&sc->sc_bioq, bp);
40198934b1fSNathan Whitehorn 		bioq_insert_tail(&sc->sc_deferredq, bp);
40298934b1fSNathan Whitehorn 	} else if (err != 0) {
40398934b1fSNathan Whitehorn 		bp->bio_error = err;
4040d317057SNathan Whitehorn 		bp->bio_flags |= BIO_ERROR;
40598934b1fSNathan Whitehorn 		bioq_remove(&sc->sc_bioq, bp);
4060d317057SNathan Whitehorn 		disk_err(bp, "hard error", -1, 1);
4070d317057SNathan Whitehorn 		biodone(bp);
4080d317057SNathan Whitehorn 	}
4090d317057SNathan Whitehorn 
4100d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
4110d317057SNathan Whitehorn }
4120d317057SNathan Whitehorn 
4130d317057SNathan Whitehorn static void
4140d317057SNathan Whitehorn ps3disk_intr(void *arg)
4150d317057SNathan Whitehorn {
4160d317057SNathan Whitehorn 	struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
4170d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
4180d317057SNathan Whitehorn 	uint64_t devid = ps3bus_get_device(dev);
41998934b1fSNathan Whitehorn 	struct bio *bp;
4200d317057SNathan Whitehorn 	uint64_t tag, status;
42198934b1fSNathan Whitehorn 
42298934b1fSNathan Whitehorn 	if (lv1_storage_get_async_status(devid, &tag, &status) != 0)
42398934b1fSNathan Whitehorn 		return;
4240d317057SNathan Whitehorn 
4250d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
4260d317057SNathan Whitehorn 
42798934b1fSNathan Whitehorn 	DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: tag 0x%016lx "
42898934b1fSNathan Whitehorn 	    "status 0x%016lx\n", __func__, tag, status);
4290d317057SNathan Whitehorn 
43098934b1fSNathan Whitehorn 	/* Locate the matching request */
43198934b1fSNathan Whitehorn 	TAILQ_FOREACH(bp, &sc->sc_bioq.queue, bio_queue) {
43298934b1fSNathan Whitehorn 		if ((uint64_t)bp->bio_driver2 != tag)
43398934b1fSNathan Whitehorn 			continue;
4340d317057SNathan Whitehorn 
43598934b1fSNathan Whitehorn 		if (status != 0) {
43698934b1fSNathan Whitehorn 			device_printf(sc->sc_dev, "%s error (%#lx)\n",
43798934b1fSNathan Whitehorn 			    (bp->bio_cmd == BIO_READ) ? "Read" : "Write",
43898934b1fSNathan Whitehorn 			    status);
43998934b1fSNathan Whitehorn 			bp->bio_error = EIO;
44098934b1fSNathan Whitehorn 			bp->bio_flags |= BIO_ERROR;
44198934b1fSNathan Whitehorn 		} else {
44298934b1fSNathan Whitehorn 			bp->bio_error = 0;
44398934b1fSNathan Whitehorn 			bp->bio_resid = 0;
44498934b1fSNathan Whitehorn 			bp->bio_flags |= BIO_DONE;
4450d317057SNathan Whitehorn 		}
4460d317057SNathan Whitehorn 
44798934b1fSNathan Whitehorn 		if (bp->bio_driver1 != NULL) {
44898934b1fSNathan Whitehorn 			if (bp->bio_cmd == BIO_READ)
44998934b1fSNathan Whitehorn 				bus_dmamap_sync(sc->sc_dmatag, (bus_dmamap_t)
45098934b1fSNathan Whitehorn 				    bp->bio_driver1, BUS_DMASYNC_POSTREAD);
45198934b1fSNathan Whitehorn 			bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
45298934b1fSNathan Whitehorn 			    bp->bio_driver1);
45398934b1fSNathan Whitehorn 			bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
45498934b1fSNathan Whitehorn 			    bp->bio_driver1);
45598934b1fSNathan Whitehorn 		}
4560d317057SNathan Whitehorn 
45798934b1fSNathan Whitehorn 		bioq_remove(&sc->sc_bioq, bp);
45898934b1fSNathan Whitehorn 		biodone(bp);
45998934b1fSNathan Whitehorn 		break;
46098934b1fSNathan Whitehorn 	}
4610d317057SNathan Whitehorn 
46298934b1fSNathan Whitehorn 	if (bioq_first(&sc->sc_deferredq) != NULL)
46398934b1fSNathan Whitehorn 		wakeup(&sc->sc_deferredq);
4640d317057SNathan Whitehorn 
4650d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
4660d317057SNathan Whitehorn }
4670d317057SNathan Whitehorn 
4680d317057SNathan Whitehorn static int
4690d317057SNathan Whitehorn ps3disk_get_disk_geometry(struct ps3disk_softc *sc)
4700d317057SNathan Whitehorn {
4710d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
4720d317057SNathan Whitehorn 	uint64_t bus_index = ps3bus_get_busidx(dev);
4730d317057SNathan Whitehorn 	uint64_t dev_index = ps3bus_get_devidx(dev);
4740d317057SNathan Whitehorn 	uint64_t junk;
4750d317057SNathan Whitehorn 	int err;
4760d317057SNathan Whitehorn 
4770d317057SNathan Whitehorn 	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
4780d317057SNathan Whitehorn 	    (lv1_repository_string("bus") >> 32) | bus_index,
4790d317057SNathan Whitehorn 	    lv1_repository_string("dev") | dev_index,
4800d317057SNathan Whitehorn 	    lv1_repository_string("blk_size"), 0, &sc->sc_blksize, &junk);
4810d317057SNathan Whitehorn 	if (err) {
4820d317057SNathan Whitehorn 		device_printf(dev, "Could not get block size (0x%08x)\n", err);
48398934b1fSNathan Whitehorn 		return (ENXIO);
4840d317057SNathan Whitehorn 	}
4850d317057SNathan Whitehorn 
4860d317057SNathan Whitehorn 	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
4870d317057SNathan Whitehorn 	    (lv1_repository_string("bus") >> 32) | bus_index,
4880d317057SNathan Whitehorn 	    lv1_repository_string("dev") | dev_index,
4890d317057SNathan Whitehorn 	    lv1_repository_string("n_blocks"), 0, &sc->sc_nblocks, &junk);
4900d317057SNathan Whitehorn 	if (err) {
49198934b1fSNathan Whitehorn 		device_printf(dev, "Could not get total number of blocks "
49298934b1fSNathan Whitehorn 		    "(0x%08x)\n", err);
4930d317057SNathan Whitehorn 		err = ENXIO;
4940d317057SNathan Whitehorn 	}
4950d317057SNathan Whitehorn 
4960d317057SNathan Whitehorn 	return (err);
4970d317057SNathan Whitehorn }
4980d317057SNathan Whitehorn 
4990d317057SNathan Whitehorn static int
5000d317057SNathan Whitehorn ps3disk_enum_regions(struct ps3disk_softc *sc)
5010d317057SNathan Whitehorn {
5020d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
5030d317057SNathan Whitehorn 	uint64_t bus_index = ps3bus_get_busidx(dev);
5040d317057SNathan Whitehorn 	uint64_t dev_index = ps3bus_get_devidx(dev);
5050d317057SNathan Whitehorn 	uint64_t junk;
5060d317057SNathan Whitehorn 	int i, err;
5070d317057SNathan Whitehorn 
5080d317057SNathan Whitehorn 	/* Read number of regions */
5090d317057SNathan Whitehorn 
5100d317057SNathan Whitehorn 	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
5110d317057SNathan Whitehorn 	    (lv1_repository_string("bus") >> 32) | bus_index,
5120d317057SNathan Whitehorn 	    lv1_repository_string("dev") | dev_index,
5130d317057SNathan Whitehorn 	    lv1_repository_string("n_regs"), 0, &sc->sc_nregs, &junk);
5140d317057SNathan Whitehorn 	if (err) {
5150d317057SNathan Whitehorn 		device_printf(dev, "Could not get number of regions (0x%08x)\n",
5160d317057SNathan Whitehorn 		    err);
5170d317057SNathan Whitehorn 		err = ENXIO;
5180d317057SNathan Whitehorn 		goto fail;
5190d317057SNathan Whitehorn 	}
5200d317057SNathan Whitehorn 
5210d317057SNathan Whitehorn 	if (!sc->sc_nregs)
5220d317057SNathan Whitehorn 		return 0;
5230d317057SNathan Whitehorn 
5240d317057SNathan Whitehorn 	sc->sc_reg = malloc(sc->sc_nregs * sizeof(struct ps3disk_region),
5250d317057SNathan Whitehorn 	    M_PS3DISK, M_ZERO | M_WAITOK);
5260d317057SNathan Whitehorn 	if (!sc->sc_reg) {
5270d317057SNathan Whitehorn 		err = ENOMEM;
5280d317057SNathan Whitehorn 		goto fail;
5290d317057SNathan Whitehorn 	}
5300d317057SNathan Whitehorn 
5310d317057SNathan Whitehorn 	/* Setup regions */
5320d317057SNathan Whitehorn 
5330d317057SNathan Whitehorn 	for (i = 0; i < sc->sc_nregs; i++) {
5340d317057SNathan Whitehorn 		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
5350d317057SNathan Whitehorn 		    (lv1_repository_string("bus") >> 32) | bus_index,
5360d317057SNathan Whitehorn 		    lv1_repository_string("dev") | dev_index,
5370d317057SNathan Whitehorn 		    lv1_repository_string("region") | i,
5380d317057SNathan Whitehorn 		    lv1_repository_string("id"), &sc->sc_reg[i].r_id, &junk);
5390d317057SNathan Whitehorn 		if (err) {
5400d317057SNathan Whitehorn 			device_printf(dev, "Could not get region id (0x%08x)\n",
5410d317057SNathan Whitehorn 			    err);
5420d317057SNathan Whitehorn 			err = ENXIO;
5430d317057SNathan Whitehorn 			goto fail;
5440d317057SNathan Whitehorn 		}
5450d317057SNathan Whitehorn 
5460d317057SNathan Whitehorn 		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
5470d317057SNathan Whitehorn 		    (lv1_repository_string("bus") >> 32) | bus_index,
5480d317057SNathan Whitehorn 		    lv1_repository_string("dev") | dev_index,
5490d317057SNathan Whitehorn 		    lv1_repository_string("region") | i,
55098934b1fSNathan Whitehorn 		    lv1_repository_string("start"), &sc->sc_reg[i].r_start,
55198934b1fSNathan Whitehorn 		    &junk);
5520d317057SNathan Whitehorn 		if (err) {
55398934b1fSNathan Whitehorn 			device_printf(dev, "Could not get region start "
55498934b1fSNathan Whitehorn 			    "(0x%08x)\n", err);
5550d317057SNathan Whitehorn 			err = ENXIO;
5560d317057SNathan Whitehorn 			goto fail;
5570d317057SNathan Whitehorn 		}
5580d317057SNathan Whitehorn 
5590d317057SNathan Whitehorn 		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
5600d317057SNathan Whitehorn 		    (lv1_repository_string("bus") >> 32) | bus_index,
5610d317057SNathan Whitehorn 		    lv1_repository_string("dev") | dev_index,
5620d317057SNathan Whitehorn 		    lv1_repository_string("region") | i,
56398934b1fSNathan Whitehorn 		    lv1_repository_string("size"), &sc->sc_reg[i].r_size,
56498934b1fSNathan Whitehorn 		    &junk);
5650d317057SNathan Whitehorn 		if (err) {
56698934b1fSNathan Whitehorn 			device_printf(dev, "Could not get region size "
56798934b1fSNathan Whitehorn 			    "(0x%08x)\n", err);
5680d317057SNathan Whitehorn 			err = ENXIO;
5690d317057SNathan Whitehorn 			goto fail;
5700d317057SNathan Whitehorn 		}
5710d317057SNathan Whitehorn 
5720d317057SNathan Whitehorn 		if (i == 0)
5730d317057SNathan Whitehorn 			sc->sc_reg[i].r_flags = 0x2;
5740d317057SNathan Whitehorn 		else
5750d317057SNathan Whitehorn 			sc->sc_reg[i].r_flags = 0;
5760d317057SNathan Whitehorn 	}
5770d317057SNathan Whitehorn 
5780d317057SNathan Whitehorn 	return (0);
5790d317057SNathan Whitehorn 
5800d317057SNathan Whitehorn fail:
5810d317057SNathan Whitehorn 
5820d317057SNathan Whitehorn 	sc->sc_nregs = 0;
5830d317057SNathan Whitehorn 	if (sc->sc_reg)
5840d317057SNathan Whitehorn 		free(sc->sc_reg, M_PS3DISK);
5850d317057SNathan Whitehorn 
5860d317057SNathan Whitehorn 	return (err);
5870d317057SNathan Whitehorn }
5880d317057SNathan Whitehorn 
58998934b1fSNathan Whitehorn static void
59098934b1fSNathan Whitehorn ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
5910d317057SNathan Whitehorn {
59298934b1fSNathan Whitehorn 	struct bio *bp = (struct bio *)(arg);
59398934b1fSNathan Whitehorn 	struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
59498934b1fSNathan Whitehorn 	struct ps3disk_region *rp = &sc->sc_reg[bp->bio_disk->d_unit];
59598934b1fSNathan Whitehorn 	uint64_t devid = ps3bus_get_device(sc->sc_dev);
59698934b1fSNathan Whitehorn 	uint64_t block;
59798934b1fSNathan Whitehorn 	int i, err;
5980d317057SNathan Whitehorn 
59998934b1fSNathan Whitehorn 	/* Locks already held by busdma */
60098934b1fSNathan Whitehorn 	PS3DISK_ASSERT_LOCKED(sc);
6010d317057SNathan Whitehorn 
60298934b1fSNathan Whitehorn 	if (error) {
60398934b1fSNathan Whitehorn 		bp->bio_error = error;
60498934b1fSNathan Whitehorn 		bp->bio_flags |= BIO_ERROR;
60598934b1fSNathan Whitehorn 		bioq_remove(&sc->sc_bioq, bp);
60698934b1fSNathan Whitehorn 		biodone(bp);
60798934b1fSNathan Whitehorn 		return;
6080d317057SNathan Whitehorn 	}
6090d317057SNathan Whitehorn 
61098934b1fSNathan Whitehorn 	block = bp->bio_pblkno;
61198934b1fSNathan Whitehorn 	for (i = 0; i < nsegs; i++) {
61298934b1fSNathan Whitehorn 		KASSERT((segs[i].ds_len % sc->sc_blksize) == 0,
61398934b1fSNathan Whitehorn 		    ("DMA fragments not blocksize multiples"));
6140d317057SNathan Whitehorn 
61598934b1fSNathan Whitehorn 		if (bp->bio_cmd == BIO_READ) {
6160d317057SNathan Whitehorn 			err = lv1_storage_read(devid, rp->r_id,
61798934b1fSNathan Whitehorn 			    block, segs[i].ds_len/sc->sc_blksize,
61898934b1fSNathan Whitehorn 			    rp->r_flags, segs[i].ds_addr,
61998934b1fSNathan Whitehorn 			    (uint64_t *)&bp->bio_driver2);
62098934b1fSNathan Whitehorn 		} else {
62198934b1fSNathan Whitehorn 			bus_dmamap_sync(sc->sc_dmatag,
62298934b1fSNathan Whitehorn 			    (bus_dmamap_t)bp->bio_driver1,
62398934b1fSNathan Whitehorn 			    BUS_DMASYNC_PREWRITE);
62498934b1fSNathan Whitehorn 			err = lv1_storage_write(devid, rp->r_id,
62598934b1fSNathan Whitehorn 			    block, segs[i].ds_len/sc->sc_blksize,
62698934b1fSNathan Whitehorn 			    rp->r_flags, segs[i].ds_addr,
62798934b1fSNathan Whitehorn 			    (uint64_t *)&bp->bio_driver2);
62898934b1fSNathan Whitehorn 		}
62998934b1fSNathan Whitehorn 
6300d317057SNathan Whitehorn 		if (err) {
63198934b1fSNathan Whitehorn 			if (err == LV1_BUSY) {
63298934b1fSNathan Whitehorn 				bioq_remove(&sc->sc_bioq, bp);
63398934b1fSNathan Whitehorn 				bioq_insert_tail(&sc->sc_deferredq, bp);
63498934b1fSNathan Whitehorn 			} else {
63598934b1fSNathan Whitehorn 				bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
63698934b1fSNathan Whitehorn 				    bp->bio_driver1);
63798934b1fSNathan Whitehorn 				bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
63898934b1fSNathan Whitehorn 				    bp->bio_driver1);
63998934b1fSNathan Whitehorn 				device_printf(sc->sc_dev, "Could not read "
64098934b1fSNathan Whitehorn 				    "sectors (0x%08x)\n", err);
64198934b1fSNathan Whitehorn 				bp->bio_error = EINVAL;
64298934b1fSNathan Whitehorn 				bp->bio_flags |= BIO_ERROR;
64398934b1fSNathan Whitehorn 				bioq_remove(&sc->sc_bioq, bp);
64498934b1fSNathan Whitehorn 				biodone(bp);
64598934b1fSNathan Whitehorn 			}
64698934b1fSNathan Whitehorn 
64798934b1fSNathan Whitehorn 			break;
6480d317057SNathan Whitehorn 		}
6490d317057SNathan Whitehorn 
6500d317057SNathan Whitehorn 		DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n",
6510d317057SNathan Whitehorn 		    __func__, sc->sc_bounce_tag);
6520d317057SNathan Whitehorn 	}
6530d317057SNathan Whitehorn }
6540d317057SNathan Whitehorn 
6550d317057SNathan Whitehorn #ifdef PS3DISK_DEBUG
6560d317057SNathan Whitehorn static int
6570d317057SNathan Whitehorn ps3disk_sysctl_debug(SYSCTL_HANDLER_ARGS)
6580d317057SNathan Whitehorn {
6590d317057SNathan Whitehorn 	struct ps3disk_softc *sc = arg1;
6600d317057SNathan Whitehorn 	int debug, error;
6610d317057SNathan Whitehorn 
6620d317057SNathan Whitehorn 	debug = sc->sc_debug;
6630d317057SNathan Whitehorn 
6640d317057SNathan Whitehorn 	error = sysctl_handle_int(oidp, &debug, 0, req);
6650d317057SNathan Whitehorn 	if (error || !req->newptr)
6660d317057SNathan Whitehorn 		return error;
6670d317057SNathan Whitehorn 
6680d317057SNathan Whitehorn 	sc->sc_debug = debug;
6690d317057SNathan Whitehorn 
6700d317057SNathan Whitehorn 	return 0;
6710d317057SNathan Whitehorn }
6720d317057SNathan Whitehorn #endif
6730d317057SNathan Whitehorn 
6740d317057SNathan Whitehorn static void
6750d317057SNathan Whitehorn ps3disk_sysctlattach(struct ps3disk_softc *sc)
6760d317057SNathan Whitehorn {
6770d317057SNathan Whitehorn #ifdef PS3DISK_DEBUG
6780d317057SNathan Whitehorn 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
6790d317057SNathan Whitehorn 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
6800d317057SNathan Whitehorn 
6810d317057SNathan Whitehorn 	sc->sc_debug = ps3disk_debug;
6820d317057SNathan Whitehorn 
6830d317057SNathan Whitehorn 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
684*7029da5cSPawel Biernacki 	    "debug", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
6850d317057SNathan Whitehorn 	    ps3disk_sysctl_debug, "I", "control debugging printfs");
6860d317057SNathan Whitehorn #endif
6870d317057SNathan Whitehorn }
6880d317057SNathan Whitehorn 
6890d317057SNathan Whitehorn static device_method_t ps3disk_methods[] = {
6900d317057SNathan Whitehorn 	DEVMETHOD(device_probe,		ps3disk_probe),
6910d317057SNathan Whitehorn 	DEVMETHOD(device_attach,	ps3disk_attach),
6920d317057SNathan Whitehorn 	DEVMETHOD(device_detach,	ps3disk_detach),
6930d317057SNathan Whitehorn 	{0, 0},
6940d317057SNathan Whitehorn };
6950d317057SNathan Whitehorn 
6960d317057SNathan Whitehorn static driver_t ps3disk_driver = {
6970d317057SNathan Whitehorn 	"ps3disk",
6980d317057SNathan Whitehorn 	ps3disk_methods,
6990d317057SNathan Whitehorn 	sizeof(struct ps3disk_softc),
7000d317057SNathan Whitehorn };
7010d317057SNathan Whitehorn 
7020d317057SNathan Whitehorn static devclass_t ps3disk_devclass;
7030d317057SNathan Whitehorn 
7040d317057SNathan Whitehorn DRIVER_MODULE(ps3disk, ps3bus, ps3disk_driver, ps3disk_devclass, 0, 0);
705