mlx_disk.c revision 240963
1238106Sdes/*- 2238106Sdes * Copyright (c) 1999 Jonathan Lemon 3238106Sdes * Copyright (c) 1999 Michael Smith 4238106Sdes * All rights reserved. 5238106Sdes * 6238106Sdes * Redistribution and use in source and binary forms, with or without 7238106Sdes * modification, are permitted provided that the following conditions 8238106Sdes * are met: 9238106Sdes * 1. Redistributions of source code must retain the above copyright 10238106Sdes * notice, this list of conditions and the following disclaimer. 11238106Sdes * 2. Redistributions in binary form must reproduce the above copyright 12238106Sdes * notice, this list of conditions and the following disclaimer in the 13238106Sdes * documentation and/or other materials provided with the distribution. 14238106Sdes * 15238106Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16238106Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17238106Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18238106Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19238106Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20238106Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21238106Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22238106Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23238106Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24285206Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25285206Sdes * SUCH DAMAGE. 26238106Sdes * 27238106Sdes */ 28238106Sdes 29238106Sdes#include <sys/cdefs.h> 30238106Sdes__FBSDID("$FreeBSD: head/sys/dev/mlx/mlx_disk.c 240963 2012-09-26 14:17:14Z jhb $"); 31238106Sdes 32238106Sdes/* 33269257Sdes * Disk driver for Mylex DAC960 RAID adapters. 34269257Sdes */ 35269257Sdes 36269257Sdes#include <sys/param.h> 37269257Sdes#include <sys/systm.h> 38249141Sdes#include <sys/bio.h> 39269257Sdes#include <sys/kernel.h> 40238106Sdes#include <sys/lock.h> 41238106Sdes#include <sys/module.h> 42238106Sdes#include <sys/sx.h> 43238106Sdes 44238106Sdes#include <sys/bus.h> 45238106Sdes#include <sys/conf.h> 46238106Sdes 47238106Sdes#include <machine/bus.h> 48285206Sdes#include <sys/rman.h> 49238106Sdes 50238106Sdes#include <geom/geom_disk.h> 51238106Sdes 52238106Sdes#include <dev/mlx/mlxio.h> 53238106Sdes#include <dev/mlx/mlxvar.h> 54238106Sdes#include <dev/mlx/mlxreg.h> 55238106Sdes 56238106Sdes/* prototypes */ 57238106Sdesstatic int mlxd_probe(device_t dev); 58238106Sdesstatic int mlxd_attach(device_t dev); 59238106Sdesstatic int mlxd_detach(device_t dev); 60238106Sdes 61285206Sdesdevclass_t mlxd_devclass; 62238106Sdes 63238106Sdesstatic device_method_t mlxd_methods[] = { 64238106Sdes DEVMETHOD(device_probe, mlxd_probe), 65238106Sdes DEVMETHOD(device_attach, mlxd_attach), 66238106Sdes DEVMETHOD(device_detach, mlxd_detach), 67238106Sdes { 0, 0 } 68238106Sdes}; 69238106Sdes 70238106Sdesstatic driver_t mlxd_driver = { 71238106Sdes "mlxd", 72269257Sdes mlxd_methods, 73238106Sdes sizeof(struct mlxd_softc) 74238106Sdes}; 75285206Sdes 76238106SdesDRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0); 77238106Sdes 78238106Sdesstatic int 79238106Sdesmlxd_open(struct disk *dp) 80269257Sdes{ 81285206Sdes struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 82238106Sdes 83285206Sdes debug_called(1); 84238106Sdes 85238106Sdes if (sc == NULL) 86238106Sdes return (ENXIO); 87238106Sdes 88238106Sdes /* controller not active? */ 89238106Sdes MLX_CONFIG_LOCK(sc->mlxd_controller); 90238106Sdes MLX_IO_LOCK(sc->mlxd_controller); 91238106Sdes if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN) { 92238106Sdes MLX_IO_UNLOCK(sc->mlxd_controller); 93238106Sdes MLX_CONFIG_UNLOCK(sc->mlxd_controller); 94238106Sdes return(ENXIO); 95238106Sdes } 96238106Sdes 97238106Sdes sc->mlxd_flags |= MLXD_OPEN; 98238106Sdes MLX_IO_UNLOCK(sc->mlxd_controller); 99238106Sdes MLX_CONFIG_UNLOCK(sc->mlxd_controller); 100238106Sdes return (0); 101238106Sdes} 102238106Sdes 103238106Sdesstatic int 104238106Sdesmlxd_close(struct disk *dp) 105238106Sdes{ 106238106Sdes struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 107238106Sdes 108238106Sdes debug_called(1); 109238106Sdes 110238106Sdes if (sc == NULL) 111249141Sdes return (ENXIO); 112285206Sdes MLX_CONFIG_LOCK(sc->mlxd_controller); 113238106Sdes MLX_IO_LOCK(sc->mlxd_controller); 114238106Sdes sc->mlxd_flags &= ~MLXD_OPEN; 115238106Sdes MLX_IO_UNLOCK(sc->mlxd_controller); 116238106Sdes MLX_CONFIG_UNLOCK(sc->mlxd_controller); 117238106Sdes return (0); 118238106Sdes} 119238106Sdes 120238106Sdesstatic int 121238106Sdesmlxd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) 122285206Sdes{ 123285206Sdes struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1; 124238106Sdes int error; 125238106Sdes 126238106Sdes debug_called(1); 127238106Sdes 128238106Sdes if (sc == NULL) 129238106Sdes return (ENXIO); 130269257Sdes 131285206Sdes if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, td)) != ENOIOCTL) { 132285206Sdes debug(0, "mlx_submit_ioctl returned %d\n", error); 133285206Sdes return(error); 134285206Sdes } 135238106Sdes return (ENOTTY); 136238106Sdes} 137285206Sdes 138269257Sdes/* 139269257Sdes * Read/write routine for a buffer. Finds the proper unit, range checks 140269257Sdes * arguments, and schedules the transfer. Does not wait for the transfer 141269257Sdes * to complete. Multi-page transfers are supported. All I/O requests must 142238106Sdes * be a multiple of a sector in length. 143238106Sdes */ 144238106Sdesstatic void 145269257Sdesmlxd_strategy(struct bio *bp) 146238106Sdes{ 147238106Sdes struct mlxd_softc *sc = bp->bio_disk->d_drv1; 148269257Sdes 149269257Sdes debug_called(1); 150269257Sdes 151238106Sdes /* bogus disk? */ 152238106Sdes if (sc == NULL) { 153238106Sdes bp->bio_error = EINVAL; 154238106Sdes bp->bio_flags |= BIO_ERROR; 155269257Sdes goto bad; 156238106Sdes } 157238106Sdes 158238106Sdes /* XXX may only be temporarily offline - sleep? */ 159269257Sdes MLX_IO_LOCK(sc->mlxd_controller); 160238106Sdes if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) { 161238106Sdes MLX_IO_UNLOCK(sc->mlxd_controller); 162238106Sdes bp->bio_error = ENXIO; 163238106Sdes bp->bio_flags |= BIO_ERROR; 164269257Sdes goto bad; 165238106Sdes } 166238106Sdes 167285206Sdes mlx_submit_buf(sc->mlxd_controller, bp); 168238106Sdes MLX_IO_UNLOCK(sc->mlxd_controller); 169238106Sdes return; 170238106Sdes 171238106Sdes bad: 172269257Sdes /* 173238106Sdes * Correctly set the bio to indicate a failed tranfer. 174238106Sdes */ 175238106Sdes bp->bio_resid = bp->bio_bcount; 176269257Sdes biodone(bp); 177269257Sdes return; 178238106Sdes} 179238106Sdes 180269257Sdesvoid 181269257Sdesmlxd_intr(struct bio *bp) 182238106Sdes{ 183238106Sdes 184285206Sdes debug_called(1); 185238106Sdes 186238106Sdes if (bp->bio_flags & BIO_ERROR) 187238106Sdes bp->bio_error = EIO; 188269257Sdes else 189238106Sdes bp->bio_resid = 0; 190238106Sdes 191269257Sdes biodone(bp); 192269257Sdes} 193238106Sdes 194238106Sdesstatic int 195238106Sdesmlxd_probe(device_t dev) 196238106Sdes{ 197238106Sdes 198269257Sdes debug_called(1); 199269257Sdes 200238106Sdes device_set_desc(dev, "Mylex System Drive"); 201238106Sdes return (0); 202269257Sdes} 203238106Sdes 204238106Sdesstatic int 205269257Sdesmlxd_attach(device_t dev) 206269257Sdes{ 207238106Sdes struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 208238106Sdes device_t parent; 209238106Sdes char *state; 210269257Sdes int s1, s2; 211238106Sdes 212238106Sdes debug_called(1); 213238106Sdes 214238106Sdes parent = device_get_parent(dev); 215238106Sdes sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent); 216238106Sdes sc->mlxd_unit = device_get_unit(dev); 217238106Sdes sc->mlxd_drive = device_get_ivars(dev); 218238106Sdes sc->mlxd_dev = dev; 219238106Sdes 220238106Sdes switch(sc->mlxd_drive->ms_state) { 221238106Sdes case MLX_SYSD_ONLINE: 222238106Sdes state = "online"; 223238106Sdes break; 224238106Sdes case MLX_SYSD_CRITICAL: 225238106Sdes state = "critical"; 226238106Sdes break; 227238106Sdes case MLX_SYSD_OFFLINE: 228238106Sdes state = "offline"; 229238106Sdes break; 230269257Sdes default: 231238106Sdes state = "unknown state"; 232238106Sdes } 233269257Sdes 234238106Sdes device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n", 235269257Sdes sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE), 236238106Sdes sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state); 237269257Sdes 238238106Sdes sc->mlxd_disk = disk_alloc(); 239238106Sdes sc->mlxd_disk->d_open = mlxd_open; 240269257Sdes sc->mlxd_disk->d_close = mlxd_close; 241238106Sdes sc->mlxd_disk->d_ioctl = mlxd_ioctl; 242269257Sdes sc->mlxd_disk->d_strategy = mlxd_strategy; 243238106Sdes sc->mlxd_disk->d_name = "mlxd"; 244238106Sdes sc->mlxd_disk->d_unit = sc->mlxd_unit; 245238106Sdes sc->mlxd_disk->d_drv1 = sc; 246238106Sdes sc->mlxd_disk->d_sectorsize = MLX_BLKSIZE; 247238106Sdes sc->mlxd_disk->d_mediasize = MLX_BLKSIZE * (off_t)sc->mlxd_drive->ms_size; 248249141Sdes sc->mlxd_disk->d_fwsectors = sc->mlxd_drive->ms_sectors; 249238106Sdes sc->mlxd_disk->d_fwheads = sc->mlxd_drive->ms_heads; 250249141Sdes 251238106Sdes /* 252249141Sdes * Set maximum I/O size to the lesser of the recommended maximum and the practical 253249141Sdes * maximum except on v2 cards where the maximum is set to 8 pages. 254238106Sdes */ 255238106Sdes if (sc->mlxd_controller->mlx_iftype == MLX_IFTYPE_2) 256238106Sdes sc->mlxd_disk->d_maxsize = 8 * MLX_PAGE_SIZE; 257238106Sdes else { 258238106Sdes s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE; 259238106Sdes s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * MLX_PAGE_SIZE; 260238106Sdes sc->mlxd_disk->d_maxsize = imin(s1, s2); 261238106Sdes } 262238106Sdes 263238106Sdes disk_create(sc->mlxd_disk, DISK_VERSION); 264238106Sdes 265238106Sdes return (0); 266238106Sdes} 267238106Sdes 268238106Sdesstatic int 269238106Sdesmlxd_detach(device_t dev) 270238106Sdes{ 271238106Sdes struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev); 272238106Sdes 273238106Sdes debug_called(1); 274238106Sdes 275238106Sdes disk_destroy(sc->mlxd_disk); 276269257Sdes 277238106Sdes return(0); 278269257Sdes} 279238106Sdes 280238106Sdes