mlx_disk.c revision 112946
1215976Sjmallett/*- 2232812Sjmallett * Copyright (c) 1999 Jonathan Lemon 3215976Sjmallett * Copyright (c) 1999 Michael Smith 4215976Sjmallett * All rights reserved. 5215976Sjmallett * 6215976Sjmallett * Redistribution and use in source and binary forms, with or without 7215976Sjmallett * modification, are permitted provided that the following conditions 8215976Sjmallett * are met: 9215976Sjmallett * 1. Redistributions of source code must retain the above copyright 10215976Sjmallett * notice, this list of conditions and the following disclaimer. 11215976Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 12215976Sjmallett * notice, this list of conditions and the following disclaimer in the 13215976Sjmallett * documentation and/or other materials provided with the distribution. 14215976Sjmallett * 15215976Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16215976Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17215976Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18232812Sjmallett * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19215976Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20215976Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21215976Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22215976Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23215976Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24215976Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25215976Sjmallett * SUCH DAMAGE. 26215976Sjmallett * 27215976Sjmallett * $FreeBSD: head/sys/dev/mlx/mlx_disk.c 112946 2003-04-01 15:06:26Z phk $ 28215976Sjmallett */ 29232812Sjmallett 30215976Sjmallett/* 31215976Sjmallett * Disk driver for Mylex DAC960 RAID adapters. 32215976Sjmallett */ 33215976Sjmallett 34215976Sjmallett#include <sys/param.h> 35215976Sjmallett#include <sys/systm.h> 36215976Sjmallett#include <sys/kernel.h> 37215976Sjmallett 38215976Sjmallett#include <sys/bus.h> 39215976Sjmallett#include <sys/conf.h> 40215976Sjmallett 41215976Sjmallett#include <machine/bus.h> 42215976Sjmallett#include <sys/rman.h> 43215976Sjmallett 44215976Sjmallett#include <geom/geom_disk.h> 45215976Sjmallett 46215976Sjmallett#include <dev/mlx/mlx_compat.h> 47215976Sjmallett#include <dev/mlx/mlxio.h> 48215976Sjmallett#include <dev/mlx/mlxvar.h> 49215976Sjmallett#include <dev/mlx/mlxreg.h> 50215976Sjmallett 51215976Sjmallett/* prototypes */ 52232812Sjmallettstatic int mlxd_probe(device_t dev); 53232812Sjmallettstatic int mlxd_attach(device_t dev); 54215976Sjmallettstatic int mlxd_detach(device_t dev); 55215976Sjmallett 56215976Sjmallettdevclass_t mlxd_devclass; 57215976Sjmallett 58215976Sjmallettstatic device_method_t mlxd_methods[] = { 59215976Sjmallett DEVMETHOD(device_probe, mlxd_probe), 60215976Sjmallett DEVMETHOD(device_attach, mlxd_attach), 61215976Sjmallett DEVMETHOD(device_detach, mlxd_detach), 62215976Sjmallett { 0, 0 } 63215976Sjmallett}; 64215976Sjmallett 65215976Sjmallettstatic driver_t mlxd_driver = { 66215976Sjmallett "mlxd", 67215976Sjmallett mlxd_methods, 68215976Sjmallett sizeof(struct mlxd_softc) 69215976Sjmallett}; 70215976Sjmallett 71215976SjmallettDRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0); 72215976Sjmallett 73215976Sjmallettstatic int 74215976Sjmallettmlxd_open(struct disk *dp) 75215976Sjmallett{ 76215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 77215976Sjmallett 78215976Sjmallett debug_called(1); 79215976Sjmallett 80215976Sjmallett if (sc == NULL) 81215976Sjmallett return (ENXIO); 82215976Sjmallett 83215976Sjmallett /* controller not active? */ 84215976Sjmallett if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN) 85215976Sjmallett return(ENXIO); 86215976Sjmallett 87215976Sjmallett sc->mlxd_flags |= MLXD_OPEN; 88215976Sjmallett return (0); 89215976Sjmallett} 90215976Sjmallett 91215976Sjmallettstatic int 92215976Sjmallettmlxd_close(struct disk *dp) 93215976Sjmallett{ 94215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 95215976Sjmallett 96215976Sjmallett debug_called(1); 97215976Sjmallett 98215976Sjmallett if (sc == NULL) 99215976Sjmallett return (ENXIO); 100215976Sjmallett sc->mlxd_flags &= ~MLXD_OPEN; 101215976Sjmallett return (0); 102215976Sjmallett} 103215976Sjmallett 104215976Sjmallettstatic int 105215976Sjmallettmlxd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) 106215976Sjmallett{ 107215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 108215976Sjmallett int error; 109215976Sjmallett 110215976Sjmallett debug_called(1); 111215976Sjmallett 112215976Sjmallett if (sc == NULL) 113215976Sjmallett return (ENXIO); 114215976Sjmallett 115215976Sjmallett if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, td)) != ENOIOCTL) { 116215976Sjmallett debug(0, "mlx_submit_ioctl returned %d\n", error); 117215976Sjmallett return(error); 118215976Sjmallett } 119215976Sjmallett return (ENOTTY); 120215976Sjmallett} 121215976Sjmallett 122215976Sjmallett/* 123215976Sjmallett * Read/write routine for a buffer. Finds the proper unit, range checks 124215976Sjmallett * arguments, and schedules the transfer. Does not wait for the transfer 125215976Sjmallett * to complete. Multi-page transfers are supported. All I/O requests must 126215976Sjmallett * be a multiple of a sector in length. 127215976Sjmallett */ 128215976Sjmallettstatic void 129215976Sjmallettmlxd_strategy(mlx_bio *bp) 130215976Sjmallett{ 131215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)MLX_BIO_SOFTC(bp); 132215976Sjmallett 133215976Sjmallett debug_called(1); 134215976Sjmallett 135215976Sjmallett /* bogus disk? */ 136215976Sjmallett if (sc == NULL) { 137215976Sjmallett MLX_BIO_SET_ERROR(bp, EINVAL); 138215976Sjmallett goto bad; 139215976Sjmallett } 140215976Sjmallett 141215976Sjmallett /* XXX may only be temporarily offline - sleep? */ 142215976Sjmallett if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) { 143215976Sjmallett MLX_BIO_SET_ERROR(bp, ENXIO); 144215976Sjmallett goto bad; 145215976Sjmallett } 146215976Sjmallett 147215976Sjmallett MLX_BIO_STATS_START(bp); 148215976Sjmallett mlx_submit_buf(sc->mlxd_controller, bp); 149215976Sjmallett return; 150215976Sjmallett 151215976Sjmallett bad: 152215976Sjmallett /* 153215976Sjmallett * Correctly set the bio to indicate a failed tranfer. 154215976Sjmallett */ 155215976Sjmallett MLX_BIO_RESID(bp) = MLX_BIO_LENGTH(bp); 156215976Sjmallett MLX_BIO_DONE(bp); 157215976Sjmallett return; 158215976Sjmallett} 159215976Sjmallett 160215976Sjmallettvoid 161215976Sjmallettmlxd_intr(void *data) 162215976Sjmallett{ 163215976Sjmallett mlx_bio *bp = (mlx_bio *)data; 164215976Sjmallett 165215976Sjmallett debug_called(1); 166215976Sjmallett 167215976Sjmallett if (MLX_BIO_HAS_ERROR(bp)) 168215976Sjmallett MLX_BIO_SET_ERROR(bp, EIO); 169215976Sjmallett else 170215976Sjmallett MLX_BIO_RESID(bp) = 0; 171215976Sjmallett 172215976Sjmallett MLX_BIO_STATS_END(bp); 173215976Sjmallett MLX_BIO_DONE(bp); 174215976Sjmallett} 175215976Sjmallett 176215976Sjmallettstatic int 177215976Sjmallettmlxd_probe(device_t dev) 178215976Sjmallett{ 179215976Sjmallett 180215976Sjmallett debug_called(1); 181215976Sjmallett 182215976Sjmallett device_set_desc(dev, "Mylex System Drive"); 183215976Sjmallett return (0); 184215976Sjmallett} 185215976Sjmallett 186215976Sjmallettstatic int 187215976Sjmallettmlxd_attach(device_t dev) 188215976Sjmallett{ 189215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 190215976Sjmallett device_t parent; 191215976Sjmallett char *state; 192215976Sjmallett int s1, s2; 193215976Sjmallett 194215976Sjmallett debug_called(1); 195215976Sjmallett 196215976Sjmallett parent = device_get_parent(dev); 197215976Sjmallett sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent); 198215976Sjmallett sc->mlxd_unit = device_get_unit(dev); 199215976Sjmallett sc->mlxd_drive = device_get_ivars(dev); 200215976Sjmallett sc->mlxd_dev = dev; 201215976Sjmallett 202215976Sjmallett switch(sc->mlxd_drive->ms_state) { 203215976Sjmallett case MLX_SYSD_ONLINE: 204215976Sjmallett state = "online"; 205215976Sjmallett break; 206215976Sjmallett case MLX_SYSD_CRITICAL: 207215976Sjmallett state = "critical"; 208215976Sjmallett break; 209215976Sjmallett case MLX_SYSD_OFFLINE: 210215976Sjmallett state = "offline"; 211215976Sjmallett break; 212215976Sjmallett default: 213215976Sjmallett state = "unknown state"; 214215976Sjmallett } 215215976Sjmallett 216215976Sjmallett device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n", 217215976Sjmallett sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE), 218215976Sjmallett sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state); 219215976Sjmallett 220215976Sjmallett sc->mlxd_disk.d_open = mlxd_open; 221215976Sjmallett sc->mlxd_disk.d_close = mlxd_close; 222215976Sjmallett sc->mlxd_disk.d_ioctl = mlxd_ioctl; 223215976Sjmallett sc->mlxd_disk.d_strategy = mlxd_strategy; 224215976Sjmallett sc->mlxd_disk.d_name = "mlxd"; 225215976Sjmallett sc->mlxd_disk.d_drv1 = sc; 226215976Sjmallett sc->mlxd_disk.d_sectorsize = MLX_BLKSIZE; 227215976Sjmallett sc->mlxd_disk.d_mediasize = MLX_BLKSIZE * (off_t)sc->mlxd_drive->ms_size; 228215976Sjmallett sc->mlxd_disk.d_fwsectors = sc->mlxd_drive->ms_sectors; 229215976Sjmallett sc->mlxd_disk.d_fwheads = sc->mlxd_drive->ms_heads; 230215976Sjmallett 231215976Sjmallett /* 232215976Sjmallett * Set maximum I/O size to the lesser of the recommended maximum and the practical 233215976Sjmallett * maximum except on v2 cards where the maximum is set to 8 pages. 234215976Sjmallett */ 235215976Sjmallett if (sc->mlxd_controller->mlx_iftype == MLX_IFTYPE_2) 236215976Sjmallett sc->mlxd_disk.d_maxsize = 8 * PAGE_SIZE; 237215976Sjmallett else { 238215976Sjmallett s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE; 239215976Sjmallett s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * PAGE_SIZE; 240215976Sjmallett sc->mlxd_disk.d_maxsize = imin(s1, s2); 241215976Sjmallett } 242215976Sjmallett 243215976Sjmallett disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, NULL, NULL); 244215976Sjmallett 245215976Sjmallett return (0); 246215976Sjmallett} 247215976Sjmallett 248215976Sjmallettstatic int 249215976Sjmallettmlxd_detach(device_t dev) 250215976Sjmallett{ 251215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 252215976Sjmallett 253215976Sjmallett debug_called(1); 254215976Sjmallett 255232812Sjmallett disk_destroy(&sc->mlxd_disk); 256215976Sjmallett 257232812Sjmallett return(0); 258232812Sjmallett} 259215976Sjmallett 260215976Sjmallett