mlx_disk.c revision 58188
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 58188 2000-03-18 02:01:37Z 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#include <dev/mlx/mlxreg.h>
52
53/* prototypes */
54static int mlxd_probe(device_t dev);
55static int mlxd_attach(device_t dev);
56static int mlxd_detach(device_t dev);
57
58static	d_open_t	mlxd_open;
59static	d_close_t	mlxd_close;
60static	d_strategy_t	mlxd_strategy;
61static	d_ioctl_t	mlxd_ioctl;
62
63#define MLXD_BDEV_MAJOR	27
64#define MLXD_CDEV_MAJOR	131
65
66static struct cdevsw mlxd_cdevsw = {
67		/* open */	mlxd_open,
68		/* close */	mlxd_close,
69		/* read */	physread,
70		/* write */	physwrite,
71		/* ioctl */	mlxd_ioctl,
72		/* poll */	nopoll,
73		/* mmap */	nommap,
74		/* strategy */	mlxd_strategy,
75		/* name */ 	"mlxd",
76		/* maj */	MLXD_CDEV_MAJOR,
77		/* dump */	nodump,
78		/* psize */ 	nopsize,
79		/* flags */	D_DISK,
80		/* bmaj */	MLXD_BDEV_MAJOR
81};
82
83static devclass_t	mlxd_devclass;
84static struct cdevsw	mlxddisk_cdevsw;
85static int		disks_registered = 0;
86
87static device_method_t mlxd_methods[] = {
88    DEVMETHOD(device_probe,	mlxd_probe),
89    DEVMETHOD(device_attach,	mlxd_attach),
90    DEVMETHOD(device_detach,	mlxd_detach),
91    { 0, 0 }
92};
93
94static driver_t mlxd_driver = {
95    "mlxd",
96    mlxd_methods,
97    sizeof(struct mlxd_softc)
98};
99
100DRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0);
101
102static int
103mlxd_open(dev_t dev, int flags, int fmt, struct proc *p)
104{
105    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
106    struct disklabel	*label;
107
108    debug_called(1);
109
110    if (sc == NULL)
111	return (ENXIO);
112
113    /* controller not active? */
114    if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN)
115	return(ENXIO);
116
117    label = &sc->mlxd_disk.d_label;
118    bzero(label, sizeof(*label));
119    label->d_type = DTYPE_SCSI;
120    label->d_secsize    = MLX_BLKSIZE;
121    label->d_nsectors   = sc->mlxd_drive->ms_sectors;
122    label->d_ntracks    = sc->mlxd_drive->ms_heads;
123    label->d_ncylinders = sc->mlxd_drive->ms_cylinders;
124    label->d_secpercyl  = sc->mlxd_drive->ms_sectors * sc->mlxd_drive->ms_heads;
125    label->d_secperunit = sc->mlxd_drive->ms_size;
126
127    sc->mlxd_flags |= MLXD_OPEN;
128    return (0);
129}
130
131static int
132mlxd_close(dev_t dev, int flags, int fmt, struct proc *p)
133{
134    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
135
136    debug_called(1);
137
138    if (sc == NULL)
139	return (ENXIO);
140    sc->mlxd_flags &= ~MLXD_OPEN;
141    return (0);
142}
143
144static int
145mlxd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
146{
147    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
148    int error;
149
150    debug_called(1);
151
152    if (sc == NULL)
153	return (ENXIO);
154
155    if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, p)) != ENOIOCTL) {
156	debug(0, "mlx_submit_ioctl returned %d\n", error);
157	return(error);
158    }
159    return (ENOTTY);
160}
161
162/*
163 * Read/write routine for a buffer.  Finds the proper unit, range checks
164 * arguments, and schedules the transfer.  Does not wait for the transfer
165 * to complete.  Multi-page transfers are supported.  All I/O requests must
166 * be a multiple of a sector in length.
167 */
168static void
169mlxd_strategy(struct buf *bp)
170{
171    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
172
173    debug_called(1);
174
175    /* bogus disk? */
176    if (sc == NULL) {
177	bp->b_error = EINVAL;
178	goto bad;
179    }
180
181    /* XXX may only be temporarily offline - sleep? */
182    if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) {
183	bp->b_error = ENXIO;
184	goto bad;
185    }
186
187    /* do-nothing operation */
188    if (bp->b_bcount == 0)
189	goto done;
190
191    devstat_start_transaction(&sc->mlxd_stats);
192    mlx_submit_buf(sc->mlxd_controller, bp);
193    return;
194
195 bad:
196    bp->b_flags |= B_ERROR;
197
198 done:
199    /*
200     * Correctly set the buf to indicate a completed transfer
201     */
202    bp->b_resid = bp->b_bcount;
203    biodone(bp);
204    return;
205}
206
207void
208mlxd_intr(void *data)
209{
210    struct buf *bp = (struct buf *)data;
211    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
212
213    debug_called(1);
214
215    if (bp->b_flags & B_ERROR)
216	bp->b_error = EIO;
217    else
218	bp->b_resid = 0;
219
220    devstat_end_transaction_buf(&sc->mlxd_stats, bp);
221    biodone(bp);
222}
223
224static int
225mlxd_probe(device_t dev)
226{
227
228    debug_called(1);
229
230    device_set_desc(dev, "Mylex System Drive");
231    return (0);
232}
233
234static int
235mlxd_attach(device_t dev)
236{
237    struct mlxd_softc	*sc = (struct mlxd_softc *)device_get_softc(dev);
238    device_t		parent;
239    char		*state;
240    dev_t		dsk;
241
242    debug_called(1);
243
244    parent = device_get_parent(dev);
245    sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
246    sc->mlxd_unit = device_get_unit(dev);
247    sc->mlxd_drive = device_get_ivars(dev);
248    sc->mlxd_dev = dev;
249
250    switch(sc->mlxd_drive->ms_state) {
251    case MLX_SYSD_ONLINE:
252	state = "online";
253	break;
254    case MLX_SYSD_CRITICAL:
255	state = "critical";
256	break;
257    case MLX_SYSD_OFFLINE:
258	state = "offline";
259	break;
260    default:
261	state = "unknown state";
262    }
263
264    device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n",
265		  sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE),
266		  sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state);
267
268    devstat_add_entry(&sc->mlxd_stats, "mlxd", sc->mlxd_unit, MLX_BLKSIZE,
269		      DEVSTAT_NO_ORDERED_TAGS,
270		      DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
271		      DEVSTAT_PRIORITY_ARRAY);
272
273    dsk = disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, &mlxd_cdevsw, &mlxddisk_cdevsw);
274    dsk->si_drv1 = sc;
275    disks_registered++;
276
277    /* set maximum I/O size */
278    dsk->si_iosize_max = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE;
279
280    return (0);
281}
282
283static int
284mlxd_detach(device_t dev)
285{
286    struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
287
288    debug_called(1);
289
290    devstat_remove_entry(&sc->mlxd_stats);
291
292    /* hack to handle lack of destroy_disk() */
293    if (--disks_registered == 0)
294	cdevsw_remove(&mlxddisk_cdevsw);
295
296    return(0);
297}
298
299