mlx_disk.c revision 59249
175584Sru/*-
275584Sru * Copyright (c) 1999 Jonathan Lemon
375584Sru * Copyright (c) 1999 Michael Smith
475584Sru * All rights reserved.
575584Sru *
618099Spst * Redistribution and use in source and binary forms, with or without
718099Spst * modification, are permitted provided that the following conditions
818099Spst * are met:
918099Spst * 1. Redistributions of source code must retain the above copyright
1018099Spst *    notice, this list of conditions and the following disclaimer.
1118099Spst * 2. Redistributions in binary form must reproduce the above copyright
1218099Spst *    notice, this list of conditions and the following disclaimer in the
1318099Spst *    documentation and/or other materials provided with the distribution.
1418099Spst *
1518099Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1618099Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1718099Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1869626Sru * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1969626Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2069626Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2169626Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2269626Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2318099Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2418099Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2518099Spst * SUCH DAMAGE.
2618099Spst *
2718099Spst * $FreeBSD: head/sys/dev/mlx/mlx_disk.c 59249 2000-04-15 05:54:02Z phk $
2818099Spst */
2918099Spst
3018099Spst/*
3118099Spst * Disk driver for Mylex DAC960 RAID adapters.
3218099Spst */
3375584Sru
3475584Sru#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
83devclass_t		mlxd_devclass;
84static struct cdevsw	mlxddisk_cdevsw;
85
86static device_method_t mlxd_methods[] = {
87    DEVMETHOD(device_probe,	mlxd_probe),
88    DEVMETHOD(device_attach,	mlxd_attach),
89    DEVMETHOD(device_detach,	mlxd_detach),
90    { 0, 0 }
91};
92
93static driver_t mlxd_driver = {
94    "mlxd",
95    mlxd_methods,
96    sizeof(struct mlxd_softc)
97};
98
99DRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0);
100
101static int
102mlxd_open(dev_t dev, int flags, int fmt, struct proc *p)
103{
104    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
105    struct disklabel	*label;
106
107    debug_called(1);
108
109    if (sc == NULL)
110	return (ENXIO);
111
112    /* controller not active? */
113    if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN)
114	return(ENXIO);
115
116    label = &sc->mlxd_disk.d_label;
117    bzero(label, sizeof(*label));
118    label->d_type = DTYPE_SCSI;
119    label->d_secsize    = MLX_BLKSIZE;
120    label->d_nsectors   = sc->mlxd_drive->ms_sectors;
121    label->d_ntracks    = sc->mlxd_drive->ms_heads;
122    label->d_ncylinders = sc->mlxd_drive->ms_cylinders;
123    label->d_secpercyl  = sc->mlxd_drive->ms_sectors * sc->mlxd_drive->ms_heads;
124    label->d_secperunit = sc->mlxd_drive->ms_size;
125
126    sc->mlxd_flags |= MLXD_OPEN;
127    return (0);
128}
129
130static int
131mlxd_close(dev_t dev, int flags, int fmt, struct proc *p)
132{
133    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
134
135    debug_called(1);
136
137    if (sc == NULL)
138	return (ENXIO);
139    sc->mlxd_flags &= ~MLXD_OPEN;
140    return (0);
141}
142
143static int
144mlxd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
145{
146    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
147    int error;
148
149    debug_called(1);
150
151    if (sc == NULL)
152	return (ENXIO);
153
154    if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, p)) != ENOIOCTL) {
155	debug(0, "mlx_submit_ioctl returned %d\n", error);
156	return(error);
157    }
158    return (ENOTTY);
159}
160
161/*
162 * Read/write routine for a buffer.  Finds the proper unit, range checks
163 * arguments, and schedules the transfer.  Does not wait for the transfer
164 * to complete.  Multi-page transfers are supported.  All I/O requests must
165 * be a multiple of a sector in length.
166 */
167static void
168mlxd_strategy(struct bio *bp)
169{
170    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->bio_dev->si_drv1;
171
172    debug_called(1);
173
174    /* bogus disk? */
175    if (sc == NULL) {
176	bp->bio_error = EINVAL;
177	goto bad;
178    }
179
180    /* XXX may only be temporarily offline - sleep? */
181    if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) {
182	bp->bio_error = ENXIO;
183	goto bad;
184    }
185
186    /* do-nothing operation */
187    if (bp->bio_bcount == 0)
188	goto done;
189
190    devstat_start_transaction(&sc->mlxd_stats);
191    mlx_submit_buf(sc->mlxd_controller, bp);
192    return;
193
194 bad:
195    bp->bio_flags |= BIO_ERROR;
196
197 done:
198    /*
199     * Correctly set the buf to indicate a completed transfer
200     */
201    bp->bio_resid = bp->bio_bcount;
202    biodone(bp);
203    return;
204}
205
206void
207mlxd_intr(void *data)
208{
209    struct bio *bp = (struct bio *)data;
210    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->bio_dev->si_drv1;
211
212    debug_called(1);
213
214    if (bp->bio_flags & BIO_ERROR)
215	bp->bio_error = EIO;
216    else
217	bp->bio_resid = 0;
218
219    devstat_end_transaction_bio(&sc->mlxd_stats, bp);
220    biodone(bp);
221}
222
223static int
224mlxd_probe(device_t dev)
225{
226
227    debug_called(1);
228
229    device_set_desc(dev, "Mylex System Drive");
230    return (0);
231}
232
233static int
234mlxd_attach(device_t dev)
235{
236    struct mlxd_softc	*sc = (struct mlxd_softc *)device_get_softc(dev);
237    device_t		parent;
238    char		*state;
239    dev_t		dsk;
240
241    debug_called(1);
242
243    parent = device_get_parent(dev);
244    sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
245    sc->mlxd_unit = device_get_unit(dev);
246    sc->mlxd_drive = device_get_ivars(dev);
247    sc->mlxd_dev = dev;
248
249    switch(sc->mlxd_drive->ms_state) {
250    case MLX_SYSD_ONLINE:
251	state = "online";
252	break;
253    case MLX_SYSD_CRITICAL:
254	state = "critical";
255	break;
256    case MLX_SYSD_OFFLINE:
257	state = "offline";
258	break;
259    default:
260	state = "unknown state";
261    }
262
263    device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n",
264		  sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE),
265		  sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state);
266
267    devstat_add_entry(&sc->mlxd_stats, "mlxd", sc->mlxd_unit, MLX_BLKSIZE,
268		      DEVSTAT_NO_ORDERED_TAGS,
269		      DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
270		      DEVSTAT_PRIORITY_ARRAY);
271
272    dsk = disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, &mlxd_cdevsw, &mlxddisk_cdevsw);
273    dsk->si_drv1 = sc;
274    sc->mlxd_dev_t = dsk;
275
276    /* set maximum I/O size */
277    dsk->si_iosize_max = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE;
278
279    return (0);
280}
281
282static int
283mlxd_detach(device_t dev)
284{
285    struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
286
287    debug_called(1);
288
289    devstat_remove_entry(&sc->mlxd_stats);
290    disk_destroy(sc->mlxd_dev_t);
291
292    return(0);
293}
294
295