1 | /* $NetBSD: ld_mlx.c,v 1.23 2016/09/27 03:33:32 pgoyette Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Andrew Doran. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Mylex DAC960 front-end for ld(4) driver. |
34 | */ |
35 | |
36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: ld_mlx.c,v 1.23 2016/09/27 03:33:32 pgoyette Exp $" ); |
38 | |
39 | #include <sys/param.h> |
40 | #include <sys/systm.h> |
41 | #include <sys/kernel.h> |
42 | #include <sys/device.h> |
43 | #include <sys/buf.h> |
44 | #include <sys/bufq.h> |
45 | #include <sys/endian.h> |
46 | #include <sys/dkio.h> |
47 | #include <sys/disk.h> |
48 | #include <sys/module.h> |
49 | #include <machine/vmparam.h> |
50 | #include <sys/bus.h> |
51 | |
52 | #include <dev/ldvar.h> |
53 | |
54 | #include <dev/ic/mlxreg.h> |
55 | #include <dev/ic/mlxio.h> |
56 | #include <dev/ic/mlxvar.h> |
57 | |
58 | #include "ioconf.h" |
59 | |
60 | struct ld_mlx_softc { |
61 | struct ld_softc sc_ld; |
62 | int sc_hwunit; |
63 | }; |
64 | |
65 | static void ld_mlx_attach(device_t, device_t, void *); |
66 | static int ld_mlx_detach(device_t, int); |
67 | static int ld_mlx_dobio(struct ld_mlx_softc *, void *, int, int, int, |
68 | struct buf *); |
69 | static int ld_mlx_dump(struct ld_softc *, void *, int, int); |
70 | static void ld_mlx_handler(struct mlx_ccb *); |
71 | static int ld_mlx_match(device_t, cfdata_t, void *); |
72 | static int ld_mlx_start(struct ld_softc *, struct buf *); |
73 | |
74 | CFATTACH_DECL_NEW(ld_mlx, sizeof(struct ld_mlx_softc), |
75 | ld_mlx_match, ld_mlx_attach, ld_mlx_detach, NULL); |
76 | |
77 | static int |
78 | ld_mlx_match(device_t parent, cfdata_t match, void *aux) |
79 | { |
80 | |
81 | return (1); |
82 | } |
83 | |
84 | static void |
85 | ld_mlx_attach(device_t parent, device_t self, void *aux) |
86 | { |
87 | struct mlx_attach_args *mlxa = aux; |
88 | struct ld_mlx_softc *sc = device_private(self); |
89 | struct ld_softc *ld = &sc->sc_ld; |
90 | struct mlx_softc *mlx = device_private(parent); |
91 | struct mlx_sysdrive *ms = &mlx->mlx_sysdrive[mlxa->mlxa_unit]; |
92 | const char *statestr; |
93 | |
94 | ld->sc_dv = self; |
95 | |
96 | sc->sc_hwunit = mlxa->mlxa_unit; |
97 | ld->sc_maxxfer = MLX_MAX_XFER; |
98 | ld->sc_secsize = MLX_SECTOR_SIZE; |
99 | ld->sc_maxqueuecnt = 1; |
100 | ld->sc_start = ld_mlx_start; |
101 | ld->sc_dump = ld_mlx_dump; |
102 | ld->sc_secperunit = ms->ms_size; |
103 | |
104 | /* |
105 | * Report on current status, and attach to the ld driver proper. |
106 | */ |
107 | switch (ms->ms_state) { |
108 | case MLX_SYSD_ONLINE: |
109 | statestr = "online" ; |
110 | ld->sc_flags = LDF_ENABLED; |
111 | break; |
112 | |
113 | case MLX_SYSD_CRITICAL: |
114 | statestr = "critical" ; |
115 | ld->sc_flags = LDF_ENABLED; |
116 | break; |
117 | |
118 | case MLX_SYSD_OFFLINE: |
119 | statestr = "offline" ; |
120 | break; |
121 | |
122 | default: |
123 | statestr = "state unknown" ; |
124 | break; |
125 | } |
126 | |
127 | if (ms->ms_raidlevel == MLX_SYS_DRV_JBOD) |
128 | aprint_normal(": JBOD, %s\n" , statestr); |
129 | else |
130 | aprint_normal(": RAID%d, %s\n" , ms->ms_raidlevel, statestr); |
131 | |
132 | ldattach(ld, BUFQ_DISK_DEFAULT_STRAT); |
133 | } |
134 | |
135 | static int |
136 | ld_mlx_detach(device_t dv, int flags) |
137 | { |
138 | struct ld_mlx_softc *sc = device_private(dv); |
139 | struct ld_softc *ld = &sc->sc_ld; |
140 | struct mlx_softc *mlx = device_private(device_parent(dv)); |
141 | int rv; |
142 | |
143 | if ((rv = ldbegindetach(ld, flags)) != 0) |
144 | return (rv); |
145 | ldenddetach(ld); |
146 | mlx_flush(mlx, 1); |
147 | |
148 | return (0); |
149 | } |
150 | |
151 | static int |
152 | ld_mlx_dobio(struct ld_mlx_softc *sc, void *data, int datasize, int blkno, |
153 | int dowrite, struct buf *bp) |
154 | { |
155 | struct mlx_ccb *mc; |
156 | struct mlx_softc *mlx; |
157 | int s, rv; |
158 | bus_addr_t sgphys; |
159 | |
160 | mlx = device_private(device_parent(sc->sc_ld.sc_dv)); |
161 | |
162 | if ((rv = mlx_ccb_alloc(mlx, &mc, bp == NULL)) != 0) |
163 | return (rv); |
164 | |
165 | /* Map the data transfer. */ |
166 | rv = mlx_ccb_map(mlx, mc, data, datasize, |
167 | dowrite ? MC_XFER_OUT : MC_XFER_IN); |
168 | if (rv != 0) { |
169 | mlx_ccb_free(mlx, mc); |
170 | return (rv); |
171 | } |
172 | |
173 | /* Build the command. */ |
174 | sgphys = mlx->mlx_sgls_paddr + (MLX_SGL_SIZE * mc->mc_ident); |
175 | datasize /= MLX_SECTOR_SIZE; |
176 | |
177 | if (mlx->mlx_ci.ci_iftype <= 2) |
178 | mlx_make_type1(mc, |
179 | dowrite ? MLX_CMD_WRITESG_OLD : MLX_CMD_READSG_OLD, |
180 | datasize & 0xff, blkno, sc->sc_hwunit, sgphys, |
181 | mc->mc_nsgent); |
182 | else |
183 | mlx_make_type5(mc, |
184 | dowrite ? MLX_CMD_WRITESG : MLX_CMD_READSG, |
185 | datasize & 0xff, |
186 | (sc->sc_hwunit << 3) | ((datasize >> 8) & 0x07), |
187 | blkno, sgphys, mc->mc_nsgent); |
188 | |
189 | if (bp == NULL) { |
190 | s = splbio(); |
191 | rv = mlx_ccb_poll(mlx, mc, 10000); |
192 | mlx_ccb_unmap(mlx, mc); |
193 | mlx_ccb_free(mlx, mc); |
194 | splx(s); |
195 | } else { |
196 | mc->mc_mx.mx_handler = ld_mlx_handler; |
197 | mc->mc_mx.mx_context = bp; |
198 | mc->mc_mx.mx_dv = sc->sc_ld.sc_dv; |
199 | mlx_ccb_enqueue(mlx, mc); |
200 | rv = 0; |
201 | } |
202 | |
203 | return (rv); |
204 | } |
205 | |
206 | static int |
207 | ld_mlx_start(struct ld_softc *ld, struct buf *bp) |
208 | { |
209 | |
210 | return (ld_mlx_dobio((struct ld_mlx_softc *)ld, bp->b_data, |
211 | bp->b_bcount, bp->b_rawblkno, (bp->b_flags & B_READ) == 0, bp)); |
212 | } |
213 | |
214 | static void |
215 | ld_mlx_handler(struct mlx_ccb *mc) |
216 | { |
217 | struct buf *bp; |
218 | struct mlx_context *mx; |
219 | struct ld_mlx_softc *sc; |
220 | struct mlx_softc *mlx; |
221 | |
222 | mx = &mc->mc_mx; |
223 | bp = mx->mx_context; |
224 | sc = device_private(mx->mx_dv); |
225 | mlx = device_private(device_parent(sc->sc_ld.sc_dv)); |
226 | |
227 | if (mc->mc_status != MLX_STATUS_OK) { |
228 | bp->b_error = EIO; |
229 | bp->b_resid = bp->b_bcount; |
230 | |
231 | if (mc->mc_status == MLX_STATUS_RDWROFFLINE) |
232 | printf("%s: drive offline\n" , |
233 | device_xname(sc->sc_ld.sc_dv)); |
234 | else |
235 | printf("%s: I/O error - %s\n" , |
236 | device_xname(sc->sc_ld.sc_dv), |
237 | mlx_ccb_diagnose(mc)); |
238 | } else |
239 | bp->b_resid = 0; |
240 | |
241 | mlx_ccb_unmap(mlx, mc); |
242 | mlx_ccb_free(mlx, mc); |
243 | lddone(&sc->sc_ld, bp); |
244 | } |
245 | |
246 | static int |
247 | ld_mlx_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt) |
248 | { |
249 | |
250 | return (ld_mlx_dobio((struct ld_mlx_softc *)ld, data, |
251 | blkcnt * ld->sc_secsize, blkno, 1, NULL)); |
252 | } |
253 | |
254 | MODULE(MODULE_CLASS_DRIVER, ld_mlx, "ld" ); |
255 | |
256 | #ifdef _MODULE |
257 | /* |
258 | * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd" |
259 | * XXX it will be defined in the common-code module |
260 | */ |
261 | #undef CFDRIVER_DECL |
262 | #define CFDRIVER_DECL(name, class, attr) |
263 | #include "ioconf.c" |
264 | #endif |
265 | |
266 | static int |
267 | ld_mlx_modcmd(modcmd_t cmd, void *opaque) |
268 | { |
269 | #ifdef _MODULE |
270 | /* |
271 | * We ignore the cfdriver_vec[] that ioconf provides, since |
272 | * the cfdrivers are attached already. |
273 | */ |
274 | static struct cfdriver * const no_cfdriver_vec[] = { NULL }; |
275 | #endif |
276 | int error = 0; |
277 | |
278 | #ifdef _MODULE |
279 | switch (cmd) { |
280 | case MODULE_CMD_INIT: |
281 | error = config_init_component(no_cfdriver_vec, |
282 | cfattach_ioconf_ld_mlx, cfdata_ioconf_ld_mlx); |
283 | break; |
284 | case MODULE_CMD_FINI: |
285 | error = config_fini_component(no_cfdriver_vec, |
286 | cfattach_ioconf_ld_mlx, cfdata_ioconf_ld_mlx); |
287 | break; |
288 | default: |
289 | error = ENOTTY; |
290 | break; |
291 | } |
292 | #endif |
293 | |
294 | return error; |
295 | } |
296 | |