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