sys/dev/disk/advansys/adw_pci.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | /* * Device probe and attach routines for the following * Advanced Systems Inc. SCSI controllers: * * ABP[3]940UW - Bus-Master PCI Ultra-Wide (253 CDB) * ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB/Channel) * ABP970UW - Bus-Master PCI Ultra-Wide (253 CDB) * ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB) * ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB) * * Copyright (c) 1998, 1999, 2000 Justin Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD: src/sys/dev/advansys/adw_pci.c,v 1.12.2.1 2000/08/02 22:22:40 peter Exp $ */ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/bus.h> #include <sys/rman.h> #include <bus/pci/pcireg.h> #include <bus/pci/pcivar.h> #include <bus/cam/cam.h> #include <bus/cam/scsi/scsi_all.h> #include "adwvar.h" #include "adwlib.h" #include "adwmcode.h" #define ADW_PCI_IOBASE PCIR_MAPS /* I/O Address */ #define ADW_PCI_MEMBASE PCIR_MAPS + 4 /* Mem I/O Address */ #define PCI_ID_ADVANSYS_3550 0x230010CD00000000ull #define PCI_ID_ADVANSYS_38C0800_REV1 0x250010CD00000000ull #define PCI_ID_ADVANSYS_38C1600_REV1 0x270010CD00000000ull #define PCI_ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull #define PCI_ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull struct adw_pci_identity; typedef int (adw_device_setup_t)(device_t, struct adw_pci_identity *, struct adw_softc *adw); struct adw_pci_identity { u_int64_t full_id; u_int64_t id_mask; char *name; adw_device_setup_t *setup; const struct adw_mcode *mcode_data; const struct adw_eeprom *default_eeprom; }; static adw_device_setup_t adw_asc3550_setup; static adw_device_setup_t adw_asc38C0800_setup; #ifdef NOTYET static adw_device_setup_t adw_asc38C1600_setup; #endif struct adw_pci_identity adw_pci_ident_table[] = { /* asc3550 based controllers */ { PCI_ID_ADVANSYS_3550, PCI_ID_DEV_VENDOR_MASK, "AdvanSys 3550 Ultra SCSI Adapter", adw_asc3550_setup, &adw_asc3550_mcode_data, &adw_asc3550_default_eeprom }, /* asc38C0800 based controllers */ { PCI_ID_ADVANSYS_38C0800_REV1, PCI_ID_DEV_VENDOR_MASK, "AdvanSys 38C0800 Ultra2 SCSI Adapter", adw_asc38C0800_setup, &adw_asc38C0800_mcode_data, &adw_asc38C0800_default_eeprom }, #if 0 /* NOTYET */ /* XXX Disabled until I have hardware to test with */ /* asc38C1600 based controllers */ { PCI_ID_ADVANSYS_38C1600_REV1, PCI_ID_DEV_VENDOR_MASK, "AdvanSys 38C1600 Ultra160 SCSI Adapter", adw_asc38C1600_setup, NULL, /* None provided by vendor thus far */ NULL /* None provided by vendor thus far */ } #endif }; static const int adw_num_pci_devs = NELEM(adw_pci_ident_table); #define ADW_PCI_MAX_DMA_ADDR (0xFFFFFFFFUL) #define ADW_PCI_MAX_DMA_COUNT (0xFFFFFFFFUL) static int adw_pci_probe(device_t dev); static int adw_pci_attach(device_t dev); static device_method_t adw_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, adw_pci_probe), DEVMETHOD(device_attach, adw_pci_attach), DEVMETHOD_END }; static driver_t adw_pci_driver = { "adw", adw_pci_methods, sizeof(struct adw_softc) }; static devclass_t adw_devclass; DRIVER_MODULE(adw, pci, adw_pci_driver, adw_devclass, NULL, NULL); static __inline u_int64_t adw_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor) { u_int64_t id; id = subvendor | (subdevice << 16) | ((u_int64_t)vendor << 32) | ((u_int64_t)device << 48); return (id); } static struct adw_pci_identity * adw_find_pci_device(device_t dev) { u_int64_t full_id; struct adw_pci_identity *entry; u_int i; full_id = adw_compose_id(pci_get_device(dev), pci_get_vendor(dev), pci_get_subdevice(dev), pci_get_subvendor(dev)); for (i = 0; i < adw_num_pci_devs; i++) { entry = &adw_pci_ident_table[i]; if (entry->full_id == (full_id & entry->id_mask)) return (entry); } return (NULL); } static int adw_pci_probe(device_t dev) { struct adw_pci_identity *entry; entry = adw_find_pci_device(dev); if (entry != NULL) { device_set_desc(dev, entry->name); return (0); } return (ENXIO); } static int adw_pci_attach(device_t dev) { struct adw_softc *adw; struct adw_pci_identity *entry; u_int32_t command; struct resource *regs; int regs_type; int regs_id; int error; int zero; command = pci_read_config(dev, PCIR_COMMAND, /*bytes*/1); entry = adw_find_pci_device(dev); if (entry == NULL) return (ENXIO); regs = NULL; regs_type = 0; regs_id = 0; #ifdef ADW_ALLOW_MEMIO if ((command & PCIM_CMD_MEMEN) != 0) { regs_type = SYS_RES_MEMORY; regs_id = ADW_PCI_MEMBASE; regs = bus_alloc_resource(dev, regs_type, ®s_id, 0, ~0, 1, RF_ACTIVE); } #endif if (regs == NULL && (command & PCIM_CMD_PORTEN) != 0) { regs_type = SYS_RES_IOPORT; regs_id = ADW_PCI_IOBASE; regs = bus_alloc_resource(dev, regs_type, ®s_id, 0, ~0, 1, RF_ACTIVE); } if (regs == NULL) { device_printf(dev, "can't allocate register resources\n"); return (ENOMEM); } adw = adw_alloc(dev, regs, regs_type, regs_id); if (adw == NULL) return(ENOMEM); /* * Now that we have access to our registers, just verify that * this really is an AdvanSys device. */ if (adw_find_signature(adw) == 0) { adw_free(adw); return (ENXIO); } adw_reset_chip(adw); error = entry->setup(dev, entry, adw); if (error != 0) return (error); /* Ensure busmastering is enabled */ command |= PCIM_CMD_BUSMASTEREN; pci_write_config(dev, PCIR_COMMAND, command, /*bytes*/1); /* Allocate a dmatag for our transfer DMA maps */ /* XXX Should be a child of the PCI bus dma tag */ error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1, /*boundary*/0, /*lowaddr*/ADW_PCI_MAX_DMA_ADDR, /*highaddr*/BUS_SPACE_MAXADDR, /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, /*nsegments*/BUS_SPACE_UNRESTRICTED, /*maxsegsz*/ADW_PCI_MAX_DMA_COUNT, /*flags*/0, &adw->parent_dmat); adw->init_level++; if (error != 0) { kprintf("%s: Could not allocate DMA tag - error %d\n", adw_name(adw), error); adw_free(adw); return (error); } adw->init_level++; error = adw_init(adw); if (error != 0) { adw_free(adw); return (error); } /* * If the PCI Configuration Command Register "Parity Error Response * Control" Bit was clear (0), then set the microcode variable * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode * to ignore DMA parity errors. */ if ((command & PCIM_CMD_PERRESPEN) == 0) adw_lram_write_16(adw, ADW_MC_CONTROL_FLAG, adw_lram_read_16(adw, ADW_MC_CONTROL_FLAG) | ADW_MC_CONTROL_IGN_PERR); zero = 0; adw->irq_res_type = SYS_RES_IRQ; adw->irq = bus_alloc_resource(dev, adw->irq_res_type, &zero, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); if (adw->irq == NULL) { adw_free(adw); return (ENOMEM); } error = adw_attach(adw); if (error != 0) adw_free(adw); return (error); } static int adw_generic_setup(device_t dev, struct adw_pci_identity *entry, struct adw_softc *adw) { adw->channel = pci_get_function(dev) == 1 ? 'B' : 'A'; adw->chip = ADW_CHIP_NONE; adw->features = ADW_FENONE; adw->flags = ADW_FNONE; adw->mcode_data = entry->mcode_data; adw->default_eeprom = entry->default_eeprom; return (0); } static int adw_asc3550_setup(device_t dev, struct adw_pci_identity *entry, struct adw_softc *adw) { int error; error = adw_generic_setup(dev, entry, adw); if (error != 0) return (error); adw->chip = ADW_CHIP_ASC3550; adw->features = ADW_ASC3550_FE; adw->memsize = ADW_3550_MEMSIZE; /* * For ASC-3550, setting the START_CTL_EMFU [3:2] bits * sets a FIFO threshold of 128 bytes. This register is * only accessible to the host. */ adw_outb(adw, ADW_DMA_CFG0, ADW_DMA_CFG0_START_CTL_EM_FU|ADW_DMA_CFG0_READ_CMD_MRM); adw_outb(adw, ADW_MEM_CFG, adw_inb(adw, ADW_MEM_CFG) | ADW_MEM_CFG_RAM_SZ_8KB); return (0); } static int adw_asc38C0800_setup(device_t dev, struct adw_pci_identity *entry, struct adw_softc *adw) { int error; error = adw_generic_setup(dev, entry, adw); if (error != 0) return (error); /* * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and * START_CTL_TH [3:2] bits for the default FIFO threshold. * * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes. * * For DMA Errata #4 set the BC_THRESH_ENB bit. */ adw_outb(adw, ADW_DMA_CFG0, ADW_DMA_CFG0_BC_THRESH_ENB|ADW_DMA_CFG0_FIFO_THRESH_80B |ADW_DMA_CFG0_START_CTL_TH|ADW_DMA_CFG0_READ_CMD_MRM); adw_outb(adw, ADW_MEM_CFG, adw_inb(adw, ADW_MEM_CFG) | ADW_MEM_CFG_RAM_SZ_16KB); adw->chip = ADW_CHIP_ASC38C0800; adw->features = ADW_ASC38C0800_FE; adw->memsize = ADW_38C0800_MEMSIZE; return (error); } #ifdef NOTYET static int adw_asc38C1600_setup(device_t dev, struct adw_pci_identity *entry, struct adw_softc *adw) { int error; error = adw_generic_setup(dev, entry, adw); if (error != 0) return (error); adw->chip = ADW_CHIP_ASC38C1600; adw->features = ADW_ASC38C1600_FE; adw->memsize = ADW_38C1600_MEMSIZE; return (error); } #endif |