]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/amr/amr_disk.c
Move SYSCTL_ADD_PROC() to unlocked context in if_ure to avoid lock order reversal.
[FreeBSD/FreeBSD.git] / sys / dev / amr / amr_disk.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1999 Jonathan Lemon
5  * Copyright (c) 1999, 2000 Michael Smith
6  * Copyright (c) 2000 BSDi
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 /*-
31  * Copyright (c) 2002 Eric Moore
32  * Copyright (c) 2002 LSI Logic Corporation
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  * 3. The party using or redistributing the source code and binary forms
44  *    agrees to the disclaimer below and the terms and conditions set forth
45  *    herein.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
51  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57  * SUCH DAMAGE.
58  */
59
60 #include <sys/cdefs.h>
61 __FBSDID("$FreeBSD$");
62
63 /*
64  * Disk driver for AMI MegaRaid controllers
65  */
66
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
70 #include <sys/module.h>
71
72 #include <sys/bio.h>
73 #include <sys/bus.h>
74 #include <sys/conf.h>
75
76 #include <machine/bus.h>
77 #include <sys/rman.h>
78
79 #include <dev/amr/amrio.h>
80 #include <dev/amr/amrreg.h>
81 #include <dev/amr/amrvar.h>
82 #include <dev/amr/amr_tables.h>
83
84 /* prototypes */
85 static int amrd_probe(device_t dev);
86 static int amrd_attach(device_t dev);
87 static int amrd_detach(device_t dev);
88
89 static  disk_open_t     amrd_open;
90 static  disk_strategy_t amrd_strategy;
91
92 static devclass_t       amrd_devclass;
93 #ifdef FREEBSD_4
94 int                     amr_disks_registered = 0;
95 #endif
96
97 static device_method_t amrd_methods[] = {
98     DEVMETHOD(device_probe,     amrd_probe),
99     DEVMETHOD(device_attach,    amrd_attach),
100     DEVMETHOD(device_detach,    amrd_detach),
101     { 0, 0 }
102 };
103
104 static driver_t amrd_driver = {
105     "amrd",
106     amrd_methods,
107     sizeof(struct amrd_softc)
108 };
109
110 DRIVER_MODULE(amrd, amr, amrd_driver, amrd_devclass, 0, 0);
111
112 static int
113 amrd_open(struct disk *dp)
114 {
115     struct amrd_softc   *sc = (struct amrd_softc *)dp->d_drv1;
116
117     debug_called(1);
118
119     if (sc == NULL)
120         return (ENXIO);
121
122     /* controller not active? */
123     if (sc->amrd_controller->amr_state & AMR_STATE_SHUTDOWN)
124         return(ENXIO);
125
126     return (0);
127 }
128 /********************************************************************************
129  * System crashdump support
130  */
131
132 static int
133 amrd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length)
134 {
135
136     struct amrd_softc   *amrd_sc;
137     struct amr_softc    *amr_sc;
138     int                 error;
139     struct disk         *dp;
140
141     dp = arg;
142     amrd_sc = (struct amrd_softc *)dp->d_drv1;
143     if (amrd_sc == NULL)
144         return(ENXIO);
145     amr_sc  = (struct amr_softc *)amrd_sc->amrd_controller;
146
147     if (length > 0) {
148         int     driveno = amrd_sc->amrd_drive - amr_sc->amr_drive;
149         if ((error = amr_dump_blocks(amr_sc,driveno,offset / AMR_BLKSIZE ,(void *)virtual,(int) length / AMR_BLKSIZE  )) != 0)
150                 return(error);
151     }
152     return(0);
153 }
154
155 /*
156  * Read/write routine for a buffer.  Finds the proper unit, range checks
157  * arguments, and schedules the transfer.  Does not wait for the transfer
158  * to complete.  Multi-page transfers are supported.  All I/O requests must
159  * be a multiple of a sector in length.
160  */
161 static void
162 amrd_strategy(struct bio *bio)
163 {
164     struct amrd_softc   *sc = (struct amrd_softc *)bio->bio_disk->d_drv1;
165
166     /* bogus disk? */
167     if (sc == NULL) {
168         bio->bio_error = EINVAL;
169         goto bad;
170     }
171
172     amr_submit_bio(sc->amrd_controller, bio);
173     return;
174
175  bad:
176     bio->bio_flags |= BIO_ERROR;
177
178     /*
179      * Correctly set the buf to indicate a completed transfer
180      */
181     bio->bio_resid = bio->bio_bcount;
182     biodone(bio);
183     return;
184 }
185
186 void
187 amrd_intr(void *data)
188 {
189     struct bio *bio = (struct bio *)data;
190
191     debug_called(2);
192
193     if (bio->bio_flags & BIO_ERROR) {
194         bio->bio_error = EIO;
195         debug(1, "i/o error\n");
196     } else {
197         bio->bio_resid = 0;
198     }
199
200     biodone(bio);
201 }
202
203 static int
204 amrd_probe(device_t dev)
205 {
206
207     debug_called(1);
208
209     device_set_desc(dev, "LSILogic MegaRAID logical drive");
210     return (0);
211 }
212
213 static int
214 amrd_attach(device_t dev)
215 {
216     struct amrd_softc   *sc = (struct amrd_softc *)device_get_softc(dev);
217     device_t            parent;
218     
219     debug_called(1);
220
221     parent = device_get_parent(dev);
222     sc->amrd_controller = (struct amr_softc *)device_get_softc(parent);
223     sc->amrd_unit = device_get_unit(dev);
224     sc->amrd_drive = device_get_ivars(dev);
225     sc->amrd_dev = dev;
226
227     device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n",
228                   sc->amrd_drive->al_size / ((1024 * 1024) / AMR_BLKSIZE),
229                   sc->amrd_drive->al_size, sc->amrd_drive->al_properties & AMR_DRV_RAID_MASK, 
230                   amr_describe_code(amr_table_drvstate, AMR_DRV_CURSTATE(sc->amrd_drive->al_state)));
231
232     sc->amrd_disk = disk_alloc();
233     sc->amrd_disk->d_drv1 = sc;
234     sc->amrd_disk->d_maxsize = (AMR_NSEG - 1) * PAGE_SIZE;
235     sc->amrd_disk->d_open = amrd_open;
236     sc->amrd_disk->d_strategy = amrd_strategy;
237     sc->amrd_disk->d_name = "amrd";
238     sc->amrd_disk->d_dump = (dumper_t *)amrd_dump;
239     sc->amrd_disk->d_unit = sc->amrd_unit;
240     sc->amrd_disk->d_flags = DISKFLAG_CANFLUSHCACHE;
241     sc->amrd_disk->d_sectorsize = AMR_BLKSIZE;
242     sc->amrd_disk->d_mediasize = (off_t)sc->amrd_drive->al_size * AMR_BLKSIZE;
243     sc->amrd_disk->d_fwsectors = sc->amrd_drive->al_sectors;
244     sc->amrd_disk->d_fwheads = sc->amrd_drive->al_heads;
245     disk_create(sc->amrd_disk, DISK_VERSION);
246
247     return (0);
248 }
249
250 static int
251 amrd_detach(device_t dev)
252 {
253     struct amrd_softc *sc = (struct amrd_softc *)device_get_softc(dev);
254
255     debug_called(1);
256
257     if (sc->amrd_disk->d_flags & DISKFLAG_OPEN)
258         return(EBUSY);
259
260 #ifdef FREEBSD_4
261     if (--amr_disks_registered == 0)
262         cdevsw_remove(&amrddisk_cdevsw);
263 #else
264     disk_destroy(sc->amrd_disk);
265 #endif
266     return(0);
267 }