xref: /freebsd/sys/dev/ida/ida_pci.c (revision 87569f75a91f298c52a71823c04d41cf53c88889)
1  /*-
2   * Copyright (c) 1999,2000 Jonathan Lemon
3   * All rights reserved.
4   *
5   * Redistribution and use in source and binary forms, with or without
6   * modification, are permitted provided that the following conditions
7   * are met:
8   * 1. Redistributions of source code must retain the above copyright
9   *    notice, this list of conditions and the following disclaimer.
10   * 2. Redistributions in binary form must reproduce the above copyright
11   *    notice, this list of conditions and the following disclaimer in the
12   *    documentation and/or other materials provided with the distribution.
13   *
14   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24   * SUCH DAMAGE.
25   */
26  
27  #include <sys/cdefs.h>
28  __FBSDID("$FreeBSD$");
29  
30  #include <sys/param.h>
31  #include <sys/systm.h>
32  #include <sys/kernel.h>
33  #include <sys/module.h>
34  
35  #include <sys/bio.h>
36  #include <sys/bus.h>
37  #include <sys/conf.h>
38  
39  #include <machine/bus.h>
40  #include <machine/resource.h>
41  #include <sys/rman.h>
42  
43  #include <dev/pci/pcireg.h>
44  #include <dev/pci/pcivar.h>
45  
46  #include <geom/geom_disk.h>
47  
48  #include <dev/ida/idavar.h>
49  #include <dev/ida/idareg.h>
50  
51  #define	IDA_PCI_MAX_DMA_ADDR	0xFFFFFFFF
52  #define	IDA_PCI_MAX_DMA_COUNT	0xFFFFFFFF
53  
54  #define	IDA_PCI_MEMADDR		PCIR_BAR(1)		/* Mem I/O Address */
55  
56  #define	IDA_DEVICEID_SMART		0xAE100E11
57  #define	IDA_DEVICEID_DEC_SMART		0x00461011
58  #define	IDA_DEVICEID_NCR_53C1510	0x00101000
59  
60  static int
61  ida_v3_fifo_full(struct ida_softc *ida)
62  {
63  	return (ida_inl(ida, R_CMD_FIFO) == 0);
64  }
65  
66  static void
67  ida_v3_submit(struct ida_softc *ida, struct ida_qcb *qcb)
68  {
69  	ida_outl(ida, R_CMD_FIFO, qcb->hwqcb_busaddr);
70  }
71  
72  static bus_addr_t
73  ida_v3_done(struct ida_softc *ida)
74  {
75  	bus_addr_t completed;
76  
77  	completed = ida_inl(ida, R_DONE_FIFO);
78  	if (completed == -1) {
79  		return (0);			/* fifo is empty */
80  	}
81  	return (completed);
82  }
83  
84  static int
85  ida_v3_int_pending(struct ida_softc *ida)
86  {
87  	return (ida_inl(ida, R_INT_PENDING));
88  }
89  
90  static void
91  ida_v3_int_enable(struct ida_softc *ida, int enable)
92  {
93  	if (enable)
94  		ida->flags |= IDA_INTERRUPTS;
95  	else
96  		ida->flags &= ~IDA_INTERRUPTS;
97  	ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE);
98  }
99  
100  static int
101  ida_v4_fifo_full(struct ida_softc *ida)
102  {
103  	return (ida_inl(ida, R_42XX_REQUEST) != 0);
104  }
105  
106  static void
107  ida_v4_submit(struct ida_softc *ida, struct ida_qcb *qcb)
108  {
109  	ida_outl(ida, R_42XX_REQUEST, qcb->hwqcb_busaddr);
110  }
111  
112  static bus_addr_t
113  ida_v4_done(struct ida_softc *ida)
114  {
115  	bus_addr_t completed;
116  
117  	completed = ida_inl(ida, R_42XX_REPLY);
118  	if (completed == -1)
119  		return (0);			/* fifo is empty */
120  	ida_outl(ida, R_42XX_REPLY, 0);		/* confirm read */
121  	return (completed);
122  }
123  
124  static int
125  ida_v4_int_pending(struct ida_softc *ida)
126  {
127  	return (ida_inl(ida, R_42XX_STATUS) & STATUS_42XX_INT_PENDING);
128  }
129  
130  static void
131  ida_v4_int_enable(struct ida_softc *ida, int enable)
132  {
133  	if (enable)
134  		ida->flags |= IDA_INTERRUPTS;
135  	else
136  		ida->flags &= ~IDA_INTERRUPTS;
137  	ida_outl(ida, R_42XX_INT_MASK,
138  	    enable ? INT_ENABLE_42XX : INT_DISABLE_42XX);
139  }
140  
141  static struct ida_access ida_v3_access = {
142  	ida_v3_fifo_full,
143  	ida_v3_submit,
144  	ida_v3_done,
145  	ida_v3_int_pending,
146  	ida_v3_int_enable,
147  };
148  
149  static struct ida_access ida_v4_access = {
150  	ida_v4_fifo_full,
151  	ida_v4_submit,
152  	ida_v4_done,
153  	ida_v4_int_pending,
154  	ida_v4_int_enable,
155  };
156  
157  static struct ida_board board_id[] = {
158  	{ 0x40300E11, "Compaq SMART-2/P array controller",
159  	    &ida_v3_access, 0 },
160  	{ 0x40310E11, "Compaq SMART-2SL array controller",
161  	    &ida_v3_access, 0 },
162  	{ 0x40320E11, "Compaq Smart Array 3200 controller",
163  	    &ida_v3_access, 0 },
164  	{ 0x40330E11, "Compaq Smart Array 3100ES controller",
165  	    &ida_v3_access, 0 },
166  	{ 0x40340E11, "Compaq Smart Array 221 controller",
167  	    &ida_v3_access, 0 },
168  
169  	{ 0x40400E11, "Compaq Integrated Array controller",
170  	    &ida_v4_access, IDA_FIRMWARE },
171  	{ 0x40480E11, "Compaq RAID LC2 controller",
172  	    &ida_v4_access, IDA_FIRMWARE },
173  	{ 0x40500E11, "Compaq Smart Array 4200 controller",
174  	    &ida_v4_access, 0 },
175  	{ 0x40510E11, "Compaq Smart Array 4250ES controller",
176  	    &ida_v4_access, 0 },
177  	{ 0x40580E11, "Compaq Smart Array 431 controller",
178  	    &ida_v4_access, 0 },
179  
180  	{ 0, "", 0, 0 },
181  };
182  
183  static int ida_pci_probe(device_t dev);
184  static int ida_pci_attach(device_t dev);
185  
186  static device_method_t ida_pci_methods[] = {
187  	DEVMETHOD(device_probe,		ida_pci_probe),
188  	DEVMETHOD(device_attach,	ida_pci_attach),
189  	DEVMETHOD(device_detach,	ida_detach),
190  
191  	DEVMETHOD(bus_print_child,	bus_generic_print_child),
192  
193  	{ 0, 0 }
194  };
195  
196  static driver_t ida_pci_driver = {
197  	"ida",
198  	ida_pci_methods,
199  	sizeof(struct ida_softc)
200  };
201  
202  static devclass_t ida_devclass;
203  
204  static struct ida_board *
205  ida_pci_match(device_t dev)
206  {
207  	int i;
208  	u_int32_t id, sub_id;
209  
210  	id = pci_get_devid(dev);
211  	sub_id = pci_get_subdevice(dev) << 16 | pci_get_subvendor(dev);
212  
213  	if (id == IDA_DEVICEID_SMART ||
214  	    id == IDA_DEVICEID_DEC_SMART ||
215  	    id == IDA_DEVICEID_NCR_53C1510) {
216  		for (i = 0; board_id[i].board; i++)
217  			if (board_id[i].board == sub_id)
218  				return (&board_id[i]);
219  	}
220  	return (NULL);
221  }
222  
223  static int
224  ida_pci_probe(device_t dev)
225  {
226  	struct ida_board *board = ida_pci_match(dev);
227  
228  	if (board != NULL) {
229  		device_set_desc(dev, board->desc);
230  		return (BUS_PROBE_DEFAULT);
231  	}
232  	return (ENXIO);
233  }
234  
235  static int
236  ida_pci_attach(device_t dev)
237  {
238  	struct ida_board *board = ida_pci_match(dev);
239  	u_int32_t id = pci_get_devid(dev);
240  	struct ida_softc *ida;
241  	u_int command;
242  	int error, rid;
243  
244  	command = pci_read_config(dev, PCIR_COMMAND, 1);
245  
246  	/*
247  	 * it appears that this board only does MEMIO access.
248  	 */
249  	if ((command & PCIM_CMD_MEMEN) == 0) {
250  	        device_printf(dev, "Only memory mapped I/O is supported\n");
251  		return (ENXIO);
252  	}
253  
254  	ida = (struct ida_softc *)device_get_softc(dev);
255  	ida->dev = dev;
256  	ida->cmd = *board->accessor;
257  	ida->flags = board->flags;
258  
259  	ida->regs_res_type = SYS_RES_MEMORY;
260  	ida->regs_res_id = IDA_PCI_MEMADDR;
261  	if (id == IDA_DEVICEID_DEC_SMART)
262  		ida->regs_res_id = PCIR_BAR(0);
263  
264  	ida->regs = bus_alloc_resource_any(dev, ida->regs_res_type,
265  	    &ida->regs_res_id, RF_ACTIVE);
266  	if (ida->regs == NULL) {
267  		device_printf(dev, "can't allocate memory resources\n");
268  		return (ENOMEM);
269  	}
270  
271  	error = bus_dma_tag_create(
272  		/* parent	*/ NULL,
273  		/* alignment	*/ 1,
274  		/* boundary	*/ 0,
275  		/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
276  		/* highaddr	*/ BUS_SPACE_MAXADDR,
277  		/* filter	*/ NULL,
278  		/* filterarg	*/ NULL,
279  		/* maxsize	*/ MAXBSIZE,
280  		/* nsegments	*/ IDA_NSEG,
281  		/* maxsegsize	*/ BUS_SPACE_MAXSIZE_32BIT,
282  		/* flags	*/ BUS_DMA_ALLOCNOW,
283  		/* lockfunc	*/ NULL,
284  		/* lockarg	*/ NULL,
285  		&ida->parent_dmat);
286  	if (error != 0) {
287  		device_printf(dev, "can't allocate DMA tag\n");
288  		ida_free(ida);
289  		return (ENOMEM);
290  	}
291  
292  	rid = 0;
293  	ida->irq_res_type = SYS_RES_IRQ;
294  	ida->irq = bus_alloc_resource_any(dev, ida->irq_res_type, &rid,
295  	    RF_ACTIVE | RF_SHAREABLE);
296  	if (ida->irq == NULL) {
297  	        ida_free(ida);
298  	        return (ENOMEM);
299  	}
300  	error = bus_setup_intr(dev, ida->irq, INTR_TYPE_BIO | INTR_ENTROPY,
301  	    ida_intr, ida, &ida->ih);
302  	if (error) {
303  		device_printf(dev, "can't setup interrupt\n");
304  		ida_free(ida);
305  		return (ENOMEM);
306  	}
307  
308  	error = ida_init(ida);
309  	if (error) {
310  	        ida_free(ida);
311  	        return (error);
312  	}
313  	ida_attach(ida);
314  	ida->flags |= IDA_ATTACHED;
315  
316  	return (0);
317  }
318  
319  DRIVER_MODULE(ida, pci, ida_pci_driver, ida_devclass, 0, 0);
320