xref: /freebsd/sys/powerpc/ps3/ps3disk.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
10d317057SNathan Whitehorn /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
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/param.h>
300d317057SNathan Whitehorn #include <sys/systm.h>
310d317057SNathan Whitehorn #include <sys/sysctl.h>
320d317057SNathan Whitehorn #include <sys/disk.h>
330d317057SNathan Whitehorn #include <sys/bio.h>
340d317057SNathan Whitehorn #include <sys/bus.h>
350d317057SNathan Whitehorn #include <sys/conf.h>
360d317057SNathan Whitehorn #include <sys/kernel.h>
370d317057SNathan Whitehorn #include <sys/kthread.h>
380d317057SNathan Whitehorn #include <sys/lock.h>
390d317057SNathan Whitehorn #include <sys/malloc.h>
400d317057SNathan Whitehorn #include <sys/module.h>
410d317057SNathan Whitehorn #include <sys/mutex.h>
420d317057SNathan Whitehorn 
430d317057SNathan Whitehorn #include <vm/vm.h>
440d317057SNathan Whitehorn #include <vm/pmap.h>
450d317057SNathan Whitehorn 
460d317057SNathan Whitehorn #include <machine/pio.h>
470d317057SNathan Whitehorn #include <machine/bus.h>
480d317057SNathan Whitehorn #include <machine/platform.h>
490d317057SNathan Whitehorn #include <machine/resource.h>
500d317057SNathan Whitehorn #include <sys/bus.h>
510d317057SNathan Whitehorn #include <sys/rman.h>
520d317057SNathan Whitehorn 
530d317057SNathan Whitehorn #include <geom/geom_disk.h>
540d317057SNathan Whitehorn 
550d317057SNathan Whitehorn #include "ps3bus.h"
560d317057SNathan Whitehorn #include "ps3-hvcall.h"
570d317057SNathan Whitehorn 
580d317057SNathan Whitehorn #define PS3DISK_LOCK_INIT(_sc)		\
590d317057SNathan Whitehorn 	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3disk", MTX_DEF)
600d317057SNathan Whitehorn #define PS3DISK_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
610d317057SNathan Whitehorn #define PS3DISK_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
620d317057SNathan Whitehorn #define	PS3DISK_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
630d317057SNathan Whitehorn #define PS3DISK_ASSERT_LOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_OWNED);
640d317057SNathan Whitehorn #define PS3DISK_ASSERT_UNLOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
650d317057SNathan Whitehorn 
660d317057SNathan Whitehorn #define LV1_STORAGE_ATA_HDDOUT 		0x23
670d317057SNathan Whitehorn 
687029da5cSPawel Biernacki static SYSCTL_NODE(_hw, OID_AUTO, ps3disk, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
696472ac3dSEd Schouten     "PS3 Disk driver parameters");
700d317057SNathan Whitehorn 
710d317057SNathan Whitehorn #ifdef PS3DISK_DEBUG
720d317057SNathan Whitehorn static int ps3disk_debug = 0;
730d317057SNathan Whitehorn SYSCTL_INT(_hw_ps3disk, OID_AUTO, debug, CTLFLAG_RW, &ps3disk_debug,
740d317057SNathan Whitehorn 	0, "control debugging printfs");
750d317057SNathan Whitehorn TUNABLE_INT("hw.ps3disk.debug", &ps3disk_debug);
760d317057SNathan Whitehorn enum {
770d317057SNathan Whitehorn 	PS3DISK_DEBUG_INTR	= 0x00000001,
780d317057SNathan Whitehorn 	PS3DISK_DEBUG_TASK	= 0x00000002,
790d317057SNathan Whitehorn 	PS3DISK_DEBUG_READ	= 0x00000004,
800d317057SNathan Whitehorn 	PS3DISK_DEBUG_WRITE	= 0x00000008,
810d317057SNathan Whitehorn 	PS3DISK_DEBUG_FLUSH	= 0x00000010,
820d317057SNathan Whitehorn 	PS3DISK_DEBUG_ANY	= 0xffffffff
830d317057SNathan Whitehorn };
840d317057SNathan Whitehorn #define	DPRINTF(sc, m, fmt, ...)				\
850d317057SNathan Whitehorn do {								\
860d317057SNathan Whitehorn 	if (sc->sc_debug & (m))					\
870d317057SNathan Whitehorn 		printf(fmt, __VA_ARGS__);			\
880d317057SNathan Whitehorn } while (0)
890d317057SNathan Whitehorn #else
900d317057SNathan Whitehorn #define	DPRINTF(sc, m, fmt, ...)
910d317057SNathan Whitehorn #endif
920d317057SNathan Whitehorn 
930d317057SNathan Whitehorn struct ps3disk_region {
940d317057SNathan Whitehorn 	uint64_t r_id;
950d317057SNathan Whitehorn 	uint64_t r_start;
960d317057SNathan Whitehorn 	uint64_t r_size;
970d317057SNathan Whitehorn 	uint64_t r_flags;
980d317057SNathan Whitehorn };
990d317057SNathan Whitehorn 
1000d317057SNathan Whitehorn struct ps3disk_softc {
1010d317057SNathan Whitehorn 	device_t sc_dev;
1020d317057SNathan Whitehorn 
1030d317057SNathan Whitehorn 	struct mtx sc_mtx;
1040d317057SNathan Whitehorn 
1050d317057SNathan Whitehorn 	uint64_t sc_blksize;
1060d317057SNathan Whitehorn 	uint64_t sc_nblocks;
1070d317057SNathan Whitehorn 
1080d317057SNathan Whitehorn 	uint64_t sc_nregs;
1090d317057SNathan Whitehorn 	struct ps3disk_region *sc_reg;
1100d317057SNathan Whitehorn 
1110d317057SNathan Whitehorn 	int sc_irqid;
1120d317057SNathan Whitehorn 	struct resource	*sc_irq;
1130d317057SNathan Whitehorn 	void *sc_irqctx;
1140d317057SNathan Whitehorn 
1150d317057SNathan Whitehorn 	struct disk **sc_disk;
1160d317057SNathan Whitehorn 
1170d317057SNathan Whitehorn 	struct bio_queue_head sc_bioq;
11898934b1fSNathan Whitehorn 	struct bio_queue_head sc_deferredq;
1190d317057SNathan Whitehorn 	struct proc *sc_task;
1200d317057SNathan Whitehorn 
12198934b1fSNathan Whitehorn 	bus_dma_tag_t sc_dmatag;
1220d317057SNathan Whitehorn 
1230d317057SNathan Whitehorn 	int sc_running;
1240d317057SNathan Whitehorn 	int sc_debug;
1250d317057SNathan Whitehorn };
1260d317057SNathan Whitehorn 
1270d317057SNathan Whitehorn static int ps3disk_open(struct disk *dp);
1280d317057SNathan Whitehorn static int ps3disk_close(struct disk *dp);
1290d317057SNathan Whitehorn static void ps3disk_strategy(struct bio *bp);
1300d317057SNathan Whitehorn 
13198934b1fSNathan Whitehorn static void ps3disk_task(void *arg);
1320d317057SNathan Whitehorn static void ps3disk_intr(void *arg);
1330d317057SNathan Whitehorn static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc);
1340d317057SNathan Whitehorn static int ps3disk_enum_regions(struct ps3disk_softc *sc);
13598934b1fSNathan Whitehorn static void ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
13698934b1fSNathan Whitehorn     int error);
1370d317057SNathan Whitehorn 
1380d317057SNathan Whitehorn static void ps3disk_sysctlattach(struct ps3disk_softc *sc);
1390d317057SNathan Whitehorn 
1400d317057SNathan Whitehorn static MALLOC_DEFINE(M_PS3DISK, "ps3disk", "PS3 Disk");
1410d317057SNathan Whitehorn 
1420d317057SNathan Whitehorn static int
ps3disk_probe(device_t dev)1430d317057SNathan Whitehorn ps3disk_probe(device_t dev)
1440d317057SNathan Whitehorn {
1450d317057SNathan Whitehorn 	if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
1460d317057SNathan Whitehorn 	    ps3bus_get_devtype(dev) != PS3_DEVTYPE_DISK)
1470d317057SNathan Whitehorn 		return (ENXIO);
1480d317057SNathan Whitehorn 
1490d317057SNathan Whitehorn 	device_set_desc(dev, "Playstation 3 Disk");
1500d317057SNathan Whitehorn 
1510d317057SNathan Whitehorn 	return (BUS_PROBE_SPECIFIC);
1520d317057SNathan Whitehorn }
1530d317057SNathan Whitehorn 
1540d317057SNathan Whitehorn static int
ps3disk_attach(device_t dev)1550d317057SNathan Whitehorn ps3disk_attach(device_t dev)
1560d317057SNathan Whitehorn {
1570d317057SNathan Whitehorn 	struct ps3disk_softc *sc;
1580d317057SNathan Whitehorn 	struct disk *d;
1590d317057SNathan Whitehorn 	intmax_t mb;
16098934b1fSNathan Whitehorn 	uint64_t junk;
1610d317057SNathan Whitehorn 	char unit;
1620d317057SNathan Whitehorn 	int i, err;
1630d317057SNathan Whitehorn 
1640d317057SNathan Whitehorn 	sc = device_get_softc(dev);
1650d317057SNathan Whitehorn 	sc->sc_dev = dev;
1660d317057SNathan Whitehorn 
1670d317057SNathan Whitehorn 	PS3DISK_LOCK_INIT(sc);
1680d317057SNathan Whitehorn 
1690d317057SNathan Whitehorn 	err = ps3disk_get_disk_geometry(sc);
1700d317057SNathan Whitehorn 	if (err) {
1710d317057SNathan Whitehorn 		device_printf(dev, "Could not get disk geometry\n");
1720d317057SNathan Whitehorn 		err = ENXIO;
1730d317057SNathan Whitehorn 		goto fail_destroy_lock;
1740d317057SNathan Whitehorn 	}
1750d317057SNathan Whitehorn 
1760d317057SNathan Whitehorn 	device_printf(dev, "block size %lu total blocks %lu\n",
1770d317057SNathan Whitehorn 	    sc->sc_blksize, sc->sc_nblocks);
1780d317057SNathan Whitehorn 
1790d317057SNathan Whitehorn 	err = ps3disk_enum_regions(sc);
1800d317057SNathan Whitehorn 	if (err) {
1810d317057SNathan Whitehorn 		device_printf(dev, "Could not enumerate disk regions\n");
1820d317057SNathan Whitehorn 		err = ENXIO;
1830d317057SNathan Whitehorn 		goto fail_destroy_lock;
1840d317057SNathan Whitehorn 	}
1850d317057SNathan Whitehorn 
1860d317057SNathan Whitehorn 	device_printf(dev, "Found %lu regions\n", sc->sc_nregs);
1870d317057SNathan Whitehorn 
1880d317057SNathan Whitehorn 	if (!sc->sc_nregs) {
1890d317057SNathan Whitehorn 		err = ENXIO;
1900d317057SNathan Whitehorn 		goto fail_destroy_lock;
1910d317057SNathan Whitehorn 	}
1920d317057SNathan Whitehorn 
1930d317057SNathan Whitehorn 	/* Setup interrupt handler */
1940d317057SNathan Whitehorn 	sc->sc_irqid = 0;
1950d317057SNathan Whitehorn 	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
1960d317057SNathan Whitehorn 	    RF_ACTIVE);
1970d317057SNathan Whitehorn 	if (!sc->sc_irq) {
1980d317057SNathan Whitehorn 		device_printf(dev, "Could not allocate IRQ\n");
1990d317057SNathan Whitehorn 		err = ENXIO;
2000d317057SNathan Whitehorn 		goto fail_free_regions;
2010d317057SNathan Whitehorn 	}
2020d317057SNathan Whitehorn 
2030d317057SNathan Whitehorn 	err = bus_setup_intr(dev, sc->sc_irq,
2040d317057SNathan Whitehorn 	    INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
20598934b1fSNathan Whitehorn 	    NULL, ps3disk_intr, sc, &sc->sc_irqctx);
2060d317057SNathan Whitehorn 	if (err) {
2070d317057SNathan Whitehorn 		device_printf(dev, "Could not setup IRQ\n");
2080d317057SNathan Whitehorn 		err = ENXIO;
2090d317057SNathan Whitehorn 		goto fail_release_intr;
2100d317057SNathan Whitehorn 	}
2110d317057SNathan Whitehorn 
21298934b1fSNathan Whitehorn 	/* Setup DMA */
2130d317057SNathan Whitehorn 	err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
2140d317057SNathan Whitehorn 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
21598934b1fSNathan Whitehorn 	    BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0,
21698934b1fSNathan Whitehorn 	    busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag);
2170d317057SNathan Whitehorn 	if (err) {
21898934b1fSNathan Whitehorn 		device_printf(dev, "Could not create DMA tag\n");
2190d317057SNathan Whitehorn 		err = ENXIO;
2200d317057SNathan Whitehorn 		goto fail_teardown_intr;
2210d317057SNathan Whitehorn 	}
2220d317057SNathan Whitehorn 
2230d317057SNathan Whitehorn 	/* Setup disks */
2240d317057SNathan Whitehorn 
2250d317057SNathan Whitehorn 	sc->sc_disk = malloc(sc->sc_nregs * sizeof(struct disk *),
2260d317057SNathan Whitehorn 	    M_PS3DISK, M_ZERO | M_WAITOK);
2270d317057SNathan Whitehorn 	if (!sc->sc_disk) {
2280d317057SNathan Whitehorn 		device_printf(dev, "Could not allocate disk(s)\n");
2290d317057SNathan Whitehorn 		err = ENOMEM;
23098934b1fSNathan Whitehorn 		goto fail_teardown_intr;
2310d317057SNathan Whitehorn 	}
2320d317057SNathan Whitehorn 
2330d317057SNathan Whitehorn 	for (i = 0; i < sc->sc_nregs; i++) {
234dfcd47a7SNathan Whitehorn 		struct ps3disk_region *rp = &sc->sc_reg[i];
235dfcd47a7SNathan Whitehorn 
2360d317057SNathan Whitehorn 		d = sc->sc_disk[i] = disk_alloc();
2370d317057SNathan Whitehorn 		d->d_open = ps3disk_open;
2380d317057SNathan Whitehorn 		d->d_close = ps3disk_close;
2390d317057SNathan Whitehorn 		d->d_strategy = ps3disk_strategy;
2400d317057SNathan Whitehorn 		d->d_name = "ps3disk";
2410d317057SNathan Whitehorn 		d->d_drv1 = sc;
24298934b1fSNathan Whitehorn 		d->d_maxsize = PAGE_SIZE;
2430d317057SNathan Whitehorn 		d->d_sectorsize = sc->sc_blksize;
2440d317057SNathan Whitehorn 		d->d_unit = i;
2450d317057SNathan Whitehorn 		d->d_mediasize = sc->sc_reg[i].r_size * sc->sc_blksize;
2460d317057SNathan Whitehorn 		d->d_flags |= DISKFLAG_CANFLUSHCACHE;
2470d317057SNathan Whitehorn 
2480d317057SNathan Whitehorn 		mb = d->d_mediasize >> 20;
2490d317057SNathan Whitehorn 		unit = 'M';
2500d317057SNathan Whitehorn 		if (mb >= 10240) {
2510d317057SNathan Whitehorn 			unit = 'G';
2520d317057SNathan Whitehorn 			mb /= 1024;
2530d317057SNathan Whitehorn 		}
2540d317057SNathan Whitehorn 
255dfcd47a7SNathan Whitehorn 		/* Test to see if we can read this region */
256dfcd47a7SNathan Whitehorn 		err = lv1_storage_read(ps3bus_get_device(dev), d->d_unit,
25798934b1fSNathan Whitehorn 		    0, 0, rp->r_flags, 0, &junk);
258dfcd47a7SNathan Whitehorn 		device_printf(dev, "region %d %ju%cB%s\n", i, mb, unit,
25998934b1fSNathan Whitehorn 		    (err == LV1_DENIED_BY_POLICY) ?  " (hypervisor protected)"
26098934b1fSNathan Whitehorn 		    : "");
2610d317057SNathan Whitehorn 
26298934b1fSNathan Whitehorn 		if (err != LV1_DENIED_BY_POLICY)
2630d317057SNathan Whitehorn 			disk_create(d, DISK_VERSION);
2640d317057SNathan Whitehorn 	}
265dfcd47a7SNathan Whitehorn 	err = 0;
2660d317057SNathan Whitehorn 
2670d317057SNathan Whitehorn 	bioq_init(&sc->sc_bioq);
26898934b1fSNathan Whitehorn 	bioq_init(&sc->sc_deferredq);
26998934b1fSNathan Whitehorn 	kproc_create(&ps3disk_task, sc, &sc->sc_task, 0, 0, "ps3disk");
2700d317057SNathan Whitehorn 
2710d317057SNathan Whitehorn 	ps3disk_sysctlattach(sc);
2720d317057SNathan Whitehorn 	sc->sc_running = 1;
2730d317057SNathan Whitehorn 	return (0);
2740d317057SNathan Whitehorn 
2750d317057SNathan Whitehorn fail_teardown_intr:
2760d317057SNathan Whitehorn 	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
2770d317057SNathan Whitehorn fail_release_intr:
2780d317057SNathan Whitehorn 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
2790d317057SNathan Whitehorn fail_free_regions:
2800d317057SNathan Whitehorn 	free(sc->sc_reg, M_PS3DISK);
2810d317057SNathan Whitehorn fail_destroy_lock:
2820d317057SNathan Whitehorn 	PS3DISK_LOCK_DESTROY(sc);
2830d317057SNathan Whitehorn 	return (err);
2840d317057SNathan Whitehorn }
2850d317057SNathan Whitehorn 
2860d317057SNathan Whitehorn static int
ps3disk_detach(device_t dev)2870d317057SNathan Whitehorn ps3disk_detach(device_t dev)
2880d317057SNathan Whitehorn {
2890d317057SNathan Whitehorn 	struct ps3disk_softc *sc = device_get_softc(dev);
2900d317057SNathan Whitehorn 	int i;
2910d317057SNathan Whitehorn 
2920d317057SNathan Whitehorn 	for (i = 0; i < sc->sc_nregs; i++)
2930d317057SNathan Whitehorn 		disk_destroy(sc->sc_disk[i]);
2940d317057SNathan Whitehorn 
29598934b1fSNathan Whitehorn 	bus_dma_tag_destroy(sc->sc_dmatag);
2960d317057SNathan Whitehorn 
2970d317057SNathan Whitehorn 	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
2980d317057SNathan Whitehorn 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
2990d317057SNathan Whitehorn 
3000d317057SNathan Whitehorn 	free(sc->sc_disk, M_PS3DISK);
3010d317057SNathan Whitehorn 	free(sc->sc_reg, M_PS3DISK);
3020d317057SNathan Whitehorn 
3030d317057SNathan Whitehorn 	PS3DISK_LOCK_DESTROY(sc);
3040d317057SNathan Whitehorn 
3050d317057SNathan Whitehorn 	return (0);
3060d317057SNathan Whitehorn }
3070d317057SNathan Whitehorn 
3080d317057SNathan Whitehorn static int
ps3disk_open(struct disk * dp)3090d317057SNathan Whitehorn ps3disk_open(struct disk *dp)
3100d317057SNathan Whitehorn {
3110d317057SNathan Whitehorn 	return (0);
3120d317057SNathan Whitehorn }
3130d317057SNathan Whitehorn 
3140d317057SNathan Whitehorn static int
ps3disk_close(struct disk * dp)3150d317057SNathan Whitehorn ps3disk_close(struct disk *dp)
3160d317057SNathan Whitehorn {
3170d317057SNathan Whitehorn 	return (0);
3180d317057SNathan Whitehorn }
3190d317057SNathan Whitehorn 
32098934b1fSNathan Whitehorn /* Process deferred blocks */
32198934b1fSNathan Whitehorn static void
ps3disk_task(void * arg)32298934b1fSNathan Whitehorn ps3disk_task(void *arg)
32398934b1fSNathan Whitehorn {
32498934b1fSNathan Whitehorn 	struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
32598934b1fSNathan Whitehorn 	struct bio *bp;
32698934b1fSNathan Whitehorn 
32798934b1fSNathan Whitehorn 	while (1) {
32898934b1fSNathan Whitehorn 		kproc_suspend_check(sc->sc_task);
32998934b1fSNathan Whitehorn 		tsleep(&sc->sc_deferredq, PRIBIO, "ps3disk", 10);
33098934b1fSNathan Whitehorn 
33198934b1fSNathan Whitehorn 		PS3DISK_LOCK(sc);
33298934b1fSNathan Whitehorn 		bp = bioq_takefirst(&sc->sc_deferredq);
33398934b1fSNathan Whitehorn 		PS3DISK_UNLOCK(sc);
33498934b1fSNathan Whitehorn 
33598934b1fSNathan Whitehorn 		if (bp == NULL)
33698934b1fSNathan Whitehorn 			continue;
33798934b1fSNathan Whitehorn 
33898934b1fSNathan Whitehorn 		if (bp->bio_driver1 != NULL) {
33998934b1fSNathan Whitehorn 			bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
34098934b1fSNathan Whitehorn 			    bp->bio_driver1);
34198934b1fSNathan Whitehorn 			bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
34298934b1fSNathan Whitehorn 			    bp->bio_driver1);
34398934b1fSNathan Whitehorn 		}
34498934b1fSNathan Whitehorn 
34598934b1fSNathan Whitehorn 		ps3disk_strategy(bp);
34698934b1fSNathan Whitehorn 	}
34798934b1fSNathan Whitehorn 
34898934b1fSNathan Whitehorn 	kproc_exit(0);
34998934b1fSNathan Whitehorn }
35098934b1fSNathan Whitehorn 
3510d317057SNathan Whitehorn static void
ps3disk_strategy(struct bio * bp)3520d317057SNathan Whitehorn ps3disk_strategy(struct bio *bp)
3530d317057SNathan Whitehorn {
3540d317057SNathan Whitehorn 	struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
35598934b1fSNathan Whitehorn 	int err;
3560d317057SNathan Whitehorn 
35798934b1fSNathan Whitehorn 	if (sc == NULL) {
3580d317057SNathan Whitehorn 		bp->bio_flags |= BIO_ERROR;
3590d317057SNathan Whitehorn 		bp->bio_error = EINVAL;
3600d317057SNathan Whitehorn 		biodone(bp);
3610d317057SNathan Whitehorn 		return;
3620d317057SNathan Whitehorn 	}
3630d317057SNathan Whitehorn 
3640d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
36598934b1fSNathan Whitehorn 	bp->bio_resid = bp->bio_bcount;
36698934b1fSNathan Whitehorn 	bioq_insert_tail(&sc->sc_bioq, bp);
3670d317057SNathan Whitehorn 
3680d317057SNathan Whitehorn 	DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_cmd 0x%02x\n",
3690d317057SNathan Whitehorn 	    __func__, bp->bio_cmd);
3700d317057SNathan Whitehorn 
37198934b1fSNathan Whitehorn 	err = 0;
3720d317057SNathan Whitehorn 	if (bp->bio_cmd == BIO_FLUSH) {
37398934b1fSNathan Whitehorn 		bp->bio_driver1 = 0;
37498934b1fSNathan Whitehorn 		err = lv1_storage_send_device_command(
37598934b1fSNathan Whitehorn 		    ps3bus_get_device(sc->sc_dev), LV1_STORAGE_ATA_HDDOUT,
37698934b1fSNathan Whitehorn 		    0, 0, 0, 0, (uint64_t *)&bp->bio_driver2);
37798934b1fSNathan Whitehorn 		if (err == LV1_BUSY)
37898934b1fSNathan Whitehorn 			err = EAGAIN;
3790d317057SNathan Whitehorn 	} else if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
38098934b1fSNathan Whitehorn 		if (bp->bio_bcount % sc->sc_blksize != 0) {
38198934b1fSNathan Whitehorn 			err = EINVAL;
3820d317057SNathan Whitehorn 		} else {
38398934b1fSNathan Whitehorn 			bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT,
38498934b1fSNathan Whitehorn 			    (bus_dmamap_t *)(&bp->bio_driver1));
38598934b1fSNathan Whitehorn 			err = bus_dmamap_load(sc->sc_dmatag,
38698934b1fSNathan Whitehorn 			    (bus_dmamap_t)(bp->bio_driver1), bp->bio_data,
38798934b1fSNathan Whitehorn 			    bp->bio_bcount, ps3disk_transfer, bp, 0);
38898934b1fSNathan Whitehorn 			if (err == EINPROGRESS)
38998934b1fSNathan Whitehorn 				err = 0;
39098934b1fSNathan Whitehorn 		}
39198934b1fSNathan Whitehorn 	} else {
39298934b1fSNathan Whitehorn 		err = EINVAL;
3930d317057SNathan Whitehorn 	}
3940d317057SNathan Whitehorn 
39598934b1fSNathan Whitehorn 	if (err == EAGAIN) {
39698934b1fSNathan Whitehorn 		bioq_remove(&sc->sc_bioq, bp);
39798934b1fSNathan Whitehorn 		bioq_insert_tail(&sc->sc_deferredq, bp);
39898934b1fSNathan Whitehorn 	} else if (err != 0) {
39998934b1fSNathan Whitehorn 		bp->bio_error = err;
4000d317057SNathan Whitehorn 		bp->bio_flags |= BIO_ERROR;
40198934b1fSNathan Whitehorn 		bioq_remove(&sc->sc_bioq, bp);
4020d317057SNathan Whitehorn 		disk_err(bp, "hard error", -1, 1);
4030d317057SNathan Whitehorn 		biodone(bp);
4040d317057SNathan Whitehorn 	}
4050d317057SNathan Whitehorn 
4060d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
4070d317057SNathan Whitehorn }
4080d317057SNathan Whitehorn 
4090d317057SNathan Whitehorn static void
ps3disk_intr(void * arg)4100d317057SNathan Whitehorn ps3disk_intr(void *arg)
4110d317057SNathan Whitehorn {
4120d317057SNathan Whitehorn 	struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
4130d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
4140d317057SNathan Whitehorn 	uint64_t devid = ps3bus_get_device(dev);
41598934b1fSNathan Whitehorn 	struct bio *bp;
4160d317057SNathan Whitehorn 	uint64_t tag, status;
41798934b1fSNathan Whitehorn 
41898934b1fSNathan Whitehorn 	if (lv1_storage_get_async_status(devid, &tag, &status) != 0)
41998934b1fSNathan Whitehorn 		return;
4200d317057SNathan Whitehorn 
4210d317057SNathan Whitehorn 	PS3DISK_LOCK(sc);
4220d317057SNathan Whitehorn 
42398934b1fSNathan Whitehorn 	DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: tag 0x%016lx "
42498934b1fSNathan Whitehorn 	    "status 0x%016lx\n", __func__, tag, status);
4250d317057SNathan Whitehorn 
42698934b1fSNathan Whitehorn 	/* Locate the matching request */
42798934b1fSNathan Whitehorn 	TAILQ_FOREACH(bp, &sc->sc_bioq.queue, bio_queue) {
42898934b1fSNathan Whitehorn 		if ((uint64_t)bp->bio_driver2 != tag)
42998934b1fSNathan Whitehorn 			continue;
4300d317057SNathan Whitehorn 
43198934b1fSNathan Whitehorn 		if (status != 0) {
43298934b1fSNathan Whitehorn 			device_printf(sc->sc_dev, "%s error (%#lx)\n",
43398934b1fSNathan Whitehorn 			    (bp->bio_cmd == BIO_READ) ? "Read" : "Write",
43498934b1fSNathan Whitehorn 			    status);
43598934b1fSNathan Whitehorn 			bp->bio_error = EIO;
43698934b1fSNathan Whitehorn 			bp->bio_flags |= BIO_ERROR;
43798934b1fSNathan Whitehorn 		} else {
43898934b1fSNathan Whitehorn 			bp->bio_error = 0;
43998934b1fSNathan Whitehorn 			bp->bio_resid = 0;
44098934b1fSNathan Whitehorn 			bp->bio_flags |= BIO_DONE;
4410d317057SNathan Whitehorn 		}
4420d317057SNathan Whitehorn 
44398934b1fSNathan Whitehorn 		if (bp->bio_driver1 != NULL) {
44498934b1fSNathan Whitehorn 			if (bp->bio_cmd == BIO_READ)
44598934b1fSNathan Whitehorn 				bus_dmamap_sync(sc->sc_dmatag, (bus_dmamap_t)
44698934b1fSNathan Whitehorn 				    bp->bio_driver1, BUS_DMASYNC_POSTREAD);
44798934b1fSNathan Whitehorn 			bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
44898934b1fSNathan Whitehorn 			    bp->bio_driver1);
44998934b1fSNathan Whitehorn 			bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
45098934b1fSNathan Whitehorn 			    bp->bio_driver1);
45198934b1fSNathan Whitehorn 		}
4520d317057SNathan Whitehorn 
45398934b1fSNathan Whitehorn 		bioq_remove(&sc->sc_bioq, bp);
45498934b1fSNathan Whitehorn 		biodone(bp);
45598934b1fSNathan Whitehorn 		break;
45698934b1fSNathan Whitehorn 	}
4570d317057SNathan Whitehorn 
45898934b1fSNathan Whitehorn 	if (bioq_first(&sc->sc_deferredq) != NULL)
45998934b1fSNathan Whitehorn 		wakeup(&sc->sc_deferredq);
4600d317057SNathan Whitehorn 
4610d317057SNathan Whitehorn 	PS3DISK_UNLOCK(sc);
4620d317057SNathan Whitehorn }
4630d317057SNathan Whitehorn 
4640d317057SNathan Whitehorn static int
ps3disk_get_disk_geometry(struct ps3disk_softc * sc)4650d317057SNathan Whitehorn ps3disk_get_disk_geometry(struct ps3disk_softc *sc)
4660d317057SNathan Whitehorn {
4670d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
4680d317057SNathan Whitehorn 	uint64_t bus_index = ps3bus_get_busidx(dev);
4690d317057SNathan Whitehorn 	uint64_t dev_index = ps3bus_get_devidx(dev);
4700d317057SNathan Whitehorn 	uint64_t junk;
4710d317057SNathan Whitehorn 	int err;
4720d317057SNathan Whitehorn 
4730d317057SNathan Whitehorn 	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
4740d317057SNathan Whitehorn 	    (lv1_repository_string("bus") >> 32) | bus_index,
4750d317057SNathan Whitehorn 	    lv1_repository_string("dev") | dev_index,
4760d317057SNathan Whitehorn 	    lv1_repository_string("blk_size"), 0, &sc->sc_blksize, &junk);
4770d317057SNathan Whitehorn 	if (err) {
4780d317057SNathan Whitehorn 		device_printf(dev, "Could not get block size (0x%08x)\n", err);
47998934b1fSNathan Whitehorn 		return (ENXIO);
4800d317057SNathan Whitehorn 	}
4810d317057SNathan Whitehorn 
4820d317057SNathan Whitehorn 	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
4830d317057SNathan Whitehorn 	    (lv1_repository_string("bus") >> 32) | bus_index,
4840d317057SNathan Whitehorn 	    lv1_repository_string("dev") | dev_index,
4850d317057SNathan Whitehorn 	    lv1_repository_string("n_blocks"), 0, &sc->sc_nblocks, &junk);
4860d317057SNathan Whitehorn 	if (err) {
48798934b1fSNathan Whitehorn 		device_printf(dev, "Could not get total number of blocks "
48898934b1fSNathan Whitehorn 		    "(0x%08x)\n", err);
4890d317057SNathan Whitehorn 		err = ENXIO;
4900d317057SNathan Whitehorn 	}
4910d317057SNathan Whitehorn 
4920d317057SNathan Whitehorn 	return (err);
4930d317057SNathan Whitehorn }
4940d317057SNathan Whitehorn 
4950d317057SNathan Whitehorn static int
ps3disk_enum_regions(struct ps3disk_softc * sc)4960d317057SNathan Whitehorn ps3disk_enum_regions(struct ps3disk_softc *sc)
4970d317057SNathan Whitehorn {
4980d317057SNathan Whitehorn 	device_t dev = sc->sc_dev;
4990d317057SNathan Whitehorn 	uint64_t bus_index = ps3bus_get_busidx(dev);
5000d317057SNathan Whitehorn 	uint64_t dev_index = ps3bus_get_devidx(dev);
5010d317057SNathan Whitehorn 	uint64_t junk;
5020d317057SNathan Whitehorn 	int i, err;
5030d317057SNathan Whitehorn 
5040d317057SNathan Whitehorn 	/* Read number of regions */
5050d317057SNathan Whitehorn 
5060d317057SNathan Whitehorn 	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
5070d317057SNathan Whitehorn 	    (lv1_repository_string("bus") >> 32) | bus_index,
5080d317057SNathan Whitehorn 	    lv1_repository_string("dev") | dev_index,
5090d317057SNathan Whitehorn 	    lv1_repository_string("n_regs"), 0, &sc->sc_nregs, &junk);
5100d317057SNathan Whitehorn 	if (err) {
5110d317057SNathan Whitehorn 		device_printf(dev, "Could not get number of regions (0x%08x)\n",
5120d317057SNathan Whitehorn 		    err);
5130d317057SNathan Whitehorn 		err = ENXIO;
5140d317057SNathan Whitehorn 		goto fail;
5150d317057SNathan Whitehorn 	}
5160d317057SNathan Whitehorn 
5170d317057SNathan Whitehorn 	if (!sc->sc_nregs)
5180d317057SNathan Whitehorn 		return 0;
5190d317057SNathan Whitehorn 
5200d317057SNathan Whitehorn 	sc->sc_reg = malloc(sc->sc_nregs * sizeof(struct ps3disk_region),
5210d317057SNathan Whitehorn 	    M_PS3DISK, M_ZERO | M_WAITOK);
5220d317057SNathan Whitehorn 	if (!sc->sc_reg) {
5230d317057SNathan Whitehorn 		err = ENOMEM;
5240d317057SNathan Whitehorn 		goto fail;
5250d317057SNathan Whitehorn 	}
5260d317057SNathan Whitehorn 
5270d317057SNathan Whitehorn 	/* Setup regions */
5280d317057SNathan Whitehorn 
5290d317057SNathan Whitehorn 	for (i = 0; i < sc->sc_nregs; i++) {
5300d317057SNathan Whitehorn 		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
5310d317057SNathan Whitehorn 		    (lv1_repository_string("bus") >> 32) | bus_index,
5320d317057SNathan Whitehorn 		    lv1_repository_string("dev") | dev_index,
5330d317057SNathan Whitehorn 		    lv1_repository_string("region") | i,
5340d317057SNathan Whitehorn 		    lv1_repository_string("id"), &sc->sc_reg[i].r_id, &junk);
5350d317057SNathan Whitehorn 		if (err) {
5360d317057SNathan Whitehorn 			device_printf(dev, "Could not get region id (0x%08x)\n",
5370d317057SNathan Whitehorn 			    err);
5380d317057SNathan Whitehorn 			err = ENXIO;
5390d317057SNathan Whitehorn 			goto fail;
5400d317057SNathan Whitehorn 		}
5410d317057SNathan Whitehorn 
5420d317057SNathan Whitehorn 		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
5430d317057SNathan Whitehorn 		    (lv1_repository_string("bus") >> 32) | bus_index,
5440d317057SNathan Whitehorn 		    lv1_repository_string("dev") | dev_index,
5450d317057SNathan Whitehorn 		    lv1_repository_string("region") | i,
54698934b1fSNathan Whitehorn 		    lv1_repository_string("start"), &sc->sc_reg[i].r_start,
54798934b1fSNathan Whitehorn 		    &junk);
5480d317057SNathan Whitehorn 		if (err) {
54998934b1fSNathan Whitehorn 			device_printf(dev, "Could not get region start "
55098934b1fSNathan Whitehorn 			    "(0x%08x)\n", err);
5510d317057SNathan Whitehorn 			err = ENXIO;
5520d317057SNathan Whitehorn 			goto fail;
5530d317057SNathan Whitehorn 		}
5540d317057SNathan Whitehorn 
5550d317057SNathan Whitehorn 		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
5560d317057SNathan Whitehorn 		    (lv1_repository_string("bus") >> 32) | bus_index,
5570d317057SNathan Whitehorn 		    lv1_repository_string("dev") | dev_index,
5580d317057SNathan Whitehorn 		    lv1_repository_string("region") | i,
55998934b1fSNathan Whitehorn 		    lv1_repository_string("size"), &sc->sc_reg[i].r_size,
56098934b1fSNathan Whitehorn 		    &junk);
5610d317057SNathan Whitehorn 		if (err) {
56298934b1fSNathan Whitehorn 			device_printf(dev, "Could not get region size "
56398934b1fSNathan Whitehorn 			    "(0x%08x)\n", err);
5640d317057SNathan Whitehorn 			err = ENXIO;
5650d317057SNathan Whitehorn 			goto fail;
5660d317057SNathan Whitehorn 		}
5670d317057SNathan Whitehorn 
5680d317057SNathan Whitehorn 		if (i == 0)
5690d317057SNathan Whitehorn 			sc->sc_reg[i].r_flags = 0x2;
5700d317057SNathan Whitehorn 		else
5710d317057SNathan Whitehorn 			sc->sc_reg[i].r_flags = 0;
5720d317057SNathan Whitehorn 	}
5730d317057SNathan Whitehorn 
5740d317057SNathan Whitehorn 	return (0);
5750d317057SNathan Whitehorn 
5760d317057SNathan Whitehorn fail:
5770d317057SNathan Whitehorn 
5780d317057SNathan Whitehorn 	sc->sc_nregs = 0;
5790d317057SNathan Whitehorn 	if (sc->sc_reg)
5800d317057SNathan Whitehorn 		free(sc->sc_reg, M_PS3DISK);
5810d317057SNathan Whitehorn 
5820d317057SNathan Whitehorn 	return (err);
5830d317057SNathan Whitehorn }
5840d317057SNathan Whitehorn 
58598934b1fSNathan Whitehorn static void
ps3disk_transfer(void * arg,bus_dma_segment_t * segs,int nsegs,int error)58698934b1fSNathan Whitehorn ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
5870d317057SNathan Whitehorn {
58898934b1fSNathan Whitehorn 	struct bio *bp = (struct bio *)(arg);
58998934b1fSNathan Whitehorn 	struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
59098934b1fSNathan Whitehorn 	struct ps3disk_region *rp = &sc->sc_reg[bp->bio_disk->d_unit];
59198934b1fSNathan Whitehorn 	uint64_t devid = ps3bus_get_device(sc->sc_dev);
59298934b1fSNathan Whitehorn 	uint64_t block;
59398934b1fSNathan Whitehorn 	int i, err;
5940d317057SNathan Whitehorn 
59598934b1fSNathan Whitehorn 	/* Locks already held by busdma */
59698934b1fSNathan Whitehorn 	PS3DISK_ASSERT_LOCKED(sc);
5970d317057SNathan Whitehorn 
59898934b1fSNathan Whitehorn 	if (error) {
59998934b1fSNathan Whitehorn 		bp->bio_error = error;
60098934b1fSNathan Whitehorn 		bp->bio_flags |= BIO_ERROR;
60198934b1fSNathan Whitehorn 		bioq_remove(&sc->sc_bioq, bp);
60298934b1fSNathan Whitehorn 		biodone(bp);
60398934b1fSNathan Whitehorn 		return;
6040d317057SNathan Whitehorn 	}
6050d317057SNathan Whitehorn 
60698934b1fSNathan Whitehorn 	block = bp->bio_pblkno;
60798934b1fSNathan Whitehorn 	for (i = 0; i < nsegs; i++) {
60898934b1fSNathan Whitehorn 		KASSERT((segs[i].ds_len % sc->sc_blksize) == 0,
60998934b1fSNathan Whitehorn 		    ("DMA fragments not blocksize multiples"));
6100d317057SNathan Whitehorn 
61198934b1fSNathan Whitehorn 		if (bp->bio_cmd == BIO_READ) {
6120d317057SNathan Whitehorn 			err = lv1_storage_read(devid, rp->r_id,
61398934b1fSNathan Whitehorn 			    block, segs[i].ds_len/sc->sc_blksize,
61498934b1fSNathan Whitehorn 			    rp->r_flags, segs[i].ds_addr,
61598934b1fSNathan Whitehorn 			    (uint64_t *)&bp->bio_driver2);
61698934b1fSNathan Whitehorn 		} else {
61798934b1fSNathan Whitehorn 			bus_dmamap_sync(sc->sc_dmatag,
61898934b1fSNathan Whitehorn 			    (bus_dmamap_t)bp->bio_driver1,
61998934b1fSNathan Whitehorn 			    BUS_DMASYNC_PREWRITE);
62098934b1fSNathan Whitehorn 			err = lv1_storage_write(devid, rp->r_id,
62198934b1fSNathan Whitehorn 			    block, segs[i].ds_len/sc->sc_blksize,
62298934b1fSNathan Whitehorn 			    rp->r_flags, segs[i].ds_addr,
62398934b1fSNathan Whitehorn 			    (uint64_t *)&bp->bio_driver2);
62498934b1fSNathan Whitehorn 		}
62598934b1fSNathan Whitehorn 
6260d317057SNathan Whitehorn 		if (err) {
62798934b1fSNathan Whitehorn 			if (err == LV1_BUSY) {
62898934b1fSNathan Whitehorn 				bioq_remove(&sc->sc_bioq, bp);
62998934b1fSNathan Whitehorn 				bioq_insert_tail(&sc->sc_deferredq, bp);
63098934b1fSNathan Whitehorn 			} else {
63198934b1fSNathan Whitehorn 				bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
63298934b1fSNathan Whitehorn 				    bp->bio_driver1);
63398934b1fSNathan Whitehorn 				bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
63498934b1fSNathan Whitehorn 				    bp->bio_driver1);
63598934b1fSNathan Whitehorn 				device_printf(sc->sc_dev, "Could not read "
63698934b1fSNathan Whitehorn 				    "sectors (0x%08x)\n", err);
63798934b1fSNathan Whitehorn 				bp->bio_error = EINVAL;
63898934b1fSNathan Whitehorn 				bp->bio_flags |= BIO_ERROR;
63998934b1fSNathan Whitehorn 				bioq_remove(&sc->sc_bioq, bp);
64098934b1fSNathan Whitehorn 				biodone(bp);
64198934b1fSNathan Whitehorn 			}
64298934b1fSNathan Whitehorn 
64398934b1fSNathan Whitehorn 			break;
6440d317057SNathan Whitehorn 		}
6450d317057SNathan Whitehorn 
6460d317057SNathan Whitehorn 		DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n",
6470d317057SNathan Whitehorn 		    __func__, sc->sc_bounce_tag);
6480d317057SNathan Whitehorn 	}
6490d317057SNathan Whitehorn }
6500d317057SNathan Whitehorn 
6510d317057SNathan Whitehorn #ifdef PS3DISK_DEBUG
6520d317057SNathan Whitehorn static int
ps3disk_sysctl_debug(SYSCTL_HANDLER_ARGS)6530d317057SNathan Whitehorn ps3disk_sysctl_debug(SYSCTL_HANDLER_ARGS)
6540d317057SNathan Whitehorn {
6550d317057SNathan Whitehorn 	struct ps3disk_softc *sc = arg1;
6560d317057SNathan Whitehorn 	int debug, error;
6570d317057SNathan Whitehorn 
6580d317057SNathan Whitehorn 	debug = sc->sc_debug;
6590d317057SNathan Whitehorn 
6600d317057SNathan Whitehorn 	error = sysctl_handle_int(oidp, &debug, 0, req);
6610d317057SNathan Whitehorn 	if (error || !req->newptr)
6620d317057SNathan Whitehorn 		return error;
6630d317057SNathan Whitehorn 
6640d317057SNathan Whitehorn 	sc->sc_debug = debug;
6650d317057SNathan Whitehorn 
6660d317057SNathan Whitehorn 	return 0;
6670d317057SNathan Whitehorn }
6680d317057SNathan Whitehorn #endif
6690d317057SNathan Whitehorn 
6700d317057SNathan Whitehorn static void
ps3disk_sysctlattach(struct ps3disk_softc * sc)6710d317057SNathan Whitehorn ps3disk_sysctlattach(struct ps3disk_softc *sc)
6720d317057SNathan Whitehorn {
6730d317057SNathan Whitehorn #ifdef PS3DISK_DEBUG
6740d317057SNathan Whitehorn 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
6750d317057SNathan Whitehorn 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
6760d317057SNathan Whitehorn 
6770d317057SNathan Whitehorn 	sc->sc_debug = ps3disk_debug;
6780d317057SNathan Whitehorn 
6790d317057SNathan Whitehorn 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
6807029da5cSPawel Biernacki 	    "debug", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
6810d317057SNathan Whitehorn 	    ps3disk_sysctl_debug, "I", "control debugging printfs");
6820d317057SNathan Whitehorn #endif
6830d317057SNathan Whitehorn }
6840d317057SNathan Whitehorn 
6850d317057SNathan Whitehorn static device_method_t ps3disk_methods[] = {
6860d317057SNathan Whitehorn 	DEVMETHOD(device_probe,		ps3disk_probe),
6870d317057SNathan Whitehorn 	DEVMETHOD(device_attach,	ps3disk_attach),
6880d317057SNathan Whitehorn 	DEVMETHOD(device_detach,	ps3disk_detach),
6890d317057SNathan Whitehorn 	{0, 0},
6900d317057SNathan Whitehorn };
6910d317057SNathan Whitehorn 
6920d317057SNathan Whitehorn static driver_t ps3disk_driver = {
6930d317057SNathan Whitehorn 	"ps3disk",
6940d317057SNathan Whitehorn 	ps3disk_methods,
6950d317057SNathan Whitehorn 	sizeof(struct ps3disk_softc),
6960d317057SNathan Whitehorn };
6970d317057SNathan Whitehorn 
698c331b0e4SJohn Baldwin DRIVER_MODULE(ps3disk, ps3bus, ps3disk_driver, 0, 0);
699