]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/buslogic/bt_isa.c
MFV r336942: 9189 Add debug to vdev_label_read_config when txg check fails
[FreeBSD/FreeBSD.git] / sys / dev / buslogic / bt_isa.c
1 /*-
2  * Product specific probe and attach routines for:
3  *      Buslogic BT-54X and BT-445 cards
4  *
5  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
6  *
7  * Copyright (c) 1998, 1999 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  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/module.h>
40 #include <sys/lock.h>
41 #include <sys/mutex.h>
42 #include <sys/bus.h>
43
44 #include <machine/bus.h>
45 #include <machine/resource.h>
46 #include <sys/rman.h>
47
48 #include <isa/isavar.h>
49 #include <dev/buslogic/btreg.h>
50
51 #include <cam/scsi/scsi_all.h>
52
53 static  bus_dma_filter_t btvlbouncefilter;
54 static  bus_dmamap_callback_t btmapsensebuffers;
55
56 static int
57 bt_isa_alloc_resources(device_t dev, u_long portstart, u_long portend)
58 {
59         int rid;
60         struct resource *port;
61         struct resource *irq;
62         struct resource *drq;
63
64         rid = 0;
65         port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
66                                   portstart, portend, BT_NREGS, RF_ACTIVE);
67         if (!port)
68                 return (ENOMEM);
69
70         if (isa_get_irq(dev) != -1) {
71                 rid = 0;
72                 irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
73                 if (!irq) {
74                         if (port)
75                                 bus_release_resource(dev, SYS_RES_IOPORT,
76                                                      0, port);
77                         return (ENOMEM);
78                 }
79         } else
80                 irq = NULL;
81
82         if (isa_get_drq(dev) != -1) {
83                 rid = 0;
84                 drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid, RF_ACTIVE);
85                 if (!drq) {
86                         if (port)
87                                 bus_release_resource(dev, SYS_RES_IOPORT,
88                                                      0, port);
89                         if (irq)
90                                 bus_release_resource(dev, SYS_RES_IRQ,
91                                                      0, irq);
92                         return (ENOMEM);
93                 }
94         } else
95                 drq = NULL;
96
97         bt_init_softc(dev, port, irq, drq);
98
99         return (0);
100 }
101
102 static void
103 bt_isa_release_resources(device_t dev)
104 {
105         struct  bt_softc *bt = device_get_softc(dev);
106
107         if (bt->port)
108                 bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port);
109         if (bt->irq)
110                 bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq);
111         if (bt->drq)
112                 bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq);
113         bt_free_softc(dev);
114 }
115
116 /*
117  * Check if the device can be found at the port given
118  * and if so, set it up ready for further work
119  * as an argument, takes the isa_device structure from
120  * autoconf.c
121  */
122 static int
123 bt_isa_probe(device_t dev)
124 {
125         /*
126          * find unit and check we have that many defined
127          */
128         int     port_index;
129         int     max_port_index;
130
131         /* No pnp support */
132         if (isa_get_vendorid(dev))
133                 return (ENXIO);
134
135         port_index = 0;
136         max_port_index = BT_NUM_ISAPORTS - 1;
137         /*
138          * Bound our board search if the user has
139          * specified an exact port.
140          */
141         bt_find_probe_range(isa_get_port(dev), &port_index, &max_port_index);
142
143         if (port_index < 0)
144                 return (ENXIO);
145
146         /* Attempt to find an adapter */
147         for (;port_index <= max_port_index; port_index++) {
148                 struct bt_probe_info info;
149                 u_int ioport;
150
151                 ioport = bt_iop_from_bio(port_index);
152
153                 /*
154                  * Ensure this port has not already been claimed already
155                  * by a PCI, ISA adapter.
156                  */
157                 if (bt_check_probed_iop(ioport) != 0)
158                         continue;
159
160                 /* Initialise the softc for use during probing */
161                 if (bt_isa_alloc_resources(dev, ioport,
162                                            ioport + BT_NREGS -1) != 0)
163                         continue;
164
165                 /* We're going to attempt to probe it now, so mark it probed */
166                 bt_mark_probed_bio(port_index);
167
168                 if (bt_port_probe(dev, &info) != 0) {
169                         if (bootverbose)
170                                 printf("bt_isa_probe: Probe failed at 0x%x\n",
171                                        ioport);
172                         bt_isa_release_resources(dev);
173                         continue;
174                 }
175
176                 bt_isa_release_resources(dev);
177
178                 bus_set_resource(dev, SYS_RES_DRQ, 0, info.drq, 1);
179                 bus_set_resource(dev, SYS_RES_IRQ, 0, info.irq, 1);
180
181                 return (BUS_PROBE_DEFAULT);
182         }
183
184         return (ENXIO);
185 }
186
187 /*
188  * Attach all the sub-devices we can find
189  */
190 static int
191 bt_isa_attach(device_t dev)
192 {
193         struct  bt_softc *bt = device_get_softc(dev);
194         bus_dma_filter_t *filter;
195         void             *filter_arg;
196         bus_addr_t       lowaddr;
197         int              error, drq;
198
199         /* Initialise softc */
200         error = bt_isa_alloc_resources(dev, 0, ~0);
201         if (error) {
202                 device_printf(dev, "can't allocate resources in bt_isa_attach\n");
203                 return error;
204         }
205
206         /* Program the DMA channel for external control */
207         if ((drq = isa_get_drq(dev)) != -1)
208                 isa_dmacascade(drq);
209
210         /* Allocate our parent dmatag */
211         filter = NULL;
212         filter_arg = NULL;
213         lowaddr = BUS_SPACE_MAXADDR_24BIT;
214         if (bt->model[0] == '4') {
215                 /*
216                  * This is a VL adapter.  Typically, VL devices have access
217                  * to the full 32bit address space.  On BT-445S adapters
218                  * prior to revision E, there is a hardware bug that causes
219                  * corruption of transfers to/from addresses in the range of
220                  * the BIOS modulo 16MB.  The only properly functioning
221                  * BT-445S Host Adapters have firmware version 3.37.
222                  * If we encounter one of these adapters and the BIOS is
223                  * installed, install a filter function for our bus_dma_map
224                  * that will catch these accesses and bounce them to a safe
225                  * region of memory.
226                  */
227                 if (bt->bios_addr != 0
228                  && strcmp(bt->model, "445S") == 0
229                  && strcmp(bt->firmware_ver, "3.37") < 0) {
230                         filter = btvlbouncefilter;
231                         filter_arg = bt;
232                 } else {
233                         lowaddr = BUS_SPACE_MAXADDR_32BIT;
234                 }
235         }
236                         
237         /* XXX Should be a child of the ISA or VL bus dma tag */
238         if (bus_dma_tag_create( /* parent       */ bus_get_dma_tag(dev),
239                                 /* alignemnt    */ 1,
240                                 /* boundary     */ 0,
241                                 /* lowaddr      */ lowaddr,
242                                 /* highaddr     */ BUS_SPACE_MAXADDR,
243                                 /* filter       */ filter,
244                                 /* filterarg    */ filter_arg,
245                                 /* maxsize      */ BUS_SPACE_MAXSIZE_32BIT,
246                                 /* nsegments    */ ~0,
247                                 /* maxsegsz     */ BUS_SPACE_MAXSIZE_32BIT,
248                                 /* flags        */ 0,
249                                 /* lockfunc     */ NULL,
250                                 /* lockarg      */ NULL,
251                                 &bt->parent_dmat) != 0) {
252                 bt_isa_release_resources(dev);
253                 return (ENOMEM);
254         }                              
255
256         error = bt_init(dev);
257         if (error) {
258                 bt_isa_release_resources(dev);
259                 return (ENOMEM);
260         }
261
262         if (lowaddr != BUS_SPACE_MAXADDR_32BIT) {
263                 /* DMA tag for our sense buffers */
264                 if (bus_dma_tag_create(
265                                 /* parent       */ bt->parent_dmat,
266                                 /* alignment    */ 1,
267                                 /* boundary     */ 0,
268                                 /* lowaddr      */ BUS_SPACE_MAXADDR,
269                                 /* highaddr     */ BUS_SPACE_MAXADDR,
270                                 /* filter       */ NULL,
271                                 /* filterarg    */ NULL,
272                                 /* maxsize      */ bt->max_ccbs *
273                                                    sizeof(struct scsi_sense_data),
274                                 /* nsegments    */ 1,
275                                 /* maxsegsz     */ BUS_SPACE_MAXSIZE_32BIT,
276                                 /* flags        */ 0,
277                                 /* lockfunc     */ NULL,
278                                 /* lockarg      */ NULL,
279                                 &bt->sense_dmat) != 0) {
280                         bt_isa_release_resources(dev);
281                         return (ENOMEM);
282                 }
283
284                 bt->init_level++;
285
286                 /* Allocation of sense buffers */
287                 if (bus_dmamem_alloc(bt->sense_dmat,
288                                      (void **)&bt->sense_buffers,
289                                      BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) {
290                         bt_isa_release_resources(dev);
291                         return (ENOMEM);
292                 }
293
294                 bt->init_level++;
295
296                 /* And permanently map them */
297                 bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap,
298                                 bt->sense_buffers,
299                                 bt->max_ccbs * sizeof(*bt->sense_buffers),
300                                 btmapsensebuffers, bt, /*flags*/0);
301
302                 bt->init_level++;
303         }
304
305         error = bt_attach(dev);
306         if (error) {
307                 bt_isa_release_resources(dev);
308                 return (error);
309         }
310
311         return (0);
312 }
313
314 #define BIOS_MAP_SIZE (16 * 1024)
315
316 static int
317 btvlbouncefilter(void *arg, bus_addr_t addr)
318 {
319         struct bt_softc *bt;
320
321         bt = (struct bt_softc *)arg;
322
323         addr &= BUS_SPACE_MAXADDR_24BIT;
324
325         if (addr == 0
326          || (addr >= bt->bios_addr
327           && addr < (bt->bios_addr + BIOS_MAP_SIZE)))
328                 return (1);
329         return (0);
330 }
331
332 static void
333 btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error)
334 {
335         struct bt_softc* bt;
336
337         bt = (struct bt_softc*)arg;
338         bt->sense_buffers_physbase = segs->ds_addr;
339 }
340
341 static device_method_t bt_isa_methods[] = {
342         /* Device interface */
343         DEVMETHOD(device_probe,         bt_isa_probe),
344         DEVMETHOD(device_attach,        bt_isa_attach),
345
346         { 0, 0 }
347 };
348
349 static driver_t bt_isa_driver = {
350         "bt",
351         bt_isa_methods,
352         sizeof(struct bt_softc),
353 };
354
355 static devclass_t bt_devclass;
356
357 DRIVER_MODULE(bt, isa, bt_isa_driver, bt_devclass, 0, 0);
358 MODULE_DEPEND(bt, isa, 1, 1, 1);