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