Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / disk / buslogic / bt_isa.c
1 /*
2  * Product specific probe and attach routines for:
3  *      Buslogic BT-54X and BT-445 cards
4  *
5  * Copyright (c) 1998, 1999 Justin T. Gibbs
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions, and the following disclaimer,
13  *    without modification, immediately at the beginning of the file.
14  * 2. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD: src/sys/dev/buslogic/bt_isa.c,v 1.18 1999/10/12 21:35:43 dfr Exp $
30  */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/bus.h>
37
38 #include <machine/bus_pio.h>
39 #include <machine/bus.h>
40 #include <machine/resource.h>
41 #include <sys/rman.h>
42
43 #include <isa/isavar.h>
44 #include <dev/buslogic/btreg.h>
45
46 #include <cam/scsi/scsi_all.h>
47
48 static  bus_dma_filter_t btvlbouncefilter;
49 static  bus_dmamap_callback_t btmapsensebuffers;
50
51 static int
52 bt_isa_alloc_resources(device_t dev, u_long portstart, u_long portend)
53 {
54         int rid;
55         struct resource *port;
56         struct resource *irq;
57         struct resource *drq;
58
59         rid = 0;
60         port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
61                                   portstart, portend, BT_NREGS, RF_ACTIVE);
62         if (!port)
63                 return (ENOMEM);
64
65         if (isa_get_irq(dev) != -1) {
66                 rid = 0;
67                 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
68                                          0, ~0, 1, RF_ACTIVE);
69                 if (!irq) {
70                         if (port)
71                                 bus_release_resource(dev, SYS_RES_IOPORT,
72                                                      0, port);
73                         return (ENOMEM);
74                 }
75         } else
76                 irq = 0;
77
78         if (isa_get_drq(dev) != -1) {
79                 rid = 0;
80                 drq = bus_alloc_resource(dev, SYS_RES_DRQ, &rid,
81                                          0, ~0, 1, RF_ACTIVE);
82                 if (!drq) {
83                         if (port)
84                                 bus_release_resource(dev, SYS_RES_IOPORT,
85                                                      0, port);
86                         if (irq)
87                                 bus_release_resource(dev, SYS_RES_IRQ,
88                                                      0, irq);
89                         return (ENOMEM);
90                 }
91         } else
92                 drq = 0;
93
94         bt_init_softc(dev, port, irq, drq);
95
96         return (0);
97 }
98
99 static void
100 bt_isa_release_resources(device_t dev)
101 {
102         struct  bt_softc *bt = device_get_softc(dev);
103
104         if (bt->port)
105                 bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port);
106         if (bt->irq)
107                 bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq);
108         if (bt->drq)
109                 bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq);
110         bt_free_softc(dev);
111 }
112
113 /*
114  * Check if the device can be found at the port given
115  * and if so, set it up ready for further work
116  * as an argument, takes the isa_device structure from
117  * autoconf.c
118  */
119 static int
120 bt_isa_probe(device_t dev)
121 {
122         /*
123          * find unit and check we have that many defined
124          */
125         int     port_index;
126         int     max_port_index;
127
128         /* No pnp support */
129         if (isa_get_vendorid(dev))
130                 return (ENXIO);
131
132         port_index = 0;
133         max_port_index = BT_NUM_ISAPORTS - 1;
134         /*
135          * Bound our board search if the user has
136          * specified an exact port.
137          */
138         bt_find_probe_range(isa_get_port(dev), &port_index, &max_port_index);
139
140         if (port_index < 0)
141                 return (ENXIO);
142
143         /* Attempt to find an adapter */
144         for (;port_index <= max_port_index; port_index++) {
145                 struct bt_probe_info info;
146                 u_int ioport;
147
148                 ioport = bt_iop_from_bio(port_index);
149
150                 /*
151                  * Ensure this port has not already been claimed already
152                  * by a PCI, EISA or ISA adapter.
153                  */
154                 if (bt_check_probed_iop(ioport) != 0)
155                         continue;
156
157                 /* Initialise the softc for use during probing */
158                 if (bt_isa_alloc_resources(dev, ioport,
159                                            ioport + BT_NREGS -1) != 0)
160                         continue;
161
162                 /* We're going to attempt to probe it now, so mark it probed */
163                 bt_mark_probed_bio(port_index);
164
165                 if (bt_port_probe(dev, &info) != 0) {
166                         if (bootverbose)
167                                 printf("bt_isa_probe: Probe failed at 0x%x\n",
168                                        ioport);
169                         bt_isa_release_resources(dev);
170                         continue;
171                 }
172
173                 bt_isa_release_resources(dev);
174
175                 bus_set_resource(dev, SYS_RES_DRQ, 0, info.drq, 1);
176                 bus_set_resource(dev, SYS_RES_IRQ, 0, info.irq, 1);
177
178                 return (0);
179         }
180
181         return (ENXIO);
182 }
183
184 /*
185  * Attach all the sub-devices we can find
186  */
187 static int
188 bt_isa_attach(device_t dev)
189 {
190         struct  bt_softc *bt = device_get_softc(dev);
191         bus_dma_filter_t *filter;
192         void             *filter_arg;
193         bus_addr_t       lowaddr;
194         int              error, drq;
195
196         /* Initialise softc */
197         error = bt_isa_alloc_resources(dev, 0, ~0);
198         if (error) {
199                 device_printf(dev, "can't allocate resources in bt_isa_attach\n");
200                 return error;
201         }
202
203         /* Program the DMA channel for external control */
204         if ((drq = isa_get_drq(dev)) != -1)
205                 isa_dmacascade(drq);
206
207         /* Allocate our parent dmatag */
208         filter = NULL;
209         filter_arg = NULL;
210         lowaddr = BUS_SPACE_MAXADDR_24BIT;
211         if (bt->model[0] == '4') {
212                 /*
213                  * This is a VL adapter.  Typically, VL devices have access
214                  * to the full 32bit address space.  On BT-445S adapters
215                  * prior to revision E, there is a hardware bug that causes
216                  * corruption of transfers to/from addresses in the range of
217                  * the BIOS modulo 16MB.  The only properly functioning
218                  * BT-445S Host Adapters have firmware version 3.37.
219                  * If we encounter one of these adapters and the BIOS is
220                  * installed, install a filter function for our bus_dma_map
221                  * that will catch these accesses and bounce them to a safe
222                  * region of memory.
223                  */
224                 if (bt->bios_addr != 0
225                  && strcmp(bt->model, "445S") == 0
226                  && strcmp(bt->firmware_ver, "3.37") < 0) {
227                         filter = btvlbouncefilter;
228                         filter_arg = bt;
229                 } else {
230                         lowaddr = BUS_SPACE_MAXADDR_32BIT;
231                 }
232         }
233                         
234         /* XXX Should be a child of the ISA or VL bus dma tag */
235         if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/1, /*boundary*/0,
236                                lowaddr, /*highaddr*/BUS_SPACE_MAXADDR,
237                                filter, filter_arg,
238                                /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
239                                /*nsegments*/BUS_SPACE_UNRESTRICTED,
240                                /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
241                                /*flags*/0, &bt->parent_dmat) != 0) {
242                 bt_isa_release_resources(dev);
243                 return (ENOMEM);
244         }                              
245
246         error = bt_init(dev);
247         if (error) {
248                 bt_isa_release_resources(dev);
249                 return (ENOMEM);
250         }
251
252         if (lowaddr != BUS_SPACE_MAXADDR_32BIT) {
253                 /* DMA tag for our sense buffers */
254                 if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/1,
255                                        /*boundary*/0,
256                                        /*lowaddr*/BUS_SPACE_MAXADDR,
257                                        /*highaddr*/BUS_SPACE_MAXADDR,
258                                        /*filter*/NULL, /*filterarg*/NULL,
259                                        bt->max_ccbs
260                                            * sizeof(struct scsi_sense_data),
261                                        /*nsegments*/1,
262                                        /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
263                                        /*flags*/0, &bt->sense_dmat) != 0) {
264                         bt_isa_release_resources(dev);
265                         return (ENOMEM);
266                 }
267
268                 bt->init_level++;
269
270                 /* Allocation of sense buffers */
271                 if (bus_dmamem_alloc(bt->sense_dmat,
272                                      (void **)&bt->sense_buffers,
273                                      BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) {
274                         bt_isa_release_resources(dev);
275                         return (ENOMEM);
276                 }
277
278                 bt->init_level++;
279
280                 /* And permanently map them */
281                 bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap,
282                                 bt->sense_buffers,
283                                 bt->max_ccbs * sizeof(*bt->sense_buffers),
284                                 btmapsensebuffers, bt, /*flags*/0);
285
286                 bt->init_level++;
287         }
288
289         error = bt_attach(dev);
290         if (error) {
291                 bt_isa_release_resources(dev);
292                 return (error);
293         }
294
295         return (0);
296 }
297
298 #define BIOS_MAP_SIZE (16 * 1024)
299
300 static int
301 btvlbouncefilter(void *arg, bus_addr_t addr)
302 {
303         struct bt_softc *bt;
304
305         bt = (struct bt_softc *)arg;
306
307         addr &= BUS_SPACE_MAXADDR_24BIT;
308
309         if (addr == 0
310          || (addr >= bt->bios_addr
311           && addr < (bt->bios_addr + BIOS_MAP_SIZE)))
312                 return (1);
313         return (0);
314 }
315
316 static void
317 btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error)
318 {
319         struct bt_softc* bt;
320
321         bt = (struct bt_softc*)arg;
322         bt->sense_buffers_physbase = segs->ds_addr;
323 }
324
325 static device_method_t bt_isa_methods[] = {
326         /* Device interface */
327         DEVMETHOD(device_probe,         bt_isa_probe),
328         DEVMETHOD(device_attach,        bt_isa_attach),
329
330         { 0, 0 }
331 };
332
333 static driver_t bt_isa_driver = {
334         "bt",
335         bt_isa_methods,
336         sizeof(struct bt_softc),
337 };
338
339 static devclass_t bt_devclass;
340
341 DRIVER_MODULE(bt, isa, bt_isa_driver, bt_devclass, 0, 0);