diff options
author | nwhitehorn <nwhitehorn@FreeBSD.org> | 2011-06-23 03:37:25 +0000 |
---|---|---|
committer | nwhitehorn <nwhitehorn@FreeBSD.org> | 2011-06-23 03:37:25 +0000 |
commit | 92790aaa8760da434387dac80633830e0948f088 (patch) | |
tree | 2edbe5bd6d72c0bc0a210b9d8cbc4bc2aa6a12e0 | |
parent | d2b9ceb5222a753c78eaae12244828f5799af35a (diff) | |
download | FreeBSD-src-92790aaa8760da434387dac80633830e0948f088.zip FreeBSD-src-92790aaa8760da434387dac80633830e0948f088.tar.gz |
Rework the PS3 disk driver to support NCQ and do its DMA a little
differently.
-rw-r--r-- | sys/powerpc/ps3/ps3disk.c | 577 |
1 files changed, 189 insertions, 388 deletions
diff --git a/sys/powerpc/ps3/ps3disk.c b/sys/powerpc/ps3/ps3disk.c index 5390f50..3bab0f2 100644 --- a/sys/powerpc/ps3/ps3disk.c +++ b/sys/powerpc/ps3/ps3disk.c @@ -116,39 +116,25 @@ struct ps3disk_softc { struct disk **sc_disk; struct bio_queue_head sc_bioq; + struct bio_queue_head sc_deferredq; + struct proc *sc_task; - struct proc *sc_task; - - int sc_bounce_maxblocks; - bus_dma_tag_t sc_bounce_dmatag; - bus_dmamap_t sc_bounce_dmamap; - bus_addr_t sc_bounce_dmaphys; - char *sc_bounce; - uint64_t sc_bounce_lpar; - int sc_bounce_busy; - uint64_t sc_bounce_tag; - uint64_t sc_bounce_status; + 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 int ps3disk_intr_filter(void *arg); +static void ps3disk_task(void *arg); static void ps3disk_intr(void *arg); -static void ps3disk_getphys(void *arg, bus_dma_segment_t *segs, int nsegs, int error); static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc); static int ps3disk_enum_regions(struct ps3disk_softc *sc); -static int ps3disk_read(struct ps3disk_softc *sc, int regidx, - uint64_t start_sector, uint64_t sector_count, char *data); -static int ps3disk_write(struct ps3disk_softc *sc, int regidx, - uint64_t start_sector, uint64_t sector_count, char *data); -static int ps3disk_flush(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); @@ -172,6 +158,7 @@ ps3disk_attach(device_t dev) struct ps3disk_softc *sc; struct disk *d; intmax_t mb; + uint64_t junk; char unit; int i, err; @@ -205,7 +192,6 @@ ps3disk_attach(device_t dev) } /* Setup interrupt handler */ - sc->sc_irqid = 0; sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid, RF_ACTIVE); @@ -217,52 +203,24 @@ ps3disk_attach(device_t dev) err = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY, - ps3disk_intr_filter, ps3disk_intr, sc, &sc->sc_irqctx); + 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 bounce buffer */ - - sc->sc_bounce_maxblocks = DFLTPHYS / sc->sc_blksize; - + /* Setup DMA */ err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, - sc->sc_bounce_maxblocks * sc->sc_blksize, 1, - sc->sc_bounce_maxblocks * sc->sc_blksize, - 0, NULL, NULL, &sc->sc_bounce_dmatag); + 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 for bounce buffer\n"); + device_printf(dev, "Could not create DMA tag\n"); err = ENXIO; goto fail_teardown_intr; } - err = bus_dmamem_alloc(sc->sc_bounce_dmatag, (void **) &sc->sc_bounce, - BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, - &sc->sc_bounce_dmamap); - if (err) { - device_printf(dev, "Could not allocate DMA memory for bounce buffer\n"); - err = ENXIO; - goto fail_destroy_dmatag; - } - - err = bus_dmamap_load(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap, - sc->sc_bounce, sc->sc_bounce_maxblocks * sc->sc_blksize, - ps3disk_getphys, &sc->sc_bounce_dmaphys, 0); - if (err) { - device_printf(dev, "Could not load DMA map for bounce buffer\n"); - err = ENXIO; - goto fail_free_dmamem; - } - - sc->sc_bounce_lpar = vtophys(sc->sc_bounce); - - if (bootverbose) - device_printf(dev, "bounce buffer lpar address 0x%016lx\n", - sc->sc_bounce_lpar); - /* Setup disks */ sc->sc_disk = malloc(sc->sc_nregs * sizeof(struct disk *), @@ -270,7 +228,7 @@ ps3disk_attach(device_t dev) if (!sc->sc_disk) { device_printf(dev, "Could not allocate disk(s)\n"); err = ENOMEM; - goto fail_unload_dmamem; + goto fail_teardown_intr; } for (i = 0; i < sc->sc_nregs; i++) { @@ -282,7 +240,7 @@ ps3disk_attach(device_t dev) d->d_strategy = ps3disk_strategy; d->d_name = "ps3disk"; d->d_drv1 = sc; - d->d_maxsize = DFLTPHYS; + 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; @@ -297,53 +255,32 @@ ps3disk_attach(device_t dev) /* Test to see if we can read this region */ err = lv1_storage_read(ps3bus_get_device(dev), d->d_unit, - 0, 1, rp->r_flags, sc->sc_bounce_lpar, &sc->sc_bounce_tag); + 0, 0, rp->r_flags, 0, &junk); device_printf(dev, "region %d %ju%cB%s\n", i, mb, unit, - (err == 0) ? "" : " (hypervisor protected)"); + (err == LV1_DENIED_BY_POLICY) ? " (hypervisor protected)" + : ""); - if (err == 0) + 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; - - kproc_create(&ps3disk_task, sc, &sc->sc_task, 0, 0, "task: ps3disk"); - return (0); -fail_unload_dmamem: - - bus_dmamap_unload(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap); - -fail_free_dmamem: - - bus_dmamem_free(sc->sc_bounce_dmatag, sc->sc_bounce, sc->sc_bounce_dmamap); - -fail_destroy_dmatag: - - bus_dma_tag_destroy(sc->sc_bounce_dmatag); - 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); } @@ -353,28 +290,15 @@ ps3disk_detach(device_t dev) struct ps3disk_softc *sc = device_get_softc(dev); int i; - PS3DISK_LOCK(sc); - sc->sc_running = 0; - wakeup(sc); - PS3DISK_UNLOCK(sc); - - PS3DISK_LOCK(sc); - while (sc->sc_running != -1) - msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0); - PS3DISK_UNLOCK(sc); - for (i = 0; i < sc->sc_nregs; i++) disk_destroy(sc->sc_disk[i]); - bus_dmamap_unload(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap); - bus_dmamem_free(sc->sc_bounce_dmatag, sc->sc_bounce, sc->sc_bounce_dmamap); - bus_dma_tag_destroy(sc->sc_bounce_dmatag); + 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); @@ -394,127 +318,94 @@ ps3disk_close(struct disk *dp) return (0); } -static void -ps3disk_strategy(struct bio *bp) -{ - struct ps3disk_softc *sc = (struct ps3disk_softc *) bp->bio_disk->d_drv1; - - if (!sc) { - bp->bio_flags |= BIO_ERROR; - bp->bio_error = EINVAL; - biodone(bp); - return; - } - - PS3DISK_LOCK(sc); - bioq_disksort(&sc->sc_bioq, bp); - if (!sc->sc_bounce_busy) - wakeup(sc); - PS3DISK_UNLOCK(sc); -} - +/* Process deferred blocks */ static void ps3disk_task(void *arg) { struct ps3disk_softc *sc = (struct ps3disk_softc *) arg; struct bio *bp; - daddr_t block, end; - u_long nblocks; - char *data; - int err; - while (sc->sc_running) { + + while (1) { + kproc_suspend_check(sc->sc_task); + tsleep(&sc->sc_deferredq, PRIBIO, "ps3disk", 10); + PS3DISK_LOCK(sc); - do { - bp = bioq_first(&sc->sc_bioq); - if (bp == NULL) - msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); - } while (bp == NULL && sc->sc_running); - if (bp) - bioq_remove(&sc->sc_bioq, bp); + bp = bioq_takefirst(&sc->sc_deferredq); PS3DISK_UNLOCK(sc); - if (!sc->sc_running) - break; + if (bp == NULL) + continue; - DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_cmd 0x%02x\n", - __func__, bp->bio_cmd); + 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); + } - if (bp->bio_cmd == BIO_FLUSH) { - err = ps3disk_flush(sc); + ps3disk_strategy(bp); + } - if (err) { - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - } else { - bp->bio_error = 0; - bp->bio_flags |= BIO_DONE; - } - } else if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { - end = bp->bio_pblkno + (bp->bio_bcount / sc->sc_blksize); - - DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_pblkno %ld bio_bcount %ld\n", - __func__, bp->bio_pblkno, bp->bio_bcount); - - for (block = bp->bio_pblkno; block < end;) { - data = bp->bio_data + - (block - bp->bio_pblkno) * sc->sc_blksize; - - nblocks = end - block; - if (nblocks > sc->sc_bounce_maxblocks) - nblocks = sc->sc_bounce_maxblocks; - - DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: nblocks %lu\n", - __func__, nblocks); - - if (bp->bio_cmd == BIO_READ) { - err = ps3disk_read(sc, bp->bio_disk->d_unit, - block, nblocks, data); - } else { - err = ps3disk_write(sc, bp->bio_disk->d_unit, - block, nblocks, data); - } - - if (err) - break; - - block += nblocks; - } + kproc_exit(0); +} - bp->bio_resid = (end - block) * sc->sc_blksize; - if (bp->bio_resid) { - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - } else { - bp->bio_error = 0; - bp->bio_flags |= BIO_DONE; - } +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_resid %ld\n", - __func__, bp->bio_resid); + 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 { - bp->bio_error = EINVAL; - bp->bio_flags |= BIO_ERROR; + 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 (bp->bio_flags & BIO_ERROR) - disk_err(bp, "hard error", -1, 1); - + 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_LOCK(sc); - sc->sc_running = -1; - wakeup(sc); PS3DISK_UNLOCK(sc); - - kproc_exit(0); -} - -static int -ps3disk_intr_filter(void *arg) -{ - return (FILTER_SCHEDULE_THREAD); } static void @@ -523,50 +414,55 @@ 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; - int err; + if (lv1_storage_get_async_status(devid, &tag, &status) != 0) + return; + PS3DISK_LOCK(sc); - err = lv1_storage_get_async_status(devid, &tag, &status); - - DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: err %d tag 0x%016lx status 0x%016lx\n", - __func__, err, tag, status); - - if (err) - goto out; + DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: tag 0x%016lx " + "status 0x%016lx\n", __func__, tag, status); - if (!sc->sc_bounce_busy) { - device_printf(dev, "Got interrupt while no request pending\n"); - goto out; - } - - if (tag != sc->sc_bounce_tag) - device_printf(dev, "Tag mismatch, got 0x%016lx expected 0x%016lx\n", - tag, sc->sc_bounce_tag); + /* Locate the matching request */ + TAILQ_FOREACH(bp, &sc->sc_bioq.queue, bio_queue) { + if ((uint64_t)bp->bio_driver2 != tag) + continue; - if (status) - device_printf(dev, "Request completed with status 0x%016lx\n", status); + 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; + } - sc->sc_bounce_status = status; - sc->sc_bounce_busy = 0; + 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); + } - wakeup(sc); + bioq_remove(&sc->sc_bioq, bp); + biodone(bp); + break; + } -out: + if (bioq_first(&sc->sc_deferredq) != NULL) + wakeup(&sc->sc_deferredq); PS3DISK_UNLOCK(sc); } -static void -ps3disk_getphys(void *arg, bus_dma_segment_t *segs, int nsegs, int error) -{ - if (error != 0) - return; - - *(bus_addr_t *) arg = segs[0].ds_addr; -} - static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc) { @@ -582,8 +478,7 @@ ps3disk_get_disk_geometry(struct ps3disk_softc *sc) lv1_repository_string("blk_size"), 0, &sc->sc_blksize, &junk); if (err) { device_printf(dev, "Could not get block size (0x%08x)\n", err); - err = ENXIO; - goto out; + return (ENXIO); } err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, @@ -591,16 +486,11 @@ ps3disk_get_disk_geometry(struct ps3disk_softc *sc) 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); + device_printf(dev, "Could not get total number of blocks " + "(0x%08x)\n", err); err = ENXIO; - goto out; } - err = 0; - -out: - return (err); } @@ -655,10 +545,11 @@ ps3disk_enum_regions(struct ps3disk_softc *sc) (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); + 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); + device_printf(dev, "Could not get region start " + "(0x%08x)\n", err); err = ENXIO; goto fail; } @@ -667,16 +558,16 @@ ps3disk_enum_regions(struct ps3disk_softc *sc) (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); + 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); + device_printf(dev, "Could not get region size " + "(0x%08x)\n", err); err = ENXIO; goto fail; } if (i == 0) - /* disables HV access control and grants access to whole disk */ sc->sc_reg[i].r_flags = 0x2; else sc->sc_reg[i].r_flags = 0; @@ -693,160 +584,70 @@ fail: return (err); } -static int -ps3disk_read(struct ps3disk_softc *sc, int regidx, - uint64_t start_sector, uint64_t sector_count, char *data) -{ - device_t dev = sc->sc_dev; - struct ps3disk_region *rp = &sc->sc_reg[regidx]; - uint64_t devid = ps3bus_get_device(dev); - int err; - - PS3DISK_LOCK(sc); - - if (sc->sc_bounce_busy) { - device_printf(dev, "busy\n"); - PS3DISK_UNLOCK(sc); - return EIO; - } - - sc->sc_bounce_busy = 1; - - err = lv1_storage_read(devid, rp->r_id, - start_sector, sector_count, rp->r_flags, - sc->sc_bounce_lpar, &sc->sc_bounce_tag); - if (err) { - device_printf(dev, "Could not read sectors (0x%08x)\n", err); - err = EIO; - goto out; - } - - DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n", - __func__, sc->sc_bounce_tag); - - err = msleep(sc, &sc->sc_mtx, PRIBIO, "read", hz); - if (err) { - device_printf(dev, "Read request timed out\n"); - err = EIO; - goto out; - } - - if (sc->sc_bounce_busy || sc->sc_bounce_status) { - err = EIO; - } else { - bus_dmamap_sync(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap, - BUS_DMASYNC_POSTREAD); - memcpy(data, sc->sc_bounce, sector_count * sc->sc_blksize); - err = 0; - } - -out: - - sc->sc_bounce_busy = 0; - - PS3DISK_UNLOCK(sc); - - return (err); -} - -static int -ps3disk_write(struct ps3disk_softc *sc, int regidx, - uint64_t start_sector, uint64_t sector_count, char *data) +static void +ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { - device_t dev = sc->sc_dev; - struct ps3disk_region *rp = &sc->sc_reg[regidx]; - uint64_t devid = ps3bus_get_device(dev); - int err; - - PS3DISK_LOCK(sc); - - if (sc->sc_bounce_busy) { - device_printf(dev, "busy\n"); - PS3DISK_UNLOCK(sc); - return EIO; - } - - memcpy(sc->sc_bounce, data, sector_count * sc->sc_blksize); - - bus_dmamap_sync(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap, - BUS_DMASYNC_PREWRITE); - - sc->sc_bounce_busy = 1; - - err = lv1_storage_write(devid, rp->r_id, - start_sector, sector_count, rp->r_flags, - sc->sc_bounce_lpar, &sc->sc_bounce_tag); - if (err) { - device_printf(dev, "Could not write sectors (0x%08x)\n", err); - err = EIO; - goto out; - } + 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; - DPRINTF(sc, PS3DISK_DEBUG_WRITE, "%s: tag 0x%016lx\n", - __func__, sc->sc_bounce_tag); + /* Locks already held by busdma */ + PS3DISK_ASSERT_LOCKED(sc); - err = msleep(sc, &sc->sc_mtx, PRIBIO, "write", hz); - if (err) { - device_printf(dev, "Write request timed out\n"); - err = EIO; - goto out; + if (error) { + bp->bio_error = error; + bp->bio_flags |= BIO_ERROR; + bioq_remove(&sc->sc_bioq, bp); + biodone(bp); + return; } - err = (sc->sc_bounce_busy || sc->sc_bounce_status) ? EIO : 0; - -out: - - sc->sc_bounce_busy = 0; - - PS3DISK_UNLOCK(sc); - - return (err); -} - -static int -ps3disk_flush(struct ps3disk_softc *sc) -{ - device_t dev = sc->sc_dev; - uint64_t devid = ps3bus_get_device(dev); - int err; - - PS3DISK_LOCK(sc); + 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 (sc->sc_bounce_busy) { - device_printf(dev, "busy\n"); - PS3DISK_UNLOCK(sc); - return EIO; - } - - sc->sc_bounce_busy = 1; + 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); + } - err = lv1_storage_send_device_command(devid, LV1_STORAGE_ATA_HDDOUT, - 0, 0, 0, 0, &sc->sc_bounce_tag); - if (err) { - device_printf(dev, "Could not flush (0x%08x)\n", err); - err = EIO; - goto out; - } + 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); + } - DPRINTF(sc, PS3DISK_DEBUG_FLUSH, "%s: tag 0x%016lx\n", - __func__, sc->sc_bounce_tag); + break; + } - err = msleep(sc, &sc->sc_mtx, PRIBIO, "flush", hz); - if (err) { - device_printf(dev, "Flush request timed out\n"); - err = EIO; - goto out; + DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n", + __func__, sc->sc_bounce_tag); } - - err = (sc->sc_bounce_busy || sc->sc_bounce_status) ? EIO : 0; - -out: - - sc->sc_bounce_busy = 0; - - PS3DISK_UNLOCK(sc); - - return (err); } #ifdef PS3DISK_DEBUG |