Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / disk / buslogic / bt_mca.c
1 /*-
2  * Copyright (c) 1999 Matthew N. Dodd <winter@jurai.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/dev/buslogic/bt_mca.c,v 1.4 1999/10/09 04:02:02 mdodd Exp $
27  */
28
29 /*
30  * Written using the bt_isa/bt_pci code as a reference.
31  *
32  * Thanks to Andy Farkas <andyf@speednet.com.au> for
33  * testing and feedback.
34  */
35
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40
41 #include <machine/cpufunc.h>
42 #include <machine/md_var.h>
43
44 #include <sys/module.h>
45 #include <sys/bus.h>
46
47 #include <machine/bus.h>
48 #include <machine/resource.h>
49 #include <sys/rman.h>
50
51 #include <dev/mca/mca_busreg.h>
52 #include <dev/mca/mca_busvar.h>
53
54 #include <i386/isa/isa_dma.h>
55
56 #include <dev/buslogic/btreg.h>
57
58 #include <cam/scsi/scsi_all.h>
59
60 static struct mca_ident bt_mca_devs[] = {
61         { 0x0708, "BusLogic 32 Bit Bus Master MCA-to-SCSI Host Adapter" },
62         { 0x0708, "BusTek BT-640A Micro Channel to SCSI Host Adapter" },
63         { 0x0708, "Storage Dimensions SDC3211B 32-bit SCSI Host Adapter" },
64         { 0x0709, "Storage Dimensions SDC3211F 32-bit FAST SCSI Host Adapter" },
65         { 0, NULL },
66 };
67
68 #define BT_MCA_IOPORT_POS1              MCA_ADP_POS(MCA_POS0)
69 #define BT_MCA_IOPORT_POS2              MCA_ADP_POS(MCA_POS1)
70 #define BT_MCA_IOPORT_MASK1             0x10
71 #define BT_MCA_IOPORT_MASK2             0x03
72 #define BT_MCA_IOPORT_SIZE              0x03
73 #define BT_MCA_IOPORT(pos)              (0x30 + \
74                                         (((u_int32_t)pos &\
75                                                 BT_MCA_IOPORT_MASK2) << 8) + \
76                                         (((u_int32_t)pos &\
77                                                 BT_MCA_IOPORT_MASK1) >> 2))
78
79 #define BT_MCA_IRQ_POS                  MCA_ADP_POS(MCA_POS0)
80 #define BT_MCA_IRQ_MASK                 0x0e
81 #define BT_MCA_IRQ(pos)                 (((pos & BT_MCA_IRQ_MASK) >> 1) + 8)
82
83 #define BT_MCA_DRQ_POS                  MCA_ADP_POS(MCA_POS3)
84 #define BT_MCA_DRQ_MASK                 0x0f
85 #define BT_MCA_DRQ(pos)                 (pos & BT_MCA_DRQ_MASK)
86
87 #define BT_MCA_SCSIID_POS               MCA_ADP_POS(MCA_POS2)
88 #define BT_MCA_SCSIID_MASK              0xe0
89 #define BT_MCA_SCSIID(pos)              ((pos & BT_MCA_SCSIID_MASK) >> 5)
90
91 static  bus_dma_filter_t        btvlbouncefilter;
92 static  bus_dmamap_callback_t   btmapsensebuffers;
93
94 static void
95 bt_mca_release_resources (device_t dev)
96 {
97         struct  bt_softc *      bt = device_get_softc(dev);
98
99         if (bt->port)
100                 bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port);
101         if (bt->irq)
102                 bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq);
103         if (bt->drq)
104                 bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq);
105
106         bt_free_softc(dev);
107 }
108
109 #define BT_MCA_PROBE    0
110 #define BT_MCA_ATTACH   1
111
112 static int
113 bt_mca_alloc_resources(device_t dev, int mode)
114 {
115         struct resource *       io = NULL;
116         struct resource *       irq = NULL;
117         struct resource *       drq = NULL;
118         int                     rid;
119
120         rid = 0;
121         io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
122                                 0, ~0, 1, RF_ACTIVE);
123         if (io == NULL) {
124                 printf("bt_mca_alloc_resources() failed to allocate IOPORT\n");
125                 return (ENOMEM);
126         }
127
128         if (mode == BT_MCA_ATTACH) {
129
130                 rid = 0;
131                 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
132                                          0, ~0, 1, RF_ACTIVE);
133                 if (irq == NULL) {
134                         printf("bt_mca_alloc_resources() failed to allocate IRQ\n");
135                         goto bad;
136                 }
137         
138                 rid = 0;
139                 drq = bus_alloc_resource(dev, SYS_RES_DRQ, &rid,
140                                                  0, ~0, 1, RF_ACTIVE);
141                 if (drq == NULL) {
142                         printf("bt_mca_alloc_resources() failed to allocate DRQ\n");
143                         goto bad;
144                 }
145         }
146         
147         bt_init_softc(dev, io, irq, drq);
148
149         return (0);
150 bad:
151         bt_mca_release_resources(dev);
152         return (ENOMEM);
153 }
154
155 static int
156 bt_mca_probe (device_t dev)
157 {
158         const char *            desc;
159         mca_id_t                id = mca_get_id(dev);
160         struct bt_probe_info    info;
161         u_int32_t               iobase = 0;
162         u_int32_t               iosize = 0;
163         u_int8_t                drq = 0;
164         u_int8_t                irq = 0;
165         u_int8_t                pos;
166         int                     result;
167
168         desc = mca_match_id(id, bt_mca_devs);
169         if (!desc)
170                 return (ENXIO);
171         device_set_desc(dev, desc);
172
173         pos = (mca_pos_read(dev, BT_MCA_IOPORT_POS1) & BT_MCA_IOPORT_MASK1) |
174               (mca_pos_read(dev, BT_MCA_IOPORT_POS2) & BT_MCA_IOPORT_MASK2);
175         iobase = BT_MCA_IOPORT(pos);
176         iosize = BT_MCA_IOPORT_SIZE;
177
178         pos = mca_pos_read(dev, BT_MCA_DRQ_POS);
179         drq = BT_MCA_DRQ(pos);
180
181         pos = mca_pos_read(dev, BT_MCA_IRQ_POS);
182         irq = BT_MCA_IRQ(pos);
183
184         bt_mark_probed_iop(iobase);
185
186         mca_add_iospace(dev, iobase, iosize);
187
188         /* And allocate them */
189         bt_mca_alloc_resources(dev, BT_MCA_PROBE);
190                         
191         if (bt_port_probe(dev, &info) != 0) {
192                 printf("bt_mca_probe: Probe failed for "
193                        "card at slot %d\n", mca_get_slot(dev) + 1);
194                 result = ENXIO;
195         } else {               
196                 mca_add_drq(dev, drq);
197                 mca_add_irq(dev, irq);
198                 result = 0;    
199         }              
200         bt_mca_release_resources(dev);
201
202         return (result);
203 }
204
205 static int
206 bt_mca_attach (device_t dev)
207 {
208         struct bt_softc *       bt = device_get_softc(dev);
209         int                     error = 0;
210
211         /* Allocate resources */      
212         if ((error = bt_mca_alloc_resources(dev, BT_MCA_ATTACH))) {
213                 device_printf(dev, "Unable to allocate resources in bt_mca_attach()\n");
214                 return (error);
215         }
216
217         isa_dmacascade(rman_get_start(bt->drq));
218
219         /* Allocate a dmatag for our CCB DMA maps */
220         if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/1, /*boundary*/0,
221                                /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
222                                /*highaddr*/BUS_SPACE_MAXADDR,
223                                /*filter*/btvlbouncefilter,
224                                /*filterarg*/bt,
225                                /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
226                                /*nsegments*/BUS_SPACE_UNRESTRICTED,
227                                /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
228                                /*flags*/0, &bt->parent_dmat) != 0) {
229                 bt_mca_release_resources(dev);
230                 return (ENOMEM);
231         }
232
233         if (bt_init(dev)) {
234                 bt_mca_release_resources(dev);
235                 return (ENOMEM);
236         }
237
238         /* DMA tag for our sense buffers */
239         if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/1, 
240                                /*boundary*/0,
241                                /*lowaddr*/BUS_SPACE_MAXADDR,    
242                                /*highaddr*/BUS_SPACE_MAXADDR,   
243                                /*filter*/NULL, /*filterarg*/NULL,
244                                bt->max_ccbs * sizeof(struct scsi_sense_data),
245                                /*nsegments*/1,
246                                /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
247                                /*flags*/0, &bt->sense_dmat) != 0) {
248                 bt_mca_release_resources(dev);
249                 return (ENOMEM);
250         }
251
252         bt->init_level++;     
253
254         /* Allocation of sense buffers */
255         if (bus_dmamem_alloc(bt->sense_dmat,
256                              (void **)&bt->sense_buffers,       
257                              BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) {
258                 bt_mca_release_resources(dev);
259                 return (ENOMEM);
260         }
261
262         bt->init_level++;     
263
264         /* And permanently map them */
265         bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap,       
266                         bt->sense_buffers,
267                         bt->max_ccbs * sizeof(*bt->sense_buffers),
268                         btmapsensebuffers, bt, /*flags*/0);     
269
270         bt->init_level++;     
271
272         if ((error = bt_attach(dev))) {
273                 bt_mca_release_resources(dev);
274                 return (error);
275         }
276
277         return (0);
278 }
279
280 /*
281  * This code should be shared with the ISA
282  * stubs as its exactly the same.
283  */
284
285 #define BIOS_MAP_SIZE (16 * 1024)
286
287 static int
288 btvlbouncefilter(void *arg, bus_addr_t addr)
289 {
290         struct bt_softc *bt;
291
292         bt = (struct bt_softc *)arg;
293
294         addr &= BUS_SPACE_MAXADDR_24BIT;
295
296         if (addr == 0
297          || (addr >= bt->bios_addr
298           && addr < (bt->bios_addr + BIOS_MAP_SIZE)))
299                 return (1);
300         return (0);
301 }
302
303 static void
304 btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error)
305 {
306         struct bt_softc* bt;
307
308         bt = (struct bt_softc*)arg;
309         bt->sense_buffers_physbase = segs->ds_addr;
310 }
311
312 static device_method_t bt_mca_methods[] = {
313         /* Device interface */
314         DEVMETHOD(device_probe,         bt_mca_probe),
315         DEVMETHOD(device_attach,        bt_mca_attach),
316
317         { 0, 0 }
318 };
319
320 static driver_t bt_mca_driver = {
321         "bt",
322         bt_mca_methods,
323         sizeof(struct bt_softc),
324 };
325
326 static devclass_t bt_devclass;
327
328 DRIVER_MODULE(bt, mca, bt_mca_driver, bt_devclass, 0, 0);