The branch main has been updated by imp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=813f244b27eba29aebaad0b725f30c58216bfab9

commit 813f244b27eba29aebaad0b725f30c58216bfab9
Author:     Chattrapat Sangmanee <aomsi...@hotmail.co.th>
AuthorDate: 2024-10-16 14:49:22 +0000
Commit:     Warner Losh <i...@freebsd.org>
CommitDate: 2025-01-24 19:40:34 +0000

    ps3disk.c: Rewrite ps3disk_transfer
    
    This function is bugged since the beginning, but it never hit because
    its variable doesn't allow.  However, since commit
    a77e1f0f81df5fa3b4a6a38728ebace599cb18a4 it happen now.
    
    First, it assume that ds_len will always equal to real user requested
    size.  So it being used for sector count calculation.  This is no longer
    true, and will fail if attempt to read last few sectors.  Use
    bp->bio_length instead.
    
    Second, this being a loop is pointless because nsegs will never be > 1
    as specified at bus_dma_tag_create() call.  And all it doing is to
    repeat very same command again but with different ds_addr.  Since
    bio_driver2 tag ident pointer are being reused, the result will be
    discarded at ps3disk_intr().
    
    Signed-off-by: Chattrapat Sangmanee <aomsi...@hotmail.co.th>
    Reviewed by: imp,mav
    Pull Request: https://github.com/freebsd/freebsd-src/pull/1414
---
 sys/powerpc/ps3/ps3disk.c | 96 +++++++++++++++++++++++++++--------------------
 1 file changed, 55 insertions(+), 41 deletions(-)

diff --git a/sys/powerpc/ps3/ps3disk.c b/sys/powerpc/ps3/ps3disk.c
index 0931e6aad58b..4d9976ecccee 100644
--- a/sys/powerpc/ps3/ps3disk.c
+++ b/sys/powerpc/ps3/ps3disk.c
@@ -588,9 +588,10 @@ 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];
+       bus_dma_segment_t *seg = &segs[0];
        uint64_t devid = ps3bus_get_device(sc->sc_dev);
-       uint64_t block;
-       int i, err;
+       uint64_t block, bio_length, sector_op_count;
+       int err;
 
        /* Locks already held by busdma */
        PS3DISK_ASSERT_LOCKED(sc);
@@ -603,49 +604,62 @@ ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int 
nsegs, int error)
                return;
        }
 
+       /* supports only 1 segment */
+
+       KASSERT(nsegs == 1,
+                   ("nsegs must be 1!, %d", nsegs));
+
        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);
-               }
+       bio_length = bp->bio_length;
 
-               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;
-               }
+       /* ds_len always >= bio_length */
+
+       KASSERT((seg->ds_len % bio_length) == 0,
+                   ("ds_len not bio_length multiples, %lu, %lu",
+                   (uint64_t)seg->ds_len, bio_length));
 
-               DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n",
-                   __func__, sc->sc_bounce_tag);
+       KASSERT((bio_length % sc->sc_blksize) == 0,
+                   ("bio_length not blocksize multiples, %lu, %lu",
+                   bio_length, (uint64_t)sc->sc_blksize));
+
+       sector_op_count = bio_length / sc->sc_blksize;
+
+       if (bp->bio_cmd == BIO_READ) {
+               err = lv1_storage_read(devid, rp->r_id,
+                               block, sector_op_count,
+                               rp->r_flags, seg->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, sector_op_count,
+                       rp->r_flags, seg->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);
+               }
+       }
+
+       DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n",
+               __func__, sc->sc_bounce_tag);
 }
 
 #ifdef PS3DISK_DEBUG

Reply via email to