summaryrefslogtreecommitdiffstats
path: root/sys/powerpc/ps3/ps3disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/powerpc/ps3/ps3disk.c')
-rw-r--r--sys/powerpc/ps3/ps3disk.c702
1 files changed, 702 insertions, 0 deletions
diff --git a/sys/powerpc/ps3/ps3disk.c b/sys/powerpc/ps3/ps3disk.c
new file mode 100644
index 0000000..3bab0f2
--- /dev/null
+++ b/sys/powerpc/ps3/ps3disk.c
@@ -0,0 +1,702 @@
+/*-
+ * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/disk.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/pio.h>
+#include <machine/bus.h>
+#include <machine/platform.h>
+#include <machine/pmap.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <geom/geom_disk.h>
+
+#include "ps3bus.h"
+#include "ps3-hvcall.h"
+
+#define PS3DISK_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3disk", MTX_DEF)
+#define PS3DISK_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+#define PS3DISK_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define PS3DISK_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define PS3DISK_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define PS3DISK_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+#define LV1_STORAGE_ATA_HDDOUT 0x23
+
+SYSCTL_NODE(_hw, OID_AUTO, ps3disk, CTLFLAG_RD, 0, "PS3 Disk driver parameters");
+
+#ifdef PS3DISK_DEBUG
+static int ps3disk_debug = 0;
+SYSCTL_INT(_hw_ps3disk, OID_AUTO, debug, CTLFLAG_RW, &ps3disk_debug,
+ 0, "control debugging printfs");
+TUNABLE_INT("hw.ps3disk.debug", &ps3disk_debug);
+enum {
+ PS3DISK_DEBUG_INTR = 0x00000001,
+ PS3DISK_DEBUG_TASK = 0x00000002,
+ PS3DISK_DEBUG_READ = 0x00000004,
+ PS3DISK_DEBUG_WRITE = 0x00000008,
+ PS3DISK_DEBUG_FLUSH = 0x00000010,
+ PS3DISK_DEBUG_ANY = 0xffffffff
+};
+#define DPRINTF(sc, m, fmt, ...) \
+do { \
+ if (sc->sc_debug & (m)) \
+ printf(fmt, __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(sc, m, fmt, ...)
+#endif
+
+struct ps3disk_region {
+ uint64_t r_id;
+ uint64_t r_start;
+ uint64_t r_size;
+ uint64_t r_flags;
+};
+
+struct ps3disk_softc {
+ device_t sc_dev;
+
+ struct mtx sc_mtx;
+
+ uint64_t sc_blksize;
+ uint64_t sc_nblocks;
+
+ uint64_t sc_nregs;
+ struct ps3disk_region *sc_reg;
+
+ int sc_irqid;
+ struct resource *sc_irq;
+ void *sc_irqctx;
+
+ struct disk **sc_disk;
+
+ struct bio_queue_head sc_bioq;
+ struct bio_queue_head sc_deferredq;
+ struct proc *sc_task;
+
+ bus_dma_tag_t sc_dmatag;
+
+ int sc_running;
+ int sc_debug;
+};
+
+static int ps3disk_open(struct disk *dp);
+static int ps3disk_close(struct disk *dp);
+static void ps3disk_strategy(struct bio *bp);
+
+static void ps3disk_task(void *arg);
+static void ps3disk_intr(void *arg);
+static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc);
+static int ps3disk_enum_regions(struct ps3disk_softc *sc);
+static void ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
+ int error);
+
+static void ps3disk_sysctlattach(struct ps3disk_softc *sc);
+
+static MALLOC_DEFINE(M_PS3DISK, "ps3disk", "PS3 Disk");
+
+static int
+ps3disk_probe(device_t dev)
+{
+ if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
+ ps3bus_get_devtype(dev) != PS3_DEVTYPE_DISK)
+ return (ENXIO);
+
+ device_set_desc(dev, "Playstation 3 Disk");
+
+ return (BUS_PROBE_SPECIFIC);
+}
+
+static int
+ps3disk_attach(device_t dev)
+{
+ struct ps3disk_softc *sc;
+ struct disk *d;
+ intmax_t mb;
+ uint64_t junk;
+ char unit;
+ int i, err;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+
+ PS3DISK_LOCK_INIT(sc);
+
+ err = ps3disk_get_disk_geometry(sc);
+ if (err) {
+ device_printf(dev, "Could not get disk geometry\n");
+ err = ENXIO;
+ goto fail_destroy_lock;
+ }
+
+ device_printf(dev, "block size %lu total blocks %lu\n",
+ sc->sc_blksize, sc->sc_nblocks);
+
+ err = ps3disk_enum_regions(sc);
+ if (err) {
+ device_printf(dev, "Could not enumerate disk regions\n");
+ err = ENXIO;
+ goto fail_destroy_lock;
+ }
+
+ device_printf(dev, "Found %lu regions\n", sc->sc_nregs);
+
+ if (!sc->sc_nregs) {
+ err = ENXIO;
+ goto fail_destroy_lock;
+ }
+
+ /* Setup interrupt handler */
+ sc->sc_irqid = 0;
+ sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
+ RF_ACTIVE);
+ if (!sc->sc_irq) {
+ device_printf(dev, "Could not allocate IRQ\n");
+ err = ENXIO;
+ goto fail_free_regions;
+ }
+
+ err = bus_setup_intr(dev, sc->sc_irq,
+ INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
+ NULL, ps3disk_intr, sc, &sc->sc_irqctx);
+ if (err) {
+ device_printf(dev, "Could not setup IRQ\n");
+ err = ENXIO;
+ goto fail_release_intr;
+ }
+
+ /* Setup DMA */
+ err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0,
+ busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag);
+ if (err) {
+ device_printf(dev, "Could not create DMA tag\n");
+ err = ENXIO;
+ goto fail_teardown_intr;
+ }
+
+ /* Setup disks */
+
+ sc->sc_disk = malloc(sc->sc_nregs * sizeof(struct disk *),
+ M_PS3DISK, M_ZERO | M_WAITOK);
+ if (!sc->sc_disk) {
+ device_printf(dev, "Could not allocate disk(s)\n");
+ err = ENOMEM;
+ goto fail_teardown_intr;
+ }
+
+ for (i = 0; i < sc->sc_nregs; i++) {
+ struct ps3disk_region *rp = &sc->sc_reg[i];
+
+ d = sc->sc_disk[i] = disk_alloc();
+ d->d_open = ps3disk_open;
+ d->d_close = ps3disk_close;
+ d->d_strategy = ps3disk_strategy;
+ d->d_name = "ps3disk";
+ d->d_drv1 = sc;
+ d->d_maxsize = PAGE_SIZE;
+ d->d_sectorsize = sc->sc_blksize;
+ d->d_unit = i;
+ d->d_mediasize = sc->sc_reg[i].r_size * sc->sc_blksize;
+ d->d_flags |= DISKFLAG_CANFLUSHCACHE;
+
+ mb = d->d_mediasize >> 20;
+ unit = 'M';
+ if (mb >= 10240) {
+ unit = 'G';
+ mb /= 1024;
+ }
+
+ /* Test to see if we can read this region */
+ err = lv1_storage_read(ps3bus_get_device(dev), d->d_unit,
+ 0, 0, rp->r_flags, 0, &junk);
+ device_printf(dev, "region %d %ju%cB%s\n", i, mb, unit,
+ (err == LV1_DENIED_BY_POLICY) ? " (hypervisor protected)"
+ : "");
+
+ if (err != LV1_DENIED_BY_POLICY)
+ disk_create(d, DISK_VERSION);
+ }
+ err = 0;
+
+ bioq_init(&sc->sc_bioq);
+ bioq_init(&sc->sc_deferredq);
+ kproc_create(&ps3disk_task, sc, &sc->sc_task, 0, 0, "ps3disk");
+
+ ps3disk_sysctlattach(sc);
+ sc->sc_running = 1;
+ return (0);
+
+fail_teardown_intr:
+ bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
+fail_release_intr:
+ bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
+fail_free_regions:
+ free(sc->sc_reg, M_PS3DISK);
+fail_destroy_lock:
+ PS3DISK_LOCK_DESTROY(sc);
+ return (err);
+}
+
+static int
+ps3disk_detach(device_t dev)
+{
+ struct ps3disk_softc *sc = device_get_softc(dev);
+ int i;
+
+ for (i = 0; i < sc->sc_nregs; i++)
+ disk_destroy(sc->sc_disk[i]);
+
+ bus_dma_tag_destroy(sc->sc_dmatag);
+
+ bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
+
+ free(sc->sc_disk, M_PS3DISK);
+ free(sc->sc_reg, M_PS3DISK);
+
+ PS3DISK_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static int
+ps3disk_open(struct disk *dp)
+{
+ return (0);
+}
+
+static int
+ps3disk_close(struct disk *dp)
+{
+ return (0);
+}
+
+/* Process deferred blocks */
+static void
+ps3disk_task(void *arg)
+{
+ struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
+ struct bio *bp;
+
+
+ while (1) {
+ kproc_suspend_check(sc->sc_task);
+ tsleep(&sc->sc_deferredq, PRIBIO, "ps3disk", 10);
+
+ PS3DISK_LOCK(sc);
+ bp = bioq_takefirst(&sc->sc_deferredq);
+ PS3DISK_UNLOCK(sc);
+
+ if (bp == NULL)
+ continue;
+
+ if (bp->bio_driver1 != NULL) {
+ bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
+ bp->bio_driver1);
+ bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
+ bp->bio_driver1);
+ }
+
+ ps3disk_strategy(bp);
+ }
+
+ kproc_exit(0);
+}
+
+static void
+ps3disk_strategy(struct bio *bp)
+{
+ struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
+ int err;
+
+ if (sc == NULL) {
+ bp->bio_flags |= BIO_ERROR;
+ bp->bio_error = EINVAL;
+ biodone(bp);
+ return;
+ }
+
+ PS3DISK_LOCK(sc);
+ bp->bio_resid = bp->bio_bcount;
+ bioq_insert_tail(&sc->sc_bioq, bp);
+
+ DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_cmd 0x%02x\n",
+ __func__, bp->bio_cmd);
+
+ err = 0;
+ if (bp->bio_cmd == BIO_FLUSH) {
+ bp->bio_driver1 = 0;
+ err = lv1_storage_send_device_command(
+ ps3bus_get_device(sc->sc_dev), LV1_STORAGE_ATA_HDDOUT,
+ 0, 0, 0, 0, (uint64_t *)&bp->bio_driver2);
+ if (err == LV1_BUSY)
+ err = EAGAIN;
+ } else if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
+ if (bp->bio_bcount % sc->sc_blksize != 0) {
+ err = EINVAL;
+ } else {
+ bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT,
+ (bus_dmamap_t *)(&bp->bio_driver1));
+ err = bus_dmamap_load(sc->sc_dmatag,
+ (bus_dmamap_t)(bp->bio_driver1), bp->bio_data,
+ bp->bio_bcount, ps3disk_transfer, bp, 0);
+ if (err == EINPROGRESS)
+ err = 0;
+ }
+ } else {
+ err = EINVAL;
+ }
+
+ if (err == EAGAIN) {
+ bioq_remove(&sc->sc_bioq, bp);
+ bioq_insert_tail(&sc->sc_deferredq, bp);
+ } else if (err != 0) {
+ bp->bio_error = err;
+ bp->bio_flags |= BIO_ERROR;
+ bioq_remove(&sc->sc_bioq, bp);
+ disk_err(bp, "hard error", -1, 1);
+ biodone(bp);
+ }
+
+ PS3DISK_UNLOCK(sc);
+}
+
+static void
+ps3disk_intr(void *arg)
+{
+ struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
+ device_t dev = sc->sc_dev;
+ uint64_t devid = ps3bus_get_device(dev);
+ struct bio *bp;
+ uint64_t tag, status;
+
+ if (lv1_storage_get_async_status(devid, &tag, &status) != 0)
+ return;
+
+ PS3DISK_LOCK(sc);
+
+ DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: tag 0x%016lx "
+ "status 0x%016lx\n", __func__, tag, status);
+
+ /* Locate the matching request */
+ TAILQ_FOREACH(bp, &sc->sc_bioq.queue, bio_queue) {
+ if ((uint64_t)bp->bio_driver2 != tag)
+ continue;
+
+ if (status != 0) {
+ device_printf(sc->sc_dev, "%s error (%#lx)\n",
+ (bp->bio_cmd == BIO_READ) ? "Read" : "Write",
+ status);
+ bp->bio_error = EIO;
+ bp->bio_flags |= BIO_ERROR;
+ } else {
+ bp->bio_error = 0;
+ bp->bio_resid = 0;
+ bp->bio_flags |= BIO_DONE;
+ }
+
+ if (bp->bio_driver1 != NULL) {
+ if (bp->bio_cmd == BIO_READ)
+ bus_dmamap_sync(sc->sc_dmatag, (bus_dmamap_t)
+ bp->bio_driver1, BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
+ bp->bio_driver1);
+ bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
+ bp->bio_driver1);
+ }
+
+ bioq_remove(&sc->sc_bioq, bp);
+ biodone(bp);
+ break;
+ }
+
+ if (bioq_first(&sc->sc_deferredq) != NULL)
+ wakeup(&sc->sc_deferredq);
+
+ PS3DISK_UNLOCK(sc);
+}
+
+static int
+ps3disk_get_disk_geometry(struct ps3disk_softc *sc)
+{
+ device_t dev = sc->sc_dev;
+ uint64_t bus_index = ps3bus_get_busidx(dev);
+ uint64_t dev_index = ps3bus_get_devidx(dev);
+ uint64_t junk;
+ int err;
+
+ err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
+ (lv1_repository_string("bus") >> 32) | bus_index,
+ lv1_repository_string("dev") | dev_index,
+ lv1_repository_string("blk_size"), 0, &sc->sc_blksize, &junk);
+ if (err) {
+ device_printf(dev, "Could not get block size (0x%08x)\n", err);
+ return (ENXIO);
+ }
+
+ err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
+ (lv1_repository_string("bus") >> 32) | bus_index,
+ lv1_repository_string("dev") | dev_index,
+ lv1_repository_string("n_blocks"), 0, &sc->sc_nblocks, &junk);
+ if (err) {
+ device_printf(dev, "Could not get total number of blocks "
+ "(0x%08x)\n", err);
+ err = ENXIO;
+ }
+
+ return (err);
+}
+
+static int
+ps3disk_enum_regions(struct ps3disk_softc *sc)
+{
+ device_t dev = sc->sc_dev;
+ uint64_t bus_index = ps3bus_get_busidx(dev);
+ uint64_t dev_index = ps3bus_get_devidx(dev);
+ uint64_t junk;
+ int i, err;
+
+ /* Read number of regions */
+
+ err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
+ (lv1_repository_string("bus") >> 32) | bus_index,
+ lv1_repository_string("dev") | dev_index,
+ lv1_repository_string("n_regs"), 0, &sc->sc_nregs, &junk);
+ if (err) {
+ device_printf(dev, "Could not get number of regions (0x%08x)\n",
+ err);
+ err = ENXIO;
+ goto fail;
+ }
+
+ if (!sc->sc_nregs)
+ return 0;
+
+ sc->sc_reg = malloc(sc->sc_nregs * sizeof(struct ps3disk_region),
+ M_PS3DISK, M_ZERO | M_WAITOK);
+ if (!sc->sc_reg) {
+ err = ENOMEM;
+ goto fail;
+ }
+
+ /* Setup regions */
+
+ for (i = 0; i < sc->sc_nregs; i++) {
+ err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
+ (lv1_repository_string("bus") >> 32) | bus_index,
+ lv1_repository_string("dev") | dev_index,
+ lv1_repository_string("region") | i,
+ lv1_repository_string("id"), &sc->sc_reg[i].r_id, &junk);
+ if (err) {
+ device_printf(dev, "Could not get region id (0x%08x)\n",
+ err);
+ err = ENXIO;
+ goto fail;
+ }
+
+ err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
+ (lv1_repository_string("bus") >> 32) | bus_index,
+ lv1_repository_string("dev") | dev_index,
+ lv1_repository_string("region") | i,
+ lv1_repository_string("start"), &sc->sc_reg[i].r_start,
+ &junk);
+ if (err) {
+ device_printf(dev, "Could not get region start "
+ "(0x%08x)\n", err);
+ err = ENXIO;
+ goto fail;
+ }
+
+ err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
+ (lv1_repository_string("bus") >> 32) | bus_index,
+ lv1_repository_string("dev") | dev_index,
+ lv1_repository_string("region") | i,
+ lv1_repository_string("size"), &sc->sc_reg[i].r_size,
+ &junk);
+ if (err) {
+ device_printf(dev, "Could not get region size "
+ "(0x%08x)\n", err);
+ err = ENXIO;
+ goto fail;
+ }
+
+ if (i == 0)
+ sc->sc_reg[i].r_flags = 0x2;
+ else
+ sc->sc_reg[i].r_flags = 0;
+ }
+
+ return (0);
+
+fail:
+
+ sc->sc_nregs = 0;
+ if (sc->sc_reg)
+ free(sc->sc_reg, M_PS3DISK);
+
+ return (err);
+}
+
+static void
+ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct bio *bp = (struct bio *)(arg);
+ struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
+ struct ps3disk_region *rp = &sc->sc_reg[bp->bio_disk->d_unit];
+ uint64_t devid = ps3bus_get_device(sc->sc_dev);
+ uint64_t block;
+ int i, err;
+
+ /* Locks already held by busdma */
+ PS3DISK_ASSERT_LOCKED(sc);
+
+ if (error) {
+ bp->bio_error = error;
+ bp->bio_flags |= BIO_ERROR;
+ bioq_remove(&sc->sc_bioq, bp);
+ biodone(bp);
+ return;
+ }
+
+ block = bp->bio_pblkno;
+ for (i = 0; i < nsegs; i++) {
+ KASSERT((segs[i].ds_len % sc->sc_blksize) == 0,
+ ("DMA fragments not blocksize multiples"));
+
+ if (bp->bio_cmd == BIO_READ) {
+ err = lv1_storage_read(devid, rp->r_id,
+ block, segs[i].ds_len/sc->sc_blksize,
+ rp->r_flags, segs[i].ds_addr,
+ (uint64_t *)&bp->bio_driver2);
+ } else {
+ bus_dmamap_sync(sc->sc_dmatag,
+ (bus_dmamap_t)bp->bio_driver1,
+ BUS_DMASYNC_PREWRITE);
+ err = lv1_storage_write(devid, rp->r_id,
+ block, segs[i].ds_len/sc->sc_blksize,
+ rp->r_flags, segs[i].ds_addr,
+ (uint64_t *)&bp->bio_driver2);
+ }
+
+ if (err) {
+ if (err == LV1_BUSY) {
+ bioq_remove(&sc->sc_bioq, bp);
+ bioq_insert_tail(&sc->sc_deferredq, bp);
+ } else {
+ bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
+ bp->bio_driver1);
+ bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
+ bp->bio_driver1);
+ device_printf(sc->sc_dev, "Could not read "
+ "sectors (0x%08x)\n", err);
+ bp->bio_error = EINVAL;
+ bp->bio_flags |= BIO_ERROR;
+ bioq_remove(&sc->sc_bioq, bp);
+ biodone(bp);
+ }
+
+ break;
+ }
+
+ DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n",
+ __func__, sc->sc_bounce_tag);
+ }
+}
+
+#ifdef PS3DISK_DEBUG
+static int
+ps3disk_sysctl_debug(SYSCTL_HANDLER_ARGS)
+{
+ struct ps3disk_softc *sc = arg1;
+ int debug, error;
+
+ debug = sc->sc_debug;
+
+ error = sysctl_handle_int(oidp, &debug, 0, req);
+ if (error || !req->newptr)
+ return error;
+
+ sc->sc_debug = debug;
+
+ return 0;
+}
+#endif
+
+static void
+ps3disk_sysctlattach(struct ps3disk_softc *sc)
+{
+#ifdef PS3DISK_DEBUG
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+ struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+
+ sc->sc_debug = ps3disk_debug;
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "debug", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ps3disk_sysctl_debug, "I", "control debugging printfs");
+#endif
+}
+
+static device_method_t ps3disk_methods[] = {
+ DEVMETHOD(device_probe, ps3disk_probe),
+ DEVMETHOD(device_attach, ps3disk_attach),
+ DEVMETHOD(device_detach, ps3disk_detach),
+ {0, 0},
+};
+
+static driver_t ps3disk_driver = {
+ "ps3disk",
+ ps3disk_methods,
+ sizeof(struct ps3disk_softc),
+};
+
+static devclass_t ps3disk_devclass;
+
+DRIVER_MODULE(ps3disk, ps3bus, ps3disk_driver, ps3disk_devclass, 0, 0);
OpenPOWER on IntegriCloud