a0f3c23086c80741a335ccc394132565b8785594
[dragonfly.git] / sys / dev / disk / advansys / adv_isa.c
1 /*
2  * Device probe and attach routines for the following
3  * Advanced Systems Inc. SCSI controllers:
4  *
5  *   Connectivity Products:
6  *      ABP510/5150 - Bus-Master ISA (240 CDB) *
7  *      ABP5140 - Bus-Master ISA PnP (16 CDB) * **
8  *      ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) ***
9  *
10  *   Single Channel Products:
11  *      ABP542 - Bus-Master ISA with floppy (240 CDB)
12  *      ABP842 - Bus-Master VL (240 CDB) 
13  *
14  *   Dual Channel Products:  
15  *      ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
16  *
17  *    * This board has been shipped by HP with the 4020i CD-R drive.
18  *      The board has no BIOS so it cannot control a boot device, but 
19  *      it can control any secondary SCSI device.
20  *   ** This board has been sold by SIIG as the i540 SpeedMaster.
21  *  *** This board has been sold by SIIG as the i542 SpeedMaster.
22  *
23  * Copyright (c) 1996, 1997 Justin T. Gibbs.
24  * All rights reserved.
25  *
26  * Redistribution and use in source and binary forms, with or without
27  * modification, are permitted provided that the following conditions
28  * are met:
29  * 1. Redistributions of source code must retain the above copyright
30  *    notice, this list of conditions, and the following disclaimer,
31  *    without modification, immediately at the beginning of the file.
32  * 2. The name of the author may not be used to endorse or promote products
33  *    derived from this software without specific prior written permission.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
36  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
39  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45  * SUCH DAMAGE.
46  *
47  * $FreeBSD: src/sys/dev/advansys/adv_isa.c,v 1.14.2.5 2002/01/06 21:21:42 dwmalone Exp $
48  * $DragonFly: src/sys/dev/disk/advansys/adv_isa.c,v 1.6 2006/10/25 20:55:52 dillon Exp $
49  */
50
51 #include <sys/param.h>
52 #include <sys/systm.h> 
53 #include <sys/kernel.h> 
54 #include <sys/bus.h> 
55 #include <sys/rman.h> 
56
57 #include <bus/isa/isavar.h>
58
59 #include "advansys.h"
60
61 #include <bus/cam/scsi/scsi_all.h>
62
63 #define ADV_ISA_MAX_DMA_ADDR    (0x00FFFFFFL)
64 #define ADV_ISA_MAX_DMA_COUNT   (0x00FFFFFFL)
65
66 #define ADV_VL_MAX_DMA_ADDR     (0x07FFFFFFL)
67 #define ADV_VL_MAX_DMA_COUNT    (0x07FFFFFFL)
68
69 /*
70  * The overrun buffer shared amongst all ISA/VL adapters.
71  */
72 static  u_int8_t*       overrun_buf;
73 static  bus_dma_tag_t   overrun_dmat;
74 static  bus_dmamap_t    overrun_dmamap;
75 static  bus_addr_t      overrun_physbase;
76
77 /* Possible port addresses an ISA or VL adapter can live at */
78 static u_int16_t adv_isa_ioports[] =
79 {
80         0x100,
81         0x110,  /* First selection in BIOS setup */
82         0x120,
83         0x130,  /* Second selection in BIOS setup */
84         0x140,
85         0x150,  /* Third selection in BIOS setup */
86         0x190,  /* Fourth selection in BIOS setup */
87         0x210,  /* Fifth selection in BIOS setup */
88         0x230,  /* Sixth selection in BIOS setup */
89         0x250,  /* Seventh selection in BIOS setup */
90         0x330   /* Eighth and default selection in BIOS setup */
91 };
92
93 #define MAX_ISA_IOPORT_INDEX (sizeof(adv_isa_ioports)/sizeof(u_int16_t) - 1)
94
95 static  int     adv_isa_probe(device_t dev);
96 static  int     adv_isa_attach(device_t dev);
97 static  void    adv_set_isapnp_wait_for_key(void);
98 static  int     adv_get_isa_dma_channel(struct adv_softc *adv);
99 static  int     adv_set_isa_dma_settings(struct adv_softc *adv);
100
101 static int
102 adv_isa_probe(device_t dev)
103 {
104         int     port_index;
105         int     max_port_index;
106         u_long  iobase, iocount, irq;
107         int     user_iobase = 0;
108         int     rid = 0;
109         void    *ih;
110         struct resource *iores, *irqres;
111
112         /*
113          * Default to scanning all possible device locations.
114          */
115         port_index = 0;
116         max_port_index = MAX_ISA_IOPORT_INDEX;
117
118         if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, &iocount) == 0) {
119                 user_iobase = 1;
120                 for (;port_index <= max_port_index; port_index++)
121                         if (iobase <= adv_isa_ioports[port_index])
122                                 break;
123                 if ((port_index > max_port_index)
124                  || (iobase != adv_isa_ioports[port_index])) {
125                         if (bootverbose)
126                             printf("adv%d: Invalid baseport of 0x%lx specified. "
127                                 "Nearest valid baseport is 0x%x.  Failing "
128                                 "probe.\n", device_get_unit(dev), iobase,
129                                 (port_index <= max_port_index) ?
130                                         adv_isa_ioports[port_index] :
131                                         adv_isa_ioports[max_port_index]);
132                         return ENXIO;
133                 }
134                 max_port_index = port_index;
135         }
136
137         /* Perform the actual probing */
138         adv_set_isapnp_wait_for_key();
139         for (;port_index <= max_port_index; port_index++) {
140                 u_int16_t port_addr = adv_isa_ioports[port_index];
141                 bus_size_t maxsegsz;
142                 bus_size_t maxsize;
143                 bus_addr_t lowaddr;
144                 int error;
145                 struct adv_softc *adv;
146
147                 if (port_addr == 0)
148                         /* Already been attached */
149                         continue;
150                 
151                 if (bus_set_resource(dev, SYS_RES_IOPORT, 0, port_addr, 1))
152                         continue;
153
154                 /* XXX what is the real portsize? */
155                 iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
156                                            RF_ACTIVE);
157                 if (iores == NULL)
158                         continue;
159
160                 if (adv_find_signature(rman_get_bustag(iores),
161                                        rman_get_bushandle(iores)) == 0) {
162                         bus_release_resource(dev, SYS_RES_IOPORT, 0, iores);
163                         continue;
164                 }
165
166                 /*
167                  * Got one.  Now allocate our softc
168                  * and see if we can initialize the card.
169                  */
170                 adv = adv_alloc(dev, rman_get_bustag(iores),
171                                 rman_get_bushandle(iores));
172                 if (adv == NULL) {
173                         bus_release_resource(dev, SYS_RES_IOPORT, 0, iores);
174                         break;
175                 }
176
177                 /*
178                  * Stop the chip.
179                  */
180                 ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
181                 ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
182                 /*
183                  * Determine the chip version.
184                  */
185                 adv->chip_version = ADV_INB(adv, ADV_NONEISA_CHIP_REVISION);
186                 if ((adv->chip_version >= ADV_CHIP_MIN_VER_VL)
187                     && (adv->chip_version <= ADV_CHIP_MAX_VER_VL)) {
188                         adv->type = ADV_VL;
189                         maxsegsz = ADV_VL_MAX_DMA_COUNT;
190                         maxsize = BUS_SPACE_MAXSIZE_32BIT;
191                         lowaddr = ADV_VL_MAX_DMA_ADDR;
192                         bus_delete_resource(dev, SYS_RES_DRQ, 0);
193                 } else if ((adv->chip_version >= ADV_CHIP_MIN_VER_ISA)
194                            && (adv->chip_version <= ADV_CHIP_MAX_VER_ISA)) {
195                         if (adv->chip_version >= ADV_CHIP_MIN_VER_ISA_PNP) {
196                                 adv->type = ADV_ISAPNP;
197                                 ADV_OUTB(adv, ADV_REG_IFC,
198                                          ADV_IFC_INIT_DEFAULT);
199                         } else {
200                                 adv->type = ADV_ISA;
201                         }
202                         maxsegsz = ADV_ISA_MAX_DMA_COUNT;
203                         maxsize = BUS_SPACE_MAXSIZE_24BIT;
204                         lowaddr = ADV_ISA_MAX_DMA_ADDR;
205                         adv->isa_dma_speed = ADV_DEF_ISA_DMA_SPEED;
206                         adv->isa_dma_channel = adv_get_isa_dma_channel(adv);
207                         bus_set_resource(dev, SYS_RES_DRQ, 0,
208                                          adv->isa_dma_channel, 1);
209                 } else {
210                         panic("advisaprobe: Unknown card revision\n");
211                 }
212
213                 /*
214                  * Allocate a parent dmatag for all tags created
215                  * by the MI portions of the advansys driver
216                  */
217                 /* XXX Should be a child of the ISA bus dma tag */ 
218                 error = bus_dma_tag_create(/*parent*/NULL,
219                                            /*alignemnt*/1,
220                                            /*boundary*/0,
221                                            lowaddr,
222                                            /*highaddr*/BUS_SPACE_MAXADDR,
223                                            /*filter*/NULL,
224                                            /*filterarg*/NULL,
225                                            maxsize,
226                                            /*nsegs*/BUS_SPACE_UNRESTRICTED,
227                                            maxsegsz,
228                                            /*flags*/0,
229                                            &adv->parent_dmat); 
230
231                 if (error != 0) {
232                         printf("%s: Could not allocate DMA tag - error %d\n",
233                                adv_name(adv), error); 
234                         adv_free(adv); 
235                         bus_release_resource(dev, SYS_RES_IOPORT, 0, iores);
236                         break;
237                 }
238
239                 adv->init_level += 2;
240
241                 if (overrun_buf == NULL) {
242                         /* Need to allocate our overrun buffer */
243                         if (bus_dma_tag_create(adv->parent_dmat,
244                                                /*alignment*/8,
245                                                /*boundary*/0,
246                                                ADV_ISA_MAX_DMA_ADDR,
247                                                BUS_SPACE_MAXADDR,
248                                                /*filter*/NULL,
249                                                /*filterarg*/NULL,
250                                                ADV_OVERRUN_BSIZE,
251                                                /*nsegments*/1,
252                                                BUS_SPACE_MAXSIZE_32BIT,
253                                                /*flags*/0,
254                                                &overrun_dmat) != 0) {
255                                 adv_free(adv);
256                                 bus_release_resource(dev, SYS_RES_IOPORT, 0,
257                                                      iores);
258                                 break;
259                         }
260                         if (bus_dmamem_alloc(overrun_dmat,
261                                              (void **)&overrun_buf,
262                                              BUS_DMA_NOWAIT,
263                                              &overrun_dmamap) != 0) {
264                                 bus_dma_tag_destroy(overrun_dmat);
265                                 adv_free(adv);
266                                 bus_release_resource(dev, SYS_RES_IOPORT, 0,
267                                                      iores);
268                                 break;
269                         }
270                         /* And permanently map it in */  
271                         bus_dmamap_load(overrun_dmat, overrun_dmamap,
272                                         overrun_buf, ADV_OVERRUN_BSIZE,
273                                         adv_map, &overrun_physbase,
274                                         /*flags*/0);
275                 }
276
277                 adv->overrun_physbase = overrun_physbase;
278
279                 if (adv_init(adv) != 0) {
280                         bus_dmamap_unload(overrun_dmat, overrun_dmamap);
281                         bus_dmamem_free(overrun_dmat, overrun_buf,
282                             overrun_dmamap);
283                         bus_dma_tag_destroy(overrun_dmat);
284                         adv_free(adv);
285                         bus_release_resource(dev, SYS_RES_IOPORT, 0, iores);
286                         break;
287                 }
288
289                 switch (adv->type) {
290                 case ADV_ISAPNP:
291                         if (adv->chip_version == ADV_CHIP_VER_ASYN_BUG) {
292                                 adv->bug_fix_control
293                                     |= ADV_BUG_FIX_ASYN_USE_SYN;
294                                 adv->fix_asyn_xfer = ~0;
295                         }
296                         /* Fall Through */
297                 case ADV_ISA:
298                         adv->max_dma_count = ADV_ISA_MAX_DMA_COUNT;
299                         adv->max_dma_addr = ADV_ISA_MAX_DMA_ADDR;
300                         adv_set_isa_dma_settings(adv);
301                         break;
302
303                 case ADV_VL:
304                         adv->max_dma_count = ADV_VL_MAX_DMA_COUNT;
305                         adv->max_dma_addr = ADV_VL_MAX_DMA_ADDR;
306                         break;
307                 default:
308                         panic("advisaprobe: Invalid card type\n");
309                 }
310                         
311                 /* Determine our IRQ */
312                 if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL))
313                         bus_set_resource(dev, SYS_RES_IRQ, 0,
314                                          adv_get_chip_irq(adv), 1);
315                 else
316                         adv_set_chip_irq(adv, irq);
317
318                 irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
319                                             RF_ACTIVE);
320                 if (irqres == NULL ||
321                     bus_setup_intr(dev, irqres, 0, adv_intr, adv,
322                                    &ih, NULL)) {
323                         bus_dmamap_unload(overrun_dmat, overrun_dmamap);
324                         bus_dmamem_free(overrun_dmat, overrun_buf,
325                             overrun_dmamap);
326                         bus_dma_tag_destroy(overrun_dmat);
327                         adv_free(adv);
328                         bus_release_resource(dev, SYS_RES_IOPORT, 0, iores);
329                         break;
330                 }
331
332                 /* Mark as probed */
333                 adv_isa_ioports[port_index] = 0;
334                 return 0;
335         }
336
337         if (user_iobase)
338                 bus_set_resource(dev, SYS_RES_IOPORT, 0, iobase, iocount);
339         else
340                 bus_delete_resource(dev, SYS_RES_IOPORT, 0);
341
342         return ENXIO;
343 }
344
345 static int
346 adv_isa_attach(device_t dev)
347 {
348         struct adv_softc *adv = device_get_softc(dev);
349
350         return (adv_attach(adv));
351 }
352
353 static int
354 adv_get_isa_dma_channel(struct adv_softc *adv)
355 {
356         int channel;
357
358         channel = ADV_INW(adv, ADV_CONFIG_LSW) & ADV_CFG_LSW_ISA_DMA_CHANNEL;  
359         if (channel == 0x03)
360                 return (0);
361         else if (channel == 0x00)
362                 return (7);
363         return (channel + 4);
364 }
365
366 static int
367 adv_set_isa_dma_settings(struct adv_softc *adv)
368 {
369         u_int16_t cfg_lsw;
370         u_int8_t  value;
371
372         if ((adv->isa_dma_channel >= 5) && (adv->isa_dma_channel <= 7)) { 
373                 if (adv->isa_dma_channel == 7)
374                         value = 0x00;
375                 else     
376                         value = adv->isa_dma_channel - 4;
377                 cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW)
378                         & ~ADV_CFG_LSW_ISA_DMA_CHANNEL;  
379                 cfg_lsw |= value;
380                 ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
381
382                 adv->isa_dma_speed &= 0x07;
383                 adv_set_bank(adv, 1);
384                 ADV_OUTB(adv, ADV_DMA_SPEED, adv->isa_dma_speed);
385                 adv_set_bank(adv, 0);
386                 isa_dmacascade(adv->isa_dma_channel);
387         }
388         return (0);
389 }
390
391 static void
392 adv_set_isapnp_wait_for_key(void)
393 {
394         static  int isapnp_wait_set = 0;
395         if (isapnp_wait_set == 0) {
396                 outb(ADV_ISA_PNP_PORT_ADDR, 0x02);
397                 outb(ADV_ISA_PNP_PORT_WRITE, 0x02);
398                 isapnp_wait_set++;
399         }
400 }
401
402 static device_method_t adv_isa_methods[] = {
403         /* Device interface */
404         DEVMETHOD(device_probe,         adv_isa_probe),
405         DEVMETHOD(device_attach,        adv_isa_attach),
406         { 0, 0 }
407 };
408
409 static driver_t adv_isa_driver = {
410         "adv", adv_isa_methods, sizeof(struct adv_softc)
411 };
412
413 static devclass_t adv_isa_devclass;
414 DRIVER_MODULE(adv, isa, adv_isa_driver, adv_isa_devclass, 0, 0);