- convert PRVERB to use device_printf()
[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  * $DragonFly: src/sys/dev/disk/aha/aha_isa.c,v 1.5 2005/09/11 13:03:16 sephe Exp $
33  */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38
39 #include <machine/bus_pio.h>
40 #include <machine/bus.h>
41 #include <machine/resource.h>
42 #include <sys/module.h>
43 #include <sys/bus.h>
44 #include <sys/rman.h>
45
46 #include <bus/isa/isavar.h>
47
48 #include "ahareg.h"
49
50 #include <bus/cam/scsi/scsi_all.h>
51
52 static struct isa_pnp_id aha_ids[] = {
53         {ADP0100_PNP,           "Adaptec 1540/1542 ISA SCSI"},  /* ADP0100 */
54         {AHA1540_PNP,           "Adaptec 1540/aha-1640/aha-1535"},/* ADP1542 */
55         {AHA1542_PNP,           "Adaptec 1542/aha-1535"},       /* ADP1542 */
56         {AHA1542_PNPCOMPAT,     "Adaptec 1542 compatible"},     /* PNP00A0 */
57         {ICU0091_PNP,           "Adaptec AHA-1540/1542 SCSI"},  /* ICU0091 */
58         {0}
59 };
60
61 /*
62  * Check if the device can be found at the port given
63  * and if so, set it up ready for further work
64  * as an argument, takes the isa_device structure from
65  * autoconf.c
66  */
67 static int
68 aha_isa_probe(device_t dev)
69 {
70         /*
71          * find unit and check we have that many defined
72          */
73         struct  aha_softc **sc = device_get_softc(dev);
74         struct  aha_softc *aha;
75         int     port_index;
76         int     max_port_index;
77         int     error;
78         u_long  port_start, port_count;
79         struct resource *port_res;
80         int     port_rid;
81         int     drq;
82         int     irq;
83
84         aha = NULL;
85
86         /* Check isapnp ids */
87         if (ISA_PNP_PROBE(device_get_parent(dev), dev, aha_ids) == ENXIO)
88                 return (ENXIO);
89
90         error = bus_get_resource(dev, SYS_RES_IOPORT, 0,
91                                  &port_start, &port_count);
92         if (error != 0)
93                 port_start = 0;
94
95         /*
96          * Bound our board search if the user has
97          * specified an exact port.
98          */
99         aha_find_probe_range(port_start, &port_index, &max_port_index);
100
101         if (port_index < 0)
102                 return ENXIO;
103
104         /* Attempt to find an adapter */
105         for (;port_index <= max_port_index; port_index++) {
106                 config_data_t config_data;
107                 u_int ioport;
108                 int error;
109
110                 ioport = aha_iop_from_bio(port_index);
111
112                 error = bus_set_resource(dev, SYS_RES_IOPORT, 0,
113                                          ioport, AHA_NREGS);
114                 if (error)
115                         return error;
116                 
117                 port_rid = 0;
118                 port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid,
119                     0, ~0, AHA_NREGS, RF_ACTIVE);
120                 if (!port_res)
121                         continue;
122
123                 /* Allocate a softc for use during probing */
124                 aha = aha_alloc(dev, rman_get_bustag(port_res),
125                     rman_get_bushandle(port_res));
126
127                 if (aha == NULL) {
128                         bus_release_resource(dev, SYS_RES_IOPORT, port_rid, 
129                             port_res);
130                         break;
131                 }
132
133                 /* See if there is really a card present */
134                 if (aha_probe(aha) || aha_fetch_adapter_info(aha)) {
135                         aha_free(aha);
136                         bus_release_resource(dev, SYS_RES_IOPORT, port_rid,
137                             port_res);
138                         continue;
139                 }
140
141                 /*
142                  * Determine our IRQ, and DMA settings and
143                  * export them to the configuration system.
144                  */
145                 error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
146                     (u_int8_t*)&config_data, sizeof(config_data), 
147                     DEFAULT_CMD_TIMEOUT);
148
149                 if (error != 0) {
150                         printf("aha_isa_probe: Could not determine IRQ or DMA "
151                             "settings for adapter at 0x%x.  Failing probe\n",
152                             ioport);
153                         aha_free(aha);
154                         bus_release_resource(dev, SYS_RES_IOPORT, port_rid, 
155                             port_res);
156                         continue;
157                 }
158
159                 bus_release_resource(dev, SYS_RES_IOPORT, port_rid, port_res);
160
161                 switch (config_data.dma_chan) {
162                 case DMA_CHAN_5:
163                         drq = 5;
164                         break;
165                 case DMA_CHAN_6:
166                         drq = 6;
167                         break;
168                 case DMA_CHAN_7:
169                         drq = 7;
170                         break;
171                 default:
172                         printf("aha_isa_probe: Invalid DMA setting "
173                             "detected for adapter at 0x%x.  "
174                             "Failing probe\n", ioport);
175                         return (ENXIO);
176                 }
177                 error = bus_set_resource(dev, SYS_RES_DRQ, 0, drq, 1);
178                 if (error)
179                         return error;
180
181                 irq = ffs(config_data.irq) + 8;
182                 error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
183                 if (error)
184                         return error;
185
186                 *sc = aha;
187                 aha_unit++;
188
189                 return (0);
190         }
191
192         return (ENXIO);
193 }
194
195 /*
196  * Attach all the sub-devices we can find
197  */
198 static int
199 aha_isa_attach(device_t dev)
200 {
201         struct  aha_softc **sc = device_get_softc(dev);
202         struct  aha_softc *aha;
203         bus_dma_filter_t *filter;
204         void             *filter_arg;
205         bus_addr_t       lowaddr;
206         void             *ih;
207         int              error;
208
209         aha = *sc;
210         aha->dev = dev;
211         aha->portrid = 0;
212         aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &aha->portrid,
213             0, ~0, AHA_NREGS, RF_ACTIVE);
214         if (!aha->port) {
215                 device_printf(dev, "Unable to allocate I/O ports\n");
216                 return ENOMEM;
217         }
218
219         aha->irqrid = 0;
220         aha->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &aha->irqrid, 0, ~0, 1,
221             RF_ACTIVE);
222         if (!aha->irq) {
223                 device_printf(dev, "Unable to allocate excluse use of irq\n");
224                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
225                 return ENOMEM;
226         }
227
228         aha->drqrid = 0;
229         aha->drq = bus_alloc_resource(dev, SYS_RES_DRQ, &aha->drqrid, 0, ~0, 1,
230             RF_ACTIVE);
231         if (!aha->drq) {
232                 device_printf(dev, "Unable to allocate drq\n");
233                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
234                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
235                 return ENOMEM;
236         }
237
238 #if 0                           /* is the drq ever unset? */
239         if (dev->id_drq != -1)
240                 isa_dmacascade(dev->id_drq);
241 #endif
242         isa_dmacascade(rman_get_start(aha->drq));
243
244         /* Allocate our parent dmatag */
245         filter = NULL;
246         filter_arg = NULL;
247         lowaddr = BUS_SPACE_MAXADDR_24BIT;
248
249         if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/1, /*boundary*/0,
250             lowaddr, /*highaddr*/BUS_SPACE_MAXADDR,
251             filter, filter_arg,
252             /*maxsize*/BUS_SPACE_MAXSIZE_24BIT,
253             /*nsegments*/BUS_SPACE_UNRESTRICTED,
254             /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
255             /*flags*/0, &aha->parent_dmat) != 0) {
256                 aha_free(aha);
257                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
258                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
259                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
260                 return (ENOMEM);
261         }                              
262
263         if (aha_init(aha)) {
264                 device_printf(dev, "init failed\n");
265                 aha_free(aha);
266                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
267                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
268                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
269                 return (ENOMEM);
270         }
271
272         error = aha_attach(aha);
273         if (error) {
274                 device_printf(dev, "attach failed\n");
275                 aha_free(aha);
276                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
277                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
278                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
279                 return (error);
280         }
281
282         error = bus_setup_intr(dev, aha->irq, INTR_TYPE_CAM, aha_intr, aha,
283                                &ih, NULL);
284         if (error) {
285                 device_printf(dev, "Unable to register interrupt handler\n");
286                 aha_free(aha);
287                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
288                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
289                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
290                 return (error);
291         }
292
293         return (0);
294 }
295
296 static int
297 aha_isa_detach(device_t dev)
298 {
299         struct aha_softc *aha = *(struct aha_softc **) device_get_softc(dev);
300         int error;
301
302         error = bus_teardown_intr(dev, aha->irq, aha->ih);
303         if (error) {
304                 device_printf(dev, "failed to unregister interrupt handler\n");
305         }
306
307         bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
308         bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
309         bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
310
311         error = aha_detach(aha);
312         if (error) {
313                 device_printf(dev, "detach failed\n");
314                 return (error);
315         }
316         aha_free(aha);
317
318         return (0);
319 }
320
321 static void
322 aha_isa_identify(driver_t *driver, device_t parent)
323 {
324 }
325
326 static device_method_t aha_isa_methods[] = {
327         /* Device interface */
328         DEVMETHOD(device_probe,         aha_isa_probe),
329         DEVMETHOD(device_attach,        aha_isa_attach),
330         DEVMETHOD(device_detach,        aha_isa_detach),
331         DEVMETHOD(device_identify,      aha_isa_identify),
332
333         { 0, 0 }
334 };
335
336 static driver_t aha_isa_driver = {
337         "aha",
338         aha_isa_methods,
339         sizeof(struct aha_softc*),
340 };
341
342 static devclass_t aha_devclass;
343
344 DRIVER_MODULE(aha, isa, aha_isa_driver, aha_devclass, 0, 0);