mlx_disk.c revision 138090
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 */
28215976Sjmallett
29232812Sjmallett#include <sys/cdefs.h>
30215976Sjmallett__FBSDID("$FreeBSD: head/sys/dev/mlx/mlx_disk.c 138090 2004-11-25 12:15:49Z scottl $");
31215976Sjmallett
32215976Sjmallett/*
33215976Sjmallett * Disk driver for Mylex DAC960 RAID adapters.
34215976Sjmallett */
35215976Sjmallett
36215976Sjmallett#include <sys/param.h>
37215976Sjmallett#include <sys/systm.h>
38215976Sjmallett#include <sys/kernel.h>
39215976Sjmallett#include <sys/module.h>
40215976Sjmallett
41215976Sjmallett#include <sys/bus.h>
42215976Sjmallett#include <sys/conf.h>
43215976Sjmallett
44215976Sjmallett#include <machine/bus.h>
45215976Sjmallett#include <sys/rman.h>
46215976Sjmallett
47215976Sjmallett#include <geom/geom_disk.h>
48215976Sjmallett
49215976Sjmallett#include <dev/mlx/mlx_compat.h>
50215976Sjmallett#include <dev/mlx/mlxio.h>
51215976Sjmallett#include <dev/mlx/mlxvar.h>
52232812Sjmallett#include <dev/mlx/mlxreg.h>
53232812Sjmallett
54215976Sjmallett/* prototypes */
55215976Sjmallettstatic int mlxd_probe(device_t dev);
56215976Sjmallettstatic int mlxd_attach(device_t dev);
57215976Sjmallettstatic int mlxd_detach(device_t dev);
58215976Sjmallett
59215976Sjmallettdevclass_t		mlxd_devclass;
60215976Sjmallett
61215976Sjmallettstatic device_method_t mlxd_methods[] = {
62215976Sjmallett    DEVMETHOD(device_probe,	mlxd_probe),
63215976Sjmallett    DEVMETHOD(device_attach,	mlxd_attach),
64215976Sjmallett    DEVMETHOD(device_detach,	mlxd_detach),
65215976Sjmallett    { 0, 0 }
66215976Sjmallett};
67215976Sjmallett
68215976Sjmallettstatic driver_t mlxd_driver = {
69215976Sjmallett    "mlxd",
70215976Sjmallett    mlxd_methods,
71215976Sjmallett    sizeof(struct mlxd_softc)
72215976Sjmallett};
73215976Sjmallett
74215976SjmallettDRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0);
75215976Sjmallett
76215976Sjmallettstatic int
77215976Sjmallettmlxd_open(struct disk *dp)
78215976Sjmallett{
79215976Sjmallett    struct mlxd_softc	*sc = (struct mlxd_softc *)dp->d_drv1;
80215976Sjmallett
81215976Sjmallett    debug_called(1);
82215976Sjmallett
83215976Sjmallett    if (sc == NULL)
84215976Sjmallett	return (ENXIO);
85215976Sjmallett
86215976Sjmallett    /* controller not active? */
87215976Sjmallett    if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN)
88215976Sjmallett	return(ENXIO);
89215976Sjmallett
90215976Sjmallett    sc->mlxd_flags |= MLXD_OPEN;
91215976Sjmallett    return (0);
92215976Sjmallett}
93215976Sjmallett
94215976Sjmallettstatic int
95215976Sjmallettmlxd_close(struct disk *dp)
96215976Sjmallett{
97215976Sjmallett    struct mlxd_softc	*sc = (struct mlxd_softc *)dp->d_drv1;
98215976Sjmallett
99215976Sjmallett    debug_called(1);
100215976Sjmallett
101215976Sjmallett    if (sc == NULL)
102215976Sjmallett	return (ENXIO);
103215976Sjmallett    sc->mlxd_flags &= ~MLXD_OPEN;
104215976Sjmallett    return (0);
105215976Sjmallett}
106215976Sjmallett
107215976Sjmallettstatic int
108215976Sjmallettmlxd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
109215976Sjmallett{
110215976Sjmallett    struct mlxd_softc	*sc = (struct mlxd_softc *)dp->d_drv1;
111215976Sjmallett    int error;
112215976Sjmallett
113215976Sjmallett    debug_called(1);
114215976Sjmallett
115215976Sjmallett    if (sc == NULL)
116215976Sjmallett	return (ENXIO);
117215976Sjmallett
118215976Sjmallett    if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, td)) != ENOIOCTL) {
119215976Sjmallett	debug(0, "mlx_submit_ioctl returned %d\n", error);
120215976Sjmallett	return(error);
121215976Sjmallett    }
122215976Sjmallett    return (ENOTTY);
123215976Sjmallett}
124215976Sjmallett
125215976Sjmallett/*
126215976Sjmallett * Read/write routine for a buffer.  Finds the proper unit, range checks
127215976Sjmallett * arguments, and schedules the transfer.  Does not wait for the transfer
128215976Sjmallett * to complete.  Multi-page transfers are supported.  All I/O requests must
129215976Sjmallett * be a multiple of a sector in length.
130215976Sjmallett */
131215976Sjmallettstatic void
132215976Sjmallettmlxd_strategy(mlx_bio *bp)
133215976Sjmallett{
134215976Sjmallett    struct mlxd_softc	*sc = (struct mlxd_softc *)MLX_BIO_SOFTC(bp);
135215976Sjmallett
136215976Sjmallett    debug_called(1);
137215976Sjmallett
138215976Sjmallett    /* bogus disk? */
139215976Sjmallett    if (sc == NULL) {
140215976Sjmallett	MLX_BIO_SET_ERROR(bp, EINVAL);
141215976Sjmallett	goto bad;
142215976Sjmallett    }
143215976Sjmallett
144215976Sjmallett    /* XXX may only be temporarily offline - sleep? */
145215976Sjmallett    if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) {
146215976Sjmallett	MLX_BIO_SET_ERROR(bp, ENXIO);
147215976Sjmallett	goto bad;
148215976Sjmallett    }
149215976Sjmallett
150215976Sjmallett    MLX_BIO_STATS_START(bp);
151215976Sjmallett    mlx_submit_buf(sc->mlxd_controller, bp);
152215976Sjmallett    return;
153215976Sjmallett
154215976Sjmallett bad:
155215976Sjmallett    /*
156215976Sjmallett     * Correctly set the bio to indicate a failed tranfer.
157215976Sjmallett     */
158215976Sjmallett    MLX_BIO_RESID(bp) = MLX_BIO_LENGTH(bp);
159215976Sjmallett    MLX_BIO_DONE(bp);
160215976Sjmallett    return;
161215976Sjmallett}
162215976Sjmallett
163215976Sjmallettvoid
164215976Sjmallettmlxd_intr(void *data)
165215976Sjmallett{
166215976Sjmallett    mlx_bio 		*bp = (mlx_bio *)data;
167215976Sjmallett
168215976Sjmallett    debug_called(1);
169215976Sjmallett
170215976Sjmallett    if (MLX_BIO_HAS_ERROR(bp))
171215976Sjmallett	MLX_BIO_SET_ERROR(bp, EIO);
172215976Sjmallett    else
173215976Sjmallett	MLX_BIO_RESID(bp) = 0;
174215976Sjmallett
175215976Sjmallett    MLX_BIO_STATS_END(bp);
176215976Sjmallett    MLX_BIO_DONE(bp);
177215976Sjmallett}
178215976Sjmallett
179215976Sjmallettstatic int
180215976Sjmallettmlxd_probe(device_t dev)
181215976Sjmallett{
182215976Sjmallett
183215976Sjmallett    debug_called(1);
184215976Sjmallett
185215976Sjmallett    device_set_desc(dev, "Mylex System Drive");
186215976Sjmallett    return (0);
187215976Sjmallett}
188215976Sjmallett
189215976Sjmallettstatic int
190215976Sjmallettmlxd_attach(device_t dev)
191215976Sjmallett{
192215976Sjmallett    struct mlxd_softc	*sc = (struct mlxd_softc *)device_get_softc(dev);
193215976Sjmallett    device_t		parent;
194215976Sjmallett    char		*state;
195215976Sjmallett    int			s1, s2;
196215976Sjmallett
197215976Sjmallett    debug_called(1);
198215976Sjmallett
199215976Sjmallett    parent = device_get_parent(dev);
200215976Sjmallett    sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
201215976Sjmallett    sc->mlxd_unit = device_get_unit(dev);
202215976Sjmallett    sc->mlxd_drive = device_get_ivars(dev);
203215976Sjmallett    sc->mlxd_dev = dev;
204215976Sjmallett
205215976Sjmallett    switch(sc->mlxd_drive->ms_state) {
206215976Sjmallett    case MLX_SYSD_ONLINE:
207215976Sjmallett	state = "online";
208215976Sjmallett	break;
209215976Sjmallett    case MLX_SYSD_CRITICAL:
210215976Sjmallett	state = "critical";
211215976Sjmallett	break;
212215976Sjmallett    case MLX_SYSD_OFFLINE:
213215976Sjmallett	state = "offline";
214215976Sjmallett	break;
215215976Sjmallett    default:
216215976Sjmallett	state = "unknown state";
217215976Sjmallett    }
218215976Sjmallett
219215976Sjmallett    device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n",
220215976Sjmallett		  sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE),
221215976Sjmallett		  sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state);
222215976Sjmallett
223215976Sjmallett    sc->mlxd_disk = disk_alloc();
224215976Sjmallett    sc->mlxd_disk->d_open = mlxd_open;
225215976Sjmallett    sc->mlxd_disk->d_close = mlxd_close;
226215976Sjmallett    sc->mlxd_disk->d_ioctl = mlxd_ioctl;
227215976Sjmallett    sc->mlxd_disk->d_strategy = mlxd_strategy;
228215976Sjmallett    sc->mlxd_disk->d_name = "mlxd";
229215976Sjmallett    sc->mlxd_disk->d_unit = sc->mlxd_unit;
230215976Sjmallett    sc->mlxd_disk->d_drv1 = sc;
231215976Sjmallett    sc->mlxd_disk->d_sectorsize = MLX_BLKSIZE;
232215976Sjmallett    sc->mlxd_disk->d_mediasize = MLX_BLKSIZE * (off_t)sc->mlxd_drive->ms_size;
233215976Sjmallett    sc->mlxd_disk->d_fwsectors = sc->mlxd_drive->ms_sectors;
234215976Sjmallett    sc->mlxd_disk->d_fwheads = sc->mlxd_drive->ms_heads;
235215976Sjmallett    sc->mlxd_disk->d_flags = DISKFLAG_NEEDSGIANT;
236215976Sjmallett
237215976Sjmallett    /*
238215976Sjmallett     * Set maximum I/O size to the lesser of the recommended maximum and the practical
239215976Sjmallett     * maximum except on v2 cards where the maximum is set to 8 pages.
240215976Sjmallett     */
241215976Sjmallett    if (sc->mlxd_controller->mlx_iftype == MLX_IFTYPE_2)
242215976Sjmallett	sc->mlxd_disk->d_maxsize = 8 * MLX_PAGE_SIZE;
243215976Sjmallett    else {
244215976Sjmallett	s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE;
245215976Sjmallett	s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * MLX_PAGE_SIZE;
246215976Sjmallett	sc->mlxd_disk->d_maxsize = imin(s1, s2);
247215976Sjmallett    }
248215976Sjmallett
249215976Sjmallett    disk_create(sc->mlxd_disk, DISK_VERSION);
250215976Sjmallett
251215976Sjmallett    return (0);
252215976Sjmallett}
253215976Sjmallett
254215976Sjmallettstatic int
255215976Sjmallettmlxd_detach(device_t dev)
256215976Sjmallett{
257215976Sjmallett    struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
258215976Sjmallett
259215976Sjmallett    debug_called(1);
260215976Sjmallett
261215976Sjmallett    disk_destroy(sc->mlxd_disk);
262215976Sjmallett
263215976Sjmallett    return(0);
264215976Sjmallett}
265215976Sjmallett
266215976Sjmallett