From baff09db2cf68bb71d0dbd02758fd44a3dfca6a0 Mon Sep 17 00:00:00 2001 From: Mike Smith Date: Sat, 6 May 2000 08:54:33 +0000 Subject: [PATCH] Change the way that scatter/gather list tables are allocated so that we can use all of the s/g entries available on smaller cards. This is necessary if we want to be able to handle a non-page-aligned 64k transfer on 2.x and 3.x firmware. Fix a missing splx() that may have left us at splbio() for longer than desired. Reduce shadowing of controller-supplied parameters a little. --- sys/dev/mlx/mlx.c | 70 +++++++++++++++++++++++++----------------- sys/dev/mlx/mlx_disk.c | 10 ++++-- sys/dev/mlx/mlx_pci.c | 2 +- sys/dev/mlx/mlxvar.h | 15 +++++---- 4 files changed, 58 insertions(+), 39 deletions(-) diff --git a/sys/dev/mlx/mlx.c b/sys/dev/mlx/mlx.c index 942bebbe1cb5..9bb87caa1cb5 100644 --- a/sys/dev/mlx/mlx.c +++ b/sys/dev/mlx/mlx.c @@ -227,7 +227,7 @@ static int mlx_sglist_map(struct mlx_softc *sc) { size_t segsize; - int error; + int error, ncmd; debug_called(1); @@ -239,9 +239,16 @@ mlx_sglist_map(struct mlx_softc *sc) /* * Create a single tag describing a region large enough to hold all of - * the s/g lists we will need. + * the s/g lists we will need. If we're called early on, we don't know how + * many commands we're going to be asked to support, so only allocate enough + * for a couple. */ - segsize = sizeof(struct mlx_sgentry) * sc->mlx_sg_nseg * sc->mlx_maxiop; + if (sc->mlx_enq2 == NULL) { + ncmd = 2; + } else { + ncmd = sc->mlx_enq2->me_max_commands; + } + segsize = sizeof(struct mlx_sgentry) * MLX_NSEG * ncmd; error = bus_dma_tag_create(sc->mlx_parent_dmat, /* parent */ 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ @@ -301,21 +308,18 @@ mlx_attach(struct mlx_softc *sc) sc->mlx_findcomplete = mlx_v3_findcomplete; sc->mlx_intaction = mlx_v3_intaction; sc->mlx_fw_handshake = mlx_v3_fw_handshake; - sc->mlx_sg_nseg = MLX_NSEG_OLD; break; case MLX_IFTYPE_4: sc->mlx_tryqueue = mlx_v4_tryqueue; sc->mlx_findcomplete = mlx_v4_findcomplete; sc->mlx_intaction = mlx_v4_intaction; sc->mlx_fw_handshake = mlx_v4_fw_handshake; - sc->mlx_sg_nseg = MLX_NSEG_NEW; break; case MLX_IFTYPE_5: sc->mlx_tryqueue = mlx_v5_tryqueue; sc->mlx_findcomplete = mlx_v5_findcomplete; sc->mlx_intaction = mlx_v5_intaction; sc->mlx_fw_handshake = mlx_v5_fw_handshake; - sc->mlx_sg_nseg = MLX_NSEG_NEW; break; default: mlx_free(sc); @@ -376,7 +380,7 @@ mlx_attach(struct mlx_softc *sc) BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - MAXBSIZE, sc->mlx_sg_nseg, /* maxsize, nsegments */ + MAXBSIZE, MLX_NSEG, /* maxsize, nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 0, /* flags */ &sc->mlx_buffer_dmat); @@ -387,9 +391,8 @@ mlx_attach(struct mlx_softc *sc) } /* - * Create an initial set of s/g mappings. + * Create some initial scatter/gather mappings so we can run the probe commands. */ - sc->mlx_maxiop = 8; error = mlx_sglist_map(sc); if (error != 0) { device_printf(sc->mlx_dev, "can't make initial s/g list mapping\n"); @@ -397,18 +400,20 @@ mlx_attach(struct mlx_softc *sc) return(error); } - /* send an ENQUIRY2 to the controller */ + /* + * We don't (yet) know where the event log is up to. + */ + sc->mlx_currevent = -1; + + /* + * Obtain controller feature information + */ if ((sc->mlx_enq2 = mlx_enquire(sc, MLX_CMD_ENQUIRY2, sizeof(struct mlx_enquiry2), NULL)) == NULL) { device_printf(sc->mlx_dev, "ENQUIRY2 failed\n"); mlx_free(sc); return(ENXIO); } - /* - * We don't (yet) know where the event log is up to. - */ - sc->mlx_currevent = -1; - /* * Do quirk/feature related things. */ @@ -456,13 +461,11 @@ mlx_attach(struct mlx_softc *sc) } /* - * Create the final set of s/g mappings now that we know how many commands - * the controller actually supports. + * Create the final scatter/gather mappings now that we have characterised the controller. */ - sc->mlx_maxiop = sc->mlx_enq2->me_max_commands; error = mlx_sglist_map(sc); if (error != 0) { - device_printf(sc->mlx_dev, "can't make permanent s/g list mapping\n"); + device_printf(sc->mlx_dev, "can't make final s/g list mapping\n"); mlx_free(sc); return(error); } @@ -1953,13 +1956,19 @@ static int mlx_getslot(struct mlx_command *mc) { struct mlx_softc *sc = mc->mc_sc; - int s, slot; + int s, slot, limit; debug_called(1); - /* enforce slot-usage limit */ - if (sc->mlx_busycmds >= ((mc->mc_flags & MLX_CMD_PRIORITY) ? - sc->mlx_maxiop : sc->mlx_maxiop - 4)) + /* + * Enforce slot-usage limit, if we have the required information. + */ + if (sc->mlx_enq2 != NULL) { + limit = sc->mlx_enq2->me_max_commands; + } else { + limit = 2; + } + if (sc->mlx_busycmds >= ((mc->mc_flags & MLX_CMD_PRIORITY) ? limit : limit - 4)) return(EBUSY); /* @@ -1968,19 +1977,19 @@ mlx_getslot(struct mlx_command *mc) * XXX linear search is slow */ s = splbio(); - for (slot = 0; slot < sc->mlx_maxiop; slot++) { + for (slot = 0; slot < limit; slot++) { debug(2, "try slot %d", slot); if (sc->mlx_busycmd[slot] == NULL) break; } - if (slot < sc->mlx_maxiop) { + if (slot < limit) { sc->mlx_busycmd[slot] = mc; sc->mlx_busycmds++; } splx(s); /* out of slots? */ - if (slot >= sc->mlx_maxiop) + if (slot >= limit) return(EBUSY); debug(2, "got slot %d", slot); @@ -2001,12 +2010,16 @@ mlx_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) debug_called(1); + /* XXX should be unnecessary */ + if (sc->mlx_enq2 && (nsegments > sc->mlx_enq2->me_max_sg)) + panic("MLX: too many s/g segments (%d, max %d)", nsegments, sc->mlx_enq2->me_max_sg); + /* get base address of s/g table */ - sg = sc->mlx_sgtable + (mc->mc_slot * sc->mlx_sg_nseg); + sg = sc->mlx_sgtable + (mc->mc_slot * MLX_NSEG); /* save s/g table information in command */ mc->mc_nsgent = nsegments; - mc->mc_sgphys = sc->mlx_sgbusaddr + (mc->mc_slot * sc->mlx_sg_nseg * sizeof(struct mlx_sgentry)); + mc->mc_sgphys = sc->mlx_sgbusaddr + (mc->mc_slot * MLX_NSEG * sizeof(struct mlx_sgentry)); mc->mc_dataphys = segs[0].ds_addr; /* populate s/g table */ @@ -2146,6 +2159,7 @@ mlx_done(struct mlx_softc *sc) break; } } + splx(s); /* if we've completed any commands, try posting some more */ if (result) diff --git a/sys/dev/mlx/mlx_disk.c b/sys/dev/mlx/mlx_disk.c index 190f7a785468..558474921fe4 100644 --- a/sys/dev/mlx/mlx_disk.c +++ b/sys/dev/mlx/mlx_disk.c @@ -236,6 +236,7 @@ mlxd_attach(device_t dev) device_t parent; char *state; dev_t dsk; + int s1, s2; debug_called(1); @@ -272,8 +273,13 @@ mlxd_attach(device_t dev) dsk->si_drv1 = sc; sc->mlxd_dev_t = dsk; - /* set maximum I/O size */ - dsk->si_iosize_max = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE; + /* + * Set maximum I/O size to the lesser of the recommended maximum and the practical + * maximum. + */ + s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE; + s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * PAGE_SIZE; + dsk->si_iosize_max = imin(s1, s2); return (0); } diff --git a/sys/dev/mlx/mlx_pci.c b/sys/dev/mlx/mlx_pci.c index 9a5a658cc4e7..118e4958d53e 100644 --- a/sys/dev/mlx/mlx_pci.c +++ b/sys/dev/mlx/mlx_pci.c @@ -185,7 +185,7 @@ mlx_pci_attach(device_t dev) BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - MAXBSIZE, MLX_NSEG_NEW, /* maxsize, nsegments */ + MAXBSIZE, MLX_NSEG, /* maxsize, nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ BUS_DMA_ALLOCNOW, /* flags */ &sc->mlx_parent_dmat); diff --git a/sys/dev/mlx/mlxvar.h b/sys/dev/mlx/mlxvar.h index 51500bd323e8..edb1a853d094 100644 --- a/sys/dev/mlx/mlxvar.h +++ b/sys/dev/mlx/mlxvar.h @@ -40,14 +40,15 @@ #define debug_called(level) #endif - /* - * We could actually use all 17/33 segments, but using only 16/32 means that - * each scatter/gather map is 128/256 bytes in size, and thus we don't have to worry about - * maps crossing page boundaries. + * Regardless of the actual capacity of the controller, we will allocate space + * for 64 s/g entries. Typically controllers support 17 or 33 entries (64k or + * 128k maximum transfer assuming 4k page size and non-optimal alignment), but + * making that fit cleanly without crossing page boundaries requires rounding up + * to the next power of two. */ -#define MLX_NSEG_OLD 16 /* max scatter/gather segments we use 3.x and earlier */ -#define MLX_NSEG_NEW 32 /* max scatter/gather segments we use 4.x and later */ +#define MLX_NSEG 64 + #define MLX_NSLOTS 256 /* max number of command slots */ #define MLX_MAXDRIVES 32 /* max number of system drives */ @@ -120,11 +121,9 @@ struct mlx_softc u_int32_t mlx_sgbusaddr; /* s/g table base address in bus space */ bus_dma_tag_t mlx_sg_dmat; /* s/g buffer DMA tag */ bus_dmamap_t mlx_sg_dmamap; /* map for s/g buffers */ - int mlx_sg_nseg; /* max number of s/g entries */ /* controller limits and features */ struct mlx_enquiry2 *mlx_enq2; - int mlx_maxiop; /* hard maximum number of commands */ int mlx_feature; /* controller features/quirks */ #define MLX_FEAT_PAUSEWORKS (1<<0) /* channel pause works as expected */