mlx_disk.c revision 54979
151973Smsmith/*-
251973Smsmith * Copyright (c) 1999 Jonathan Lemon
351973Smsmith * Copyright (c) 1999 Michael Smith
451973Smsmith * All rights reserved.
551973Smsmith *
651973Smsmith * Redistribution and use in source and binary forms, with or without
751973Smsmith * modification, are permitted provided that the following conditions
851973Smsmith * are met:
951973Smsmith * 1. Redistributions of source code must retain the above copyright
1051973Smsmith *    notice, this list of conditions and the following disclaimer.
1151973Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1251973Smsmith *    notice, this list of conditions and the following disclaimer in the
1351973Smsmith *    documentation and/or other materials provided with the distribution.
1451973Smsmith *
1551973Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1651973Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1751973Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1851973Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1951973Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2051973Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2151973Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2251973Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2351973Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2451973Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2551973Smsmith * SUCH DAMAGE.
2651973Smsmith *
2751973Smsmith * $FreeBSD: head/sys/dev/mlx/mlx_disk.c 54979 1999-12-22 01:21:28Z msmith $
2851973Smsmith */
2951973Smsmith
3051973Smsmith/*
3151973Smsmith * Disk driver for Mylex DAC960 RAID adapters.
3251973Smsmith */
3351973Smsmith
3451973Smsmith#include <sys/param.h>
3551973Smsmith#include <sys/systm.h>
3651973Smsmith#include <sys/malloc.h>
3751973Smsmith#include <sys/kernel.h>
3851973Smsmith
3951973Smsmith#include <sys/buf.h>
4051973Smsmith#include <sys/bus.h>
4151973Smsmith#include <sys/conf.h>
4251973Smsmith#include <sys/devicestat.h>
4351973Smsmith#include <sys/disk.h>
4451973Smsmith
4551973Smsmith#include <machine/bus.h>
4651973Smsmith#include <machine/clock.h>
4751973Smsmith#include <sys/rman.h>
4851973Smsmith
4951973Smsmith#include <dev/mlx/mlxio.h>
5051973Smsmith#include <dev/mlx/mlxvar.h>
5152544Smsmith#include <dev/mlx/mlxreg.h>
5251973Smsmith
5351973Smsmith#if 0
5451973Smsmith#define debug(fmt, args...)	printf("%s: " fmt "\n", __FUNCTION__ , ##args)
5551973Smsmith#else
5651973Smsmith#define debug(fmt, args...)
5751973Smsmith#endif
5851973Smsmith
5951973Smsmith/* prototypes */
6051973Smsmithstatic int mlxd_probe(device_t dev);
6151973Smsmithstatic int mlxd_attach(device_t dev);
6251973Smsmithstatic int mlxd_detach(device_t dev);
6351973Smsmith
6451973Smsmithstatic	d_open_t	mlxd_open;
6551973Smsmithstatic	d_close_t	mlxd_close;
6651973Smsmithstatic	d_strategy_t	mlxd_strategy;
6751973Smsmithstatic	d_ioctl_t	mlxd_ioctl;
6851973Smsmith
6951973Smsmith#define MLXD_BDEV_MAJOR	27
7051973Smsmith#define MLXD_CDEV_MAJOR	131
7151973Smsmith
7251973Smsmithstatic struct cdevsw mlxd_cdevsw = {
7351973Smsmith		/* open */	mlxd_open,
7451973Smsmith		/* close */	mlxd_close,
7551973Smsmith		/* read */	physread,
7651973Smsmith		/* write */	physwrite,
7751973Smsmith		/* ioctl */	mlxd_ioctl,
7851973Smsmith		/* poll */	nopoll,
7951973Smsmith		/* mmap */	nommap,
8051973Smsmith		/* strategy */	mlxd_strategy,
8151973Smsmith		/* name */ 	"mlxd",
8251973Smsmith		/* maj */	MLXD_CDEV_MAJOR,
8351973Smsmith		/* dump */	nodump,
8451973Smsmith		/* psize */ 	nopsize,
8551973Smsmith		/* flags */	D_DISK,
8651973Smsmith		/* bmaj */	MLXD_BDEV_MAJOR
8751973Smsmith};
8851973Smsmith
8951973Smsmithstatic devclass_t	mlxd_devclass;
9051973Smsmithstatic struct cdevsw	mlxddisk_cdevsw;
9151973Smsmithstatic int		disks_registered = 0;
9251973Smsmith
9351973Smsmithstatic device_method_t mlxd_methods[] = {
9451973Smsmith    DEVMETHOD(device_probe,	mlxd_probe),
9551973Smsmith    DEVMETHOD(device_attach,	mlxd_attach),
9651973Smsmith    DEVMETHOD(device_detach,	mlxd_detach),
9751973Smsmith    { 0, 0 }
9851973Smsmith};
9951973Smsmith
10051973Smsmithstatic driver_t mlxd_driver = {
10151973Smsmith    "mlxd",
10251973Smsmith    mlxd_methods,
10351973Smsmith    sizeof(struct mlxd_softc)
10451973Smsmith};
10551973Smsmith
10651973SmsmithDRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0);
10751973Smsmith
10851973Smsmithstatic int
10951973Smsmithmlxd_open(dev_t dev, int flags, int fmt, struct proc *p)
11051973Smsmith{
11152225Smsmith    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
11251973Smsmith    struct disklabel	*label;
11351973Smsmith
11451973Smsmith    debug("called");
11551973Smsmith
11651973Smsmith    if (sc == NULL)
11751973Smsmith	return (ENXIO);
11851973Smsmith
11951973Smsmith    /* controller not active? */
12051973Smsmith    if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN)
12151973Smsmith	return(ENXIO);
12251973Smsmith
12351973Smsmith    label = &sc->mlxd_disk.d_label;
12451973Smsmith    bzero(label, sizeof(*label));
12551973Smsmith    label->d_type = DTYPE_SCSI;
12651973Smsmith    label->d_secsize    = MLX_BLKSIZE;
12751973Smsmith    label->d_nsectors   = sc->mlxd_drive->ms_sectors;
12851973Smsmith    label->d_ntracks    = sc->mlxd_drive->ms_heads;
12951973Smsmith    label->d_ncylinders = sc->mlxd_drive->ms_cylinders;
13051973Smsmith    label->d_secpercyl  = sc->mlxd_drive->ms_sectors * sc->mlxd_drive->ms_heads;
13151973Smsmith    label->d_secperunit = sc->mlxd_drive->ms_size;
13251973Smsmith
13351973Smsmith    sc->mlxd_flags |= MLXD_OPEN;
13451973Smsmith    return (0);
13551973Smsmith}
13651973Smsmith
13751973Smsmithstatic int
13851973Smsmithmlxd_close(dev_t dev, int flags, int fmt, struct proc *p)
13951973Smsmith{
14052225Smsmith    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
14151973Smsmith
14251973Smsmith    debug("called");
14351973Smsmith
14451973Smsmith    if (sc == NULL)
14551973Smsmith	return (ENXIO);
14651973Smsmith    sc->mlxd_flags &= ~MLXD_OPEN;
14751973Smsmith    return (0);
14851973Smsmith}
14951973Smsmith
15051973Smsmithstatic int
15151973Smsmithmlxd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
15251973Smsmith{
15352225Smsmith    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
15451973Smsmith    int error;
15551973Smsmith
15651973Smsmith    debug("called");
15751973Smsmith
15851973Smsmith    if (sc == NULL)
15951973Smsmith	return (ENXIO);
16051973Smsmith
16151973Smsmith    if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, p)) != ENOIOCTL) {
16251973Smsmith	debug("mlx_submit_ioctl returned %d\n", error);
16351973Smsmith	return(error);
16451973Smsmith    }
16551973Smsmith    return (ENOTTY);
16651973Smsmith}
16751973Smsmith
16851973Smsmith/*
16951973Smsmith * Read/write routine for a buffer.  Finds the proper unit, range checks
17051973Smsmith * arguments, and schedules the transfer.  Does not wait for the transfer
17151973Smsmith * to complete.  Multi-page transfers are supported.  All I/O requests must
17251973Smsmith * be a multiple of a sector in length.
17351973Smsmith */
17451973Smsmithstatic void
17551973Smsmithmlxd_strategy(struct buf *bp)
17651973Smsmith{
17752225Smsmith    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
17851973Smsmith
17951973Smsmith    debug("called");
18051973Smsmith
18151973Smsmith    /* bogus disk? */
18251973Smsmith    if (sc == NULL) {
18351973Smsmith	bp->b_error = EINVAL;
18451973Smsmith	goto bad;
18551973Smsmith    }
18651973Smsmith
18751973Smsmith    /* XXX may only be temporarily offline - sleep? */
18851973Smsmith    if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) {
18951973Smsmith	bp->b_error = ENXIO;
19051973Smsmith	goto bad;
19151973Smsmith    }
19251973Smsmith
19351973Smsmith    /* do-nothing operation */
19451973Smsmith    if (bp->b_bcount == 0)
19551973Smsmith	goto done;
19651973Smsmith
19751973Smsmith    devstat_start_transaction(&sc->mlxd_stats);
19851973Smsmith    mlx_submit_buf(sc->mlxd_controller, bp);
19951973Smsmith    return;
20051973Smsmith
20151973Smsmith bad:
20251973Smsmith    bp->b_flags |= B_ERROR;
20351973Smsmith
20451973Smsmith done:
20551973Smsmith    /*
20651973Smsmith     * Correctly set the buf to indicate a completed transfer
20751973Smsmith     */
20851973Smsmith    bp->b_resid = bp->b_bcount;
20951973Smsmith    biodone(bp);
21051973Smsmith    return;
21151973Smsmith}
21251973Smsmith
21351973Smsmithvoid
21451973Smsmithmlxd_intr(void *data)
21551973Smsmith{
21651973Smsmith    struct buf *bp = (struct buf *)data;
21752225Smsmith    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
21851973Smsmith
21951973Smsmith    debug("called");
22051973Smsmith
22151973Smsmith    if (bp->b_flags & B_ERROR)
22251973Smsmith	bp->b_error = EIO;
22351973Smsmith    else
22451973Smsmith	bp->b_resid = 0;
22551973Smsmith
22651973Smsmith    devstat_end_transaction_buf(&sc->mlxd_stats, bp);
22751973Smsmith    biodone(bp);
22851973Smsmith}
22951973Smsmith
23051973Smsmithstatic int
23151973Smsmithmlxd_probe(device_t dev)
23251973Smsmith{
23351973Smsmith
23451973Smsmith    debug("called");
23551973Smsmith
23651973Smsmith    device_set_desc(dev, "Mylex System Drive");
23751973Smsmith    return (0);
23851973Smsmith}
23951973Smsmith
24051973Smsmithstatic int
24151973Smsmithmlxd_attach(device_t dev)
24251973Smsmith{
24351973Smsmith    struct mlxd_softc	*sc = (struct mlxd_softc *)device_get_softc(dev);
24451973Smsmith    device_t		parent;
24551973Smsmith    char		*state;
24652225Smsmith    dev_t		dsk;
24751973Smsmith
24851973Smsmith    debug("called");
24951973Smsmith
25051973Smsmith    parent = device_get_parent(dev);
25151973Smsmith    sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
25251973Smsmith    sc->mlxd_unit = device_get_unit(dev);
25351973Smsmith    sc->mlxd_drive = device_get_ivars(dev);
25452273Smsmith    sc->mlxd_dev = dev;
25551973Smsmith
25651973Smsmith    switch(sc->mlxd_drive->ms_state) {
25751973Smsmith    case MLX_SYSD_ONLINE:
25851973Smsmith	state = "online";
25951973Smsmith	break;
26051973Smsmith    case MLX_SYSD_CRITICAL:
26151973Smsmith	state = "critical";
26251973Smsmith	break;
26351973Smsmith    case MLX_SYSD_OFFLINE:
26451973Smsmith	state = "offline";
26551973Smsmith	break;
26651973Smsmith    default:
26751973Smsmith	state = "unknown state";
26851973Smsmith    }
26951973Smsmith
27052785Smsmith    device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n",
27151973Smsmith		  sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE),
27251973Smsmith		  sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state);
27351973Smsmith
27451973Smsmith    devstat_add_entry(&sc->mlxd_stats, "mlxd", sc->mlxd_unit, MLX_BLKSIZE,
27551973Smsmith		      DEVSTAT_NO_ORDERED_TAGS,
27654279Sken		      DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
27754279Sken		      DEVSTAT_PRIORITY_ARRAY);
27851973Smsmith
27952225Smsmith    dsk = disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, &mlxd_cdevsw, &mlxddisk_cdevsw);
28054419Smsmith    dsk->si_drv1 = sc;
28151973Smsmith    disks_registered++;
28251973Smsmith
28352225Smsmith    /* set maximum I/O size */
28454979Smsmith    dsk->si_iosize_max = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE;
28552225Smsmith
28651973Smsmith    return (0);
28751973Smsmith}
28851973Smsmith
28951973Smsmithstatic int
29051973Smsmithmlxd_detach(device_t dev)
29151973Smsmith{
29251973Smsmith    struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
29351973Smsmith
29451973Smsmith    debug("called");
29551973Smsmith
29651973Smsmith    devstat_remove_entry(&sc->mlxd_stats);
29751973Smsmith
29851973Smsmith    /* hack to handle lack of destroy_disk() */
29951973Smsmith    if (--disks_registered == 0)
30051973Smsmith	cdevsw_remove(&mlxddisk_cdevsw);
30151973Smsmith
30251973Smsmith    return(0);
30351973Smsmith}
30451973Smsmith
305