Commit | Line | Data |
---|---|---|
984263bc MD |
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> | |
984263bc MD |
37 | #include <sys/bus.h> |
38 | #include <sys/conf.h> | |
39 | #include <sys/devicestat.h> | |
40 | #include <sys/disk.h> | |
ba0cc1ab | 41 | #include <sys/dtype.h> |
984263bc MD |
42 | #include <sys/rman.h> |
43 | ||
1f2de5d4 MD |
44 | #include "mlx_compat.h" |
45 | #include "mlxio.h" | |
46 | #include "mlxvar.h" | |
47 | #include "mlxreg.h" | |
984263bc MD |
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 | ||
fef8985e | 59 | static struct dev_ops mlxd_ops = { |
88abd8b5 | 60 | { "mlxd", 0, D_DISK }, |
fef8985e MD |
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, | |
984263bc MD |
67 | }; |
68 | ||
69 | devclass_t mlxd_devclass; | |
984263bc MD |
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), | |
d3c9c58e | 75 | DEVMETHOD_END |
984263bc MD |
76 | }; |
77 | ||
78 | static driver_t mlxd_driver = { | |
79 | "mlxd", | |
80 | mlxd_methods, | |
81 | sizeof(struct mlxd_softc) | |
82 | }; | |
83 | ||
aa2b9d05 | 84 | DRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, NULL, NULL); |
984263bc MD |
85 | |
86 | static int | |
fef8985e | 87 | mlxd_open(struct dev_open_args *ap) |
984263bc | 88 | { |
b13267a5 | 89 | cdev_t dev = ap->a_head.a_dev; |
984263bc | 90 | struct mlxd_softc *sc = (struct mlxd_softc *)dev->si_drv1; |
984263bc MD |
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); | |
cd29885a | 100 | #if 0 |
a688b15c MD |
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); | |
cd29885a | 112 | #endif |
984263bc MD |
113 | sc->mlxd_flags |= MLXD_OPEN; |
114 | return (0); | |
115 | } | |
116 | ||
117 | static int | |
fef8985e | 118 | mlxd_close(struct dev_close_args *ap) |
984263bc | 119 | { |
b13267a5 | 120 | cdev_t dev = ap->a_head.a_dev; |
984263bc MD |
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 | |
fef8985e | 132 | mlxd_ioctl(struct dev_ioctl_args *ap) |
984263bc | 133 | { |
b13267a5 | 134 | cdev_t dev = ap->a_head.a_dev; |
984263bc MD |
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 | ||
fef8985e | 143 | if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, ap->a_cmd, ap->a_data, ap->a_fflag)) != ENOIOCTL) { |
984263bc MD |
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 | */ | |
fef8985e MD |
156 | static int |
157 | mlxd_strategy(struct dev_strategy_args *ap) | |
984263bc | 158 | { |
fef8985e | 159 | struct bio *bio = ap->a_bio; |
81b5c339 MD |
160 | struct buf *bp = bio->bio_buf; |
161 | struct mlxd_softc *sc = (struct mlxd_softc *)bio->bio_driver_info; | |
984263bc MD |
162 | |
163 | debug_called(1); | |
164 | ||
165 | /* bogus disk? */ | |
166 | if (sc == NULL) { | |
81b5c339 MD |
167 | bp->b_error = EINVAL; |
168 | bp->b_flags |= B_ERROR; | |
984263bc MD |
169 | goto bad; |
170 | } | |
171 | ||
172 | /* XXX may only be temporarily offline - sleep? */ | |
173 | if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) { | |
81b5c339 MD |
174 | bp->b_error = ENXIO; |
175 | bp->b_flags |= B_ERROR; | |
984263bc MD |
176 | goto bad; |
177 | } | |
178 | ||
81b5c339 MD |
179 | devstat_start_transaction(&sc->mlxd_stats); |
180 | mlx_submit_bio(sc->mlxd_controller, bio); | |
fef8985e | 181 | return(0); |
984263bc MD |
182 | |
183 | bad: | |
184 | /* | |
185 | * Correctly set the bio to indicate a failed tranfer. | |
186 | */ | |
81b5c339 MD |
187 | bp->b_resid = bp->b_bcount; |
188 | biodone(bio); | |
fef8985e | 189 | return(0); |
984263bc MD |
190 | } |
191 | ||
192 | void | |
81b5c339 | 193 | mlxd_intr(struct bio *bio) |
984263bc | 194 | { |
81b5c339 MD |
195 | struct buf *bp = bio->bio_buf; |
196 | struct mlxd_softc *sc = (struct mlxd_softc *)bio->bio_driver_info; | |
984263bc MD |
197 | |
198 | debug_called(1); | |
984263bc | 199 | |
81b5c339 MD |
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); | |
984263bc MD |
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); | |
cd29885a | 222 | struct disk_info info; |
984263bc MD |
223 | device_t parent; |
224 | char *state; | |
b13267a5 | 225 | cdev_t dsk; |
984263bc MD |
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 | ||
a688b15c | 259 | dsk = disk_create(sc->mlxd_unit, &sc->mlxd_disk, &mlxd_ops); |
984263bc MD |
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 | ||
cd29885a MD |
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 | ||
984263bc MD |
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); | |
335dda38 | 298 | disk_destroy(&sc->mlxd_disk); |
984263bc MD |
299 | |
300 | return(0); | |
301 | } | |
302 |