mlx_disk.c revision 52273
1/*- 2 * Copyright (c) 1999 Jonathan Lemon 3 * Copyright (c) 1999 Michael Smith 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/dev/mlx/mlx_disk.c 52273 1999-10-16 01:46:59Z msmith $ 28 */ 29 30/* 31 * Disk driver for Mylex DAC960 RAID adapters. 32 */ 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/malloc.h> 37#include <sys/kernel.h> 38 39#include <sys/buf.h> 40#include <sys/bus.h> 41#include <sys/conf.h> 42#include <sys/devicestat.h> 43#include <sys/disk.h> 44 45#include <machine/bus.h> 46#include <machine/clock.h> 47#include <sys/rman.h> 48 49#include <dev/mlx/mlxio.h> 50#include <dev/mlx/mlxvar.h> 51 52#if 0 53#define debug(fmt, args...) printf("%s: " fmt "\n", __FUNCTION__ , ##args) 54#else 55#define debug(fmt, args...) 56#endif 57 58/* prototypes */ 59static int mlxd_probe(device_t dev); 60static int mlxd_attach(device_t dev); 61static int mlxd_detach(device_t dev); 62 63static d_open_t mlxd_open; 64static d_close_t mlxd_close; 65static d_strategy_t mlxd_strategy; 66static d_ioctl_t mlxd_ioctl; 67 68#define MLXD_BDEV_MAJOR 27 69#define MLXD_CDEV_MAJOR 131 70 71static struct cdevsw mlxd_cdevsw = { 72 /* open */ mlxd_open, 73 /* close */ mlxd_close, 74 /* read */ physread, 75 /* write */ physwrite, 76 /* ioctl */ mlxd_ioctl, 77 /* poll */ nopoll, 78 /* mmap */ nommap, 79 /* strategy */ mlxd_strategy, 80 /* name */ "mlxd", 81 /* maj */ MLXD_CDEV_MAJOR, 82 /* dump */ nodump, 83 /* psize */ nopsize, 84 /* flags */ D_DISK, 85 /* bmaj */ MLXD_BDEV_MAJOR 86}; 87 88static devclass_t mlxd_devclass; 89static struct cdevsw mlxddisk_cdevsw; 90static int disks_registered = 0; 91 92static device_method_t mlxd_methods[] = { 93 DEVMETHOD(device_probe, mlxd_probe), 94 DEVMETHOD(device_attach, mlxd_attach), 95 DEVMETHOD(device_detach, mlxd_detach), 96 { 0, 0 } 97}; 98 99static driver_t mlxd_driver = { 100 "mlxd", 101 mlxd_methods, 102 sizeof(struct mlxd_softc) 103}; 104 105DRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0); 106 107static int 108mlxd_open(dev_t dev, int flags, int fmt, struct proc *p) 109{ 110 struct mlxd_softc *sc = (struct mlxd_softc *)dev->si_drv1; 111 struct disklabel *label; 112 113 debug("called"); 114 115 if (sc == NULL) 116 return (ENXIO); 117 118 /* controller not active? */ 119 if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN) 120 return(ENXIO); 121 122 label = &sc->mlxd_disk.d_label; 123 bzero(label, sizeof(*label)); 124 label->d_type = DTYPE_SCSI; 125 label->d_secsize = MLX_BLKSIZE; 126 label->d_nsectors = sc->mlxd_drive->ms_sectors; 127 label->d_ntracks = sc->mlxd_drive->ms_heads; 128 label->d_ncylinders = sc->mlxd_drive->ms_cylinders; 129 label->d_secpercyl = sc->mlxd_drive->ms_sectors * sc->mlxd_drive->ms_heads; 130 label->d_secperunit = sc->mlxd_drive->ms_size; 131 132 sc->mlxd_flags |= MLXD_OPEN; 133 return (0); 134} 135 136static int 137mlxd_close(dev_t dev, int flags, int fmt, struct proc *p) 138{ 139 struct mlxd_softc *sc = (struct mlxd_softc *)dev->si_drv1; 140 141 debug("called"); 142 143 if (sc == NULL) 144 return (ENXIO); 145 sc->mlxd_flags &= ~MLXD_OPEN; 146 return (0); 147} 148 149static int 150mlxd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) 151{ 152 struct mlxd_softc *sc = (struct mlxd_softc *)dev->si_drv1; 153 int error; 154 155 debug("called"); 156 157 if (sc == NULL) 158 return (ENXIO); 159 160 if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, p)) != ENOIOCTL) { 161 debug("mlx_submit_ioctl returned %d\n", error); 162 return(error); 163 } 164 return (ENOTTY); 165} 166 167/* 168 * Read/write routine for a buffer. Finds the proper unit, range checks 169 * arguments, and schedules the transfer. Does not wait for the transfer 170 * to complete. Multi-page transfers are supported. All I/O requests must 171 * be a multiple of a sector in length. 172 */ 173static void 174mlxd_strategy(struct buf *bp) 175{ 176 struct mlxd_softc *sc = (struct mlxd_softc *)bp->b_dev->si_drv1; 177 int s; 178 179 debug("called"); 180 181 /* bogus disk? */ 182 if (sc == NULL) { 183 bp->b_error = EINVAL; 184 goto bad; 185 } 186 187 /* XXX may only be temporarily offline - sleep? */ 188 if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) { 189 bp->b_error = ENXIO; 190 goto bad; 191 } 192 193 /* do-nothing operation */ 194 if (bp->b_bcount == 0) 195 goto done; 196 197 s = splbio(); 198 devstat_start_transaction(&sc->mlxd_stats); 199 mlx_submit_buf(sc->mlxd_controller, bp); 200 splx(s); 201 return; 202 203 bad: 204 bp->b_flags |= B_ERROR; 205 206 done: 207 /* 208 * Correctly set the buf to indicate a completed transfer 209 */ 210 bp->b_resid = bp->b_bcount; 211 biodone(bp); 212 return; 213} 214 215void 216mlxd_intr(void *data) 217{ 218 struct buf *bp = (struct buf *)data; 219 struct mlxd_softc *sc = (struct mlxd_softc *)bp->b_dev->si_drv1; 220 221 debug("called"); 222 223 if (bp->b_flags & B_ERROR) 224 bp->b_error = EIO; 225 else 226 bp->b_resid = 0; 227 228 devstat_end_transaction_buf(&sc->mlxd_stats, bp); 229 biodone(bp); 230} 231 232static int 233mlxd_probe(device_t dev) 234{ 235 236 debug("called"); 237 238 device_set_desc(dev, "Mylex System Drive"); 239 return (0); 240} 241 242static int 243mlxd_attach(device_t dev) 244{ 245 struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 246 device_t parent; 247 char *state; 248 dev_t dsk; 249 250 debug("called"); 251 252 parent = device_get_parent(dev); 253 sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent); 254 sc->mlxd_unit = device_get_unit(dev); 255 sc->mlxd_drive = device_get_ivars(dev); 256 sc->mlxd_dev = dev; 257 258 switch(sc->mlxd_drive->ms_state) { 259 case MLX_SYSD_ONLINE: 260 state = "online"; 261 break; 262 case MLX_SYSD_CRITICAL: 263 state = "critical"; 264 break; 265 case MLX_SYSD_OFFLINE: 266 state = "offline"; 267 break; 268 default: 269 state = "unknown state"; 270 } 271 272 device_printf(dev, "%uMB (%u sectors), RAID %d (%s)\n", 273 sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE), 274 sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state); 275 276 devstat_add_entry(&sc->mlxd_stats, "mlxd", sc->mlxd_unit, MLX_BLKSIZE, 277 DEVSTAT_NO_ORDERED_TAGS, 278 DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER, 279 DEVSTAT_PRIORITY_DA); 280 281 dsk = disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, &mlxd_cdevsw, &mlxddisk_cdevsw); 282 disks_registered++; 283 284 /* set maximum I/O size */ 285 dsk->si_iosize_max = sc->mlxd_controller->mlx_maxiosize * MLX_BLKSIZE; 286 dsk->si_drv1 = sc; 287 288 return (0); 289} 290 291static int 292mlxd_detach(device_t dev) 293{ 294 struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 295 296 debug("called"); 297 298 devstat_remove_entry(&sc->mlxd_stats); 299 300 /* hack to handle lack of destroy_disk() */ 301 if (--disks_registered == 0) 302 cdevsw_remove(&mlxddisk_cdevsw); 303 304 return(0); 305} 306 307