11ac4b82bSMike Smith /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
41ac4b82bSMike Smith * Copyright (c) 1999 Jonathan Lemon
51ac4b82bSMike Smith * Copyright (c) 1999 Michael Smith
61ac4b82bSMike Smith * All rights reserved.
71ac4b82bSMike Smith *
81ac4b82bSMike Smith * Redistribution and use in source and binary forms, with or without
91ac4b82bSMike Smith * modification, are permitted provided that the following conditions
101ac4b82bSMike Smith * are met:
111ac4b82bSMike Smith * 1. Redistributions of source code must retain the above copyright
121ac4b82bSMike Smith * notice, this list of conditions and the following disclaimer.
131ac4b82bSMike Smith * 2. Redistributions in binary form must reproduce the above copyright
141ac4b82bSMike Smith * notice, this list of conditions and the following disclaimer in the
151ac4b82bSMike Smith * documentation and/or other materials provided with the distribution.
161ac4b82bSMike Smith *
171ac4b82bSMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
181ac4b82bSMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191ac4b82bSMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201ac4b82bSMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
211ac4b82bSMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221ac4b82bSMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231ac4b82bSMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241ac4b82bSMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251ac4b82bSMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261ac4b82bSMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271ac4b82bSMike Smith * SUCH DAMAGE.
281ac4b82bSMike Smith *
291ac4b82bSMike Smith */
301ac4b82bSMike Smith
31aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
321ac4b82bSMike Smith /*
331ac4b82bSMike Smith * Disk driver for Mylex DAC960 RAID adapters.
341ac4b82bSMike Smith */
351ac4b82bSMike Smith
361ac4b82bSMike Smith #include <sys/param.h>
371ac4b82bSMike Smith #include <sys/systm.h>
38b04e4c12SJohn Baldwin #include <sys/bio.h>
391ac4b82bSMike Smith #include <sys/kernel.h>
400fca6f8bSJohn Baldwin #include <sys/lock.h>
41fe12f24bSPoul-Henning Kamp #include <sys/module.h>
420fca6f8bSJohn Baldwin #include <sys/sx.h>
431ac4b82bSMike Smith
441ac4b82bSMike Smith #include <sys/bus.h>
451ac4b82bSMike Smith #include <sys/conf.h>
461ac4b82bSMike Smith
471ac4b82bSMike Smith #include <machine/bus.h>
481ac4b82bSMike Smith #include <sys/rman.h>
491ac4b82bSMike Smith
50891619a6SPoul-Henning Kamp #include <geom/geom_disk.h>
51891619a6SPoul-Henning Kamp
521ac4b82bSMike Smith #include <dev/mlx/mlxio.h>
531ac4b82bSMike Smith #include <dev/mlx/mlxvar.h>
544b006d7bSMike Smith #include <dev/mlx/mlxreg.h>
551ac4b82bSMike Smith
561ac4b82bSMike Smith /* prototypes */
571ac4b82bSMike Smith static int mlxd_probe(device_t dev);
581ac4b82bSMike Smith static int mlxd_attach(device_t dev);
591ac4b82bSMike Smith static int mlxd_detach(device_t dev);
601ac4b82bSMike Smith
611ac4b82bSMike Smith static device_method_t mlxd_methods[] = {
621ac4b82bSMike Smith DEVMETHOD(device_probe, mlxd_probe),
631ac4b82bSMike Smith DEVMETHOD(device_attach, mlxd_attach),
641ac4b82bSMike Smith DEVMETHOD(device_detach, mlxd_detach),
651ac4b82bSMike Smith { 0, 0 }
661ac4b82bSMike Smith };
671ac4b82bSMike Smith
681ac4b82bSMike Smith static driver_t mlxd_driver = {
691ac4b82bSMike Smith "mlxd",
701ac4b82bSMike Smith mlxd_methods,
711ac4b82bSMike Smith sizeof(struct mlxd_softc)
721ac4b82bSMike Smith };
731ac4b82bSMike Smith
749cd54db5SJohn Baldwin DRIVER_MODULE(mlxd, mlx, mlxd_driver, 0, 0);
751ac4b82bSMike Smith
761ac4b82bSMike Smith static int
mlxd_open(struct disk * dp)77b2fe65c5SPoul-Henning Kamp mlxd_open(struct disk *dp)
781ac4b82bSMike Smith {
79b2fe65c5SPoul-Henning Kamp struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1;
801ac4b82bSMike Smith
81da8bb3a3SMike Smith debug_called(1);
821ac4b82bSMike Smith
831ac4b82bSMike Smith if (sc == NULL)
841ac4b82bSMike Smith return (ENXIO);
851ac4b82bSMike Smith
861ac4b82bSMike Smith /* controller not active? */
870fca6f8bSJohn Baldwin MLX_CONFIG_LOCK(sc->mlxd_controller);
880fca6f8bSJohn Baldwin MLX_IO_LOCK(sc->mlxd_controller);
890fca6f8bSJohn Baldwin if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN) {
900fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc->mlxd_controller);
910fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc->mlxd_controller);
921ac4b82bSMike Smith return(ENXIO);
930fca6f8bSJohn Baldwin }
941ac4b82bSMike Smith
951ac4b82bSMike Smith sc->mlxd_flags |= MLXD_OPEN;
960fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc->mlxd_controller);
970fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc->mlxd_controller);
981ac4b82bSMike Smith return (0);
991ac4b82bSMike Smith }
1001ac4b82bSMike Smith
1011ac4b82bSMike Smith static int
mlxd_close(struct disk * dp)102b2fe65c5SPoul-Henning Kamp mlxd_close(struct disk *dp)
1031ac4b82bSMike Smith {
104b2fe65c5SPoul-Henning Kamp struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1;
1051ac4b82bSMike Smith
106da8bb3a3SMike Smith debug_called(1);
1071ac4b82bSMike Smith
1081ac4b82bSMike Smith if (sc == NULL)
1091ac4b82bSMike Smith return (ENXIO);
1100fca6f8bSJohn Baldwin MLX_CONFIG_LOCK(sc->mlxd_controller);
1110fca6f8bSJohn Baldwin MLX_IO_LOCK(sc->mlxd_controller);
1121ac4b82bSMike Smith sc->mlxd_flags &= ~MLXD_OPEN;
1130fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc->mlxd_controller);
1140fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc->mlxd_controller);
1151ac4b82bSMike Smith return (0);
1161ac4b82bSMike Smith }
1171ac4b82bSMike Smith
1181ac4b82bSMike Smith static int
mlxd_ioctl(struct disk * dp,u_long cmd,void * addr,int flag,struct thread * td)119b2fe65c5SPoul-Henning Kamp mlxd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
1201ac4b82bSMike Smith {
121b2fe65c5SPoul-Henning Kamp struct mlxd_softc *sc = (struct mlxd_softc *)dp->d_drv1;
1221ac4b82bSMike Smith int error;
1231ac4b82bSMike Smith
124da8bb3a3SMike Smith debug_called(1);
1251ac4b82bSMike Smith
1261ac4b82bSMike Smith if (sc == NULL)
1271ac4b82bSMike Smith return (ENXIO);
1281ac4b82bSMike Smith
129b40ce416SJulian Elischer if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, td)) != ENOIOCTL) {
130da8bb3a3SMike Smith debug(0, "mlx_submit_ioctl returned %d\n", error);
1311ac4b82bSMike Smith return(error);
1321ac4b82bSMike Smith }
1331ac4b82bSMike Smith return (ENOTTY);
1341ac4b82bSMike Smith }
1351ac4b82bSMike Smith
1361ac4b82bSMike Smith /*
1371ac4b82bSMike Smith * Read/write routine for a buffer. Finds the proper unit, range checks
1381ac4b82bSMike Smith * arguments, and schedules the transfer. Does not wait for the transfer
1391ac4b82bSMike Smith * to complete. Multi-page transfers are supported. All I/O requests must
1401ac4b82bSMike Smith * be a multiple of a sector in length.
1411ac4b82bSMike Smith */
1421ac4b82bSMike Smith static void
mlxd_strategy(struct bio * bp)143b04e4c12SJohn Baldwin mlxd_strategy(struct bio *bp)
1441ac4b82bSMike Smith {
145b04e4c12SJohn Baldwin struct mlxd_softc *sc = bp->bio_disk->d_drv1;
1461ac4b82bSMike Smith
147da8bb3a3SMike Smith debug_called(1);
1481ac4b82bSMike Smith
1491ac4b82bSMike Smith /* bogus disk? */
1501ac4b82bSMike Smith if (sc == NULL) {
151b04e4c12SJohn Baldwin bp->bio_error = EINVAL;
152b04e4c12SJohn Baldwin bp->bio_flags |= BIO_ERROR;
1531ac4b82bSMike Smith goto bad;
1541ac4b82bSMike Smith }
1551ac4b82bSMike Smith
156d176b803SScott Long if ((bp->bio_cmd != BIO_READ) && (bp->bio_cmd != BIO_WRITE)) {
157d176b803SScott Long bp->bio_error = EOPNOTSUPP;
158d176b803SScott Long goto bad;
159d176b803SScott Long }
160d176b803SScott Long
1611ac4b82bSMike Smith /* XXX may only be temporarily offline - sleep? */
1620fca6f8bSJohn Baldwin MLX_IO_LOCK(sc->mlxd_controller);
1631ac4b82bSMike Smith if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) {
1640fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc->mlxd_controller);
165b04e4c12SJohn Baldwin bp->bio_error = ENXIO;
166b04e4c12SJohn Baldwin bp->bio_flags |= BIO_ERROR;
1671ac4b82bSMike Smith goto bad;
1681ac4b82bSMike Smith }
1691ac4b82bSMike Smith
1701ac4b82bSMike Smith mlx_submit_buf(sc->mlxd_controller, bp);
1710fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc->mlxd_controller);
1721ac4b82bSMike Smith return;
1731ac4b82bSMike Smith
1741ac4b82bSMike Smith bad:
1751ac4b82bSMike Smith /*
176453130d9SPedro F. Giffuni * Correctly set the bio to indicate a failed transfer.
1771ac4b82bSMike Smith */
178b04e4c12SJohn Baldwin bp->bio_resid = bp->bio_bcount;
179b04e4c12SJohn Baldwin biodone(bp);
1801ac4b82bSMike Smith return;
1811ac4b82bSMike Smith }
1821ac4b82bSMike Smith
1831ac4b82bSMike Smith void
mlxd_intr(struct bio * bp)184b04e4c12SJohn Baldwin mlxd_intr(struct bio *bp)
1851ac4b82bSMike Smith {
1861ac4b82bSMike Smith
187da8bb3a3SMike Smith debug_called(1);
1881ac4b82bSMike Smith
189b04e4c12SJohn Baldwin if (bp->bio_flags & BIO_ERROR)
190b04e4c12SJohn Baldwin bp->bio_error = EIO;
1911ac4b82bSMike Smith else
192b04e4c12SJohn Baldwin bp->bio_resid = 0;
1931ac4b82bSMike Smith
194b04e4c12SJohn Baldwin biodone(bp);
1951ac4b82bSMike Smith }
1961ac4b82bSMike Smith
1971ac4b82bSMike Smith static int
mlxd_probe(device_t dev)1981ac4b82bSMike Smith mlxd_probe(device_t dev)
1991ac4b82bSMike Smith {
2001ac4b82bSMike Smith
201da8bb3a3SMike Smith debug_called(1);
2021ac4b82bSMike Smith
2031ac4b82bSMike Smith device_set_desc(dev, "Mylex System Drive");
2041ac4b82bSMike Smith return (0);
2051ac4b82bSMike Smith }
2061ac4b82bSMike Smith
2071ac4b82bSMike Smith static int
mlxd_attach(device_t dev)2081ac4b82bSMike Smith mlxd_attach(device_t dev)
2091ac4b82bSMike Smith {
2101ac4b82bSMike Smith struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
2111ac4b82bSMike Smith device_t parent;
2121ac4b82bSMike Smith char *state;
213baff09dbSMike Smith int s1, s2;
2141ac4b82bSMike Smith
215da8bb3a3SMike Smith debug_called(1);
2161ac4b82bSMike Smith
2171ac4b82bSMike Smith parent = device_get_parent(dev);
2181ac4b82bSMike Smith sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
2191ac4b82bSMike Smith sc->mlxd_unit = device_get_unit(dev);
2201ac4b82bSMike Smith sc->mlxd_drive = device_get_ivars(dev);
221f01f2af6SMike Smith sc->mlxd_dev = dev;
2221ac4b82bSMike Smith
2231ac4b82bSMike Smith switch(sc->mlxd_drive->ms_state) {
2241ac4b82bSMike Smith case MLX_SYSD_ONLINE:
2251ac4b82bSMike Smith state = "online";
2261ac4b82bSMike Smith break;
2271ac4b82bSMike Smith case MLX_SYSD_CRITICAL:
2281ac4b82bSMike Smith state = "critical";
2291ac4b82bSMike Smith break;
2301ac4b82bSMike Smith case MLX_SYSD_OFFLINE:
2311ac4b82bSMike Smith state = "offline";
2321ac4b82bSMike Smith break;
2331ac4b82bSMike Smith default:
2341ac4b82bSMike Smith state = "unknown state";
2351ac4b82bSMike Smith }
2361ac4b82bSMike Smith
23797adfbafSMike Smith device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n",
2381ac4b82bSMike Smith sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE),
2391ac4b82bSMike Smith sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state);
2401ac4b82bSMike Smith
2410b7ed341SPoul-Henning Kamp sc->mlxd_disk = disk_alloc();
2420b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_open = mlxd_open;
2430b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_close = mlxd_close;
2440b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_ioctl = mlxd_ioctl;
2450b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_strategy = mlxd_strategy;
2460b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_name = "mlxd";
2470b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_unit = sc->mlxd_unit;
2480b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_drv1 = sc;
2490b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_sectorsize = MLX_BLKSIZE;
2500b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_mediasize = MLX_BLKSIZE * (off_t)sc->mlxd_drive->ms_size;
2510b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_fwsectors = sc->mlxd_drive->ms_sectors;
2520b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_fwheads = sc->mlxd_drive->ms_heads;
2531ac4b82bSMike Smith
254baff09dbSMike Smith /*
255baff09dbSMike Smith * Set maximum I/O size to the lesser of the recommended maximum and the practical
256e1159d10SJohn Baldwin * maximum except on v2 cards where the maximum is set to 8 pages.
257baff09dbSMike Smith */
258e1159d10SJohn Baldwin if (sc->mlxd_controller->mlx_iftype == MLX_IFTYPE_2)
2594161b1a1SScott Long sc->mlxd_disk->d_maxsize = 8 * MLX_PAGE_SIZE;
260e1159d10SJohn Baldwin else {
261baff09dbSMike Smith s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE;
2624161b1a1SScott Long s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * MLX_PAGE_SIZE;
2630b7ed341SPoul-Henning Kamp sc->mlxd_disk->d_maxsize = imin(s1, s2);
264e1159d10SJohn Baldwin }
265b2fe65c5SPoul-Henning Kamp
2660b7ed341SPoul-Henning Kamp disk_create(sc->mlxd_disk, DISK_VERSION);
267f6b84b08SMike Smith
2681ac4b82bSMike Smith return (0);
2691ac4b82bSMike Smith }
2701ac4b82bSMike Smith
2711ac4b82bSMike Smith static int
mlxd_detach(device_t dev)2721ac4b82bSMike Smith mlxd_detach(device_t dev)
2731ac4b82bSMike Smith {
2741ac4b82bSMike Smith struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
2751ac4b82bSMike Smith
276da8bb3a3SMike Smith debug_called(1);
2771ac4b82bSMike Smith
2780b7ed341SPoul-Henning Kamp disk_destroy(sc->mlxd_disk);
2791ac4b82bSMike Smith
2801ac4b82bSMike Smith return(0);
2811ac4b82bSMike Smith }
2821ac4b82bSMike Smith
283