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