1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 1999 Jonathan Lemon 5 * Copyright (c) 1999 Michael Smith 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31 #include <sys/cdefs.h> 32 /* 33 * Disk driver for Mylex DAC960 RAID adapters. 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/bio.h> 39 #include <sys/kernel.h> 40 #include <sys/lock.h> 41 #include <sys/module.h> 42 #include <sys/sx.h> 43 44 #include <sys/bus.h> 45 #include <sys/conf.h> 46 47 #include <machine/bus.h> 48 #include <sys/rman.h> 49 50 #include <geom/geom_disk.h> 51 52 #include <dev/mlx/mlxio.h> 53 #include <dev/mlx/mlxvar.h> 54 #include <dev/mlx/mlxreg.h> 55 56 /* prototypes */ 57 static int mlxd_probe(device_t dev); 58 static int mlxd_attach(device_t dev); 59 static int mlxd_detach(device_t dev); 60 61 static device_method_t mlxd_methods[] = { 62 DEVMETHOD(device_probe, mlxd_probe), 63 DEVMETHOD(device_attach, mlxd_attach), 64 DEVMETHOD(device_detach, mlxd_detach), 65 { 0, 0 } 66 }; 67 68 static driver_t mlxd_driver = { 69 "mlxd", 70 mlxd_methods, 71 sizeof(struct mlxd_softc) 72 }; 73 74 DRIVER_MODULE(mlxd, mlx, mlxd_driver, 0, 0); 75 76 static int 77 mlxd_open(struct disk *dp) 78 { 79 struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 80 81 debug_called(1); 82 83 if (sc == NULL) 84 return (ENXIO); 85 86 /* controller not active? */ 87 MLX_CONFIG_LOCK(sc->mlxd_controller); 88 MLX_IO_LOCK(sc->mlxd_controller); 89 if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN) { 90 MLX_IO_UNLOCK(sc->mlxd_controller); 91 MLX_CONFIG_UNLOCK(sc->mlxd_controller); 92 return(ENXIO); 93 } 94 95 sc->mlxd_flags |= MLXD_OPEN; 96 MLX_IO_UNLOCK(sc->mlxd_controller); 97 MLX_CONFIG_UNLOCK(sc->mlxd_controller); 98 return (0); 99 } 100 101 static int 102 mlxd_close(struct disk *dp) 103 { 104 struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 105 106 debug_called(1); 107 108 if (sc == NULL) 109 return (ENXIO); 110 MLX_CONFIG_LOCK(sc->mlxd_controller); 111 MLX_IO_LOCK(sc->mlxd_controller); 112 sc->mlxd_flags &= ~MLXD_OPEN; 113 MLX_IO_UNLOCK(sc->mlxd_controller); 114 MLX_CONFIG_UNLOCK(sc->mlxd_controller); 115 return (0); 116 } 117 118 static int 119 mlxd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) 120 { 121 struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 122 int error; 123 124 debug_called(1); 125 126 if (sc == NULL) 127 return (ENXIO); 128 129 if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, td)) != ENOIOCTL) { 130 debug(0, "mlx_submit_ioctl returned %d\n", error); 131 return(error); 132 } 133 return (ENOTTY); 134 } 135 136 /* 137 * Read/write routine for a buffer. Finds the proper unit, range checks 138 * arguments, and schedules the transfer. Does not wait for the transfer 139 * to complete. Multi-page transfers are supported. All I/O requests must 140 * be a multiple of a sector in length. 141 */ 142 static void 143 mlxd_strategy(struct bio *bp) 144 { 145 struct mlxd_softc *sc = bp->bio_disk->d_drv1; 146 147 debug_called(1); 148 149 /* bogus disk? */ 150 if (sc == NULL) { 151 bp->bio_error = EINVAL; 152 bp->bio_flags |= BIO_ERROR; 153 goto bad; 154 } 155 156 if ((bp->bio_cmd != BIO_READ) && (bp->bio_cmd != BIO_WRITE)) { 157 bp->bio_error = EOPNOTSUPP; 158 goto bad; 159 } 160 161 /* XXX may only be temporarily offline - sleep? */ 162 MLX_IO_LOCK(sc->mlxd_controller); 163 if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) { 164 MLX_IO_UNLOCK(sc->mlxd_controller); 165 bp->bio_error = ENXIO; 166 bp->bio_flags |= BIO_ERROR; 167 goto bad; 168 } 169 170 mlx_submit_buf(sc->mlxd_controller, bp); 171 MLX_IO_UNLOCK(sc->mlxd_controller); 172 return; 173 174 bad: 175 /* 176 * Correctly set the bio to indicate a failed transfer. 177 */ 178 bp->bio_resid = bp->bio_bcount; 179 biodone(bp); 180 return; 181 } 182 183 void 184 mlxd_intr(struct bio *bp) 185 { 186 187 debug_called(1); 188 189 if (bp->bio_flags & BIO_ERROR) 190 bp->bio_error = EIO; 191 else 192 bp->bio_resid = 0; 193 194 biodone(bp); 195 } 196 197 static int 198 mlxd_probe(device_t dev) 199 { 200 201 debug_called(1); 202 203 device_set_desc(dev, "Mylex System Drive"); 204 return (0); 205 } 206 207 static int 208 mlxd_attach(device_t dev) 209 { 210 struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 211 device_t parent; 212 char *state; 213 int s1, s2; 214 215 debug_called(1); 216 217 parent = device_get_parent(dev); 218 sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent); 219 sc->mlxd_unit = device_get_unit(dev); 220 sc->mlxd_drive = device_get_ivars(dev); 221 sc->mlxd_dev = dev; 222 223 switch(sc->mlxd_drive->ms_state) { 224 case MLX_SYSD_ONLINE: 225 state = "online"; 226 break; 227 case MLX_SYSD_CRITICAL: 228 state = "critical"; 229 break; 230 case MLX_SYSD_OFFLINE: 231 state = "offline"; 232 break; 233 default: 234 state = "unknown state"; 235 } 236 237 device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n", 238 sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE), 239 sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state); 240 241 sc->mlxd_disk = disk_alloc(); 242 sc->mlxd_disk->d_open = mlxd_open; 243 sc->mlxd_disk->d_close = mlxd_close; 244 sc->mlxd_disk->d_ioctl = mlxd_ioctl; 245 sc->mlxd_disk->d_strategy = mlxd_strategy; 246 sc->mlxd_disk->d_name = "mlxd"; 247 sc->mlxd_disk->d_unit = sc->mlxd_unit; 248 sc->mlxd_disk->d_drv1 = sc; 249 sc->mlxd_disk->d_sectorsize = MLX_BLKSIZE; 250 sc->mlxd_disk->d_mediasize = MLX_BLKSIZE * (off_t)sc->mlxd_drive->ms_size; 251 sc->mlxd_disk->d_fwsectors = sc->mlxd_drive->ms_sectors; 252 sc->mlxd_disk->d_fwheads = sc->mlxd_drive->ms_heads; 253 254 /* 255 * Set maximum I/O size to the lesser of the recommended maximum and the practical 256 * maximum except on v2 cards where the maximum is set to 8 pages. 257 */ 258 if (sc->mlxd_controller->mlx_iftype == MLX_IFTYPE_2) 259 sc->mlxd_disk->d_maxsize = 8 * MLX_PAGE_SIZE; 260 else { 261 s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE; 262 s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * MLX_PAGE_SIZE; 263 sc->mlxd_disk->d_maxsize = imin(s1, s2); 264 } 265 266 disk_create(sc->mlxd_disk, DISK_VERSION); 267 268 return (0); 269 } 270 271 static int 272 mlxd_detach(device_t dev) 273 { 274 struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 275 276 debug_called(1); 277 278 disk_destroy(sc->mlxd_disk); 279 280 return(0); 281 } 282 283