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