kernel: Use NULL for DRIVER_MODULE()'s evh & arg (which are pointers).
[dragonfly.git] / sys / dev / disk / aha / aha_isa.c
1 /*
2  * Product specific probe and attach routines for:
3  *      Adaptec 154x.
4  *
5  * Derived from code written by:
6  *
7  * Copyright (c) 1998 Justin T. Gibbs
8  * All rights reserved.
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  *    without modification, immediately at the beginning of the file.
16  * 2. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD: src/sys/dev/aha/aha_isa.c,v 1.17.2.1 2000/08/02 22:24:40 peter Exp $
32  */
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/bus.h>
39 #include <sys/rman.h>
40
41 #include <bus/isa/isavar.h>
42
43 #include "ahareg.h"
44
45 #include <bus/cam/scsi/scsi_all.h>
46
47 static struct isa_pnp_id aha_ids[] = {
48         {ADP0100_PNP,           "Adaptec 1540/1542 ISA SCSI"},  /* ADP0100 */
49         {AHA1540_PNP,           "Adaptec 1540/aha-1640/aha-1535"},/* ADP1542 */
50         {AHA1542_PNP,           "Adaptec 1542/aha-1535"},       /* ADP1542 */
51         {AHA1542_PNPCOMPAT,     "Adaptec 1542 compatible"},     /* PNP00A0 */
52         {ICU0091_PNP,           "Adaptec AHA-1540/1542 SCSI"},  /* ICU0091 */
53         {0}
54 };
55
56 /*
57  * Check if the device can be found at the port given
58  * and if so, set it up ready for further work
59  * as an argument, takes the isa_device structure from
60  * autoconf.c
61  */
62 static int
63 aha_isa_probe(device_t dev)
64 {
65         /*
66          * find unit and check we have that many defined
67          */
68         struct  aha_softc **sc = device_get_softc(dev);
69         struct  aha_softc *aha;
70         int     port_index;
71         int     max_port_index;
72         int     error;
73         u_long  port_start, port_count;
74         struct resource *port_res;
75         int     port_rid;
76         int     drq;
77         int     irq;
78
79         aha = NULL;
80
81         /* Check isapnp ids */
82         if (ISA_PNP_PROBE(device_get_parent(dev), dev, aha_ids) == ENXIO)
83                 return (ENXIO);
84
85         error = bus_get_resource(dev, SYS_RES_IOPORT, 0,
86                                  &port_start, &port_count);
87         if (error != 0)
88                 port_start = 0;
89
90         /*
91          * Bound our board search if the user has
92          * specified an exact port.
93          */
94         aha_find_probe_range(port_start, &port_index, &max_port_index);
95
96         if (port_index < 0)
97                 return ENXIO;
98
99         /* Attempt to find an adapter */
100         for (;port_index <= max_port_index; port_index++) {
101                 config_data_t config_data;
102                 u_int ioport;
103                 int error;
104
105                 ioport = aha_iop_from_bio(port_index);
106
107                 error = bus_set_resource(dev, SYS_RES_IOPORT, 0,
108                                          ioport, AHA_NREGS);
109                 if (error)
110                         return error;
111                 
112                 port_rid = 0;
113                 port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid,
114                     0, ~0, AHA_NREGS, RF_ACTIVE);
115                 if (!port_res)
116                         continue;
117
118                 /* Allocate a softc for use during probing */
119                 aha = aha_alloc(dev, rman_get_bustag(port_res),
120                     rman_get_bushandle(port_res));
121
122                 if (aha == NULL) {
123                         bus_release_resource(dev, SYS_RES_IOPORT, port_rid, 
124                             port_res);
125                         break;
126                 }
127
128                 /* See if there is really a card present */
129                 if (aha_probe(aha) || aha_fetch_adapter_info(aha)) {
130                         aha_free(aha);
131                         bus_release_resource(dev, SYS_RES_IOPORT, port_rid,
132                             port_res);
133                         continue;
134                 }
135
136                 /*
137                  * Determine our IRQ, and DMA settings and
138                  * export them to the configuration system.
139                  */
140                 error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
141                     (u_int8_t*)&config_data, sizeof(config_data), 
142                     DEFAULT_CMD_TIMEOUT);
143
144                 if (error != 0) {
145                         kprintf("aha_isa_probe: Could not determine IRQ or DMA "
146                             "settings for adapter at 0x%x.  Failing probe\n",
147                             ioport);
148                         aha_free(aha);
149                         bus_release_resource(dev, SYS_RES_IOPORT, port_rid, 
150                             port_res);
151                         continue;
152                 }
153
154                 bus_release_resource(dev, SYS_RES_IOPORT, port_rid, port_res);
155
156                 switch (config_data.dma_chan) {
157                 case DMA_CHAN_5:
158                         drq = 5;
159                         break;
160                 case DMA_CHAN_6:
161                         drq = 6;
162                         break;
163                 case DMA_CHAN_7:
164                         drq = 7;
165                         break;
166                 default:
167                         kprintf("aha_isa_probe: Invalid DMA setting "
168                             "detected for adapter at 0x%x.  "
169                             "Failing probe\n", ioport);
170                         return (ENXIO);
171                 }
172                 error = bus_set_resource(dev, SYS_RES_DRQ, 0, drq, 1);
173                 if (error)
174                         return error;
175
176                 irq = ffs(config_data.irq) + 8;
177                 error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
178                 if (error)
179                         return error;
180
181                 *sc = aha;
182                 aha_unit++;
183
184                 return (0);
185         }
186
187         return (ENXIO);
188 }
189
190 /*
191  * Attach all the sub-devices we can find
192  */
193 static int
194 aha_isa_attach(device_t dev)
195 {
196         struct  aha_softc **sc = device_get_softc(dev);
197         struct  aha_softc *aha;
198         bus_dma_filter_t *filter;
199         void             *filter_arg;
200         bus_addr_t       lowaddr;
201         void             *ih;
202         int              error;
203
204         aha = *sc;
205         aha->dev = dev;
206         aha->portrid = 0;
207         aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &aha->portrid,
208             0, ~0, AHA_NREGS, RF_ACTIVE);
209         if (!aha->port) {
210                 device_printf(dev, "Unable to allocate I/O ports\n");
211                 return ENOMEM;
212         }
213
214         aha->irqrid = 0;
215         aha->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &aha->irqrid, 0, ~0, 1,
216             RF_ACTIVE);
217         if (!aha->irq) {
218                 device_printf(dev, "Unable to allocate excluse use of irq\n");
219                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
220                 return ENOMEM;
221         }
222
223         aha->drqrid = 0;
224         aha->drq = bus_alloc_resource(dev, SYS_RES_DRQ, &aha->drqrid, 0, ~0, 1,
225             RF_ACTIVE);
226         if (!aha->drq) {
227                 device_printf(dev, "Unable to allocate drq\n");
228                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
229                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
230                 return ENOMEM;
231         }
232
233 #if 0                           /* is the drq ever unset? */
234         if (dev->id_drq != -1)
235                 isa_dmacascade(dev->id_drq);
236 #endif
237         isa_dmacascade(rman_get_start(aha->drq));
238
239         /* Allocate our parent dmatag */
240         filter = NULL;
241         filter_arg = NULL;
242         lowaddr = BUS_SPACE_MAXADDR_24BIT;
243
244         if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/1, /*boundary*/0,
245             lowaddr, /*highaddr*/BUS_SPACE_MAXADDR,
246             filter, filter_arg,
247             /*maxsize*/BUS_SPACE_MAXSIZE_24BIT,
248             /*nsegments*/BUS_SPACE_UNRESTRICTED,
249             /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
250             /*flags*/0, &aha->parent_dmat) != 0) {
251                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
252                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
253                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
254                 aha_free(aha);
255                 return (ENOMEM);
256         }                              
257
258         if (aha_init(aha)) {
259                 device_printf(dev, "init failed\n");
260                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
261                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
262                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
263                 aha_free(aha);
264                 return (ENOMEM);
265         }
266
267         error = aha_attach(aha);
268         if (error) {
269                 device_printf(dev, "attach failed\n");
270                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
271                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
272                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
273                 aha_free(aha);
274                 return (error);
275         }
276
277         error = bus_setup_intr(dev, aha->irq, 0, aha_intr, aha, &ih, NULL);
278         if (error) {
279                 device_printf(dev, "Unable to register interrupt handler\n");
280                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
281                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
282                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
283                 aha_free(aha);
284                 return (error);
285         }
286
287         return (0);
288 }
289
290 static int
291 aha_isa_detach(device_t dev)
292 {
293         struct aha_softc *aha = *(struct aha_softc **) device_get_softc(dev);
294         int error;
295
296         error = bus_teardown_intr(dev, aha->irq, aha->ih);
297         if (error) {
298                 device_printf(dev, "failed to unregister interrupt handler\n");
299         }
300
301         bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
302         bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
303         bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
304
305         error = aha_detach(aha);
306         if (error) {
307                 device_printf(dev, "detach failed\n");
308                 return (error);
309         }
310         aha_free(aha);
311
312         return (0);
313 }
314
315 static device_method_t aha_isa_methods[] = {
316         /* Device interface */
317         DEVMETHOD(device_probe,         aha_isa_probe),
318         DEVMETHOD(device_attach,        aha_isa_attach),
319         DEVMETHOD(device_detach,        aha_isa_detach),
320
321         { 0, 0 }
322 };
323
324 static driver_t aha_isa_driver = {
325         "aha",
326         aha_isa_methods,
327         sizeof(struct aha_softc*),
328 };
329
330 static devclass_t aha_devclass;
331
332 DRIVER_MODULE(aha, isa, aha_isa_driver, aha_devclass, NULL, NULL);