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