#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <bus/pci/pcireg.h>
#include <bus/pci/pcivar.h>
#include "advansys.h"
#define PCI_BASEADR0 PCIR_MAPS
#define PCI_BASEADR1 PCIR_MAPS + 4
#define PCI_DEVICE_ID_ADVANSYS_1200A 0x110010CD
#define PCI_DEVICE_ID_ADVANSYS_1200B 0x120010CD
#define PCI_DEVICE_ID_ADVANSYS_3000 0x130010CD
#define PCI_DEVICE_REV_ADVANSYS_3150 0x02
#define PCI_DEVICE_REV_ADVANSYS_3050 0x03
#define ADV_PCI_MAX_DMA_ADDR (0xFFFFFFFFL)
#define ADV_PCI_MAX_DMA_COUNT (0xFFFFFFFFL)
static int adv_pci_probe(device_t);
static int adv_pci_attach(device_t);
static u_int8_t* overrun_buf;
static bus_dma_tag_t overrun_dmat;
static bus_dmamap_t overrun_dmamap;
static bus_addr_t overrun_physbase;
static int
adv_pci_probe(device_t dev)
{
int rev = pci_get_revid(dev);
switch (pci_get_devid(dev)) {
case PCI_DEVICE_ID_ADVANSYS_1200A:
device_set_desc(dev, "AdvanSys ASC1200A SCSI controller");
return 0;
case PCI_DEVICE_ID_ADVANSYS_1200B:
device_set_desc(dev, "AdvanSys ASC1200B SCSI controller");
return 0;
case PCI_DEVICE_ID_ADVANSYS_3000:
if (rev == PCI_DEVICE_REV_ADVANSYS_3150) {
device_set_desc(dev,
"AdvanSys ASC3150 SCSI controller");
return 0;
} else if (rev == PCI_DEVICE_REV_ADVANSYS_3050) {
device_set_desc(dev,
"AdvanSys ASC3030/50 SCSI controller");
return 0;
} else if (rev >= PCI_DEVICE_REV_ADVANSYS_3150) {
device_set_desc(dev, "Unknown AdvanSys controller");
return 0;
}
break;
default:
break;
}
return ENXIO;
}
static int
adv_pci_attach(device_t dev)
{
struct adv_softc *adv;
u_int32_t id;
u_int32_t command;
int error, rid, irqrid;
void *ih;
struct resource *iores, *irqres;
id = pci_read_config(dev, PCIR_DEVVENDOR, 4);
command = pci_read_config(dev, PCIR_COMMAND, 1);
if ((command & (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN))
!= (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN)) {
command |= PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN;
pci_write_config(dev, PCIR_COMMAND, command, 1);
}
if (id == PCI_DEVICE_ID_ADVANSYS_1200A
|| id == PCI_DEVICE_ID_ADVANSYS_1200B) {
pci_write_config(dev, PCIR_LATTIMER, 0, 1);
}
rid = PCI_BASEADR0;
iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
RF_ACTIVE);
if (iores == NULL)
return ENXIO;
if (adv_find_signature(rman_get_bustag(iores),
rman_get_bushandle(iores)) == 0) {
bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
return ENXIO;
}
adv = adv_alloc(dev, rman_get_bustag(iores), rman_get_bushandle(iores));
if (adv == NULL) {
bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
return ENXIO;
}
error = bus_dma_tag_create(NULL, 1,
0,
ADV_PCI_MAX_DMA_ADDR,
BUS_SPACE_MAXADDR,
BUS_SPACE_MAXSIZE_32BIT,
BUS_SPACE_UNRESTRICTED,
ADV_PCI_MAX_DMA_COUNT,
0,
&adv->parent_dmat);
if (error != 0) {
kprintf("%s: Could not allocate DMA tag - error %d\n",
adv_name(adv), error);
adv_free(adv);
bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
return ENXIO;
}
adv->init_level++;
if (overrun_buf == NULL) {
if (bus_dma_tag_create(adv->parent_dmat,
8, 0,
ADV_PCI_MAX_DMA_ADDR, BUS_SPACE_MAXADDR,
ADV_OVERRUN_BSIZE, 1,
BUS_SPACE_MAXSIZE_32BIT, 0,
&overrun_dmat) != 0) {
bus_dma_tag_destroy(adv->parent_dmat);
adv_free(adv);
bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
return ENXIO;
}
if (bus_dmamem_alloc(overrun_dmat,
(void *)&overrun_buf,
BUS_DMA_NOWAIT,
&overrun_dmamap) != 0) {
bus_dma_tag_destroy(overrun_dmat);
bus_dma_tag_destroy(adv->parent_dmat);
adv_free(adv);
bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
return ENXIO;
}
bus_dmamap_load(overrun_dmat, overrun_dmamap,
overrun_buf, ADV_OVERRUN_BSIZE,
adv_map, &overrun_physbase,
0);
}
adv->overrun_physbase = overrun_physbase;
ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
adv->chip_version = ADV_INB(adv, ADV_NONEISA_CHIP_REVISION);
adv->type = ADV_PCI;
{
u_int8_t extra_cfg;
if (adv->chip_version >= ADV_CHIP_VER_PCI_ULTRA_3150)
adv->type |= ADV_ULTRA;
if (adv->chip_version == ADV_CHIP_VER_PCI_ULTRA_3050)
extra_cfg = ADV_IFC_ACT_NEG | ADV_IFC_WR_EN_FILTER;
else
extra_cfg = ADV_IFC_ACT_NEG | ADV_IFC_SLEW_RATE;
ADV_OUTB(adv, ADV_REG_IFC, extra_cfg);
}
if (adv_init(adv) != 0) {
adv_free(adv);
bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
return ENXIO;
}
adv->max_dma_count = ADV_PCI_MAX_DMA_COUNT;
adv->max_dma_addr = ADV_PCI_MAX_DMA_ADDR;
#if defined(CC_DISABLE_PCI_PARITY_INT) && CC_DISABLE_PCI_PARITY_INT
{
u_int16_t config_msw;
config_msw = ADV_INW(adv, ADV_CONFIG_MSW);
config_msw &= 0xFFC0;
ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
}
#endif
if (id == PCI_DEVICE_ID_ADVANSYS_1200A
|| id == PCI_DEVICE_ID_ADVANSYS_1200B) {
adv->bug_fix_control |= ADV_BUG_FIX_IF_NOT_DWB;
adv->bug_fix_control |= ADV_BUG_FIX_ASYN_USE_SYN;
adv->fix_asyn_xfer = ~0;
}
irqrid = 0;
irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &irqrid, 0, ~0, 1,
RF_SHAREABLE | RF_ACTIVE);
if (irqres == NULL ||
bus_setup_intr(dev, irqres, 0, adv_intr, adv, &ih, NULL)) {
adv_free(adv);
bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);
return ENXIO;
}
adv_attach(adv);
return 0;
}
static device_method_t adv_pci_methods[] = {
DEVMETHOD(device_probe, adv_pci_probe),
DEVMETHOD(device_attach, adv_pci_attach),
DEVMETHOD_END
};
static driver_t adv_pci_driver = {
"adv", adv_pci_methods, sizeof(struct adv_softc)
};
static devclass_t adv_pci_devclass;
DRIVER_MODULE(adv, pci, adv_pci_driver, adv_pci_devclass, NULL, NULL);