1 /* $FreeBSD: src/sys/dev/mpt/mpt_pci.c,v 1.3.2.3 2002/09/24 21:37:25 mjacob Exp $ */
2 /* $DragonFly: src/sys/dev/disk/mpt/mpt_pci.c,v 1.12 2008/06/05 18:06:31 swildner Exp $ */
4 * PCI specific probe and attach routines for LSI '909 FC adapters.
7 * Copyright (c) 2000, 2001 by Greg Ansley
8 * Partially derived from Matt Jacob's ISP driver.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice immediately at the beginning of the file, without modification,
15 * this list of conditions, and the following disclaimer.
16 * 2. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * Additional Copyright (c) 2002 by Matthew Jacob under same license.
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
41 #include <sys/malloc.h>
43 #include <bus/pci/pcidevs.h>
44 #include <bus/pci/pcireg.h>
45 #include <bus/pci/pcivar.h>
47 #include "mpt_freebsd.h"
49 #ifndef PCIM_CMD_SERRESPEN
50 #define PCIM_CMD_SERRESPEN 0x0100
55 #define MEM_MAP_REG 0x14
56 #define MEM_MAP_SRAM 0x1C
58 static int mpt_probe(device_t
);
59 static int mpt_attach(device_t
);
60 static void mpt_free_bus_resources(mpt_softc_t
*mpt
);
61 static int mpt_detach(device_t
);
62 static int mpt_shutdown(device_t
);
63 static int mpt_dma_mem_alloc(mpt_softc_t
*mpt
);
64 static void mpt_dma_mem_free(mpt_softc_t
*mpt
);
65 static void mpt_read_config_regs(mpt_softc_t
*mpt
);
66 static void mpt_pci_intr(void *);
68 static device_method_t mpt_methods
[] = {
69 /* Device interface */
70 DEVMETHOD(device_probe
, mpt_probe
),
71 DEVMETHOD(device_attach
, mpt_attach
),
72 DEVMETHOD(device_detach
, mpt_detach
),
73 DEVMETHOD(device_shutdown
, mpt_shutdown
),
77 static driver_t mpt_driver
= {
78 "mpt", mpt_methods
, sizeof (mpt_softc_t
)
80 static devclass_t mpt_devclass
;
81 DRIVER_MODULE(mpt
, pci
, mpt_driver
, mpt_devclass
, 0, 0);
82 MODULE_VERSION(mpt
, 1);
89 mpt_softc_t
*mpt
= (mpt_softc_t
*)dummy
;
91 if ((mpt_read(mpt
, MPT_OFFSET_INTR_STATUS
) & MPT_INTR_REPLY_READY
) == 0)
93 reply
= mpt_pop_reply_queue(mpt
);
94 while (reply
!= MPT_REPLY_EMPTY
) {
96 if (mpt
->verbose
> 1) {
97 if ((reply
& MPT_CONTEXT_REPLY
) != 0) {
98 /* Address reply; IOC has something to say */
99 mpt_print_reply(MPT_REPLY_PTOV(mpt
, reply
));
101 /* Context reply ; all went well */
102 device_printf(mpt
->dev
,
103 "context %u reply OK\n", reply
);
106 mpt_done(mpt
, reply
);
107 reply
= mpt_pop_reply_queue(mpt
);
113 mpt_probe(device_t dev
)
117 if (pci_get_vendor(dev
) != PCI_VENDOR_SYMBIOS
)
120 switch ((pci_get_device(dev
) & ~1)) {
121 case PCI_PRODUCT_SYMBIOS_FC909
:
122 desc
= "LSILogic FC909 FC Adapter";
124 case PCI_PRODUCT_SYMBIOS_FC909A
:
125 desc
= "LSILogic FC909A FC Adapter";
127 case PCI_PRODUCT_SYMBIOS_FC919
:
128 desc
= "LSILogic FC919 FC Adapter";
130 case PCI_PRODUCT_SYMBIOS_FC929
:
131 desc
= "LSILogic FC929 FC Adapter";
133 case PCI_PRODUCT_SYMBIOS_FC929X
:
134 desc
= "LSILogic FC929 FC Adapter";
136 case PCI_PRODUCT_SYMBIOS_1030
:
137 desc
= "LSILogic 1030 Ultra4 Adapter";
143 device_set_desc(dev
, desc
);
148 mpt_set_options(mpt_softc_t
*mpt
)
153 if (kgetenv_int("mpt_disable", &bitmap
)) {
154 if (bitmap
& (1 << mpt
->unit
)) {
160 if (kgetenv_int("mpt_debug", &bitmap
)) {
161 if (bitmap
& (1 << mpt
->unit
)) {
169 mpt_link_peer(mpt_softc_t
*mpt
)
173 if (mpt
->unit
== 0) {
178 * XXX: depends on probe order
180 mpt2
= (mpt_softc_t
*) devclass_get_softc(mpt_devclass
, mpt
->unit
-1);
185 if (pci_get_vendor(mpt2
->dev
) != pci_get_vendor(mpt
->dev
)) {
188 if (pci_get_device(mpt2
->dev
) != pci_get_device(mpt
->dev
)) {
194 device_printf(mpt
->dev
, "linking with peer (mpt%d)\n",
195 device_get_unit(mpt2
->dev
));
201 mpt_attach(device_t dev
)
207 /* Allocate the softc structure */
208 mpt
= (mpt_softc_t
*) device_get_softc(dev
);
210 device_printf(dev
, "cannot allocate softc\n");
213 bzero(mpt
, sizeof (mpt_softc_t
));
214 switch ((pci_get_device(dev
) & ~1)) {
215 case PCI_PRODUCT_SYMBIOS_FC909
:
216 case PCI_PRODUCT_SYMBIOS_FC909A
:
217 case PCI_PRODUCT_SYMBIOS_FC919
:
218 case PCI_PRODUCT_SYMBIOS_FC929
:
219 case PCI_PRODUCT_SYMBIOS_FC929X
:
226 mpt
->unit
= device_get_unit(dev
);
227 mpt_set_options(mpt
);
228 mpt
->verbose
+= (bootverbose
!= 0)? 1 : 0;
230 /* Make sure memory access decoders are enabled */
231 cmd
= pci_read_config(dev
, PCIR_COMMAND
, 2);
232 if ((cmd
& PCIM_CMD_MEMEN
) == 0) {
233 device_printf(dev
, "Memory accesses disabled");
238 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER are set.
241 PCIM_CMD_SERRESPEN
| PCIM_CMD_PERRESPEN
|
242 PCIM_CMD_BUSMASTEREN
| PCIM_CMD_MWRICEN
;
243 pci_write_config(dev
, PCIR_COMMAND
, cmd
, 2);
246 * Make sure we've disabled the ROM.
248 data
= pci_read_config(dev
, PCIR_BIOS
, 4);
250 pci_write_config(dev
, PCIR_BIOS
, data
, 4);
254 * Is this part a dual?
255 * If so, link with our partner (around yet)
257 if ((pci_get_device(dev
) & ~1) == PCI_PRODUCT_SYMBIOS_FC929
||
258 (pci_get_device(dev
) & ~1) == PCI_PRODUCT_SYMBIOS_FC929X
||
259 (pci_get_device(dev
) & ~1) == PCI_PRODUCT_SYMBIOS_1030
) {
263 /* Set up the memory regions */
264 /* Allocate kernel virtual memory for the 9x9's Mem0 region */
265 mpt
->pci_reg_id
= MEM_MAP_REG
;
266 mpt
->pci_reg
= bus_alloc_resource(dev
, SYS_RES_MEMORY
,
267 &mpt
->pci_reg_id
, 0, ~0, 0, RF_ACTIVE
);
268 if (mpt
->pci_reg
== NULL
) {
269 device_printf(dev
, "unable to map any ports\n");
272 mpt
->pci_st
= rman_get_bustag(mpt
->pci_reg
);
273 mpt
->pci_sh
= rman_get_bushandle(mpt
->pci_reg
);
274 /* Get the Physical Address */
275 mpt
->pci_pa
= rman_get_start(mpt
->pci_reg
);
277 /* Get a handle to the interrupt */
279 mpt
->pci_irq
= bus_alloc_resource(dev
, SYS_RES_IRQ
, &iqd
, 0, ~0,
280 1, RF_ACTIVE
| RF_SHAREABLE
);
281 if (mpt
->pci_irq
== NULL
) {
282 device_printf(dev
, "could not allocate interrupt\n");
286 /* Register the interrupt handler */
287 if (bus_setup_intr(dev
, mpt
->pci_irq
, MPT_IFLAGS
, mpt_pci_intr
,
288 mpt
, &mpt
->ih
, NULL
)) {
289 device_printf(dev
, "could not setup interrupt\n");
295 /* Disable interrupts at the part */
296 mpt_disable_ints(mpt
);
298 /* Allocate dma memory */
299 if (mpt_dma_mem_alloc(mpt
)) {
300 device_printf(dev
, "Could not allocate DMA memory\n");
305 * Save the PCI config register values
307 * Hard resets are known to screw up the BAR for diagnostic
308 * memory accesses (Mem1).
310 * Using Mem1 is known to make the chip stop responding to
311 * configuration space transfers, so we need to save it now
314 mpt_read_config_regs(mpt
);
316 /* Initialize the hardware */
317 if (mpt
->disabled
== 0) {
319 if (mpt_init(mpt
, MPT_DB_INIT_HOST
) != 0) {
334 mpt_dma_mem_free(mpt
);
335 mpt_free_bus_resources(mpt
);
338 * but return zero to preserve unit numbering
347 mpt_free_bus_resources(mpt_softc_t
*mpt
)
350 bus_teardown_intr(mpt
->dev
, mpt
->pci_irq
, mpt
->ih
);
355 bus_release_resource(mpt
->dev
, SYS_RES_IRQ
, 0, mpt
->pci_irq
);
360 bus_release_resource(mpt
->dev
, SYS_RES_MEMORY
, mpt
->pci_reg_id
,
364 MPT_LOCK_DESTROY(mpt
);
369 * Disconnect ourselves from the system.
372 mpt_detach(device_t dev
)
375 mpt
= (mpt_softc_t
*) device_get_softc(dev
);
377 device_printf(mpt
->dev
,"mpt_detach!\n");
380 mpt_disable_ints(mpt
);
383 mpt_dma_mem_free(mpt
);
384 mpt_free_bus_resources(mpt
);
391 * Disable the hardware
394 mpt_shutdown(device_t dev
)
397 mpt
= (mpt_softc_t
*) device_get_softc(dev
);
413 mpt_map_rquest(void *arg
, bus_dma_segment_t
*segs
, int nseg
, int error
)
415 struct imush
*imushp
= (struct imush
*) arg
;
416 imushp
->error
= error
;
417 imushp
->phys
= segs
->ds_addr
;
422 mpt_dma_mem_alloc(mpt_softc_t
*mpt
)
429 device_t dev
= mpt
->dev
;
431 /* Check if we alreay have allocated the reply memory */
432 if (mpt
->reply_phys
!= 0) {
436 len
= sizeof (request_t
*) * MPT_REQ_MEM_SIZE(mpt
);
437 mpt
->request_pool
= (request_t
*) kmalloc(len
, M_DEVBUF
, M_WAITOK
);
438 bzero(mpt
->request_pool
, len
);
441 * Create a dma tag for this device
443 * Align at page boundaries, limit to 32-bit addressing
444 * (The chip supports 64-bit addressing, but this driver doesn't)
446 if (bus_dma_tag_create(NULL
, PAGE_SIZE
, 0, BUS_SPACE_MAXADDR_32BIT
,
447 BUS_SPACE_MAXADDR
, NULL
, NULL
, BUS_SPACE_MAXSIZE_32BIT
,
448 BUS_SPACE_MAXSIZE_32BIT
, BUS_SPACE_UNRESTRICTED
, 0,
449 &mpt
->parent_dmat
) != 0) {
450 device_printf(dev
, "cannot create parent dma tag\n");
454 /* Create a child tag for reply buffers */
455 if (bus_dma_tag_create(mpt
->parent_dmat
, PAGE_SIZE
,
456 0, BUS_SPACE_MAXADDR
, BUS_SPACE_MAXADDR
,
457 NULL
, NULL
, PAGE_SIZE
, 1, BUS_SPACE_MAXSIZE_32BIT
, 0,
458 &mpt
->reply_dmat
) != 0) {
459 device_printf(dev
, "cannot create a dma tag for replies\n");
463 /* Allocate some DMA accessable memory for replies */
464 if (bus_dmamem_alloc(mpt
->reply_dmat
, (void **)&mpt
->reply
,
465 BUS_DMA_NOWAIT
, &mpt
->reply_dmap
) != 0) {
466 device_printf(dev
, "cannot allocate %d bytes of reply memory\n",
474 /* Load and lock it into "bus space" */
475 bus_dmamap_load(mpt
->reply_dmat
, mpt
->reply_dmap
, mpt
->reply
,
476 PAGE_SIZE
, mpt_map_rquest
, &im
, 0);
480 "error %d loading dma map for DMA reply queue\n", im
.error
);
483 mpt
->reply_phys
= im
.phys
;
485 /* Create a child tag for data buffers */
486 if (bus_dma_tag_create(mpt
->parent_dmat
, PAGE_SIZE
,
487 0, BUS_SPACE_MAXADDR
, BUS_SPACE_MAXADDR
,
488 NULL
, NULL
, MAXBSIZE
, MPT_SGL_MAX
, BUS_SPACE_MAXSIZE_32BIT
, 0,
489 &mpt
->buffer_dmat
) != 0) {
491 "cannot create a dma tag for data buffers\n");
495 /* Create a child tag for request buffers */
496 if (bus_dma_tag_create(mpt
->parent_dmat
, PAGE_SIZE
,
497 0, BUS_SPACE_MAXADDR
, BUS_SPACE_MAXADDR
,
498 NULL
, NULL
, MPT_REQ_MEM_SIZE(mpt
), 1, BUS_SPACE_MAXSIZE_32BIT
, 0,
499 &mpt
->request_dmat
) != 0) {
500 device_printf(dev
, "cannot create a dma tag for requests\n");
504 /* Allocate some DMA accessable memory for requests */
505 if (bus_dmamem_alloc(mpt
->request_dmat
, (void **)&mpt
->request
,
506 BUS_DMA_NOWAIT
, &mpt
->request_dmap
) != 0) {
508 "cannot allocate %d bytes of request memory\n",
509 MPT_REQ_MEM_SIZE(mpt
));
516 /* Load and lock it into "bus space" */
517 bus_dmamap_load(mpt
->request_dmat
, mpt
->request_dmap
, mpt
->request
,
518 MPT_REQ_MEM_SIZE(mpt
), mpt_map_rquest
, &im
, 0);
522 "error %d loading dma map for DMA request queue\n",
526 mpt
->request_phys
= im
.phys
;
529 pptr
= mpt
->request_phys
;
531 end
= pptr
+ MPT_REQ_MEM_SIZE(mpt
);
533 request_t
*req
= &mpt
->request_pool
[i
];
536 /* Store location of Request Data */
537 req
->req_pbuf
= pptr
;
538 req
->req_vbuf
= vptr
;
540 pptr
+= MPT_REQUEST_AREA
;
541 vptr
+= MPT_REQUEST_AREA
;
543 req
->sense_pbuf
= (pptr
- MPT_SENSE_SIZE
);
544 req
->sense_vbuf
= (vptr
- MPT_SENSE_SIZE
);
546 error
= bus_dmamap_create(mpt
->buffer_dmat
, 0, &req
->dmap
);
549 "error %d creating per-cmd DMA maps\n", error
);
558 /* Deallocate memory that was allocated by mpt_dma_mem_alloc
561 mpt_dma_mem_free(mpt_softc_t
*mpt
)
565 /* Make sure we aren't double destroying */
566 if (mpt
->reply_dmat
== 0) {
568 device_printf(mpt
->dev
,"Already released dma memory\n");
572 for (i
= 0; i
< MPT_MAX_REQUESTS(mpt
); i
++) {
573 bus_dmamap_destroy(mpt
->buffer_dmat
, mpt
->request_pool
[i
].dmap
);
575 bus_dmamap_unload(mpt
->request_dmat
, mpt
->request_dmap
);
576 bus_dmamem_free(mpt
->request_dmat
, mpt
->request
, mpt
->request_dmap
);
577 bus_dma_tag_destroy(mpt
->request_dmat
);
578 bus_dma_tag_destroy(mpt
->buffer_dmat
);
579 bus_dmamap_unload(mpt
->reply_dmat
, mpt
->reply_dmap
);
580 bus_dmamem_free(mpt
->reply_dmat
, mpt
->reply
, mpt
->reply_dmap
);
581 bus_dma_tag_destroy(mpt
->reply_dmat
);
582 bus_dma_tag_destroy(mpt
->parent_dmat
);
584 kfree(mpt
->request_pool
, M_DEVBUF
);
585 mpt
->request_pool
= 0;
591 /* Reads modifiable (via PCI transactions) config registers */
593 mpt_read_config_regs(mpt_softc_t
*mpt
)
595 mpt
->pci_cfg
.Command
= pci_read_config(mpt
->dev
, PCIR_COMMAND
, 2);
596 mpt
->pci_cfg
.LatencyTimer_LineSize
=
597 pci_read_config(mpt
->dev
, PCIR_CACHELNSZ
, 2);
598 mpt
->pci_cfg
.IO_BAR
= pci_read_config(mpt
->dev
, PCIR_MAPS
, 4);
599 mpt
->pci_cfg
.Mem0_BAR
[0] = pci_read_config(mpt
->dev
, PCIR_MAPS
+0x4, 4);
600 mpt
->pci_cfg
.Mem0_BAR
[1] = pci_read_config(mpt
->dev
, PCIR_MAPS
+0x8, 4);
601 mpt
->pci_cfg
.Mem1_BAR
[0] = pci_read_config(mpt
->dev
, PCIR_MAPS
+0xC, 4);
602 mpt
->pci_cfg
.Mem1_BAR
[1] = pci_read_config(mpt
->dev
, PCIR_MAPS
+0x10, 4);
603 mpt
->pci_cfg
.ROM_BAR
= pci_read_config(mpt
->dev
, PCIR_BIOS
, 4);
604 mpt
->pci_cfg
.IntLine
= pci_read_config(mpt
->dev
, PCIR_INTLINE
, 1);
605 mpt
->pci_cfg
.PMCSR
= pci_read_config(mpt
->dev
, 0x44, 4);
608 /* Sets modifiable config registers */
610 mpt_set_config_regs(mpt_softc_t
*mpt
)
614 #define MPT_CHECK(reg, offset, size) \
615 val = pci_read_config(mpt->dev, offset, size); \
616 if (mpt->pci_cfg.reg != val) { \
617 device_printf(mpt->dev, \
618 "Restoring " #reg " to 0x%X from 0x%X\n", \
619 mpt->pci_cfg.reg, val); \
623 MPT_CHECK(Command
, PCIR_COMMAND
, 2);
624 MPT_CHECK(LatencyTimer_LineSize
, PCIR_CACHELNSZ
, 2);
625 MPT_CHECK(IO_BAR
, PCIR_MAPS
, 4);
626 MPT_CHECK(Mem0_BAR
[0], PCIR_MAPS
+0x4, 4);
627 MPT_CHECK(Mem0_BAR
[1], PCIR_MAPS
+0x8, 4);
628 MPT_CHECK(Mem1_BAR
[0], PCIR_MAPS
+0xC, 4);
629 MPT_CHECK(Mem1_BAR
[1], PCIR_MAPS
+0x10, 4);
630 MPT_CHECK(ROM_BAR
, PCIR_BIOS
, 4);
631 MPT_CHECK(IntLine
, PCIR_INTLINE
, 1);
632 MPT_CHECK(PMCSR
, 0x44, 4);
636 pci_write_config(mpt
->dev
, PCIR_COMMAND
, mpt
->pci_cfg
.Command
, 2);
637 pci_write_config(mpt
->dev
, PCIR_CACHELNSZ
,
638 mpt
->pci_cfg
.LatencyTimer_LineSize
, 2);
639 pci_write_config(mpt
->dev
, PCIR_MAPS
, mpt
->pci_cfg
.IO_BAR
, 4);
640 pci_write_config(mpt
->dev
, PCIR_MAPS
+0x4, mpt
->pci_cfg
.Mem0_BAR
[0], 4);
641 pci_write_config(mpt
->dev
, PCIR_MAPS
+0x8, mpt
->pci_cfg
.Mem0_BAR
[1], 4);
642 pci_write_config(mpt
->dev
, PCIR_MAPS
+0xC, mpt
->pci_cfg
.Mem1_BAR
[0], 4);
643 pci_write_config(mpt
->dev
, PCIR_MAPS
+0x10, mpt
->pci_cfg
.Mem1_BAR
[1], 4);
644 pci_write_config(mpt
->dev
, PCIR_BIOS
, mpt
->pci_cfg
.ROM_BAR
, 4);
645 pci_write_config(mpt
->dev
, PCIR_INTLINE
, mpt
->pci_cfg
.IntLine
, 1);
646 pci_write_config(mpt
->dev
, 0x44, mpt
->pci_cfg
.PMCSR
, 4);
650 mpt_pci_intr(void *arg
)
652 mpt_softc_t
*mpt
= arg
;
654 (void) mpt_intr(mpt
);