mlx_disk.c revision 52273
1/*-
2 * Copyright (c) 1999 Jonathan Lemon
3 * Copyright (c) 1999 Michael Smith
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/sys/dev/mlx/mlx_disk.c 52273 1999-10-16 01:46:59Z msmith $
28 */
29
30/*
31 * Disk driver for Mylex DAC960 RAID adapters.
32 */
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/malloc.h>
37#include <sys/kernel.h>
38
39#include <sys/buf.h>
40#include <sys/bus.h>
41#include <sys/conf.h>
42#include <sys/devicestat.h>
43#include <sys/disk.h>
44
45#include <machine/bus.h>
46#include <machine/clock.h>
47#include <sys/rman.h>
48
49#include <dev/mlx/mlxio.h>
50#include <dev/mlx/mlxvar.h>
51
52#if 0
53#define debug(fmt, args...)	printf("%s: " fmt "\n", __FUNCTION__ , ##args)
54#else
55#define debug(fmt, args...)
56#endif
57
58/* prototypes */
59static int mlxd_probe(device_t dev);
60static int mlxd_attach(device_t dev);
61static int mlxd_detach(device_t dev);
62
63static	d_open_t	mlxd_open;
64static	d_close_t	mlxd_close;
65static	d_strategy_t	mlxd_strategy;
66static	d_ioctl_t	mlxd_ioctl;
67
68#define MLXD_BDEV_MAJOR	27
69#define MLXD_CDEV_MAJOR	131
70
71static struct cdevsw mlxd_cdevsw = {
72		/* open */	mlxd_open,
73		/* close */	mlxd_close,
74		/* read */	physread,
75		/* write */	physwrite,
76		/* ioctl */	mlxd_ioctl,
77		/* poll */	nopoll,
78		/* mmap */	nommap,
79		/* strategy */	mlxd_strategy,
80		/* name */ 	"mlxd",
81		/* maj */	MLXD_CDEV_MAJOR,
82		/* dump */	nodump,
83		/* psize */ 	nopsize,
84		/* flags */	D_DISK,
85		/* bmaj */	MLXD_BDEV_MAJOR
86};
87
88static devclass_t	mlxd_devclass;
89static struct cdevsw	mlxddisk_cdevsw;
90static int		disks_registered = 0;
91
92static device_method_t mlxd_methods[] = {
93    DEVMETHOD(device_probe,	mlxd_probe),
94    DEVMETHOD(device_attach,	mlxd_attach),
95    DEVMETHOD(device_detach,	mlxd_detach),
96    { 0, 0 }
97};
98
99static driver_t mlxd_driver = {
100    "mlxd",
101    mlxd_methods,
102    sizeof(struct mlxd_softc)
103};
104
105DRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0);
106
107static int
108mlxd_open(dev_t dev, int flags, int fmt, struct proc *p)
109{
110    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
111    struct disklabel	*label;
112
113    debug("called");
114
115    if (sc == NULL)
116	return (ENXIO);
117
118    /* controller not active? */
119    if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN)
120	return(ENXIO);
121
122    label = &sc->mlxd_disk.d_label;
123    bzero(label, sizeof(*label));
124    label->d_type = DTYPE_SCSI;
125    label->d_secsize    = MLX_BLKSIZE;
126    label->d_nsectors   = sc->mlxd_drive->ms_sectors;
127    label->d_ntracks    = sc->mlxd_drive->ms_heads;
128    label->d_ncylinders = sc->mlxd_drive->ms_cylinders;
129    label->d_secpercyl  = sc->mlxd_drive->ms_sectors * sc->mlxd_drive->ms_heads;
130    label->d_secperunit = sc->mlxd_drive->ms_size;
131
132    sc->mlxd_flags |= MLXD_OPEN;
133    return (0);
134}
135
136static int
137mlxd_close(dev_t dev, int flags, int fmt, struct proc *p)
138{
139    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
140
141    debug("called");
142
143    if (sc == NULL)
144	return (ENXIO);
145    sc->mlxd_flags &= ~MLXD_OPEN;
146    return (0);
147}
148
149static int
150mlxd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
151{
152    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
153    int error;
154
155    debug("called");
156
157    if (sc == NULL)
158	return (ENXIO);
159
160    if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, p)) != ENOIOCTL) {
161	debug("mlx_submit_ioctl returned %d\n", error);
162	return(error);
163    }
164    return (ENOTTY);
165}
166
167/*
168 * Read/write routine for a buffer.  Finds the proper unit, range checks
169 * arguments, and schedules the transfer.  Does not wait for the transfer
170 * to complete.  Multi-page transfers are supported.  All I/O requests must
171 * be a multiple of a sector in length.
172 */
173static void
174mlxd_strategy(struct buf *bp)
175{
176    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
177    int			s;
178
179    debug("called");
180
181    /* bogus disk? */
182    if (sc == NULL) {
183	bp->b_error = EINVAL;
184	goto bad;
185    }
186
187    /* XXX may only be temporarily offline - sleep? */
188    if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) {
189	bp->b_error = ENXIO;
190	goto bad;
191    }
192
193    /* do-nothing operation */
194    if (bp->b_bcount == 0)
195	goto done;
196
197    s = splbio();
198    devstat_start_transaction(&sc->mlxd_stats);
199    mlx_submit_buf(sc->mlxd_controller, bp);
200    splx(s);
201    return;
202
203 bad:
204    bp->b_flags |= B_ERROR;
205
206 done:
207    /*
208     * Correctly set the buf to indicate a completed transfer
209     */
210    bp->b_resid = bp->b_bcount;
211    biodone(bp);
212    return;
213}
214
215void
216mlxd_intr(void *data)
217{
218    struct buf *bp = (struct buf *)data;
219    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
220
221    debug("called");
222
223    if (bp->b_flags & B_ERROR)
224	bp->b_error = EIO;
225    else
226	bp->b_resid = 0;
227
228    devstat_end_transaction_buf(&sc->mlxd_stats, bp);
229    biodone(bp);
230}
231
232static int
233mlxd_probe(device_t dev)
234{
235
236    debug("called");
237
238    device_set_desc(dev, "Mylex System Drive");
239    return (0);
240}
241
242static int
243mlxd_attach(device_t dev)
244{
245    struct mlxd_softc	*sc = (struct mlxd_softc *)device_get_softc(dev);
246    device_t		parent;
247    char		*state;
248    dev_t		dsk;
249
250    debug("called");
251
252    parent = device_get_parent(dev);
253    sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
254    sc->mlxd_unit = device_get_unit(dev);
255    sc->mlxd_drive = device_get_ivars(dev);
256    sc->mlxd_dev = dev;
257
258    switch(sc->mlxd_drive->ms_state) {
259    case MLX_SYSD_ONLINE:
260	state = "online";
261	break;
262    case MLX_SYSD_CRITICAL:
263	state = "critical";
264	break;
265    case MLX_SYSD_OFFLINE:
266	state = "offline";
267	break;
268    default:
269	state = "unknown state";
270    }
271
272    device_printf(dev, "%uMB (%u sectors), RAID %d (%s)\n",
273		  sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE),
274		  sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state);
275
276    devstat_add_entry(&sc->mlxd_stats, "mlxd", sc->mlxd_unit, MLX_BLKSIZE,
277		      DEVSTAT_NO_ORDERED_TAGS,
278		      DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER,
279		      DEVSTAT_PRIORITY_DA);
280
281    dsk = disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, &mlxd_cdevsw, &mlxddisk_cdevsw);
282    disks_registered++;
283
284    /* set maximum I/O size */
285    dsk->si_iosize_max = sc->mlxd_controller->mlx_maxiosize * MLX_BLKSIZE;
286    dsk->si_drv1 = sc;
287
288    return (0);
289}
290
291static int
292mlxd_detach(device_t dev)
293{
294    struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
295
296    debug("called");
297
298    devstat_remove_entry(&sc->mlxd_stats);
299
300    /* hack to handle lack of destroy_disk() */
301    if (--disks_registered == 0)
302	cdevsw_remove(&mlxddisk_cdevsw);
303
304    return(0);
305}
306
307