kernel: Add D_MPSAFE to the ops of mfi(4), mrsas(4) and twa(4).
[dragonfly.git] / sys / dev / raid / mlx / mlx_disk.c
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: src/sys/dev/mlx/mlx_disk.c,v 1.8.2.4 2001/06/25 04:37:51 msmith Exp $
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/kernel.h>
37 #include <sys/bus.h>
38 #include <sys/conf.h>
39 #include <sys/devicestat.h>
40 #include <sys/disk.h>
41 #include <sys/dtype.h>
42 #include <sys/rman.h>
43
44 #include "mlx_compat.h"
45 #include "mlxio.h"
46 #include "mlxvar.h"
47 #include "mlxreg.h"
48
49 /* prototypes */
50 static int mlxd_probe(device_t dev);
51 static int mlxd_attach(device_t dev);
52 static int mlxd_detach(device_t dev);
53
54 static  d_open_t        mlxd_open;
55 static  d_close_t       mlxd_close;
56 static  d_strategy_t    mlxd_strategy;
57 static  d_ioctl_t       mlxd_ioctl;
58
59 static struct dev_ops mlxd_ops = {
60                 { "mlxd", 0, D_DISK },
61                 .d_open =       mlxd_open,
62                 .d_close =      mlxd_close,
63                 .d_read =       physread,
64                 .d_write =      physwrite,
65                 .d_ioctl =      mlxd_ioctl,
66                 .d_strategy =   mlxd_strategy,
67 };
68
69 devclass_t              mlxd_devclass;
70
71 static device_method_t mlxd_methods[] = {
72     DEVMETHOD(device_probe,     mlxd_probe),
73     DEVMETHOD(device_attach,    mlxd_attach),
74     DEVMETHOD(device_detach,    mlxd_detach),
75     DEVMETHOD_END
76 };
77
78 static driver_t mlxd_driver = {
79     "mlxd",
80     mlxd_methods,
81     sizeof(struct mlxd_softc)
82 };
83
84 DRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, NULL, NULL);
85
86 static int
87 mlxd_open(struct dev_open_args *ap)
88 {
89     cdev_t dev = ap->a_head.a_dev;
90     struct mlxd_softc   *sc = (struct mlxd_softc *)dev->si_drv1;
91
92     debug_called(1);
93         
94     if (sc == NULL)
95         return (ENXIO);
96
97     /* controller not active? */
98     if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN)
99         return(ENXIO);
100 #if 0
101     bzero(&info, sizeof(info));
102     info.d_media_blksize= MLX_BLKSIZE;          /* mandatory */
103     info.d_media_blocks = sc->mlxd_drive->ms_size;
104
105     info.d_type         = DTYPE_SCSI;           /* optional */
106     info.d_secpertrack  = sc->mlxd_drive->ms_sectors;
107     info.d_nheads       = sc->mlxd_drive->ms_heads;
108     info.d_ncylinders   = sc->mlxd_drive->ms_cylinders;
109     info.d_secpercyl    = sc->mlxd_drive->ms_sectors * sc->mlxd_drive->ms_heads;
110
111     disk_setdiskinfo(&sc->mlxd_disk, &info);
112 #endif
113     sc->mlxd_flags |= MLXD_OPEN;
114     return (0);
115 }
116
117 static int
118 mlxd_close(struct dev_close_args *ap)
119 {
120     cdev_t dev = ap->a_head.a_dev;
121     struct mlxd_softc   *sc = (struct mlxd_softc *)dev->si_drv1;
122
123     debug_called(1);
124         
125     if (sc == NULL)
126         return (ENXIO);
127     sc->mlxd_flags &= ~MLXD_OPEN;
128     return (0);
129 }
130
131 static int
132 mlxd_ioctl(struct dev_ioctl_args *ap)
133 {
134     cdev_t dev = ap->a_head.a_dev;
135     struct mlxd_softc   *sc = (struct mlxd_softc *)dev->si_drv1;
136     int error;
137
138     debug_called(1);
139         
140     if (sc == NULL)
141         return (ENXIO);
142
143     if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, ap->a_cmd, ap->a_data, ap->a_fflag)) != ENOIOCTL) {
144         debug(0, "mlx_submit_ioctl returned %d\n", error);
145         return(error);
146     }
147     return (ENOTTY);
148 }
149
150 /*
151  * Read/write routine for a buffer.  Finds the proper unit, range checks
152  * arguments, and schedules the transfer.  Does not wait for the transfer
153  * to complete.  Multi-page transfers are supported.  All I/O requests must
154  * be a multiple of a sector in length.
155  */
156 static int
157 mlxd_strategy(struct dev_strategy_args *ap)
158 {
159     struct bio *bio = ap->a_bio;
160     struct buf *bp = bio->bio_buf;
161     struct mlxd_softc   *sc = (struct mlxd_softc *)bio->bio_driver_info;
162
163     debug_called(1);
164
165     /* bogus disk? */
166     if (sc == NULL) {
167         bp->b_error = EINVAL;
168         bp->b_flags |= B_ERROR;
169         goto bad;
170     }
171
172     /* XXX may only be temporarily offline - sleep? */
173     if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) {
174         bp->b_error = ENXIO;
175         bp->b_flags |= B_ERROR;
176         goto bad;
177     }
178
179     devstat_start_transaction(&sc->mlxd_stats);
180     mlx_submit_bio(sc->mlxd_controller, bio);
181     return(0);
182
183  bad:
184     /*
185      * Correctly set the bio to indicate a failed tranfer.
186      */
187     bp->b_resid = bp->b_bcount;
188     biodone(bio);
189     return(0);
190 }
191
192 void
193 mlxd_intr(struct bio *bio)
194 {
195     struct buf *bp = bio->bio_buf;
196     struct mlxd_softc   *sc = (struct mlxd_softc *)bio->bio_driver_info;
197
198     debug_called(1);
199
200     if (bp->b_flags & B_ERROR)
201         bp->b_error = EIO;
202     else
203         bp->b_resid = 0;
204     devstat_end_transaction_buf(&sc->mlxd_stats, bp);
205     biodone(bio);
206 }
207
208 static int
209 mlxd_probe(device_t dev)
210 {
211
212     debug_called(1);
213         
214     device_set_desc(dev, "Mylex System Drive");
215     return (0);
216 }
217
218 static int
219 mlxd_attach(device_t dev)
220 {
221     struct mlxd_softc   *sc = (struct mlxd_softc *)device_get_softc(dev);
222         struct disk_info info;
223     device_t            parent;
224     char                *state;
225     cdev_t              dsk;
226     int                 s1, s2;
227     
228     debug_called(1);
229
230     parent = device_get_parent(dev);
231     sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
232     sc->mlxd_unit = device_get_unit(dev);
233     sc->mlxd_drive = device_get_ivars(dev);
234     sc->mlxd_dev = dev;
235
236     switch(sc->mlxd_drive->ms_state) {
237     case MLX_SYSD_ONLINE:
238         state = "online";
239         break;
240     case MLX_SYSD_CRITICAL:
241         state = "critical";
242         break;
243     case MLX_SYSD_OFFLINE:
244         state = "offline";
245         break;
246     default:
247         state = "unknown state";
248     }
249
250     device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n",
251                   sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE),
252                   sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state);
253
254     devstat_add_entry(&sc->mlxd_stats, "mlxd", sc->mlxd_unit, MLX_BLKSIZE,
255                       DEVSTAT_NO_ORDERED_TAGS,
256                       DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 
257                       DEVSTAT_PRIORITY_ARRAY);
258
259     dsk = disk_create(sc->mlxd_unit, &sc->mlxd_disk, &mlxd_ops);
260     dsk->si_drv1 = sc;
261     sc->mlxd_dev_t = dsk;
262
263     /* 
264      * Set maximum I/O size to the lesser of the recommended maximum and the practical
265      * maximum.
266      */
267     s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE;
268     s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * PAGE_SIZE;
269     dsk->si_iosize_max = imin(s1, s2);
270
271         /*
272          * Set disk info, as it appears that all needed data is available already.
273          * Setting the disk info will also cause the probing to start.
274          */
275         bzero(&info, sizeof(info));
276     info.d_media_blksize= MLX_BLKSIZE;          /* mandatory */
277     info.d_media_blocks = sc->mlxd_drive->ms_size;
278
279     info.d_type         = DTYPE_SCSI;           /* optional */
280     info.d_secpertrack  = sc->mlxd_drive->ms_sectors;
281     info.d_nheads       = sc->mlxd_drive->ms_heads;
282     info.d_ncylinders   = sc->mlxd_drive->ms_cylinders;
283     info.d_secpercyl    = sc->mlxd_drive->ms_sectors * sc->mlxd_drive->ms_heads;
284
285     disk_setdiskinfo(&sc->mlxd_disk, &info);
286
287     return (0);
288 }
289
290 static int
291 mlxd_detach(device_t dev)
292 {
293     struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
294
295     debug_called(1);
296
297     devstat_remove_entry(&sc->mlxd_stats);
298     disk_destroy(&sc->mlxd_disk);
299
300     return(0);
301 }
302