mlx_disk.c revision 112946
1215976Sjmallett/*-
2232812Sjmallett * Copyright (c) 1999 Jonathan Lemon
3215976Sjmallett * Copyright (c) 1999 Michael Smith
4215976Sjmallett * All rights reserved.
5215976Sjmallett *
6215976Sjmallett * Redistribution and use in source and binary forms, with or without
7215976Sjmallett * modification, are permitted provided that the following conditions
8215976Sjmallett * are met:
9215976Sjmallett * 1. Redistributions of source code must retain the above copyright
10215976Sjmallett *    notice, this list of conditions and the following disclaimer.
11215976Sjmallett * 2. Redistributions in binary form must reproduce the above copyright
12215976Sjmallett *    notice, this list of conditions and the following disclaimer in the
13215976Sjmallett *    documentation and/or other materials provided with the distribution.
14215976Sjmallett *
15215976Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16215976Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17215976Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18232812Sjmallett * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19215976Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20215976Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21215976Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22215976Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23215976Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24215976Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25215976Sjmallett * SUCH DAMAGE.
26215976Sjmallett *
27215976Sjmallett * $FreeBSD: head/sys/dev/mlx/mlx_disk.c 112946 2003-04-01 15:06:26Z phk $
28215976Sjmallett */
29232812Sjmallett
30215976Sjmallett/*
31215976Sjmallett * Disk driver for Mylex DAC960 RAID adapters.
32215976Sjmallett */
33215976Sjmallett
34215976Sjmallett#include <sys/param.h>
35215976Sjmallett#include <sys/systm.h>
36215976Sjmallett#include <sys/kernel.h>
37215976Sjmallett
38215976Sjmallett#include <sys/bus.h>
39215976Sjmallett#include <sys/conf.h>
40215976Sjmallett
41215976Sjmallett#include <machine/bus.h>
42215976Sjmallett#include <sys/rman.h>
43215976Sjmallett
44215976Sjmallett#include <geom/geom_disk.h>
45215976Sjmallett
46215976Sjmallett#include <dev/mlx/mlx_compat.h>
47215976Sjmallett#include <dev/mlx/mlxio.h>
48215976Sjmallett#include <dev/mlx/mlxvar.h>
49215976Sjmallett#include <dev/mlx/mlxreg.h>
50215976Sjmallett
51215976Sjmallett/* prototypes */
52232812Sjmallettstatic int mlxd_probe(device_t dev);
53232812Sjmallettstatic int mlxd_attach(device_t dev);
54215976Sjmallettstatic int mlxd_detach(device_t dev);
55215976Sjmallett
56215976Sjmallettdevclass_t		mlxd_devclass;
57215976Sjmallett
58215976Sjmallettstatic device_method_t mlxd_methods[] = {
59215976Sjmallett    DEVMETHOD(device_probe,	mlxd_probe),
60215976Sjmallett    DEVMETHOD(device_attach,	mlxd_attach),
61215976Sjmallett    DEVMETHOD(device_detach,	mlxd_detach),
62215976Sjmallett    { 0, 0 }
63215976Sjmallett};
64215976Sjmallett
65215976Sjmallettstatic driver_t mlxd_driver = {
66215976Sjmallett    "mlxd",
67215976Sjmallett    mlxd_methods,
68215976Sjmallett    sizeof(struct mlxd_softc)
69215976Sjmallett};
70215976Sjmallett
71215976SjmallettDRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0);
72215976Sjmallett
73215976Sjmallettstatic int
74215976Sjmallettmlxd_open(struct disk *dp)
75215976Sjmallett{
76215976Sjmallett    struct mlxd_softc	*sc = (struct mlxd_softc *)dp->d_drv1;
77215976Sjmallett
78215976Sjmallett    debug_called(1);
79215976Sjmallett
80215976Sjmallett    if (sc == NULL)
81215976Sjmallett	return (ENXIO);
82215976Sjmallett
83215976Sjmallett    /* controller not active? */
84215976Sjmallett    if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN)
85215976Sjmallett	return(ENXIO);
86215976Sjmallett
87215976Sjmallett    sc->mlxd_flags |= MLXD_OPEN;
88215976Sjmallett    return (0);
89215976Sjmallett}
90215976Sjmallett
91215976Sjmallettstatic int
92215976Sjmallettmlxd_close(struct disk *dp)
93215976Sjmallett{
94215976Sjmallett    struct mlxd_softc	*sc = (struct mlxd_softc *)dp->d_drv1;
95215976Sjmallett
96215976Sjmallett    debug_called(1);
97215976Sjmallett
98215976Sjmallett    if (sc == NULL)
99215976Sjmallett	return (ENXIO);
100215976Sjmallett    sc->mlxd_flags &= ~MLXD_OPEN;
101215976Sjmallett    return (0);
102215976Sjmallett}
103215976Sjmallett
104215976Sjmallettstatic int
105215976Sjmallettmlxd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
106215976Sjmallett{
107215976Sjmallett    struct mlxd_softc	*sc = (struct mlxd_softc *)dp->d_drv1;
108215976Sjmallett    int error;
109215976Sjmallett
110215976Sjmallett    debug_called(1);
111215976Sjmallett
112215976Sjmallett    if (sc == NULL)
113215976Sjmallett	return (ENXIO);
114215976Sjmallett
115215976Sjmallett    if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, td)) != ENOIOCTL) {
116215976Sjmallett	debug(0, "mlx_submit_ioctl returned %d\n", error);
117215976Sjmallett	return(error);
118215976Sjmallett    }
119215976Sjmallett    return (ENOTTY);
120215976Sjmallett}
121215976Sjmallett
122215976Sjmallett/*
123215976Sjmallett * Read/write routine for a buffer.  Finds the proper unit, range checks
124215976Sjmallett * arguments, and schedules the transfer.  Does not wait for the transfer
125215976Sjmallett * to complete.  Multi-page transfers are supported.  All I/O requests must
126215976Sjmallett * be a multiple of a sector in length.
127215976Sjmallett */
128215976Sjmallettstatic void
129215976Sjmallettmlxd_strategy(mlx_bio *bp)
130215976Sjmallett{
131215976Sjmallett    struct mlxd_softc	*sc = (struct mlxd_softc *)MLX_BIO_SOFTC(bp);
132215976Sjmallett
133215976Sjmallett    debug_called(1);
134215976Sjmallett
135215976Sjmallett    /* bogus disk? */
136215976Sjmallett    if (sc == NULL) {
137215976Sjmallett	MLX_BIO_SET_ERROR(bp, EINVAL);
138215976Sjmallett	goto bad;
139215976Sjmallett    }
140215976Sjmallett
141215976Sjmallett    /* XXX may only be temporarily offline - sleep? */
142215976Sjmallett    if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) {
143215976Sjmallett	MLX_BIO_SET_ERROR(bp, ENXIO);
144215976Sjmallett	goto bad;
145215976Sjmallett    }
146215976Sjmallett
147215976Sjmallett    MLX_BIO_STATS_START(bp);
148215976Sjmallett    mlx_submit_buf(sc->mlxd_controller, bp);
149215976Sjmallett    return;
150215976Sjmallett
151215976Sjmallett bad:
152215976Sjmallett    /*
153215976Sjmallett     * Correctly set the bio to indicate a failed tranfer.
154215976Sjmallett     */
155215976Sjmallett    MLX_BIO_RESID(bp) = MLX_BIO_LENGTH(bp);
156215976Sjmallett    MLX_BIO_DONE(bp);
157215976Sjmallett    return;
158215976Sjmallett}
159215976Sjmallett
160215976Sjmallettvoid
161215976Sjmallettmlxd_intr(void *data)
162215976Sjmallett{
163215976Sjmallett    mlx_bio 		*bp = (mlx_bio *)data;
164215976Sjmallett
165215976Sjmallett    debug_called(1);
166215976Sjmallett
167215976Sjmallett    if (MLX_BIO_HAS_ERROR(bp))
168215976Sjmallett	MLX_BIO_SET_ERROR(bp, EIO);
169215976Sjmallett    else
170215976Sjmallett	MLX_BIO_RESID(bp) = 0;
171215976Sjmallett
172215976Sjmallett    MLX_BIO_STATS_END(bp);
173215976Sjmallett    MLX_BIO_DONE(bp);
174215976Sjmallett}
175215976Sjmallett
176215976Sjmallettstatic int
177215976Sjmallettmlxd_probe(device_t dev)
178215976Sjmallett{
179215976Sjmallett
180215976Sjmallett    debug_called(1);
181215976Sjmallett
182215976Sjmallett    device_set_desc(dev, "Mylex System Drive");
183215976Sjmallett    return (0);
184215976Sjmallett}
185215976Sjmallett
186215976Sjmallettstatic int
187215976Sjmallettmlxd_attach(device_t dev)
188215976Sjmallett{
189215976Sjmallett    struct mlxd_softc	*sc = (struct mlxd_softc *)device_get_softc(dev);
190215976Sjmallett    device_t		parent;
191215976Sjmallett    char		*state;
192215976Sjmallett    int			s1, s2;
193215976Sjmallett
194215976Sjmallett    debug_called(1);
195215976Sjmallett
196215976Sjmallett    parent = device_get_parent(dev);
197215976Sjmallett    sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
198215976Sjmallett    sc->mlxd_unit = device_get_unit(dev);
199215976Sjmallett    sc->mlxd_drive = device_get_ivars(dev);
200215976Sjmallett    sc->mlxd_dev = dev;
201215976Sjmallett
202215976Sjmallett    switch(sc->mlxd_drive->ms_state) {
203215976Sjmallett    case MLX_SYSD_ONLINE:
204215976Sjmallett	state = "online";
205215976Sjmallett	break;
206215976Sjmallett    case MLX_SYSD_CRITICAL:
207215976Sjmallett	state = "critical";
208215976Sjmallett	break;
209215976Sjmallett    case MLX_SYSD_OFFLINE:
210215976Sjmallett	state = "offline";
211215976Sjmallett	break;
212215976Sjmallett    default:
213215976Sjmallett	state = "unknown state";
214215976Sjmallett    }
215215976Sjmallett
216215976Sjmallett    device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n",
217215976Sjmallett		  sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE),
218215976Sjmallett		  sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state);
219215976Sjmallett
220215976Sjmallett    sc->mlxd_disk.d_open = mlxd_open;
221215976Sjmallett    sc->mlxd_disk.d_close = mlxd_close;
222215976Sjmallett    sc->mlxd_disk.d_ioctl = mlxd_ioctl;
223215976Sjmallett    sc->mlxd_disk.d_strategy = mlxd_strategy;
224215976Sjmallett    sc->mlxd_disk.d_name = "mlxd";
225215976Sjmallett    sc->mlxd_disk.d_drv1 = sc;
226215976Sjmallett    sc->mlxd_disk.d_sectorsize = MLX_BLKSIZE;
227215976Sjmallett    sc->mlxd_disk.d_mediasize = MLX_BLKSIZE * (off_t)sc->mlxd_drive->ms_size;
228215976Sjmallett    sc->mlxd_disk.d_fwsectors = sc->mlxd_drive->ms_sectors;
229215976Sjmallett    sc->mlxd_disk.d_fwheads = sc->mlxd_drive->ms_heads;
230215976Sjmallett
231215976Sjmallett    /*
232215976Sjmallett     * Set maximum I/O size to the lesser of the recommended maximum and the practical
233215976Sjmallett     * maximum except on v2 cards where the maximum is set to 8 pages.
234215976Sjmallett     */
235215976Sjmallett    if (sc->mlxd_controller->mlx_iftype == MLX_IFTYPE_2)
236215976Sjmallett	sc->mlxd_disk.d_maxsize = 8 * PAGE_SIZE;
237215976Sjmallett    else {
238215976Sjmallett	s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE;
239215976Sjmallett	s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * PAGE_SIZE;
240215976Sjmallett	sc->mlxd_disk.d_maxsize = imin(s1, s2);
241215976Sjmallett    }
242215976Sjmallett
243215976Sjmallett    disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, NULL, NULL);
244215976Sjmallett
245215976Sjmallett    return (0);
246215976Sjmallett}
247215976Sjmallett
248215976Sjmallettstatic int
249215976Sjmallettmlxd_detach(device_t dev)
250215976Sjmallett{
251215976Sjmallett    struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
252215976Sjmallett
253215976Sjmallett    debug_called(1);
254215976Sjmallett
255232812Sjmallett    disk_destroy(&sc->mlxd_disk);
256215976Sjmallett
257232812Sjmallett    return(0);
258232812Sjmallett}
259215976Sjmallett
260215976Sjmallett