ips_pci.c revision 126364
1100969Siwasaki/*-
2100969Siwasaki * Copyright (c) 2002 Adaptec Inc.
3100969Siwasaki * All rights reserved.
4100969Siwasaki *
5100969Siwasaki * Written by: David Jeffery
6100969Siwasaki *
7100969Siwasaki * Redistribution and use in source and binary forms, with or without
8100969Siwasaki * modification, are permitted provided that the following conditions
9100969Siwasaki * are met:
10100969Siwasaki * 1. Redistributions of source code must retain the above copyright
11100969Siwasaki *    notice, this list of conditions and the following disclaimer.
12100969Siwasaki * 2. Redistributions in binary form must reproduce the above copyright
13100969Siwasaki *    notice, this list of conditions and the following disclaimer in the
14100969Siwasaki *    documentation and/or other materials provided with the distribution.
15100969Siwasaki *
16100969Siwasaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17100969Siwasaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18100969Siwasaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19100969Siwasaki * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20100969Siwasaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21100969Siwasaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22100969Siwasaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23100969Siwasaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24100969Siwasaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25100969Siwasaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26100969Siwasaki * SUCH DAMAGE.
27100969Siwasaki */
28100969Siwasaki
29100969Siwasaki#include <sys/cdefs.h>
30100969Siwasaki__FBSDID("$FreeBSD: head/sys/dev/ips/ips_pci.c 126364 2004-02-28 19:14:41Z scottl $");
31100969Siwasaki
32100969Siwasaki#include <dev/ips/ips.h>
33100969Siwasaki
34100969Siwasakistatic int ips_pci_free(ips_softc_t *sc);
35100969Siwasakistatic void ips_intrhook(void *arg);
36100969Siwasaki
37167814Sjkimstatic int ips_pci_probe(device_t dev)
38100969Siwasaki{
39100969Siwasaki
40100969Siwasaki        if ((pci_get_vendor(dev) == IPS_VENDOR_ID) &&
41100969Siwasaki	    (pci_get_device(dev) == IPS_MORPHEUS_DEVICE_ID)) {
42100969Siwasaki		device_set_desc(dev, "IBM ServeRAID Adapter");
43100969Siwasaki                return 0;
44100969Siwasaki        } else if ((pci_get_vendor(dev) == IPS_VENDOR_ID) &&
45100969Siwasaki	    (pci_get_device(dev) == IPS_COPPERHEAD_DEVICE_ID)) {
46100969Siwasaki		device_set_desc(dev, "IBM ServeRAID Adapter");
47100969Siwasaki		return (0);
48100969Siwasaki        }
49167814Sjkim        return(ENXIO);
50167814Sjkim}
51167814Sjkim
52167814Sjkimstatic int ips_pci_attach(device_t dev)
53100969Siwasaki{
54100969Siwasaki        u_int32_t command;
55100969Siwasaki        ips_softc_t *sc;
56167814Sjkim
57167814Sjkim
58205713Smarcel	if (resource_disabled(device_get_name(dev), device_get_unit(dev))) {
59205713Smarcel		device_printf(dev, "device is disabled\n");
60100969Siwasaki		/* but return 0 so the !$)$)*!$*) unit isn't reused */
61167814Sjkim		return (0);
62100969Siwasaki	}
63254300Sjkim        DEVICE_PRINTF(1, dev, "in attach.\n");
64254300Sjkim        sc = (ips_softc_t *)device_get_softc(dev);
65254300Sjkim        if(!sc){
66167814Sjkim                printf("how is sc NULL?!\n");
67167814Sjkim                return (ENXIO);
68167814Sjkim        }
69167814Sjkim        bzero(sc, sizeof(ips_softc_t));
70167814Sjkim        sc->dev = dev;
71167814Sjkim
72100969Siwasaki        if(pci_get_device(dev) == IPS_MORPHEUS_DEVICE_ID){
73252280Sjkim		sc->ips_adapter_reinit = ips_morpheus_reinit;
74252280Sjkim                sc->ips_adapter_intr = ips_morpheus_intr;
75100969Siwasaki		sc->ips_issue_cmd    = ips_issue_morpheus_cmd;
76100969Siwasaki        } else if(pci_get_device(dev) == IPS_COPPERHEAD_DEVICE_ID){
77100969Siwasaki		sc->ips_adapter_reinit = ips_copperhead_reinit;
78                sc->ips_adapter_intr = ips_copperhead_intr;
79		sc->ips_issue_cmd    = ips_issue_copperhead_cmd;
80	} else
81                goto error;
82        /* make sure busmastering is on */
83        command = pci_read_config(dev, PCIR_COMMAND, 1);
84	command |= PCIM_CMD_BUSMASTEREN;
85	pci_write_config(dev, PCIR_COMMAND, command, 1);
86        /* seting up io space */
87        sc->iores = NULL;
88        if(command & PCIM_CMD_MEMEN){
89                PRINTF(10, "trying MEMIO\n");
90		if(pci_get_device(dev) == IPS_MORPHEUS_DEVICE_ID)
91                	sc->rid = PCIR_BAR(0);
92		else
93			sc->rid = PCIR_BAR(1);
94                sc->iotype = SYS_RES_MEMORY;
95                sc->iores = bus_alloc_resource(dev, sc->iotype, &sc->rid, 0, ~0, 1, RF_ACTIVE);
96        }
97        if(!sc->iores && command & PCIM_CMD_PORTEN){
98                PRINTF(10, "trying PORTIO\n");
99                sc->rid = PCIR_BAR(0);
100                sc->iotype = SYS_RES_IOPORT;
101                sc->iores = bus_alloc_resource(dev, sc->iotype, &sc->rid, 0, ~0, 1, RF_ACTIVE);
102        }
103        if(sc->iores == NULL){
104                device_printf(dev, "resource allocation failed\n");
105                return (ENXIO);
106        }
107        sc->bustag = rman_get_bustag(sc->iores);
108        sc->bushandle = rman_get_bushandle(sc->iores);
109        /*allocate an interrupt. when does the irq become active? after leaving attach? */
110        sc->irqrid = 0;
111        if(!(sc->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqrid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE))){
112                device_printf(dev, "irq allocation failed\n");
113                goto error;
114        }
115	if(bus_setup_intr(dev, sc->irqres, INTR_TYPE_BIO, sc->ips_adapter_intr, sc, &sc->irqcookie)){
116                device_printf(dev, "irq setup failed\n");
117                goto error;
118        }
119	if (bus_dma_tag_create(	/* parent    */	NULL,
120				/* alignemnt */	1,
121				/* boundary  */	0,
122				/* lowaddr   */	BUS_SPACE_MAXADDR_32BIT,
123				/* highaddr  */	BUS_SPACE_MAXADDR,
124				/* filter    */	NULL,
125				/* filterarg */	NULL,
126				/* maxsize   */	BUS_SPACE_MAXSIZE_32BIT,
127				/* numsegs   */	IPS_MAX_SG_ELEMENTS,
128				/* maxsegsize*/	BUS_SPACE_MAXSIZE_32BIT,
129				/* flags     */	0,
130				/* lockfunc  */ busdma_lock_mutex,
131				/* lockarg   */ &Giant,
132				&sc->adapter_dmatag) != 0) {
133                printf("IPS can't alloc dma tag\n");
134                goto error;
135        }
136	sc->ips_ich.ich_func = ips_intrhook;
137	sc->ips_ich.ich_arg = sc;
138	mtx_init(&sc->queue_mtx, "IPS bioqueue lock", MTX_DEF, 0);
139	bioq_init(&sc->queue);
140	if (config_intrhook_establish(&sc->ips_ich) != 0) {
141		printf("IPS can't establish configuration hook\n");
142		goto error;
143	}
144        return 0;
145error:
146	ips_pci_free(sc);
147        return (ENXIO);
148}
149
150static void
151ips_intrhook(void *arg)
152{
153	struct ips_softc *sc = (struct ips_softc *)arg;
154
155	config_intrhook_disestablish(&sc->ips_ich);
156	if (ips_adapter_init(sc))
157		ips_pci_free(sc);
158	else
159		sc->configured = 1;
160}
161
162static int ips_pci_free(ips_softc_t *sc)
163{
164	if(sc->adapter_dmatag)
165		bus_dma_tag_destroy(sc->adapter_dmatag);
166	if(sc->irqcookie)
167                bus_teardown_intr(sc->dev, sc->irqres, sc->irqcookie);
168        if(sc->irqres)
169               bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irqrid, sc->irqres);
170        if(sc->iores)
171                bus_release_resource(sc->dev, sc->iotype, sc->rid, sc->iores);
172	sc->configured = 0;
173	return 0;
174}
175
176static int ips_pci_detach(device_t dev)
177{
178        ips_softc_t *sc;
179        DEVICE_PRINTF(1, dev, "detaching ServeRaid\n");
180        sc = (ips_softc_t *) device_get_softc(dev);
181	if (sc->configured) {
182		sc->configured = 0;
183		ips_flush_cache(sc);
184		if(ips_adapter_free(sc))
185			return EBUSY;
186		ips_pci_free(sc);
187		bioq_flush(&sc->queue, NULL, ENXIO);
188	}
189	return 0;
190}
191
192static int ips_pci_shutdown(device_t dev)
193{
194	ips_softc_t *sc = (ips_softc_t *) device_get_softc(dev);
195	if (sc->configured) {
196		ips_flush_cache(sc);
197	}
198	return 0;
199}
200
201static device_method_t ips_driver_methods[] = {
202        DEVMETHOD(device_probe, ips_pci_probe),
203        DEVMETHOD(device_attach, ips_pci_attach),
204        DEVMETHOD(device_detach, ips_pci_detach),
205	DEVMETHOD(device_shutdown, ips_pci_shutdown),
206        {0,0}
207};
208
209static driver_t ips_pci_driver = {
210        "ips",
211        ips_driver_methods,
212        sizeof(ips_softc_t),
213};
214
215static devclass_t ips_devclass;
216DRIVER_MODULE(ips, pci, ips_pci_driver, ips_devclass, 0, 0);
217