mlx_disk.c revision 60074
1326941Sdim/*- 2326941Sdim * Copyright (c) 1999 Jonathan Lemon 3353358Sdim * Copyright (c) 1999 Michael Smith 4353358Sdim * All rights reserved. 5353358Sdim * 6326941Sdim * Redistribution and use in source and binary forms, with or without 7326941Sdim * modification, are permitted provided that the following conditions 8326941Sdim * are met: 9326941Sdim * 1. Redistributions of source code must retain the above copyright 10326941Sdim * notice, this list of conditions and the following disclaimer. 11326941Sdim * 2. Redistributions in binary form must reproduce the above copyright 12326941Sdim * notice, this list of conditions and the following disclaimer in the 13326941Sdim * documentation and/or other materials provided with the distribution. 14326941Sdim * 15326941Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16326941Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17326941Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18326941Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19326941Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20326941Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21326941Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22326941Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23326941Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24326941Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25326941Sdim * SUCH DAMAGE. 26326941Sdim * 27326941Sdim * $FreeBSD: head/sys/dev/mlx/mlx_disk.c 60074 2000-05-06 08:54:33Z msmith $ 28326941Sdim */ 29326941Sdim 30326941Sdim/* 31326941Sdim * Disk driver for Mylex DAC960 RAID adapters. 32326941Sdim */ 33326941Sdim 34326941Sdim#include <sys/param.h> 35326941Sdim#include <sys/systm.h> 36326941Sdim#include <sys/kernel.h> 37326941Sdim 38360784Sdim#include <sys/bio.h> 39360784Sdim#include <sys/bus.h> 40326941Sdim#include <sys/conf.h> 41326941Sdim#include <sys/devicestat.h> 42326941Sdim#include <sys/disk.h> 43326941Sdim 44326941Sdim#include <machine/bus.h> 45326941Sdim#include <machine/clock.h> 46326941Sdim#include <sys/rman.h> 47326941Sdim 48326941Sdim#include <dev/mlx/mlxio.h> 49326941Sdim#include <dev/mlx/mlxvar.h> 50326941Sdim#include <dev/mlx/mlxreg.h> 51326941Sdim 52326941Sdim/* prototypes */ 53326941Sdimstatic int mlxd_probe(device_t dev); 54326941Sdimstatic int mlxd_attach(device_t dev); 55326941Sdimstatic int mlxd_detach(device_t dev); 56326941Sdim 57326941Sdimstatic d_open_t mlxd_open; 58326941Sdimstatic d_close_t mlxd_close; 59326941Sdimstatic d_strategy_t mlxd_strategy; 60326941Sdimstatic d_ioctl_t mlxd_ioctl; 61326941Sdim 62326941Sdim#define MLXD_BDEV_MAJOR 27 63326941Sdim#define MLXD_CDEV_MAJOR 131 64326941Sdim 65326941Sdimstatic struct cdevsw mlxd_cdevsw = { 66326941Sdim /* open */ mlxd_open, 67326941Sdim /* close */ mlxd_close, 68326941Sdim /* read */ physread, 69326941Sdim /* write */ physwrite, 70326941Sdim /* ioctl */ mlxd_ioctl, 71326941Sdim /* poll */ nopoll, 72326941Sdim /* mmap */ nommap, 73326941Sdim /* strategy */ mlxd_strategy, 74326941Sdim /* name */ "mlxd", 75326941Sdim /* maj */ MLXD_CDEV_MAJOR, 76326941Sdim /* dump */ nodump, 77326941Sdim /* psize */ nopsize, 78326941Sdim /* flags */ D_DISK, 79326941Sdim /* bmaj */ MLXD_BDEV_MAJOR 80326941Sdim}; 81326941Sdim 82326941Sdimdevclass_t mlxd_devclass; 83326941Sdimstatic struct cdevsw mlxddisk_cdevsw; 84326941Sdim 85326941Sdimstatic device_method_t mlxd_methods[] = { 86326941Sdim DEVMETHOD(device_probe, mlxd_probe), 87326941Sdim DEVMETHOD(device_attach, mlxd_attach), 88326941Sdim DEVMETHOD(device_detach, mlxd_detach), 89326941Sdim { 0, 0 } 90326941Sdim}; 91326941Sdim 92326941Sdimstatic driver_t mlxd_driver = { 93326941Sdim "mlxd", 94326941Sdim mlxd_methods, 95326941Sdim sizeof(struct mlxd_softc) 96326941Sdim}; 97326941Sdim 98326941SdimDRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0); 99326941Sdim 100326941Sdimstatic int 101326941Sdimmlxd_open(dev_t dev, int flags, int fmt, struct proc *p) 102326941Sdim{ 103326941Sdim struct mlxd_softc *sc = (struct mlxd_softc *)dev->si_drv1; 104326941Sdim struct disklabel *label; 105326941Sdim 106326941Sdim debug_called(1); 107326941Sdim 108326941Sdim if (sc == NULL) 109326941Sdim return (ENXIO); 110326941Sdim 111326941Sdim /* controller not active? */ 112326941Sdim if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN) 113326941Sdim return(ENXIO); 114326941Sdim 115326941Sdim label = &sc->mlxd_disk.d_label; 116326941Sdim bzero(label, sizeof(*label)); 117326941Sdim label->d_type = DTYPE_SCSI; 118326941Sdim label->d_secsize = MLX_BLKSIZE; 119326941Sdim label->d_nsectors = sc->mlxd_drive->ms_sectors; 120326941Sdim label->d_ntracks = sc->mlxd_drive->ms_heads; 121326941Sdim label->d_ncylinders = sc->mlxd_drive->ms_cylinders; 122326941Sdim label->d_secpercyl = sc->mlxd_drive->ms_sectors * sc->mlxd_drive->ms_heads; 123326941Sdim label->d_secperunit = sc->mlxd_drive->ms_size; 124326941Sdim 125326941Sdim sc->mlxd_flags |= MLXD_OPEN; 126326941Sdim return (0); 127326941Sdim} 128326941Sdim 129326941Sdimstatic int 130326941Sdimmlxd_close(dev_t dev, int flags, int fmt, struct proc *p) 131326941Sdim{ 132326941Sdim struct mlxd_softc *sc = (struct mlxd_softc *)dev->si_drv1; 133326941Sdim 134326941Sdim debug_called(1); 135326941Sdim 136326941Sdim if (sc == NULL) 137326941Sdim return (ENXIO); 138326941Sdim sc->mlxd_flags &= ~MLXD_OPEN; 139326941Sdim return (0); 140326941Sdim} 141326941Sdim 142326941Sdimstatic int 143326941Sdimmlxd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) 144326941Sdim{ 145326941Sdim struct mlxd_softc *sc = (struct mlxd_softc *)dev->si_drv1; 146326941Sdim int error; 147326941Sdim 148326941Sdim debug_called(1); 149326941Sdim 150326941Sdim if (sc == NULL) 151326941Sdim return (ENXIO); 152326941Sdim 153326941Sdim if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, p)) != ENOIOCTL) { 154326941Sdim debug(0, "mlx_submit_ioctl returned %d\n", error); 155326941Sdim return(error); 156326941Sdim } 157326941Sdim return (ENOTTY); 158326941Sdim} 159326941Sdim 160326941Sdim/* 161326941Sdim * Read/write routine for a buffer. Finds the proper unit, range checks 162326941Sdim * arguments, and schedules the transfer. Does not wait for the transfer 163326941Sdim * to complete. Multi-page transfers are supported. All I/O requests must 164326941Sdim * be a multiple of a sector in length. 165326941Sdim */ 166326941Sdimstatic void 167326941Sdimmlxd_strategy(struct bio *bp) 168326941Sdim{ 169326941Sdim struct mlxd_softc *sc = (struct mlxd_softc *)bp->bio_dev->si_drv1; 170326941Sdim 171326941Sdim debug_called(1); 172326941Sdim 173326941Sdim /* bogus disk? */ 174326941Sdim if (sc == NULL) { 175326941Sdim bp->bio_error = EINVAL; 176326941Sdim goto bad; 177326941Sdim } 178326941Sdim 179326941Sdim /* XXX may only be temporarily offline - sleep? */ 180326941Sdim if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) { 181326941Sdim bp->bio_error = ENXIO; 182326941Sdim goto bad; 183326941Sdim } 184326941Sdim 185326941Sdim /* do-nothing operation */ 186326941Sdim if (bp->bio_bcount == 0) 187326941Sdim goto done; 188326941Sdim 189326941Sdim devstat_start_transaction(&sc->mlxd_stats); 190326941Sdim mlx_submit_buf(sc->mlxd_controller, bp); 191326941Sdim return; 192326941Sdim 193326941Sdim bad: 194326941Sdim bp->bio_flags |= BIO_ERROR; 195326941Sdim 196326941Sdim done: 197326941Sdim /* 198326941Sdim * Correctly set the buf to indicate a completed transfer 199326941Sdim */ 200326941Sdim bp->bio_resid = bp->bio_bcount; 201326941Sdim biodone(bp); 202326941Sdim return; 203326941Sdim} 204326941Sdim 205326941Sdimvoid 206326941Sdimmlxd_intr(void *data) 207326941Sdim{ 208326941Sdim struct bio *bp = (struct bio *)data; 209326941Sdim struct mlxd_softc *sc = (struct mlxd_softc *)bp->bio_dev->si_drv1; 210326941Sdim 211326941Sdim debug_called(1); 212326941Sdim 213326941Sdim if (bp->bio_flags & BIO_ERROR) 214326941Sdim bp->bio_error = EIO; 215326941Sdim else 216326941Sdim bp->bio_resid = 0; 217326941Sdim 218326941Sdim devstat_end_transaction_bio(&sc->mlxd_stats, bp); 219326941Sdim biodone(bp); 220326941Sdim} 221326941Sdim 222326941Sdimstatic int 223326941Sdimmlxd_probe(device_t dev) 224326941Sdim{ 225326941Sdim 226326941Sdim debug_called(1); 227326941Sdim 228326941Sdim device_set_desc(dev, "Mylex System Drive"); 229326941Sdim return (0); 230326941Sdim} 231326941Sdim 232326941Sdimstatic int 233326941Sdimmlxd_attach(device_t dev) 234326941Sdim{ 235326941Sdim struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 236326941Sdim device_t parent; 237326941Sdim char *state; 238326941Sdim dev_t dsk; 239326941Sdim int s1, s2; 240353358Sdim 241353358Sdim debug_called(1); 242326941Sdim 243326941Sdim parent = device_get_parent(dev); 244326941Sdim sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent); 245326941Sdim sc->mlxd_unit = device_get_unit(dev); 246326941Sdim sc->mlxd_drive = device_get_ivars(dev); 247326941Sdim sc->mlxd_dev = dev; 248326941Sdim 249326941Sdim switch(sc->mlxd_drive->ms_state) { 250326941Sdim case MLX_SYSD_ONLINE: 251326941Sdim state = "online"; 252326941Sdim break; 253326941Sdim case MLX_SYSD_CRITICAL: 254326941Sdim state = "critical"; 255326941Sdim break; 256326941Sdim case MLX_SYSD_OFFLINE: 257326941Sdim state = "offline"; 258326941Sdim break; 259326941Sdim default: 260326941Sdim state = "unknown state"; 261326941Sdim } 262326941Sdim 263326941Sdim device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n", 264326941Sdim sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE), 265326941Sdim sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state); 266326941Sdim 267326941Sdim devstat_add_entry(&sc->mlxd_stats, "mlxd", sc->mlxd_unit, MLX_BLKSIZE, 268326941Sdim DEVSTAT_NO_ORDERED_TAGS, 269326941Sdim DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 270326941Sdim DEVSTAT_PRIORITY_ARRAY); 271326941Sdim 272326941Sdim dsk = disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, &mlxd_cdevsw, &mlxddisk_cdevsw); 273326941Sdim dsk->si_drv1 = sc; 274326941Sdim sc->mlxd_dev_t = dsk; 275326941Sdim 276326941Sdim /* 277326941Sdim * Set maximum I/O size to the lesser of the recommended maximum and the practical 278326941Sdim * maximum. 279326941Sdim */ 280326941Sdim s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE; 281326941Sdim s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * PAGE_SIZE; 282326941Sdim dsk->si_iosize_max = imin(s1, s2); 283326941Sdim 284326941Sdim return (0); 285326941Sdim} 286326941Sdim 287326941Sdimstatic int 288326941Sdimmlxd_detach(device_t dev) 289326941Sdim{ 290326941Sdim struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 291326941Sdim 292326941Sdim debug_called(1); 293326941Sdim 294326941Sdim devstat_remove_entry(&sc->mlxd_stats); 295326941Sdim disk_destroy(sc->mlxd_dev_t); 296326941Sdim 297326941Sdim return(0); 298326941Sdim} 299326941Sdim 300326941Sdim