dpt_pci.c revision 38115
1/* 2 * Copyright (c) 1997 by Simon Shapiro 3 * All Rights Reserved 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions, and the following disclaimer, 10 * without modification, immediately at the beginning of the file. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31/* 32 * dptpci.c: Pseudo device drivers for DPT on PCI on FreeBSD 33 * 34 * caveats: We may need an eisa and an isa files too 35 */ 36 37#ident "$Id: dpt_pci.c,v 1.6 1998/06/02 00:32:38 eivind Exp $" 38 39#include "opt_devfs.h" 40#include "opt_dpt.h" 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/malloc.h> 45#include <sys/buf.h> 46#include <sys/kernel.h> 47 48#include <scsi/scsiconf.h> 49 50#include <pci/pcireg.h> 51#include <pci/pcivar.h> 52 53#include <sys/dpt.h> 54#include <pci/dpt_pci.h> 55 56#include <vm/vm.h> 57#include <vm/pmap.h> 58 59#define PCI_BASEADR0 PCI_MAP_REG_START /* I/O Address */ 60#define PCI_BASEADR1 PCI_MAP_REG_START + 4 /* Mem I/O Address */ 61 62#define ISA_PRIMARY_WD_ADDRESS 0x1f8 63 64/* Global variables */ 65 66/* Function Prototypes */ 67 68static char *dpt_pci_probe(pcici_t tag, pcidi_t type); 69static void dpt_pci_attach(pcici_t config_id, int unit); 70static int dpt_pci_shutdown(int foo, int bar); 71 72extern struct cdevsw dpt_cdevsw; 73 74static struct pci_device dpt_pci_driver = 75{ 76 "dpt", 77 dpt_pci_probe, 78 dpt_pci_attach, 79 &dpt_unit, 80 dpt_pci_shutdown 81}; 82 83DATA_SET(pcidevice_set, dpt_pci_driver); 84 85/* 86 * Probe the PCI device. 87 * Some of this work will have to be duplicated in _attach 88 * because we do not know for sure how the two relate. 89 */ 90 91static char * 92dpt_pci_probe(pcici_t tag, pcidi_t type) 93{ 94 static char silly_message[64]; 95 static int already_announced = 0; 96 97 u_int32_t dpt_id; 98 u_int32_t command; 99 u_int32_t class; 100 101#define pci_device tag.cfg2.port 102#define pci_bus tag.cfg2.forward 103#define pci_index tag.cfg2.enable 104 105#ifndef PCI_COMMAND_MASTER_ENABLE 106#define PCI_COMMAND_MASTER_ENABLE 0x00000004 107#endif 108 109#ifndef PCI_SUBCLASS_MASS_STORAGE_SCSI 110#define PCI_SUBCLASS_MASS_STORAGE_SCSI 0x00000000 111#endif 112 113 if ( bootverbose && !already_announced ) { 114 printf("DPT: PCI SCSI HBA Driver, version %d.%d.%d\n", 115 DPT_RELEASE, DPT_VERSION, DPT_PATCH); 116 ++already_announced; 117 } 118 119 if ((dpt_id = (type & 0xffff0000) >> 16) == DPT_DEVICE_ID) { 120 /* This one appears to belong to us, but what is it? */ 121 class = pci_conf_read(tag, PCI_CLASS_REG); 122 if (((class & PCI_CLASS_MASK) == PCI_CLASS_MASS_STORAGE) && 123 ((class & PCI_SUBCLASS_MASK) == PCI_SUBCLASS_MASS_STORAGE_SCSI) ) { 124 /* It is a SCSI storage device. How do talk to it? */ 125 command = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); 126#ifdef DPT_ALLOW_MEMIO 127 if ( ((command & PCI_COMMAND_IO_ENABLE) == 0) 128 && ((command & PCI_COMMAND_MEM_ENABLE) == 0) ) 129#else 130 if ( ((command & PCI_COMMAND_IO_ENABLE) == 0) ) 131#endif /* DPT_ALLOW_MEMIO */ 132 { 133 printf("DPT: Cannot map the controller registers :-(\n"); 134 return(NULL); 135 } 136 } else { 137 printf("DPT: Device is not Mass Storage, nor SCSI controller\n"); 138 return(NULL); 139 } 140 141 command = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); 142 if ( (command & PCI_COMMAND_MASTER_ENABLE) == 0 ) { 143 printf("DPT: Cannot be functional without BUSMASTER. :-(\n"); 144 return (NULL); 145 } 146 147#ifdef DPT_DEBUG_PCI 148 printf("DPT: Controller is %s mapable\n", 149 (command & PCI_COMMAND_MEM_ENABLE) 150 ? "MEMORY" 151 : ((command & PCI_COMMAND_IO_ENABLE) 152 ? "I/O" 153 : "NOT")); 154#endif 155 return ("DPT Caching SCSI RAID Controller"); 156 } 157 158#if defined(DPT_DEBUG_PCI) && defined(DPT_DEBUG_WARN) 159 printf("DPT: Unknown Controller Type %x Found\n", dpt_id); 160 printf(" (class = %x, command = %x\n", class, command); 161#endif 162 return (NULL); 163} 164 165static void 166dpt_pci_attach(pcici_t config_id, int unit) 167{ 168 int ospl; 169 int result; 170 int ndx; 171 172 vm_offset_t vaddr; 173 vm_offset_t paddr; 174 u_int16_t io_base; 175 u_int32_t command; 176 u_int32_t data; 177 dpt_conf_t *config; 178 dpt_softc_t *dpt; 179 180 if (dpt_controllers_present >= DPT_MAX_ADAPTERS) { 181 printf("dpt%d: More than %d Adapters found! Adapter rejected\n", 182 unit, DPT_MAX_ADAPTERS); 183 return; 184 } 185 186 if ((dpt = (dpt_softc_t *) malloc(sizeof(dpt_softc_t), M_DEVBUF, M_NOWAIT)) 187 == NULL) { 188 printf("dpt%d: Failed to allocate %d bytes for a DPT softc\n", 189 unit, sizeof(dpt_softc_t)); 190 return; 191 } 192 193 /* 194 * Initialize the queues. See dpt.h for details. We do this here, 195 * as we may get hit with interrupts at any moment and we want to 196 * have a minimal structure in place to handle them. We also want to 197 * register interrupts correctly. To do so, we need a valid dpt 198 * structure. To have that, we need this minimal setup here. 199 */ 200 bzero(dpt, sizeof(dpt_softc_t)); 201 202 TAILQ_INIT(&dpt->free_ccbs); 203 TAILQ_INIT(&dpt->waiting_ccbs); 204 TAILQ_INIT(&dpt->submitted_ccbs); 205 TAILQ_INIT(&dpt->completed_ccbs); 206 207 if (TAILQ_EMPTY(&dpt_softc_list)) { 208 TAILQ_INIT(&dpt_softc_list); 209 } 210 211 TAILQ_INSERT_TAIL(&dpt_softc_list, dpt, links); 212 dpt->queue_status = DPT_QUEUES_NONE_ACTIVE; 213 dpt->commands_processed = 0; 214 215#ifdef DPT_MEASURE_PERFORMANCE 216 dpt_reset_performance(dpt); 217#endif /* DPT_MEASURE_PERFORMANCE */ 218 219 dpt->unit = unit; 220 dpt->handle_interrupts = 0; /* 221 * Do not set to 1 until all 222 * initialization is done 223 */ 224 dpt->v_membase = NULL; 225 dpt->p_membase = NULL; 226 io_base = 0; 227 vaddr = 0; 228 paddr = 0; 229 command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); 230 231#ifdef DPT_ALLOW_MEMIO 232 if ( (command & PCI_COMMAND_MEM_ENABLE) == 0 ) { 233#ifdef DPT_DEBUG_PCI 234 printf("dpt%d: Cannot be memory mapped\n", unit); 235#endif 236 force_io: 237 if ((command & PCI_COMMAND_IO_ENABLE) == 0 ) { 238 printf("dpt%d: Cannot be I/O mapped either :-(\n", unit); 239 free(dpt, M_DEVBUF); 240 return; 241 } else { 242 data = pci_conf_read(config_id, PCI_MAP_REG_START); 243 if ( pci_map_port(config_id, PCI_MAP_REG_START, &io_base) == 0 ) { 244#ifdef DPT_DEBUG_ERROR 245 printf("dpt%d: Failed to map as I/O :-(\n", unit); 246#endif 247 free(dpt, M_DEVBUF); 248 return; 249 } else { 250 dpt->io_base = io_base + 0x10; 251#ifdef DPT_DEBUG_PCI 252 printf("dpt%d: Mapped registers to I/O space, " 253 "starting at %x\n", 254 dpt->unit, dpt->io_base); 255#endif 256 } 257 } 258 } else { 259 if ( pci_map_mem(config_id, PCI_MAP_REG_START + 4, &vaddr, 260 &paddr) == 0 ) { 261#ifdef DPT_DEBUG_ERROR 262 printf("dpt%d: Failed to map as MEMORY.\n" 263 " Attemting to force I/O mapping\n", unit); 264#endif 265 goto force_io; 266 } else { 267 dpt->v_membase = (volatile u_int8_t *)(vaddr + 0x10); 268 dpt->p_membase = (volatile u_int8_t *)(paddr + 0x10); 269#ifdef DPT_DEBUG_PCI 270 printf("dpt%d: Mapped registers to MEMORY space, " 271 "starting at %x/%x\n", 272 dpt->unit, dpt->v_membase, dpt->p_membase); 273#endif 274 } 275 } 276 277#else /* !DPT_ALLOW_MEMIO */ 278 data = pci_conf_read(config_id, PCI_MAP_REG_START); 279 if ((command & PCI_COMMAND_IO_ENABLE) == 0 ) { 280 printf("dpt%d: Registers cannot be I/O mapped :-(\n", unit); 281 free(dpt, M_DEVBUF); 282 return; 283 } else { 284 if ( pci_map_port(config_id, PCI_MAP_REG_START, &io_base) == 0 ) { 285#ifdef DPT_DEBUG_ERROR 286 printf("dpt%d: Failed to map registers as I/O :-(\n", unit); 287#endif 288 free(dpt, M_DEVBUF); 289 return; 290 } else { 291 dpt->io_base = io_base + 0x10; 292#ifdef DPT_DEBUG_PCI 293 printf("dpt%d: Mapped registers to I/O space, starting at %x\n", 294 dpt->unit, dpt->io_base); 295#endif 296 } 297 } 298#endif /* !DPT_ALLOW_MEMIO */ 299 300 if (pci_map_int(config_id, dpt_intr, (void *)dpt, &cam_imask) == 0) { 301#ifdef DPT_DEBUG_WARN 302 printf("dpt%d: Failed to map interrupt :-(\n", unit); 303#endif 304 free(dpt, M_DEVBUF); 305 return; 306 } 307 308 /* If the DPT is mapped as an IDE controller, let it be IDE controller */ 309 if (io_base == (ISA_PRIMARY_WD_ADDRESS)) { 310#ifdef DPT_DEBUG_WARN 311 printf("dpt%d: Mapped as an IDE controller. " 312 "Disabling SCSI setup\n", unit); 313#endif 314 free(dpt, M_DEVBUF); 315 return; 316 } else { 317 if ((config = dpt_get_conf(dpt, 0xc1, 7, 318 sizeof(dpt_conf_t), 1)) == NULL) { 319#ifdef DPT_DEBUG_ERROR 320 printf("dpt%d: Failed to get board configuration (%x)\n", 321 unit, BaseRegister(dpt)); 322#endif 323 free(dpt, M_DEVBUF); 324 return; 325 } 326 } 327 328 dpt->max_id = config->MAX_ID; 329 dpt->max_lun = config->MAX_LUN; 330 dpt->irq = config->IRQ; 331 dpt->channels = config->MAX_CHAN; 332 dpt->dma_channel = (8 - config->DMA_channel) & 7; 333 334#ifdef DPT_DEBUG_SETUP 335 printf("dpt%d: max_id = %d, max_chan = %d, max_lun = %d\n", 336 dpt->unit, dpt->max_id, dpt->channels, dpt->max_lun); 337#endif 338 339 if (result = dpt_setup(dpt, config)) { 340 free(config, M_TEMP); 341 free(dpt, M_DEVBUF); 342 printf("dpt%d: dpt_setup failed (%d). Driver Disabled :-(\n", 343 dpt->unit, result); 344 } else { 345 /* clean up the informational data, and display */ 346 char clean_vendor[9]; 347 char clean_model[17]; 348 char clean_firmware[5]; 349 char clean_protocol[5]; 350 char clean_other[7]; 351 352 int ndx; 353 354 strncpy(clean_other, dpt->board_data.otherData, 8); 355 clean_other[6] = '\0'; 356 for (ndx = 5; ndx >= 0; ndx--) { 357 if (clean_other[ndx] == ' ') 358 clean_other[ndx] = '\0'; 359 else 360 break; 361 } 362 strncpy(dpt->board_data.otherData, clean_other, 6); 363 364 strncpy(clean_vendor, dpt->board_data.vendor, 8); 365 clean_vendor[8] = '\0'; 366 for (ndx = 7; ndx >= 0; ndx--) { 367 if (clean_vendor[ndx] == ' ') 368 clean_vendor[ndx] = '\0'; 369 else 370 break; 371 } 372 strncpy(dpt->board_data.vendor, clean_vendor, 8); 373 374 strncpy(clean_model, dpt->board_data.modelNum, 16); 375 clean_model[16] = '\0'; 376 for (ndx = 15; ndx >= 0; ndx--) { 377 if (clean_model[ndx] == ' ') 378 clean_model[ndx] = '\0'; 379 else 380 break; 381 } 382 strncpy(dpt->board_data.modelNum, clean_model, 16); 383 384 strncpy(clean_firmware, dpt->board_data.firmware, 4); 385 clean_firmware[4] = '\0'; 386 for (ndx = 3; ndx >= 0; ndx--) { 387 if (clean_firmware[ndx] == ' ') 388 clean_firmware[ndx] = '\0'; 389 else 390 break; 391 } 392 strncpy(dpt->board_data.firmware, clean_firmware, 4); 393 394 strncpy(clean_protocol, dpt->board_data.protocol, 4); 395 clean_protocol[4] = '\0'; 396 for (ndx = 3; ndx >= 0; ndx--) { 397 if (clean_protocol[ndx] == ' ') 398 clean_protocol[ndx] = '\0'; 399 else 400 break; 401 } 402 strncpy(dpt->board_data.protocol, clean_protocol, 4); 403 404 dpt_detect_cache(dpt); 405 406 printf("dpt%d: %s type %x, model %s firmware %s, Protocol %s \n" 407 " on port %x with %s cache. LED = %s\n", 408 dpt->unit, clean_vendor, dpt->board_data.deviceType, 409 clean_model, clean_firmware, clean_protocol, dpt->io_base, 410 (dpt->cache_type == DPT_NO_CACHE) 411 ? "Disabled" 412 : (dpt->cache_type == DPT_CACHE_WRITETHROUGH) 413 ? "Write-Through" 414 : "Write-Back", 415 i2bin(dpt_blinking_led(dpt), 8)); 416 printf("dpt%d: Enabled Options:\n", dpt->unit); 417#ifdef DPT_LOST_IRQ 418 printf(" Recover Lost Interrupts\n"); 419#endif 420#ifdef DPT_VERIFY_HINTR 421 printf(" Verify Lost Transactions\n"); 422#endif 423#ifdef DPT_RESTRICTED_FREELIST 424 printf(" Restrict the Freelist Size\n"); 425#endif 426#ifdef DPT_MEASURE_PERFORMANCE 427 printf(" Collect Metrics\n"); 428#endif 429#ifdef DPT_FREELIST_IS_STACK 430 printf(" Optimize CPU Cache\n"); 431#endif 432#ifdef DPT_HANDLE_TIMEOUTS 433 printf(" Handle Timeouts\n"); 434#endif 435#ifdef DPT_ALLOW_MEMIO 436 printf(" Allow I/O to be Memeory Mapped\n"); 437#endif 438#ifdef DPT_HINTR_CHECK_SOFTC 439 printf(" Validate SoftC at Interrupt\n"); 440#endif 441 442 /* register shutdown handlers */ 443 result = at_shutdown((bootlist_fn)dpt_shutdown, (void *)dpt, 444 SHUTDOWN_POST_SYNC); 445 switch ( result ) { 446 case 0: 447#ifdef DPT_DEBUG_SHUTDOWN 448 printf("dpt%d: Shutdown handler registered\n", dpt->unit); 449#endif 450 break; 451 default: 452#ifdef DPT_DEBUG_WARN 453 printf("dpt%d: Failed to register shutdown handler (%d)\n", 454 dpt->unit, result); 455#endif 456 break; 457 } 458 459 /* Attach SCSI devices */ 460 dpt_attach(dpt); 461 ++dpt_controllers_present; 462 463 /* 464 * Now we create the DEVFS entry. 465 * This would be normally done from dpt_control.c, 466 * But since it appears to be called before we do here, 467 * We never get the entries made. 468 */ 469#ifdef DEVFS 470 (void) devfs_add_devswf(&dpt_cdevsw, dpt->unit, DV_CHR, 471 UID_ROOT, GID_WHEEL, 0600, 472 "dpt%d", dpt->unit); 473 (void) devfs_add_devswf(&dpt_cdevsw, dpt->unit | SCSI_CONTROL_MASK, 474 DV_CHR, 475 UID_ROOT, GID_WHEEL, 0600, 476 "dpt%d.ctl", dpt->unit); 477#endif 478 } 479} 480 481static int 482dpt_pci_shutdown(int foo, int bar) 483{ 484#ifdef DPT_DEBUG_WARN 485 printf("dpt_pci_shutdown(%x, %x)\n", foo, bar); 486#endif 487 return (0); 488} 489 490/* End of the DPT PCI part of the driver */ 491 492/* 493 * Hello emacs, these are the 494 * Local Variables: 495 * c-indent-level: 8 496 * c-continued-statement-offset: 8 497 * c-continued-brace-offset: 0 498 * c-brace-offset: -8 499 * c-brace-imaginary-offset: 0 500 * c-argdecl-indent: 8 501 * c-label-offset: -8 502 * c++-hanging-braces: 1 503 * c++-access-specifier-offset: -8 504 * c++-empty-arglist-indent: 8 505 * c++-friend-offset: 0 506 * End: 507 */ 508