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: head/sys/dev/mlx/mlx_disk.c 59136 2000-04-11 02:52:46Z msmith $
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/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 buf *bp)
169{
170 struct mlxd_softc *sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
171
172 debug_called(1);
173
174 /* bogus disk? */
175 if (sc == NULL) {
176 bp->b_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->b_error = ENXIO;
183 goto bad;
184 }
185
186 /* do-nothing operation */
187 if (bp->b_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->b_ioflags |= BIO_ERROR;
196
197 done:
198 /*
199 * Correctly set the buf to indicate a completed transfer
200 */
201 bp->b_resid = bp->b_bcount;
202 biodone(bp);
203 return;
204}
205
206void
207mlxd_intr(void *data)
208{
209 struct buf *bp = (struct buf *)data;
210 struct mlxd_softc *sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
211
212 debug_called(1);
213
214 if (bp->b_ioflags & BIO_ERROR)
215 bp->b_error = EIO;
216 else
217 bp->b_resid = 0;
218
219 devstat_end_transaction_buf(&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
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: head/sys/dev/mlx/mlx_disk.c 59136 2000-04-11 02:52:46Z msmith $
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/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 buf *bp)
169{
170 struct mlxd_softc *sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
171
172 debug_called(1);
173
174 /* bogus disk? */
175 if (sc == NULL) {
176 bp->b_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->b_error = ENXIO;
183 goto bad;
184 }
185
186 /* do-nothing operation */
187 if (bp->b_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->b_ioflags |= BIO_ERROR;
196
197 done:
198 /*
199 * Correctly set the buf to indicate a completed transfer
200 */
201 bp->b_resid = bp->b_bcount;
202 biodone(bp);
203 return;
204}
205
206void
207mlxd_intr(void *data)
208{
209 struct buf *bp = (struct buf *)data;
210 struct mlxd_softc *sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
211
212 debug_called(1);
213
214 if (bp->b_ioflags & BIO_ERROR)
215 bp->b_error = EIO;
216 else
217 bp->b_resid = 0;
218
219 devstat_end_transaction_buf(&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