1139749Simp/*- 239223Sgibbs * Product specific probe and attach routines for: 339223Sgibbs * Buslogic BT74x SCSI controllers 439223Sgibbs * 544580Sgibbs * Copyright (c) 1995, 1998, 1999 Justin T. Gibbs 639223Sgibbs * All rights reserved. 739223Sgibbs * 839223Sgibbs * Redistribution and use in source and binary forms, with or without 939223Sgibbs * modification, are permitted provided that the following conditions 1039223Sgibbs * are met: 1139223Sgibbs * 1. Redistributions of source code must retain the above copyright 1239223Sgibbs * notice immediately at the beginning of the file, without modification, 1339223Sgibbs * this list of conditions, and the following disclaimer. 1439223Sgibbs * 2. The name of the author may not be used to endorse or promote products 1539223Sgibbs * derived from this software without specific prior written permission. 1639223Sgibbs * 1739223Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1839223Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1939223Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2039223Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2139223Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2239223Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2339223Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2439223Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2539223Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2639223Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2739223Sgibbs * SUCH DAMAGE. 2839223Sgibbs * 2939223Sgibbs */ 3039223Sgibbs 31119418Sobrien#include <sys/cdefs.h> 32119418Sobrien__FBSDID("$FreeBSD$"); 33119418Sobrien 3439223Sgibbs#include <sys/param.h> 3539223Sgibbs#include <sys/systm.h> 3639223Sgibbs#include <sys/kernel.h> 3745791Speter#include <sys/module.h> 38117126Sscottl#include <sys/lock.h> 39117126Sscottl#include <sys/mutex.h> 4045791Speter#include <sys/bus.h> 4139223Sgibbs 4239223Sgibbs#include <machine/bus.h> 4345791Speter#include <machine/resource.h> 4445791Speter#include <sys/rman.h> 4539223Sgibbs 4655953Speter#include <dev/eisa/eisaconf.h> 4739223Sgibbs 4839223Sgibbs#include <dev/buslogic/btreg.h> 4939223Sgibbs 5039223Sgibbs#define EISA_DEVICE_ID_BUSLOGIC_74X_B 0x0ab34201 5139223Sgibbs#define EISA_DEVICE_ID_BUSLOGIC_74X_C 0x0ab34202 5268661Sgibbs#define EISA_DEVICE_ID_SDC3222B 0x0ab34281 5339223Sgibbs#define EISA_DEVICE_ID_SDC3222F 0x0ab34781 5468661Sgibbs#define EISA_DEVICE_ID_SDC3222WS 0x0ab34981 5568661Sgibbs#define EISA_DEVICE_ID_SDC3222WB 0x0ab34982 5639223Sgibbs#define EISA_DEVICE_ID_AMI_4801 0x05a94801 5739223Sgibbs 5839223Sgibbs#define BT_IOSIZE 0x04 /* Move to central header */ 5939223Sgibbs#define BT_EISA_IOSIZE 0x100 6039223Sgibbs#define BT_EISA_SLOT_OFFSET 0xc00 6139223Sgibbs 6239223Sgibbs#define EISA_IOCONF 0x08C 6339223Sgibbs#define PORTADDR 0x07 6439223Sgibbs#define PORT_330 0x00 6539223Sgibbs#define PORT_334 0x01 6639223Sgibbs#define PORT_230 0x02 6739223Sgibbs#define PORT_234 0x03 6839223Sgibbs#define PORT_130 0x04 6939223Sgibbs#define PORT_134 0x05 7039223Sgibbs#define IRQ_CHANNEL 0xe0 7139223Sgibbs#define INT_11 0x40 7239223Sgibbs#define INT_10 0x20 7339223Sgibbs#define INT_15 0xa0 7439223Sgibbs#define INT_12 0x60 7539223Sgibbs#define INT_14 0x80 7639223Sgibbs#define INT_9 0x00 7739223Sgibbs 7839223Sgibbs#define EISA_IRQ_TYPE 0x08D 7939223Sgibbs#define LEVEL 0x40 8039223Sgibbs 8139223Sgibbs/* Definitions for the AMI Series 48 controler */ 8239223Sgibbs#define AMI_EISA_IOSIZE 0x500 /* Two separate ranges?? */ 8339223Sgibbs#define AMI_EISA_SLOT_OFFSET 0x800 8439223Sgibbs#define AMI_EISA_IOCONF 0x000 8539223Sgibbs#define AMI_DMA_CHANNEL 0x03 8639223Sgibbs#define AMI_IRQ_CHANNEL 0x1c 8739223Sgibbs#define AMI_INT_15 0x14 8839223Sgibbs#define AMI_INT_14 0x10 8939223Sgibbs#define AMI_INT_12 0x0c 9039223Sgibbs#define AMI_INT_11 0x00 9139223Sgibbs#define AMI_INT_10 0x08 9239223Sgibbs#define AMI_INT_9 0x04 9339223Sgibbs#define AMI_BIOS_ADDR 0xe0 9439223Sgibbs 9539223Sgibbs#define AMI_EISA_IOCONF1 0x001 9639223Sgibbs#define AMI_PORTADDR 0x0e 9739223Sgibbs#define AMI_PORT_334 0x08 9839223Sgibbs#define AMI_PORT_330 0x00 9939223Sgibbs#define AMI_PORT_234 0x0c 10039223Sgibbs#define AMI_PORT_230 0x04 10139223Sgibbs#define AMI_PORT_134 0x0a 10239223Sgibbs#define AMI_PORT_130 0x02 10339223Sgibbs#define AMI_IRQ_LEVEL 0x01 10439223Sgibbs 10539223Sgibbs 10639223Sgibbs#define AMI_MISC2_OPTIONS 0x49E 10739223Sgibbs#define AMI_ENABLE_ISA_DMA 0x08 10839223Sgibbs 10945791Speterstatic const char *bt_match(eisa_id_t type); 11039223Sgibbs 11145791Speterstatic int 11245791Speterbt_eisa_alloc_resources(device_t dev) 11345791Speter{ 11445791Speter struct bt_softc *bt = device_get_softc(dev); 11545791Speter int rid; 11645791Speter struct resource *port; 11745791Speter struct resource *irq; 11845791Speter int shared; 11939223Sgibbs 12045791Speter /* 12145791Speter * XXX assumes that the iospace ranges are sorted in increasing 12245791Speter * order. 12345791Speter */ 12445859Sdfr rid = 0; 125127135Snjl port = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 12645791Speter if (!port) 12745791Speter return (ENOMEM); 12839223Sgibbs 12945791Speter bt_init_softc(dev, port, 0, 0); 13039223Sgibbs 13145791Speter if (eisa_get_irq(dev) != -1) { 13245791Speter shared = bt->level_trigger_ints ? RF_SHAREABLE : 0; 13345791Speter rid = 0; 134127135Snjl irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 135127135Snjl shared | RF_ACTIVE); 13645791Speter if (!irq) { 13745791Speter if (port) 13845791Speter bus_release_resource(dev, SYS_RES_IOPORT, 13945791Speter 0, port); 14045791Speter return (ENOMEM); 14145791Speter } 14245791Speter } else 143241592Sjhb irq = NULL; 14445791Speter bt->irq = irq; 14545791Speter 14645791Speter return (0); 14745791Speter} 14845791Speter 14945791Speterstatic void 15045791Speterbt_eisa_release_resources(device_t dev) 15145791Speter{ 15245791Speter struct bt_softc *bt = device_get_softc(dev); 15345791Speter 15445791Speter if (bt->port) 15545791Speter bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port); 15645791Speter if (bt->irq) 15745984Speter bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq); 15845791Speter bt_free_softc(dev); 15945791Speter} 16045791Speter 16139223Sgibbsstatic const char* 16239223Sgibbsbt_match(eisa_id_t type) 16339223Sgibbs{ 16439223Sgibbs switch(type) { 16539223Sgibbs case EISA_DEVICE_ID_BUSLOGIC_74X_B: 16639223Sgibbs return ("Buslogic 74xB SCSI host adapter"); 16739223Sgibbs case EISA_DEVICE_ID_BUSLOGIC_74X_C: 16839223Sgibbs return ("Buslogic 74xC SCSI host adapter"); 16968661Sgibbs case EISA_DEVICE_ID_SDC3222B: 17068661Sgibbs return ("Storage Dimensions SDC3222B SCSI host adapter"); 17139223Sgibbs case EISA_DEVICE_ID_SDC3222F: 17239223Sgibbs return ("Storage Dimensions SDC3222F SCSI host adapter"); 17368661Sgibbs case EISA_DEVICE_ID_SDC3222WS: 17468661Sgibbs return ("Storage Dimensions SDC3222WS SCSI host adapter"); 17568661Sgibbs case EISA_DEVICE_ID_SDC3222WB: 17668661Sgibbs return ("Storage Dimensions SDC3222WB SCSI host adapter"); 17739223Sgibbs case EISA_DEVICE_ID_AMI_4801: 17839223Sgibbs return ("AMI Series 48 SCSI host adapter"); 17939223Sgibbs default: 18039223Sgibbs break; 18139223Sgibbs } 18239223Sgibbs return (NULL); 18339223Sgibbs} 18439223Sgibbs 18539223Sgibbsstatic int 18645791Speterbt_eisa_probe(device_t dev) 18739223Sgibbs{ 18845791Speter const char *desc; 18939223Sgibbs u_long iobase; 19045791Speter struct bt_probe_info info; 19145791Speter u_long port; 19245791Speter u_long iosize; 19345791Speter u_int ioconf; 19445791Speter int result; 19549360Smdodd int shared; 19639223Sgibbs 19745791Speter desc = bt_match(eisa_get_id(dev)); 19845791Speter if (!desc) 19945791Speter return (ENXIO); 20045791Speter device_set_desc(dev, desc); 20139223Sgibbs 20245791Speter iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE); 20345791Speter if (eisa_get_id(dev) == EISA_DEVICE_ID_AMI_4801) { 20445791Speter u_int ioconf1; 20544580Sgibbs 20645791Speter iobase += AMI_EISA_SLOT_OFFSET; 20745791Speter iosize = AMI_EISA_IOSIZE; 20845791Speter ioconf1 = inb(iobase + AMI_EISA_IOCONF1); 20945791Speter /* Determine "ISA" I/O port */ 21045791Speter switch (ioconf1 & AMI_PORTADDR) { 21145791Speter case AMI_PORT_330: 21245791Speter port = 0x330; 21345791Speter break; 21445791Speter case AMI_PORT_334: 21545791Speter port = 0x334; 21645791Speter break; 21745791Speter case AMI_PORT_230: 21845791Speter port = 0x230; 21945791Speter break; 22045791Speter case AMI_PORT_234: 22145791Speter port = 0x234; 22245791Speter break; 22345791Speter case AMI_PORT_134: 22445791Speter port = 0x134; 22545791Speter break; 22645791Speter case AMI_PORT_130: 22745791Speter port = 0x130; 22845791Speter break; 22945791Speter default: 23045791Speter /* Disabled */ 23145791Speter printf("bt: AMI EISA Adapter at " 23245791Speter "slot %d has a disabled I/O " 23345791Speter "port. Cannot attach.\n", 23445791Speter eisa_get_slot(dev)); 23545791Speter return (ENXIO); 23644580Sgibbs } 23749360Smdodd shared = (inb(iobase + AMI_EISA_IOCONF1) & AMI_IRQ_LEVEL) ? 23849360Smdodd EISA_TRIGGER_LEVEL : EISA_TRIGGER_EDGE; 23945791Speter } else { 24045791Speter iobase += BT_EISA_SLOT_OFFSET; 24145791Speter iosize = BT_EISA_IOSIZE; 24239223Sgibbs 24345791Speter ioconf = inb(iobase + EISA_IOCONF); 24445791Speter /* Determine "ISA" I/O port */ 24545791Speter switch (ioconf & PORTADDR) { 24645791Speter case PORT_330: 24745791Speter port = 0x330; 24845791Speter break; 24945791Speter case PORT_334: 25045791Speter port = 0x334; 25145791Speter break; 25245791Speter case PORT_230: 25345791Speter port = 0x230; 25445791Speter break; 25545791Speter case PORT_234: 25645791Speter port = 0x234; 25745791Speter break; 25845791Speter case PORT_130: 25945791Speter port = 0x130; 26045791Speter break; 26145791Speter case PORT_134: 26245791Speter port = 0x134; 26345791Speter break; 26445791Speter default: 26545791Speter /* Disabled */ 26645791Speter printf("bt: Buslogic EISA Adapter at " 26745791Speter "slot %d has a disabled I/O " 26845791Speter "port. Cannot attach.\n", 26945791Speter eisa_get_slot(dev)); 27045791Speter return (ENXIO); 27139223Sgibbs } 27249360Smdodd shared = (inb(iobase + EISA_IRQ_TYPE) & LEVEL) ? 27349360Smdodd EISA_TRIGGER_LEVEL : EISA_TRIGGER_EDGE; 27445791Speter } 27545791Speter bt_mark_probed_iop(port); 27639223Sgibbs 27745791Speter /* Tell parent where our resources are going to be */ 27845791Speter eisa_add_iospace(dev, iobase, iosize, RESVADDR_NONE); 27945791Speter eisa_add_iospace(dev, port, BT_IOSIZE, RESVADDR_NONE); 28039223Sgibbs 28145791Speter /* And allocate them */ 28245791Speter bt_eisa_alloc_resources(dev); 28344580Sgibbs 28445791Speter if (bt_port_probe(dev, &info) != 0) { 28545791Speter printf("bt_eisa_probe: Probe failed for " 28645791Speter "card at slot 0x%x\n", eisa_get_slot(dev)); 28745791Speter result = ENXIO; 28845791Speter } else { 28949360Smdodd eisa_add_intr(dev, info.irq, shared); 290241592Sjhb result = BUS_PROBE_DEFAULT; 29139223Sgibbs } 29245791Speter bt_eisa_release_resources(dev); 29345791Speter 29445791Speter return (result); 29539223Sgibbs} 29639223Sgibbs 29739223Sgibbsstatic int 29845791Speterbt_eisa_attach(device_t dev) 29939223Sgibbs{ 30045791Speter struct bt_softc *bt = device_get_softc(dev); 30139223Sgibbs 30245791Speter /* Allocate resources */ 30345791Speter bt_eisa_alloc_resources(dev); 30439223Sgibbs 30539223Sgibbs /* Allocate a dmatag for our SCB DMA maps */ 30639223Sgibbs /* XXX Should be a child of the PCI bus dma tag */ 307112782Smdodd if (bus_dma_tag_create( /* parent */ NULL, 308112782Smdodd /* alignment */ 1, 309112782Smdodd /* boundary */ 0, 310112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 311112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 312112782Smdodd /* filter */ NULL, 313112782Smdodd /* filterarg */ NULL, 314112782Smdodd /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 315112782Smdodd /* nsegments */ ~0, 316112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 317112782Smdodd /* flags */ 0, 318241592Sjhb /* lockfunc */ NULL, 319241592Sjhb /* lockarg, */ NULL, 320112782Smdodd &bt->parent_dmat) != 0) { 32145791Speter bt_eisa_release_resources(dev); 322241592Sjhb return (ENOMEM); 32339223Sgibbs } 32439223Sgibbs 32539223Sgibbs /* 32639223Sgibbs * Now that we know we own the resources we need, do the full 32739223Sgibbs * card initialization. 32839223Sgibbs */ 32945791Speter if (bt_probe(dev) || bt_fetch_adapter_info(dev) || bt_init(dev)) { 33045791Speter bt_eisa_release_resources(dev); 331241592Sjhb return (ENXIO); 33239223Sgibbs } 33339223Sgibbs 33445791Speter /* Attach sub-devices - always succeeds (sets up intr) */ 33545791Speter bt_attach(dev); 33639223Sgibbs 33739223Sgibbs return 0; 33839223Sgibbs} 33939223Sgibbs 34045791Speterstatic device_method_t bt_eisa_methods[] = { 34145791Speter /* Device interface */ 34245791Speter DEVMETHOD(device_probe, bt_eisa_probe), 34345791Speter DEVMETHOD(device_attach, bt_eisa_attach), 34445791Speter 34545791Speter { 0, 0 } 34645791Speter}; 34745791Speter 34845791Speterstatic driver_t bt_eisa_driver = { 34945791Speter "bt", 35045791Speter bt_eisa_methods, 35145791Speter sizeof(struct bt_softc), 35245791Speter}; 35345791Speter 35445791Speterstatic devclass_t bt_devclass; 35545791Speter 35645791SpeterDRIVER_MODULE(bt, eisa, bt_eisa_driver, bt_devclass, 0, 0); 357165102SmjacobMODULE_DEPEND(bt, eisa, 1, 1, 1); 358