mlx_disk.c revision 138090
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 */ 28215976Sjmallett 29232812Sjmallett#include <sys/cdefs.h> 30215976Sjmallett__FBSDID("$FreeBSD: head/sys/dev/mlx/mlx_disk.c 138090 2004-11-25 12:15:49Z scottl $"); 31215976Sjmallett 32215976Sjmallett/* 33215976Sjmallett * Disk driver for Mylex DAC960 RAID adapters. 34215976Sjmallett */ 35215976Sjmallett 36215976Sjmallett#include <sys/param.h> 37215976Sjmallett#include <sys/systm.h> 38215976Sjmallett#include <sys/kernel.h> 39215976Sjmallett#include <sys/module.h> 40215976Sjmallett 41215976Sjmallett#include <sys/bus.h> 42215976Sjmallett#include <sys/conf.h> 43215976Sjmallett 44215976Sjmallett#include <machine/bus.h> 45215976Sjmallett#include <sys/rman.h> 46215976Sjmallett 47215976Sjmallett#include <geom/geom_disk.h> 48215976Sjmallett 49215976Sjmallett#include <dev/mlx/mlx_compat.h> 50215976Sjmallett#include <dev/mlx/mlxio.h> 51215976Sjmallett#include <dev/mlx/mlxvar.h> 52232812Sjmallett#include <dev/mlx/mlxreg.h> 53232812Sjmallett 54215976Sjmallett/* prototypes */ 55215976Sjmallettstatic int mlxd_probe(device_t dev); 56215976Sjmallettstatic int mlxd_attach(device_t dev); 57215976Sjmallettstatic int mlxd_detach(device_t dev); 58215976Sjmallett 59215976Sjmallettdevclass_t mlxd_devclass; 60215976Sjmallett 61215976Sjmallettstatic device_method_t mlxd_methods[] = { 62215976Sjmallett DEVMETHOD(device_probe, mlxd_probe), 63215976Sjmallett DEVMETHOD(device_attach, mlxd_attach), 64215976Sjmallett DEVMETHOD(device_detach, mlxd_detach), 65215976Sjmallett { 0, 0 } 66215976Sjmallett}; 67215976Sjmallett 68215976Sjmallettstatic driver_t mlxd_driver = { 69215976Sjmallett "mlxd", 70215976Sjmallett mlxd_methods, 71215976Sjmallett sizeof(struct mlxd_softc) 72215976Sjmallett}; 73215976Sjmallett 74215976SjmallettDRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0); 75215976Sjmallett 76215976Sjmallettstatic int 77215976Sjmallettmlxd_open(struct disk *dp) 78215976Sjmallett{ 79215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 80215976Sjmallett 81215976Sjmallett debug_called(1); 82215976Sjmallett 83215976Sjmallett if (sc == NULL) 84215976Sjmallett return (ENXIO); 85215976Sjmallett 86215976Sjmallett /* controller not active? */ 87215976Sjmallett if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN) 88215976Sjmallett return(ENXIO); 89215976Sjmallett 90215976Sjmallett sc->mlxd_flags |= MLXD_OPEN; 91215976Sjmallett return (0); 92215976Sjmallett} 93215976Sjmallett 94215976Sjmallettstatic int 95215976Sjmallettmlxd_close(struct disk *dp) 96215976Sjmallett{ 97215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 98215976Sjmallett 99215976Sjmallett debug_called(1); 100215976Sjmallett 101215976Sjmallett if (sc == NULL) 102215976Sjmallett return (ENXIO); 103215976Sjmallett sc->mlxd_flags &= ~MLXD_OPEN; 104215976Sjmallett return (0); 105215976Sjmallett} 106215976Sjmallett 107215976Sjmallettstatic int 108215976Sjmallettmlxd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) 109215976Sjmallett{ 110215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 111215976Sjmallett int error; 112215976Sjmallett 113215976Sjmallett debug_called(1); 114215976Sjmallett 115215976Sjmallett if (sc == NULL) 116215976Sjmallett return (ENXIO); 117215976Sjmallett 118215976Sjmallett if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, td)) != ENOIOCTL) { 119215976Sjmallett debug(0, "mlx_submit_ioctl returned %d\n", error); 120215976Sjmallett return(error); 121215976Sjmallett } 122215976Sjmallett return (ENOTTY); 123215976Sjmallett} 124215976Sjmallett 125215976Sjmallett/* 126215976Sjmallett * Read/write routine for a buffer. Finds the proper unit, range checks 127215976Sjmallett * arguments, and schedules the transfer. Does not wait for the transfer 128215976Sjmallett * to complete. Multi-page transfers are supported. All I/O requests must 129215976Sjmallett * be a multiple of a sector in length. 130215976Sjmallett */ 131215976Sjmallettstatic void 132215976Sjmallettmlxd_strategy(mlx_bio *bp) 133215976Sjmallett{ 134215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)MLX_BIO_SOFTC(bp); 135215976Sjmallett 136215976Sjmallett debug_called(1); 137215976Sjmallett 138215976Sjmallett /* bogus disk? */ 139215976Sjmallett if (sc == NULL) { 140215976Sjmallett MLX_BIO_SET_ERROR(bp, EINVAL); 141215976Sjmallett goto bad; 142215976Sjmallett } 143215976Sjmallett 144215976Sjmallett /* XXX may only be temporarily offline - sleep? */ 145215976Sjmallett if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) { 146215976Sjmallett MLX_BIO_SET_ERROR(bp, ENXIO); 147215976Sjmallett goto bad; 148215976Sjmallett } 149215976Sjmallett 150215976Sjmallett MLX_BIO_STATS_START(bp); 151215976Sjmallett mlx_submit_buf(sc->mlxd_controller, bp); 152215976Sjmallett return; 153215976Sjmallett 154215976Sjmallett bad: 155215976Sjmallett /* 156215976Sjmallett * Correctly set the bio to indicate a failed tranfer. 157215976Sjmallett */ 158215976Sjmallett MLX_BIO_RESID(bp) = MLX_BIO_LENGTH(bp); 159215976Sjmallett MLX_BIO_DONE(bp); 160215976Sjmallett return; 161215976Sjmallett} 162215976Sjmallett 163215976Sjmallettvoid 164215976Sjmallettmlxd_intr(void *data) 165215976Sjmallett{ 166215976Sjmallett mlx_bio *bp = (mlx_bio *)data; 167215976Sjmallett 168215976Sjmallett debug_called(1); 169215976Sjmallett 170215976Sjmallett if (MLX_BIO_HAS_ERROR(bp)) 171215976Sjmallett MLX_BIO_SET_ERROR(bp, EIO); 172215976Sjmallett else 173215976Sjmallett MLX_BIO_RESID(bp) = 0; 174215976Sjmallett 175215976Sjmallett MLX_BIO_STATS_END(bp); 176215976Sjmallett MLX_BIO_DONE(bp); 177215976Sjmallett} 178215976Sjmallett 179215976Sjmallettstatic int 180215976Sjmallettmlxd_probe(device_t dev) 181215976Sjmallett{ 182215976Sjmallett 183215976Sjmallett debug_called(1); 184215976Sjmallett 185215976Sjmallett device_set_desc(dev, "Mylex System Drive"); 186215976Sjmallett return (0); 187215976Sjmallett} 188215976Sjmallett 189215976Sjmallettstatic int 190215976Sjmallettmlxd_attach(device_t dev) 191215976Sjmallett{ 192215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 193215976Sjmallett device_t parent; 194215976Sjmallett char *state; 195215976Sjmallett int s1, s2; 196215976Sjmallett 197215976Sjmallett debug_called(1); 198215976Sjmallett 199215976Sjmallett parent = device_get_parent(dev); 200215976Sjmallett sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent); 201215976Sjmallett sc->mlxd_unit = device_get_unit(dev); 202215976Sjmallett sc->mlxd_drive = device_get_ivars(dev); 203215976Sjmallett sc->mlxd_dev = dev; 204215976Sjmallett 205215976Sjmallett switch(sc->mlxd_drive->ms_state) { 206215976Sjmallett case MLX_SYSD_ONLINE: 207215976Sjmallett state = "online"; 208215976Sjmallett break; 209215976Sjmallett case MLX_SYSD_CRITICAL: 210215976Sjmallett state = "critical"; 211215976Sjmallett break; 212215976Sjmallett case MLX_SYSD_OFFLINE: 213215976Sjmallett state = "offline"; 214215976Sjmallett break; 215215976Sjmallett default: 216215976Sjmallett state = "unknown state"; 217215976Sjmallett } 218215976Sjmallett 219215976Sjmallett device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n", 220215976Sjmallett sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE), 221215976Sjmallett sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state); 222215976Sjmallett 223215976Sjmallett sc->mlxd_disk = disk_alloc(); 224215976Sjmallett sc->mlxd_disk->d_open = mlxd_open; 225215976Sjmallett sc->mlxd_disk->d_close = mlxd_close; 226215976Sjmallett sc->mlxd_disk->d_ioctl = mlxd_ioctl; 227215976Sjmallett sc->mlxd_disk->d_strategy = mlxd_strategy; 228215976Sjmallett sc->mlxd_disk->d_name = "mlxd"; 229215976Sjmallett sc->mlxd_disk->d_unit = sc->mlxd_unit; 230215976Sjmallett sc->mlxd_disk->d_drv1 = sc; 231215976Sjmallett sc->mlxd_disk->d_sectorsize = MLX_BLKSIZE; 232215976Sjmallett sc->mlxd_disk->d_mediasize = MLX_BLKSIZE * (off_t)sc->mlxd_drive->ms_size; 233215976Sjmallett sc->mlxd_disk->d_fwsectors = sc->mlxd_drive->ms_sectors; 234215976Sjmallett sc->mlxd_disk->d_fwheads = sc->mlxd_drive->ms_heads; 235215976Sjmallett sc->mlxd_disk->d_flags = DISKFLAG_NEEDSGIANT; 236215976Sjmallett 237215976Sjmallett /* 238215976Sjmallett * Set maximum I/O size to the lesser of the recommended maximum and the practical 239215976Sjmallett * maximum except on v2 cards where the maximum is set to 8 pages. 240215976Sjmallett */ 241215976Sjmallett if (sc->mlxd_controller->mlx_iftype == MLX_IFTYPE_2) 242215976Sjmallett sc->mlxd_disk->d_maxsize = 8 * MLX_PAGE_SIZE; 243215976Sjmallett else { 244215976Sjmallett s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE; 245215976Sjmallett s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * MLX_PAGE_SIZE; 246215976Sjmallett sc->mlxd_disk->d_maxsize = imin(s1, s2); 247215976Sjmallett } 248215976Sjmallett 249215976Sjmallett disk_create(sc->mlxd_disk, DISK_VERSION); 250215976Sjmallett 251215976Sjmallett return (0); 252215976Sjmallett} 253215976Sjmallett 254215976Sjmallettstatic int 255215976Sjmallettmlxd_detach(device_t dev) 256215976Sjmallett{ 257215976Sjmallett struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 258215976Sjmallett 259215976Sjmallett debug_called(1); 260215976Sjmallett 261215976Sjmallett disk_destroy(sc->mlxd_disk); 262215976Sjmallett 263215976Sjmallett return(0); 264215976Sjmallett} 265215976Sjmallett 266215976Sjmallett