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