xref: /dragonfly/sys/dev/raid/mlx/mlx_disk.c (revision d3c9c58e)
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
mlxd_open(struct dev_open_args * ap)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
mlxd_close(struct dev_close_args * ap)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
mlxd_ioctl(struct dev_ioctl_args * ap)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
mlxd_strategy(struct dev_strategy_args * ap)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
mlxd_intr(struct bio * bio)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
mlxd_probe(device_t dev)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
mlxd_attach(device_t dev)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
mlxd_detach(device_t dev)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 
303