mlx_disk.c revision 52273
118334Speter/*-
252284Sobrien * Copyright (c) 1999 Jonathan Lemon
318334Speter * Copyright (c) 1999 Michael Smith
418334Speter * All rights reserved.
518334Speter *
618334Speter * Redistribution and use in source and binary forms, with or without
718334Speter * modification, are permitted provided that the following conditions
818334Speter * are met:
918334Speter * 1. Redistributions of source code must retain the above copyright
1018334Speter *    notice, this list of conditions and the following disclaimer.
1118334Speter * 2. Redistributions in binary form must reproduce the above copyright
1218334Speter *    notice, this list of conditions and the following disclaimer in the
1318334Speter *    documentation and/or other materials provided with the distribution.
1418334Speter *
1518334Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1618334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1718334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1818334Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1918334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2018334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2150397Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2250397Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2318334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2418334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2518334Speter * SUCH DAMAGE.
2618334Speter *
2718334Speter * $FreeBSD: head/sys/dev/mlx/mlx_disk.c 52273 1999-10-16 01:46:59Z msmith $
2818334Speter */
2918334Speter
3018334Speter/*
3118334Speter * Disk driver for Mylex DAC960 RAID adapters.
3218334Speter */
3318334Speter
3418334Speter#include <sys/param.h>
3518334Speter#include <sys/systm.h>
3618334Speter#include <sys/malloc.h>
3718334Speter#include <sys/kernel.h>
3818334Speter
3918334Speter#include <sys/buf.h>
4018334Speter#include <sys/bus.h>
4118334Speter#include <sys/conf.h>
4218334Speter#include <sys/devicestat.h>
4318334Speter#include <sys/disk.h>
4418334Speter
4518334Speter#include <machine/bus.h>
4618334Speter#include <machine/clock.h>
4718334Speter#include <sys/rman.h>
4818334Speter
4918334Speter#include <dev/mlx/mlxio.h>
5018334Speter#include <dev/mlx/mlxvar.h>
5118334Speter
5250397Sobrien#if 0
5318334Speter#define debug(fmt, args...)	printf("%s: " fmt "\n", __FUNCTION__ , ##args)
5418334Speter#else
5550397Sobrien#define debug(fmt, args...)
5618334Speter#endif
5718334Speter
5850397Sobrien/* prototypes */
5918334Speterstatic int mlxd_probe(device_t dev);
6018334Speterstatic int mlxd_attach(device_t dev);
6150397Sobrienstatic int mlxd_detach(device_t dev);
6218334Speter
6350397Sobrienstatic	d_open_t	mlxd_open;
6450397Sobrienstatic	d_close_t	mlxd_close;
6550397Sobrienstatic	d_strategy_t	mlxd_strategy;
6650397Sobrienstatic	d_ioctl_t	mlxd_ioctl;
6750397Sobrien
6850397Sobrien#define MLXD_BDEV_MAJOR	27
6950397Sobrien#define MLXD_CDEV_MAJOR	131
7050397Sobrien
7150397Sobrienstatic struct cdevsw mlxd_cdevsw = {
7250397Sobrien		/* open */	mlxd_open,
7350397Sobrien		/* close */	mlxd_close,
7450397Sobrien		/* read */	physread,
7550397Sobrien		/* write */	physwrite,
7650397Sobrien		/* ioctl */	mlxd_ioctl,
7750397Sobrien		/* poll */	nopoll,
7850397Sobrien		/* mmap */	nommap,
7950397Sobrien		/* strategy */	mlxd_strategy,
8050397Sobrien		/* name */ 	"mlxd",
8118334Speter		/* maj */	MLXD_CDEV_MAJOR,
8218334Speter		/* dump */	nodump,
8318334Speter		/* psize */ 	nopsize,
8418334Speter		/* flags */	D_DISK,
8518334Speter		/* bmaj */	MLXD_BDEV_MAJOR
8618334Speter};
8718334Speter
8818334Speterstatic devclass_t	mlxd_devclass;
8918334Speterstatic struct cdevsw	mlxddisk_cdevsw;
9018334Speterstatic int		disks_registered = 0;
9150397Sobrien
9250397Sobrienstatic device_method_t mlxd_methods[] = {
9350397Sobrien    DEVMETHOD(device_probe,	mlxd_probe),
9452284Sobrien    DEVMETHOD(device_attach,	mlxd_attach),
9518334Speter    DEVMETHOD(device_detach,	mlxd_detach),
9618334Speter    { 0, 0 }
9718334Speter};
9818334Speter
9918334Speterstatic driver_t mlxd_driver = {
10018334Speter    "mlxd",
10118334Speter    mlxd_methods,
10218334Speter    sizeof(struct mlxd_softc)
10318334Speter};
10418334Speter
10518334SpeterDRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0);
10618334Speter
10718334Speterstatic int
10818334Spetermlxd_open(dev_t dev, int flags, int fmt, struct proc *p)
10918334Speter{
11018334Speter    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
11118334Speter    struct disklabel	*label;
11218334Speter
11318334Speter    debug("called");
11418334Speter
11518334Speter    if (sc == NULL)
11618334Speter	return (ENXIO);
11752284Sobrien
11818334Speter    /* controller not active? */
11952284Sobrien    if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN)
12018334Speter	return(ENXIO);
12118334Speter
12218334Speter    label = &sc->mlxd_disk.d_label;
12318334Speter    bzero(label, sizeof(*label));
12418334Speter    label->d_type = DTYPE_SCSI;
12518334Speter    label->d_secsize    = MLX_BLKSIZE;
12618334Speter    label->d_nsectors   = sc->mlxd_drive->ms_sectors;
12718334Speter    label->d_ntracks    = sc->mlxd_drive->ms_heads;
12818334Speter    label->d_ncylinders = sc->mlxd_drive->ms_cylinders;
12918334Speter    label->d_secpercyl  = sc->mlxd_drive->ms_sectors * sc->mlxd_drive->ms_heads;
13018334Speter    label->d_secperunit = sc->mlxd_drive->ms_size;
13118334Speter
13218334Speter    sc->mlxd_flags |= MLXD_OPEN;
13318334Speter    return (0);
13418334Speter}
13518334Speter
13618334Speterstatic int
13718334Spetermlxd_close(dev_t dev, int flags, int fmt, struct proc *p)
13818334Speter{
13950397Sobrien    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
14018334Speter
14118334Speter    debug("called");
14218334Speter
14318334Speter    if (sc == NULL)
14418334Speter	return (ENXIO);
14518334Speter    sc->mlxd_flags &= ~MLXD_OPEN;
14618334Speter    return (0);
14718334Speter}
14818334Speter
14918334Speterstatic int
15018334Spetermlxd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
15118334Speter{
15218334Speter    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
15318334Speter    int error;
15418334Speter
15518334Speter    debug("called");
15618334Speter
15718334Speter    if (sc == NULL)
15818334Speter	return (ENXIO);
15918334Speter
16018334Speter    if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, p)) != ENOIOCTL) {
16118334Speter	debug("mlx_submit_ioctl returned %d\n", error);
16218334Speter	return(error);
16318334Speter    }
16418334Speter    return (ENOTTY);
16518334Speter}
16652284Sobrien
16752284Sobrien/*
16852284Sobrien * Read/write routine for a buffer.  Finds the proper unit, range checks
16952284Sobrien * arguments, and schedules the transfer.  Does not wait for the transfer
17052284Sobrien * to complete.  Multi-page transfers are supported.  All I/O requests must
17150397Sobrien * be a multiple of a sector in length.
17218334Speter */
17318334Speterstatic void
17418334Spetermlxd_strategy(struct buf *bp)
17518334Speter{
17618334Speter    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
17718334Speter    int			s;
17818334Speter
17918334Speter    debug("called");
18018334Speter
18118334Speter    /* bogus disk? */
18218334Speter    if (sc == NULL) {
18318334Speter	bp->b_error = EINVAL;
18418334Speter	goto bad;
18518334Speter    }
18618334Speter
18718334Speter    /* XXX may only be temporarily offline - sleep? */
18818334Speter    if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) {
18918334Speter	bp->b_error = ENXIO;
19018334Speter	goto bad;
19118334Speter    }
19218334Speter
19318334Speter    /* do-nothing operation */
19418334Speter    if (bp->b_bcount == 0)
19550397Sobrien	goto done;
19618334Speter
19718334Speter    s = splbio();
19818334Speter    devstat_start_transaction(&sc->mlxd_stats);
19918334Speter    mlx_submit_buf(sc->mlxd_controller, bp);
20018334Speter    splx(s);
20118334Speter    return;
20250397Sobrien
20318334Speter bad:
20418334Speter    bp->b_flags |= B_ERROR;
20518334Speter
20618334Speter done:
20718334Speter    /*
20818334Speter     * Correctly set the buf to indicate a completed transfer
20950397Sobrien     */
21018334Speter    bp->b_resid = bp->b_bcount;
21118334Speter    biodone(bp);
21218334Speter    return;
21318334Speter}
21418334Speter
21518334Spetervoid
21618334Spetermlxd_intr(void *data)
21718334Speter{
21818334Speter    struct buf *bp = (struct buf *)data;
21918334Speter    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
22018334Speter
22118334Speter    debug("called");
22250397Sobrien
22350397Sobrien    if (bp->b_flags & B_ERROR)
22418334Speter	bp->b_error = EIO;
22518334Speter    else
22618334Speter	bp->b_resid = 0;
22718334Speter
22818334Speter    devstat_end_transaction_buf(&sc->mlxd_stats, bp);
22918334Speter    biodone(bp);
23018334Speter}
23118334Speter
23218334Speterstatic int
23318334Spetermlxd_probe(device_t dev)
23450397Sobrien{
23550397Sobrien
23650397Sobrien    debug("called");
23718334Speter
23818334Speter    device_set_desc(dev, "Mylex System Drive");
23918334Speter    return (0);
24018334Speter}
24118334Speter
24218334Speterstatic int
24318334Spetermlxd_attach(device_t dev)
24418334Speter{
24518334Speter    struct mlxd_softc	*sc = (struct mlxd_softc *)device_get_softc(dev);
24618334Speter    device_t		parent;
24718334Speter    char		*state;
24818334Speter    dev_t		dsk;
24918334Speter
25018334Speter    debug("called");
25118334Speter
25218334Speter    parent = device_get_parent(dev);
25318334Speter    sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
25418334Speter    sc->mlxd_unit = device_get_unit(dev);
25518334Speter    sc->mlxd_drive = device_get_ivars(dev);
25618334Speter    sc->mlxd_dev = dev;
25718334Speter
25818334Speter    switch(sc->mlxd_drive->ms_state) {
25918334Speter    case MLX_SYSD_ONLINE:
26018334Speter	state = "online";
26118334Speter	break;
26218334Speter    case MLX_SYSD_CRITICAL:
26318334Speter	state = "critical";
26418334Speter	break;
26518334Speter    case MLX_SYSD_OFFLINE:
26618334Speter	state = "offline";
26718334Speter	break;
26818334Speter    default:
26918334Speter	state = "unknown state";
27018334Speter    }
27118334Speter
27218334Speter    device_printf(dev, "%uMB (%u sectors), RAID %d (%s)\n",
27318334Speter		  sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE),
27418334Speter		  sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state);
27518334Speter
27618334Speter    devstat_add_entry(&sc->mlxd_stats, "mlxd", sc->mlxd_unit, MLX_BLKSIZE,
27718334Speter		      DEVSTAT_NO_ORDERED_TAGS,
27818334Speter		      DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER,
27918334Speter		      DEVSTAT_PRIORITY_DA);
28018334Speter
28118334Speter    dsk = disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, &mlxd_cdevsw, &mlxddisk_cdevsw);
28218334Speter    disks_registered++;
28318334Speter
28418334Speter    /* set maximum I/O size */
28518334Speter    dsk->si_iosize_max = sc->mlxd_controller->mlx_maxiosize * MLX_BLKSIZE;
28618334Speter    dsk->si_drv1 = sc;
28750397Sobrien
28850397Sobrien    return (0);
28950397Sobrien}
29050397Sobrien
29118334Speterstatic int
29250397Sobrienmlxd_detach(device_t dev)
29350397Sobrien{
29450397Sobrien    struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
29550397Sobrien
29618334Speter    debug("called");
29718334Speter
29818334Speter    devstat_remove_entry(&sc->mlxd_stats);
29918334Speter
30018334Speter    /* hack to handle lack of destroy_disk() */
30118334Speter    if (--disks_registered == 0)
30218334Speter	cdevsw_remove(&mlxddisk_cdevsw);
30318334Speter
30418334Speter    return(0);
30518334Speter}
30618334Speter
30718334Speter