adv_pci.c revision 76307
139217Sgibbs/*
239217Sgibbs * Device probe and attach routines for the following
339217Sgibbs * Advanced Systems Inc. SCSI controllers:
439217Sgibbs *
539217Sgibbs *   Connectivity Products:
655945Sgibbs *	ABP902/3902	- Bus-Master PCI (16 CDB)
755945Sgibbs *	ABP3905		- Bus-Master PCI (16 CDB)
855945Sgibbs *	ABP915		- Bus-Master PCI (16 CDB)
955945Sgibbs *	ABP920		- Bus-Master PCI (16 CDB)
1055945Sgibbs *	ABP3922		- Bus-Master PCI (16 CDB)
1155945Sgibbs *	ABP3925		- Bus-Master PCI (16 CDB)
1255945Sgibbs *	ABP930		- Bus-Master PCI (16 CDB) *
1355945Sgibbs *	ABP930U		- Bus-Master PCI Ultra (16 CDB)
1455945Sgibbs *	ABP930UA	- Bus-Master PCI Ultra (16 CDB)
1555945Sgibbs *	ABP960		- Bus-Master PCI MAC/PC (16 CDB) **
1657679Sgibbs *	ABP960U		- Bus-Master PCI MAC/PC (16 CDB) **
1739217Sgibbs *
1839217Sgibbs *   Single Channel Products:
1957679Sgibbs *	ABP940		- Bus-Master PCI (240 CDB)
2057679Sgibbs *	ABP940U		- Bus-Master PCI Ultra (240 CDB)
2157679Sgibbs *	ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
2257679Sgibbs *	ABP3960UA	- Bus-Master PCI MAC/PC (240 CDB)
2357679Sgibbs *	ABP970		- Bus-Master PCI MAC/PC (240 CDB)
2457679Sgibbs *	ABP970U		- Bus-Master PCI MAC/PC Ultra (240 CDB)
2539217Sgibbs *
2639217Sgibbs *   Dual Channel Products:
2739217Sgibbs *	ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
2857679Sgibbs *      ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
2957679Sgibbs *      ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
3055945Sgibbs *	ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
3139217Sgibbs *
3239217Sgibbs *   Footnotes:
3339217Sgibbs *	 * This board has been sold by SIIG as the Fast SCSI Pro PCI.
3439217Sgibbs *	** This board has been sold by Iomega as a Jaz Jet PCI adapter.
3539217Sgibbs *
3639217Sgibbs * Copyright (c) 1997 Justin Gibbs.
3739217Sgibbs * All rights reserved.
3839217Sgibbs *
3939217Sgibbs * Redistribution and use in source and binary forms, with or without
4039217Sgibbs * modification, are permitted provided that the following conditions
4139217Sgibbs * are met:
4239217Sgibbs * 1. Redistributions of source code must retain the above copyright
4339217Sgibbs *    notice, this list of conditions, and the following disclaimer,
4455945Sgibbs *    without modification.
4539217Sgibbs * 2. The name of the author may not be used to endorse or promote products
4639217Sgibbs *    derived from this software without specific prior written permission.
4739217Sgibbs *
4839217Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4939217Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5039217Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5139217Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
5239217Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5339217Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5439217Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5539217Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5639217Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5739217Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5839217Sgibbs * SUCH DAMAGE.
5939217Sgibbs *
6050477Speter * $FreeBSD: head/sys/dev/advansys/adv_pci.c 76307 2001-05-06 08:33:29Z nyan $
6139217Sgibbs */
6239217Sgibbs
6339217Sgibbs#include <sys/param.h>
6439217Sgibbs#include <sys/systm.h>
6539217Sgibbs#include <sys/kernel.h>
6639217Sgibbs
6739217Sgibbs#include <machine/bus_pio.h>
6839217Sgibbs#include <machine/bus.h>
6959082Snyan#include <machine/resource.h>
7059082Snyan#include <sys/bus.h>
7159082Snyan#include <sys/rman.h>
7239217Sgibbs
7339217Sgibbs#include <pci/pcireg.h>
7439217Sgibbs#include <pci/pcivar.h>
7539217Sgibbs
7639217Sgibbs#include <dev/advansys/advansys.h>
7739217Sgibbs
7861034Speter#define PCI_BASEADR0	PCIR_MAPS		/* I/O Address */
7961034Speter#define PCI_BASEADR1	PCIR_MAPS + 4		/* Mem I/O Address */
8039217Sgibbs
8139217Sgibbs#define	PCI_DEVICE_ID_ADVANSYS_1200A	0x110010CD
8239217Sgibbs#define	PCI_DEVICE_ID_ADVANSYS_1200B	0x120010CD
8355945Sgibbs#define	PCI_DEVICE_ID_ADVANSYS_3000	0x130010CD
8439217Sgibbs#define	PCI_DEVICE_REV_ADVANSYS_3150	0x02
8539217Sgibbs#define	PCI_DEVICE_REV_ADVANSYS_3050	0x03
8639217Sgibbs
8739217Sgibbs#define ADV_PCI_MAX_DMA_ADDR    (0xFFFFFFFFL)
8839217Sgibbs#define ADV_PCI_MAX_DMA_COUNT   (0xFFFFFFFFL)
8939217Sgibbs
9059082Snyanstatic int adv_pci_probe(device_t);
9159082Snyanstatic int adv_pci_attach(device_t);
9239217Sgibbs
9339217Sgibbs/*
9439217Sgibbs * The overrun buffer shared amongst all PCI adapters.
9539217Sgibbs */
9639217Sgibbsstatic  u_int8_t*	overrun_buf;
9742012Sgibbsstatic	bus_dma_tag_t	overrun_dmat;
9842012Sgibbsstatic	bus_dmamap_t	overrun_dmamap;
9942012Sgibbsstatic	bus_addr_t	overrun_physbase;
10039217Sgibbs
10159082Snyanstatic int
10259082Snyanadv_pci_probe(device_t dev)
10339217Sgibbs{
10459082Snyan	int	rev = pci_get_revid(dev);
10555945Sgibbs
10659082Snyan	switch (pci_get_devid(dev)) {
10739217Sgibbs	case PCI_DEVICE_ID_ADVANSYS_1200A:
10859082Snyan		device_set_desc(dev, "AdvanSys ASC1200A SCSI controller");
10959082Snyan		return 0;
11039217Sgibbs	case PCI_DEVICE_ID_ADVANSYS_1200B:
11159082Snyan		device_set_desc(dev, "AdvanSys ASC1200B SCSI controller");
11259082Snyan		return 0;
11355945Sgibbs	case PCI_DEVICE_ID_ADVANSYS_3000:
11459082Snyan		if (rev == PCI_DEVICE_REV_ADVANSYS_3150) {
11559082Snyan			device_set_desc(dev,
11659082Snyan					"AdvanSys ASC3150 SCSI controller");
11759082Snyan			return 0;
11859082Snyan		} else if (rev == PCI_DEVICE_REV_ADVANSYS_3050) {
11959082Snyan			device_set_desc(dev,
12059082Snyan					"AdvanSys ASC3030/50 SCSI controller");
12159082Snyan			return 0;
12259082Snyan		} else if (rev >= PCI_DEVICE_REV_ADVANSYS_3150) {
12359082Snyan			device_set_desc(dev, "Unknown AdvanSys controller");
12459082Snyan			return 0;
12559082Snyan		}
12639217Sgibbs		break;
12739217Sgibbs	default:
12839217Sgibbs		break;
12939217Sgibbs	}
13059082Snyan	return ENXIO;
13139217Sgibbs}
13239217Sgibbs
13359082Snyanstatic int
13459082Snyanadv_pci_attach(device_t dev)
13539217Sgibbs{
13639217Sgibbs	struct		adv_softc *adv;
13739217Sgibbs	u_int32_t	id;
13839217Sgibbs	u_int32_t	command;
13976307Snyan	int		error, rid, irqrid;
14059082Snyan	void		*ih;
14159082Snyan	struct resource	*iores, *irqres;
14259082Snyan
14339217Sgibbs	/*
14439217Sgibbs	 * Determine the chip version.
14539217Sgibbs	 */
14661034Speter	id = pci_read_config(dev, PCIR_DEVVENDOR, /*bytes*/4);
14759082Snyan	command = pci_read_config(dev, PCIR_COMMAND, /*bytes*/1);
14839217Sgibbs
14939217Sgibbs	/*
15039217Sgibbs	 * These cards do not allow memory mapped accesses, so we must
15139217Sgibbs	 * ensure that I/O accesses are available or we won't be able
15239217Sgibbs	 * to talk to them.
15339217Sgibbs	 */
15439217Sgibbs	if ((command & (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN))
15539217Sgibbs	 != (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN)) {
15639217Sgibbs		command |= PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN;
15759082Snyan		pci_write_config(dev, PCIR_COMMAND, command, /*bytes*/1);
15839217Sgibbs	}
15939217Sgibbs
16039217Sgibbs	/*
16139217Sgibbs	 * Early chips can't handle non-zero latency timer settings.
16239217Sgibbs	 */
16339217Sgibbs	if (id == PCI_DEVICE_ID_ADVANSYS_1200A
16439217Sgibbs	 || id == PCI_DEVICE_ID_ADVANSYS_1200B) {
16559082Snyan		pci_write_config(dev, PCIR_LATTIMER, /*value*/0, /*bytes*/1);
16639217Sgibbs	}
16739217Sgibbs
16859171Snyan	rid = PCI_BASEADR0;
16959082Snyan	iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
17059082Snyan				   RF_ACTIVE);
17159082Snyan	if (iores == NULL)
17259082Snyan		return ENXIO;
17339217Sgibbs
17459082Snyan	if (adv_find_signature(rman_get_bustag(iores),
17559171Snyan			       rman_get_bushandle(iores)) == 0) {
17676307Snyan		bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
17759082Snyan		return ENXIO;
17859171Snyan	}
17939217Sgibbs
18059082Snyan	adv = adv_alloc(dev, rman_get_bustag(iores), rman_get_bushandle(iores));
18159171Snyan	if (adv == NULL) {
18276307Snyan		bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
18359082Snyan		return ENXIO;
18459171Snyan	}
18539217Sgibbs
18639217Sgibbs	/* Allocate a dmatag for our transfer DMA maps */
18739217Sgibbs	/* XXX Should be a child of the PCI bus dma tag */
18849860Sgibbs	error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1,
18939217Sgibbs				   /*boundary*/0,
19039217Sgibbs				   /*lowaddr*/ADV_PCI_MAX_DMA_ADDR,
19139217Sgibbs				   /*highaddr*/BUS_SPACE_MAXADDR,
19239217Sgibbs				   /*filter*/NULL, /*filterarg*/NULL,
19339217Sgibbs				   /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
19439217Sgibbs				   /*nsegments*/BUS_SPACE_UNRESTRICTED,
19539217Sgibbs				   /*maxsegsz*/ADV_PCI_MAX_DMA_COUNT,
19639217Sgibbs				   /*flags*/0,
19739217Sgibbs				   &adv->parent_dmat);
19839217Sgibbs
19939217Sgibbs	if (error != 0) {
20039217Sgibbs		printf("%s: Could not allocate DMA tag - error %d\n",
20139217Sgibbs		       adv_name(adv), error);
20239217Sgibbs		adv_free(adv);
20376307Snyan		bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
20459082Snyan		return ENXIO;
20539217Sgibbs	}
20639217Sgibbs
20739217Sgibbs	adv->init_level++;
20839217Sgibbs
20939217Sgibbs	if (overrun_buf == NULL) {
21039217Sgibbs		/* Need to allocate our overrun buffer */
21139217Sgibbs		if (bus_dma_tag_create(adv->parent_dmat,
21239217Sgibbs				       /*alignment*/8, /*boundary*/0,
21339217Sgibbs				       ADV_PCI_MAX_DMA_ADDR, BUS_SPACE_MAXADDR,
21439217Sgibbs				       /*filter*/NULL, /*filterarg*/NULL,
21539217Sgibbs				       ADV_OVERRUN_BSIZE, /*nsegments*/1,
21639217Sgibbs				       BUS_SPACE_MAXSIZE_32BIT, /*flags*/0,
21739217Sgibbs				       &overrun_dmat) != 0) {
21839217Sgibbs			bus_dma_tag_destroy(adv->parent_dmat);
21939217Sgibbs			adv_free(adv);
22076307Snyan			bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
22159082Snyan			return ENXIO;
22239217Sgibbs       		}
22339217Sgibbs		if (bus_dmamem_alloc(overrun_dmat,
22439217Sgibbs				     (void **)&overrun_buf,
22539217Sgibbs				     BUS_DMA_NOWAIT,
22639217Sgibbs				     &overrun_dmamap) != 0) {
22739217Sgibbs			bus_dma_tag_destroy(overrun_dmat);
22839217Sgibbs			bus_dma_tag_destroy(adv->parent_dmat);
22939217Sgibbs			adv_free(adv);
23076307Snyan			bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
23159082Snyan			return ENXIO;
23239217Sgibbs		}
23339217Sgibbs		/* And permanently map it in */
23439217Sgibbs		bus_dmamap_load(overrun_dmat, overrun_dmamap,
23539217Sgibbs				overrun_buf, ADV_OVERRUN_BSIZE,
23639217Sgibbs				adv_map, &overrun_physbase,
23739217Sgibbs				/*flags*/0);
23839217Sgibbs	}
23939217Sgibbs
24039217Sgibbs	adv->overrun_physbase = overrun_physbase;
24139217Sgibbs
24239217Sgibbs	/*
24339217Sgibbs	 * Stop the chip.
24439217Sgibbs	 */
24539217Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
24639217Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
24739217Sgibbs
24839217Sgibbs	adv->chip_version = ADV_INB(adv, ADV_NONEISA_CHIP_REVISION);
24939217Sgibbs	adv->type = ADV_PCI;
25039217Sgibbs
25139217Sgibbs	/*
25239217Sgibbs	 * Setup active negation and signal filtering.
25339217Sgibbs	 */
25439217Sgibbs	{
25539217Sgibbs		u_int8_t extra_cfg;
25639217Sgibbs
25739217Sgibbs		if (adv->chip_version >= ADV_CHIP_VER_PCI_ULTRA_3150)
25839217Sgibbs			adv->type |= ADV_ULTRA;
25955945Sgibbs		if (adv->chip_version == ADV_CHIP_VER_PCI_ULTRA_3050)
26039217Sgibbs			extra_cfg = ADV_IFC_ACT_NEG | ADV_IFC_WR_EN_FILTER;
26139217Sgibbs		else
26239217Sgibbs			extra_cfg = ADV_IFC_ACT_NEG | ADV_IFC_SLEW_RATE;
26339217Sgibbs		ADV_OUTB(adv, ADV_REG_IFC, extra_cfg);
26439217Sgibbs	}
26539217Sgibbs
26639217Sgibbs	if (adv_init(adv) != 0) {
26739217Sgibbs		adv_free(adv);
26876307Snyan		bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
26959082Snyan		return ENXIO;
27039217Sgibbs	}
27139217Sgibbs
27239217Sgibbs	adv->max_dma_count = ADV_PCI_MAX_DMA_COUNT;
27339217Sgibbs	adv->max_dma_addr = ADV_PCI_MAX_DMA_ADDR;
27439217Sgibbs
27539217Sgibbs#if CC_DISABLE_PCI_PARITY_INT
27641591Sarchie	{
27741591Sarchie		u_int16_t config_msw;
27841591Sarchie
27941591Sarchie		config_msw = ADV_INW(adv, ADV_CONFIG_MSW);
28041591Sarchie		config_msw &= 0xFFC0;
28141591Sarchie		ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
28241591Sarchie	}
28339217Sgibbs#endif
28439217Sgibbs
28539217Sgibbs	if (id == PCI_DEVICE_ID_ADVANSYS_1200A
28639217Sgibbs	 || id == PCI_DEVICE_ID_ADVANSYS_1200B) {
28739217Sgibbs		adv->bug_fix_control |= ADV_BUG_FIX_IF_NOT_DWB;
28839217Sgibbs		adv->bug_fix_control |= ADV_BUG_FIX_ASYN_USE_SYN;
28939217Sgibbs		adv->fix_asyn_xfer = ~0;
29039217Sgibbs	}
29139217Sgibbs
29276307Snyan	irqrid = 0;
29376307Snyan	irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &irqrid, 0, ~0, 1,
29459082Snyan				    RF_SHAREABLE | RF_ACTIVE);
29559082Snyan	if (irqres == NULL ||
29673280Smarkm	    bus_setup_intr(dev, irqres, INTR_TYPE_CAM|INTR_ENTROPY, adv_intr, adv, &ih)) {
29739217Sgibbs		adv_free(adv);
29876307Snyan		bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
29959082Snyan		return ENXIO;
30039217Sgibbs	}
30159082Snyan
30239217Sgibbs	adv_attach(adv);
30359082Snyan	return 0;
30439217Sgibbs}
30559082Snyan
30659082Snyanstatic device_method_t adv_pci_methods[] = {
30759082Snyan	/* Device interface */
30859082Snyan	DEVMETHOD(device_probe,		adv_pci_probe),
30959082Snyan	DEVMETHOD(device_attach,	adv_pci_attach),
31059082Snyan	{ 0, 0 }
31159082Snyan};
31259082Snyan
31359082Snyanstatic driver_t adv_pci_driver = {
31459082Snyan	"adv", adv_pci_methods, sizeof(struct adv_softc)
31559082Snyan};
31659082Snyan
31759082Snyanstatic devclass_t adv_pci_devclass;
31859082SnyanDRIVER_MODULE(adv, pci, adv_pci_driver, adv_pci_devclass, 0, 0);
319