]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/advansys/adv_eisa.c
Start each of the license/copyright comments with /*-, minor shuffle of lines
[FreeBSD/FreeBSD.git] / sys / dev / advansys / adv_eisa.c
1 /*-
2  * Device probe and attach routines for the following
3  * Advanced Systems Inc. SCSI controllers:
4  *
5  *   Single Channel Products:
6  *      ABP742 - Bus-Master EISA (240 CDB)
7  *
8  *   Dual Channel Products:  
9  *      ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
10  *
11  * Copyright (c) 1997 Justin Gibbs.
12  * All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions, and the following disclaimer,
19  *    without modification, immediately at the beginning of the file.
20  * 2. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
27  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/bus.h>
46
47 #include <machine/bus_pio.h>
48 #include <machine/bus.h>
49 #include <machine/resource.h>
50 #include <sys/rman.h>
51
52 #include <dev/eisa/eisaconf.h>
53
54 #include <dev/advansys/advansys.h>
55
56 #define EISA_DEVICE_ID_ADVANSYS_740     0x04507400
57 #define EISA_DEVICE_ID_ADVANSYS_750     0x04507500
58
59 #define ADV_EISA_SLOT_OFFSET            0xc00
60 #define ADV_EISA_OFFSET_CHAN1           0x30
61 #define ADV_EISA_OFFSET_CHAN2           0x50
62 #define ADV_EISA_IOSIZE                 0x100
63
64 #define ADV_EISA_ROM_BIOS_ADDR_REG      0x86
65 #define ADV_EISA_IRQ_BURST_LEN_REG      0x87
66 #define         ADV_EISA_IRQ_MASK       0x07
67 #define         ADV_EISA_IRQ_10         0x00
68 #define         ADV_EISA_IRQ_11         0x01
69 #define         ADV_EISA_IRQ_12         0x02
70 #define         ADV_EISA_IRQ_14         0x04
71 #define         ADV_EISA_IRQ_15         0x05
72
73 #define ADV_EISA_MAX_DMA_ADDR   (0x07FFFFFFL)
74 #define ADV_EISA_MAX_DMA_COUNT  (0x07FFFFFFL)
75
76 /* 
77  * The overrun buffer shared amongst all EISA adapters.
78  */
79 static  u_int8_t*       overrun_buf;
80 static  bus_dma_tag_t   overrun_dmat;
81 static  bus_dmamap_t    overrun_dmamap;
82 static  bus_addr_t      overrun_physbase;
83
84 static const char*
85 adv_eisa_match(eisa_id_t type)
86 {
87         switch (type & ~0xF) {
88         case EISA_DEVICE_ID_ADVANSYS_740:
89                 return ("AdvanSys ABP-740/742 SCSI adapter");
90                 break;
91         case EISA_DEVICE_ID_ADVANSYS_750:
92                 return ("AdvanSys ABP-750/752 SCSI adapter");
93                 break;
94         default:
95                 break;
96         }
97         return (NULL);
98 }
99
100 static int
101 adv_eisa_probe(device_t dev)
102 {
103         const char *desc;
104         u_int32_t iobase;
105         u_int8_t irq;
106
107         desc = adv_eisa_match(eisa_get_id(dev));
108         if (!desc)
109                 return (ENXIO);
110         device_set_desc(dev, desc);
111
112         iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + ADV_EISA_SLOT_OFFSET;
113
114         eisa_add_iospace(dev, iobase, ADV_EISA_IOSIZE, RESVADDR_NONE);
115         irq = inb(iobase + ADV_EISA_IRQ_BURST_LEN_REG);
116         irq &= ADV_EISA_IRQ_MASK;
117         switch (irq) {
118         case 0:
119         case 1:
120         case 2:
121         case 4:
122         case 5:
123             break;
124         default:
125             printf("adv at slot %d: illegal "
126                    "irq setting %d\n", eisa_get_slot(dev),
127                    irq);
128             return ENXIO;
129         }
130         eisa_add_intr(dev, irq + 10, EISA_TRIGGER_LEVEL);
131
132         return 0;
133 }
134
135 static int
136 adv_eisa_attach(device_t dev)
137 {
138         struct adv_softc *adv;
139         struct adv_softc *adv_b;
140         struct resource *io;
141         struct resource *irq;
142         int rid, error;
143         void *ih;
144
145         adv_b = NULL;
146
147         rid = 0;
148         io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
149         if (!io) {
150                 device_printf(dev, "No I/O space?!\n");
151                 return ENOMEM;
152         }
153
154         rid = 0;
155         irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
156                                      RF_SHAREABLE | RF_ACTIVE);
157         if (!irq) {
158                 device_printf(dev, "No irq?!\n");
159                 bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
160                 return ENOMEM;
161
162         }
163
164         switch (eisa_get_id(dev) & ~0xF) {
165         case EISA_DEVICE_ID_ADVANSYS_750:
166                 adv_b = adv_alloc(dev, rman_get_bustag(io),
167                                   rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN2);
168                 if (adv_b == NULL)
169                         goto bad;
170                 
171                 /*
172                  * Allocate a parent dmatag for all tags created
173                  * by the MI portions of the advansys driver
174                  */
175                 /* XXX Should be a child of the PCI bus dma tag */
176                 error = bus_dma_tag_create(
177                                 /* parent       */ NULL,
178                                 /* alignment    */ 1,
179                                 /* boundary     */ 0,
180                                 /* lowaddr      */ ADV_EISA_MAX_DMA_ADDR,
181                                 /* highaddr     */ BUS_SPACE_MAXADDR,
182                                 /* filter       */ NULL,
183                                 /* filterarg    */ NULL,
184                                 /* maxsize      */ BUS_SPACE_MAXSIZE_32BIT,
185                                 /* nsegments    */ ~0,
186                                 /* maxsegsz     */ ADV_EISA_MAX_DMA_COUNT,
187                                 /* flags        */ 0,
188                                 /* lockfunc     */ busdma_lock_mutex,
189                                 /* lockarg      */ &Giant,
190                                 &adv_b->parent_dmat);
191  
192                 if (error != 0) {
193                         printf("%s: Could not allocate DMA tag - error %d\n",
194                                adv_name(adv_b), error);
195                         adv_free(adv_b);
196                         goto bad;
197                 }
198
199                 adv_b->init_level++;
200
201                 /* FALLTHROUGH */
202         case EISA_DEVICE_ID_ADVANSYS_740:
203                 adv = adv_alloc(dev, rman_get_bustag(io),
204                                 rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN1);
205                 if (adv == NULL) {
206                         if (adv_b != NULL)
207                                 adv_free(adv_b);
208                         goto bad;
209                 }
210
211                 /*
212                  * Allocate a parent dmatag for all tags created
213                  * by the MI portions of the advansys driver
214                  */
215                 /* XXX Should be a child of the PCI bus dma tag */
216                 error = bus_dma_tag_create(
217                                 /* parent       */ NULL,
218                                 /* alignment    */ 1,
219                                 /* boundary     */ 0,
220                                 /* lowaddr      */ ADV_EISA_MAX_DMA_ADDR,
221                                 /* highaddr     */ BUS_SPACE_MAXADDR,
222                                 /* filter       */ NULL,
223                                 /* filterarg    */ NULL,
224                                 /* maxsize      */ BUS_SPACE_MAXSIZE_32BIT,
225                                 /* nsegments    */ ~0,
226                                 /* maxsegsz     */ ADV_EISA_MAX_DMA_COUNT,
227                                 /* flags        */ 0,
228                                 /* lockfunc     */ busdma_lock_mutex,
229                                 /* lockarg      */ &Giant,
230                                 &adv->parent_dmat);
231  
232                 if (error != 0) {
233                         printf("%s: Could not allocate DMA tag - error %d\n",
234                                adv_name(adv), error);
235                         adv_free(adv);
236                         goto bad;
237                 }
238
239                 adv->init_level++;
240                 break;
241         default: 
242                 printf("adveisaattach: Unknown device type!\n");
243                 goto bad;
244                 break;
245         }
246
247         if (overrun_buf == NULL) {
248                 /* Need to allocate our overrun buffer */
249                 if (bus_dma_tag_create(
250                                 /* parent       */ adv->parent_dmat,
251                                 /* alignment    */ 8,
252                                 /* boundary     */ 0,
253                                 /* lowaddr      */ ADV_EISA_MAX_DMA_ADDR,
254                                 /* highaddr     */ BUS_SPACE_MAXADDR,
255                                 /* filter       */ NULL,
256                                 /* filterarg    */ NULL,
257                                 /* maxsize      */ ADV_OVERRUN_BSIZE,
258                                 /* nsegments    */ 1,
259                                 /* maxsegsz     */ BUS_SPACE_MAXSIZE_32BIT,
260                                 /* flags        */ 0,
261                                 /* lockfunc     */ busdma_lock_mutex,
262                                 /* lockarg      */ &Giant,
263                                 &overrun_dmat) != 0) {
264                         adv_free(adv);
265                         goto bad;
266                 }
267                 if (bus_dmamem_alloc(overrun_dmat,
268                                      (void **)&overrun_buf,
269                                      BUS_DMA_NOWAIT,
270                                      &overrun_dmamap) != 0) {
271                         bus_dma_tag_destroy(overrun_dmat);
272                         adv_free(adv);
273                         goto bad;
274                 }
275                 /* And permanently map it in */  
276                 bus_dmamap_load(overrun_dmat, overrun_dmamap,
277                                 overrun_buf, ADV_OVERRUN_BSIZE,
278                                 adv_map, &overrun_physbase,
279                                 /*flags*/0);
280         }
281         
282         /*
283          * Now that we know we own the resources we need, do the 
284          * card initialization.
285          */
286
287         /*
288          * Stop the chip.
289          */
290         ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
291         ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
292
293         adv->chip_version = EISA_REVISION_ID(eisa_get_id(dev))
294                           + ADV_CHIP_MIN_VER_EISA - 1;
295
296         if (adv_init(adv) != 0) {
297                 adv_free(adv);
298                 if (adv_b != NULL)
299                         adv_free(adv_b);
300                 return(-1);
301         }
302
303         adv->max_dma_count = ADV_EISA_MAX_DMA_COUNT;
304         adv->max_dma_addr = ADV_EISA_MAX_DMA_ADDR;
305
306         if (adv_b != NULL) {
307                 /*
308                  * Stop the chip.
309                  */
310                 ADV_OUTB(adv_b, ADV_CHIP_CTRL, ADV_CC_HALT);
311                 ADV_OUTW(adv_b, ADV_CHIP_STATUS, 0);
312
313                 adv_b->chip_version = EISA_REVISION_ID(eisa_get_id(dev))
314                                     + ADV_CHIP_MIN_VER_EISA - 1;
315
316                 if (adv_init(adv_b) != 0) {
317                         adv_free(adv_b);
318                 } else {
319                         adv_b->max_dma_count = ADV_EISA_MAX_DMA_COUNT;
320                         adv_b->max_dma_addr = ADV_EISA_MAX_DMA_ADDR;
321                 }
322         }
323
324         /*
325          * Enable our interrupt handler.
326          */
327         bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY, adv_intr, adv, &ih);
328
329         /* Attach sub-devices - always succeeds */
330         adv_attach(adv);
331         if (adv_b != NULL)
332                 adv_attach(adv_b);
333
334         return 0;
335
336  bad:
337         bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
338         bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
339         return -1;
340 }
341
342 static device_method_t adv_eisa_methods[] = {
343         /* Device interface */
344         DEVMETHOD(device_probe,         adv_eisa_probe),
345         DEVMETHOD(device_attach,        adv_eisa_attach),
346         { 0, 0 }
347 };
348
349 static driver_t adv_eisa_driver = {
350         "adv", adv_eisa_methods, sizeof(struct adv_softc)
351 };
352
353 static devclass_t adv_eisa_devclass;
354 DRIVER_MODULE(adv, eisa, adv_eisa_driver, adv_eisa_devclass, 0, 0);