1 /*-
2 * Copyright (c) 2000 Matthew N. Dodd <winter@jurai.net>
3 * All rights reserved.
4 *
5 * Copyright (c) 1997 Simon Shapiro
6 * All Rights Reserved
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: src/sys/dev/dpt/dpt_pci.c,v 1.17.2.2 2000/08/26 22:21:21 peter Exp $
30 */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/bus.h>
37 #include <sys/rman.h>
38 #include <sys/thread2.h>
39
40 #include <bus/pci/pcireg.h>
41 #include <bus/pci/pcivar.h>
42
43 #include <bus/cam/scsi/scsi_all.h>
44
45 #include "dpt.h"
46
47 #define DPT_VENDOR_ID 0x1044
48 #define DPT_DEVICE_ID 0xa400
49
50 #define DPT_PCI_IOADDR PCIR_MAPS /* I/O Address */
51 #define DPT_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */
52
53 #define ISA_PRIMARY_WD_ADDRESS 0x1f8
54
55 static int dpt_pci_probe (device_t);
56 static int dpt_pci_attach (device_t);
57
58 static int
dpt_pci_probe(device_t dev)59 dpt_pci_probe (device_t dev)
60 {
61 if ((pci_get_vendor(dev) == DPT_VENDOR_ID) &&
62 (pci_get_device(dev) == DPT_DEVICE_ID)) {
63 device_set_desc(dev, "DPT Caching SCSI RAID Controller");
64 return (0);
65 }
66 return (ENXIO);
67 }
68
69 static int
dpt_pci_attach(device_t dev)70 dpt_pci_attach (device_t dev)
71 {
72 dpt_softc_t * dpt;
73 struct resource *io = NULL;
74 struct resource *irq = NULL;
75 int rid;
76 void * ih;
77 int error = 0;
78
79 int iotype = 0;
80 u_int32_t command;
81
82 command = pci_read_config(dev, PCIR_COMMAND, /*bytes*/1);
83
84 #ifdef DPT_ALLOW_MMIO
85 if ((command & PCIM_CMD_MEMEN) != 0) {
86 rid = DPT_PCI_MEMADDR;
87 iotype = SYS_RES_MEMORY;
88 io = bus_alloc_resource(dev, iotype, &rid, 0, ~0, 1, RF_ACTIVE);
89 }
90 #endif
91 if (io == NULL && (command & PCIM_CMD_PORTEN) != 0) {
92 rid = DPT_PCI_IOADDR;
93 iotype = SYS_RES_IOPORT;
94 io = bus_alloc_resource(dev, iotype, &rid, 0, ~0, 1, RF_ACTIVE);
95 }
96
97 if (io == NULL) {
98 device_printf(dev, "can't allocate register resources\n");
99 error = ENOMEM;
100 goto bad;
101 }
102
103 rid = 0;
104 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
105 RF_ACTIVE | RF_SHAREABLE);
106 if (!irq) {
107 device_printf(dev, "No irq?!\n");
108 error = ENOMEM;
109 goto bad;
110 }
111
112 /* Ensure busmastering is enabled */
113 command |= PCIM_CMD_BUSMASTEREN;
114 pci_write_config(dev, PCIR_COMMAND, command, /*bytes*/1);
115
116 if (rman_get_start(io) == (ISA_PRIMARY_WD_ADDRESS - 0x10)) {
117 #ifdef DPT_DEBUG_WARN
118 device_printf(dev, "Mapped as an IDE controller. "
119 "Disabling SCSI setup\n");
120 #endif
121 error = ENXIO;
122 goto bad;
123 }
124
125 /* Device registers are offset 0x10 into the register window. FEH */
126 dpt = dpt_alloc(dev, rman_get_bustag(io), rman_get_bushandle(io) + 0x10);
127 if (dpt == NULL) {
128 error = ENXIO;
129 goto bad;
130 }
131
132 /* Allocate a dmatag representing the capabilities of this attachment */
133 /* XXX Should be a child of the PCI bus dma tag */
134 if (bus_dma_tag_create( /* parent */ NULL,
135 /* alignemnt */ 1,
136 /* boundary */ 0,
137 /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
138 /* highaddr */ BUS_SPACE_MAXADDR,
139 /* maxsize */ BUS_SPACE_MAXSIZE_32BIT,
140 /* nsegments */ BUS_SPACE_UNRESTRICTED,
141 /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT,
142 /* flags */ 0,
143 &dpt->parent_dmat) != 0) {
144 dpt_free(dpt);
145 error = ENXIO;
146 goto bad;
147 }
148
149 crit_enter();
150
151 if (dpt_init(dpt) != 0) {
152 dpt_free(dpt);
153 error = ENXIO;
154 crit_exit();
155 goto bad;
156 }
157
158 /* Register with the XPT */
159 dpt_attach(dpt);
160
161 crit_exit();
162
163 error = bus_setup_intr(dev, irq, 0, dpt_intr, dpt,
164 &ih, NULL);
165 if (error) {
166 device_printf(dev, "Unable to register interrupt handler\n");
167 error = ENXIO;
168 goto bad;
169 }
170
171 return (error);
172
173 bad:
174 if (io)
175 bus_release_resource(dev, iotype, 0, io);
176 if (irq)
177 bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
178
179 return (error);
180 }
181
182 static device_method_t dpt_pci_methods[] = {
183 /* Device interface */
184 DEVMETHOD(device_probe, dpt_pci_probe),
185 DEVMETHOD(device_attach, dpt_pci_attach),
186
187 DEVMETHOD_END
188 };
189
190 static driver_t dpt_pci_driver = {
191 "dpt",
192 dpt_pci_methods,
193 sizeof(dpt_softc_t),
194 };
195
196 static devclass_t dpt_devclass;
197
198 DRIVER_MODULE(dpt, pci, dpt_pci_driver, dpt_devclass, NULL, NULL);
199