1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (C) 2013 Hewlett-Packard Development Company, L.P. 14 */ 15 16 #include "cpqary3.h" 17 18 /* 19 * Local Autoconfiguration Function Prototype Declations 20 */ 21 22 int cpqary3_attach(dev_info_t *, ddi_attach_cmd_t); 23 int cpqary3_detach(dev_info_t *, ddi_detach_cmd_t); 24 int cpqary3_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 25 26 /* 27 * Local Functions Definitions 28 */ 29 30 static void cpqary3_cleanup(cpqary3_t *, uint32_t); 31 static uint8_t cpqary3_update_ctlrdetails(cpqary3_t *, uint32_t *); 32 int8_t cpqary3_detect_target_geometry(cpqary3_t *); 33 34 /* 35 * External Variable Definitions 36 */ 37 38 extern cpqary3_driver_info_t gdriver_info; 39 40 /* 41 * Global Variables Definitions 42 */ 43 44 static char cpqary3_brief[] = "HP Smart Array Driver"; 45 void *cpqary3_state; 46 47 /* HPQaculi Changes */ 48 49 /* 50 * HBA minor number schema 51 * 52 * The minor numbers for any minor device nodes that we create are 53 * governed by the SCSA framework. We use the macros below to 54 * fabricate minor numbers for nodes that we own. 55 * 56 * See sys/impl/transport.h for more info. 57 */ 58 59 /* Macro to extract interface from minor number */ 60 #define CPQARY3_MINOR2INTERFACE(_x) ((_x) & (TRAN_MINOR_MASK)) 61 62 /* Base of range assigned to HBAs: */ 63 #define SCSA_MINOR_HBABASE (32) 64 65 /* Our minor nodes: */ 66 #define CPQARY3_MINOR (0 + SCSA_MINOR_HBABASE) 67 68 /* Convenience macros to convert device instances to minor numbers */ 69 #define CPQARY3_INST2x(_i, _x) (((_i) << INST_MINOR_SHIFT) | (_x)) 70 #define CPQARY3_INST2CPQARY3(_i) CPQARY3_INST2x(_i, CPQARY3_MINOR) 71 72 /* HPQacucli Changes */ 73 74 /* 75 * The Driver DMA Limit structure. 76 * Data used for SMART Integrated Array Controller shall be used. 77 */ 78 79 ddi_dma_attr_t cpqary3_dma_attr = { 80 DMA_ATTR_V0, /* ddi_dma_attr version */ 81 0, /* Low Address */ 82 0xFFFFFFFFFFFFFFFF, /* High Address */ 83 0x00FFFFFF, /* Max DMA Counter register */ 84 0x20, /* Byte Alignment */ 85 0x20, /* Burst Sizes : 32 Byte */ 86 DMA_UNIT_8, /* Minimum DMA xfer Size */ 87 0xFFFFFFFF, /* Maximum DMA xfer Size */ 88 /* 89 * Segment boundary restrictions 90 * The addr should not cross 4GB boundry. 91 * This is required to address an issue 92 * in the Surge ASIC, with earlier FW versions. 93 */ 94 0xFFFFFFFF, 95 CPQARY3_SG_CNT, /* Scatter/Gather List Length */ 96 512, /* Device Granularity */ 97 0 /* DMA flags */ 98 }; 99 100 /* 101 * The Device Access Attribute Structure. 102 */ 103 104 ddi_device_acc_attr_t cpqary3_dev_attributes = { 105 DDI_DEVICE_ATTR_V0, 106 DDI_STRUCTURE_LE_ACC, 107 DDI_STRICTORDER_ACC 108 }; 109 110 /* 111 * Character-Block Operations Structure 112 */ 113 114 static struct cb_ops cpqary3_cb_ops = { 115 /* HPQacucli Changes */ 116 scsi_hba_open, 117 scsi_hba_close, 118 /* HPQacucli Changes */ 119 nodev, /* cb_strategy */ 120 nodev, /* cb_print */ 121 nodev, /* cb_dump */ 122 nodev, /* cb_read */ 123 nodev, /* cb_write */ 124 cpqary3_ioctl, /* cb_ioctl */ 125 nodev, /* cb_devmap */ 126 nodev, /* cb_mmap */ 127 nodev, /* cb_segmap */ 128 nochpoll, /* cb_chpoll */ 129 ddi_prop_op, /* cb_prop_op */ 130 NULL, /* cb_stream */ 131 (int)(D_NEW|D_MP), /* cb_flag */ 132 CB_REV, 133 nodev, 134 nodev 135 }; 136 137 /* 138 * Device Operations Structure 139 */ 140 141 static struct dev_ops cpqary3_dev_ops = { 142 DEVO_REV, /* Driver Build Version */ 143 0, /* Driver reference count */ 144 nodev, /* Get Info */ 145 nulldev, /* Identify not required */ 146 nulldev, /* Probe, obselete for s2.6 and up */ 147 cpqary3_attach, /* Attach routine */ 148 cpqary3_detach, /* Detach routine */ 149 nodev, /* Reset */ 150 &cpqary3_cb_ops, /* Entry Points for C&B drivers */ 151 NULL, /* Bus ops */ 152 nodev /* cpqary3_power */ 153 }; 154 155 /* 156 * Linkage structures 157 */ 158 159 static struct modldrv cpqary3_modldrv = { 160 &mod_driverops, /* Module Type - driver */ 161 cpqary3_brief, /* Driver Desc */ 162 &cpqary3_dev_ops /* Driver Ops */ 163 }; 164 165 static struct modlinkage cpqary3_modlinkage = { 166 MODREV_1, /* Loadable module rev. no. */ 167 &cpqary3_modldrv, /* Loadable module */ 168 NULL /* end */ 169 }; 170 171 172 /* 173 * Function : _init 174 * Description : This routine allocates soft state resources for the 175 * driver, registers the HBA with the system and 176 * adds the driver(loadable module). 177 * Called By : Kernel 178 * Parameters : None 179 * Return Values: 0 / Non-Zero 180 * [as returned by the mod_install OS function] 181 */ 182 int 183 _init() 184 { 185 int retvalue; 186 187 /* 188 * Allocate Soft State Resources; if failure, return. 189 */ 190 retvalue = ddi_soft_state_init(&cpqary3_state, 191 sizeof (cpqary3_t), MAX_CTLRS); 192 VERIFY(retvalue == 0); 193 194 /* 195 * Initialise the HBA Interface. 196 */ 197 if (!(retvalue = scsi_hba_init(&cpqary3_modlinkage))) { 198 /* Load the driver */ 199 if ((retvalue = mod_install(&cpqary3_modlinkage))) { 200 /* 201 * Failed to load the driver, undo HBA interface 202 * and soft state allocation. 203 */ 204 scsi_hba_fini(&cpqary3_modlinkage); 205 ddi_soft_state_fini(&cpqary3_state); 206 } 207 } else { 208 /* 209 * Failed to register HBA interface, undo all soft state 210 * allocation 211 */ 212 ddi_soft_state_fini(&cpqary3_state); 213 } 214 215 return (retvalue); 216 } 217 218 /* 219 * Function : _fini 220 * Description : This routine removes the loadable module, cancels the 221 * HBA registration and deallocates soft state resources. 222 * Called By : Kernel 223 * Parameters : None 224 * Return Values: 0 - Success / Non-Zero - Failure 225 * [as returned by the mod_remove(OS provided) function] 226 */ 227 int 228 _fini() 229 { 230 int retvalue; 231 232 /* Unload the Driver(loadable module) */ 233 234 if ((retvalue = mod_remove(&cpqary3_modlinkage)) == 0) { 235 236 /* Cancel the registeration for the HBA Interface */ 237 scsi_hba_fini(&cpqary3_modlinkage); 238 239 /* dealloacte soft state resources of the driver */ 240 ddi_soft_state_fini(&cpqary3_state); 241 } 242 243 return (retvalue); 244 } 245 246 /* 247 * Function : _info 248 * Description : This routine returns information about the driver. 249 * Called By : Kernel 250 * Parameters : None 251 * Return Values: 0 / Non-Zero 252 * [as returned by mod_info(OS provided) function] 253 */ 254 int 255 _info(struct modinfo *modinfop) 256 { 257 /* 258 * Get the module information. 259 */ 260 return (mod_info(&cpqary3_modlinkage, modinfop)); 261 } 262 263 264 /* 265 * Function : cpqary3_attach 266 * Description : This routine initializes the driver specific soft state 267 * structure, initializes the HBA, interrupt handlers, 268 * memory pool, timeout handler, various mutex, creates the 269 * minor node. 270 * Called By : kernel 271 * Parameters : dip, command for attach 272 * Return Values: DDI_SUCCESS / DDI_FAILURE 273 * [Success on overall initialization & configuration 274 * being successful. Failure if any of the initialization 275 * or any driver-specific mandatory configuration fails] 276 */ 277 int 278 cpqary3_attach(dev_info_t *dip, ddi_attach_cmd_t attach_cmd) 279 { 280 int8_t minor_node_name[14]; 281 uint32_t instance; 282 uint32_t retvalue; 283 uint32_t cleanstatus = 0; 284 cpqary3_t *cpqary3p; /* per-controller */ 285 ddi_dma_attr_t tmp_dma_attr; 286 287 /* Return Failure, If the Command is other than - DDI_ATTACH. */ 288 289 if (attach_cmd != DDI_ATTACH) 290 return (DDI_FAILURE); 291 292 /* Get the Instance of the Device */ 293 294 instance = ddi_get_instance(dip); 295 296 /* Allocate the per-device-instance soft state structure */ 297 298 retvalue = ddi_soft_state_zalloc(cpqary3_state, instance); 299 VERIFY(retvalue == 0); 300 301 cleanstatus |= CPQARY3_SOFTSTATE_ALLOC_DONE; 302 303 /* Per Controller Pointer */ 304 cpqary3p = ddi_get_soft_state(cpqary3_state, instance); 305 if (!cpqary3p) { 306 cmn_err(CE_WARN, "CPQary3: Soft State Retrieval Failed"); 307 cpqary3_cleanup(cpqary3p, cleanstatus); 308 return (DDI_FAILURE); 309 } 310 311 /* Maintain a record in per-ctlr structure */ 312 cpqary3p->dip = dip; 313 cpqary3p->instance = instance; 314 315 /* Get the User Configuration information from Driver's conf File */ 316 cpqary3_read_conf_file(dip, cpqary3p); 317 318 /* Get and Map the HW Configuration */ 319 retvalue = cpqary3_update_ctlrdetails(cpqary3p, &cleanstatus); 320 if (retvalue == CPQARY3_FAILURE) { 321 cpqary3_cleanup(cpqary3p, cleanstatus); 322 return (DDI_FAILURE); 323 } 324 325 /* Get the Cookie for hardware Interrupt Handler */ 326 if (ddi_get_iblock_cookie(dip, 0, &cpqary3p->hw_iblock_cookie) != 327 DDI_SUCCESS) { 328 cpqary3_cleanup(cpqary3p, cleanstatus); 329 return (DDI_FAILURE); 330 } 331 332 /* Initialize Per Controller Mutex */ 333 mutex_init(&cpqary3p->hw_mutex, NULL, MUTEX_DRIVER, 334 (void *)cpqary3p->hw_iblock_cookie); 335 336 cleanstatus |= CPQARY3_MUTEX_INIT_DONE; 337 338 /* Get the Cookie for Soft(low level) Interrupt Handler */ 339 if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_HIGH, 340 &cpqary3p->sw_iblock_cookie) != DDI_SUCCESS) { 341 cpqary3_cleanup(cpqary3p, cleanstatus); 342 return (DDI_FAILURE); 343 } 344 345 /* Initialize the s/w Mutex */ 346 mutex_init(&cpqary3p->sw_mutex, NULL, MUTEX_DRIVER, 347 (void *)cpqary3p->sw_iblock_cookie); 348 cleanstatus |= CPQARY3_SW_MUTEX_INIT_DONE; 349 350 /* Initialize per Controller private details */ 351 retvalue = cpqary3_init_ctlr_resource(cpqary3p); 352 if (retvalue != CPQARY3_SUCCESS) { 353 cpqary3_cleanup(cpqary3p, cleanstatus); 354 return (DDI_FAILURE); 355 } 356 cleanstatus |= CPQARY3_CTLR_CONFIG_DONE; 357 358 /* 359 * Allocate HBA transport structure 360 */ 361 cpqary3p->hba_tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP); 362 if (!cpqary3p->hba_tran) { 363 cpqary3_cleanup(cpqary3p, cleanstatus); 364 return (DDI_FAILURE); 365 } 366 cleanstatus |= CPQARY3_HBA_TRAN_ALLOC_DONE; 367 368 /* 369 * Set private field for the HBA tran structure. 370 * Initialise the HBA tran entry points. 371 * Attach the controller to HBA. 372 */ 373 cpqary3_init_hbatran(cpqary3p); 374 375 /* PERF */ 376 /* SG */ 377 tmp_dma_attr = cpqary3_dma_attr; 378 tmp_dma_attr.dma_attr_sgllen = cpqary3p->sg_cnt; 379 /* SG */ 380 /* PERF */ 381 /* 382 * Register the DMA attributes and the transport vectors 383 * of each instance of the HBA device. 384 */ 385 if (scsi_hba_attach_setup(dip, &tmp_dma_attr, cpqary3p->hba_tran, 386 SCSI_HBA_TRAN_CLONE) == DDI_FAILURE) { 387 cpqary3_cleanup(cpqary3p, cleanstatus); 388 return (DDI_FAILURE); 389 } 390 cleanstatus |= CPQARY3_HBA_TRAN_ATTACH_DONE; 391 392 /* 393 * Create a minor node for Ioctl interface. 394 * The nomenclature used will be "cpqary3" immediately followed by 395 * the current driver instance in the system. 396 * for e.g.: for 0th instance : cpqary3,0 397 * for 1st instance : cpqary3,1 398 */ 399 400 (void) sprintf(minor_node_name, "cpqary3,%d", instance); 401 402 /* HPQacucli Changes */ 403 if (ddi_create_minor_node(dip, minor_node_name, S_IFCHR, 404 CPQARY3_INST2CPQARY3(instance), DDI_NT_SCSI_NEXUS, 0) == 405 DDI_SUCCESS) { 406 /* HPQacucli Changes */ 407 cleanstatus |= CPQARY3_CREATE_MINOR_NODE; 408 } else { 409 cmn_err(CE_NOTE, "CPQary3 : Failed to create minor node"); 410 cpqary3_cleanup(cpqary3p, cleanstatus); 411 return (DDI_FAILURE); 412 } 413 414 415 /* Register a timeout driver-routine to be called every 2 secs */ 416 cpqary3p->tick_tmout_id = timeout(cpqary3_tick_hdlr, 417 (caddr_t)cpqary3p, drv_usectohz(CPQARY3_TICKTMOUT_VALUE)); 418 cleanstatus |= CPQARY3_TICK_TMOUT_REGD; 419 420 /* Register Software Interrupt Handler */ 421 if (ddi_add_softintr(dip, DDI_SOFTINT_HIGH, 422 &cpqary3p->cpqary3_softintr_id, &cpqary3p->sw_iblock_cookie, NULL, 423 cpqary3_sw_isr, (caddr_t)cpqary3p) != DDI_SUCCESS) { 424 cpqary3_cleanup(cpqary3p, cleanstatus); 425 return (DDI_FAILURE); 426 } 427 cleanstatus |= CPQARY3_SW_INTR_HDLR_SET; 428 429 /* Register Interrupt Handler */ 430 if (ddi_add_intr(dip, 0, &cpqary3p->hw_iblock_cookie, NULL, 431 cpqary3_hw_isr, (caddr_t)cpqary3p) != DDI_SUCCESS) { 432 cpqary3_cleanup(cpqary3p, cleanstatus); 433 return (DDI_FAILURE); 434 } 435 cleanstatus |= CPQARY3_INTR_HDLR_SET; 436 437 /* Enable the Controller Interrupt */ 438 cpqary3_intr_onoff(cpqary3p, CPQARY3_INTR_ENABLE); 439 if (cpqary3p->host_support & 0x4) 440 cpqary3_lockup_intr_onoff(cpqary3p, CPQARY3_LOCKUP_INTR_ENABLE); 441 442 /* 443 * We have come with hmaeventd - which logs the storage events on 444 * console as well as in IML. So we are commenting the NOE support in 445 * the driver 446 */ 447 448 /* NOE */ 449 if (cpqary3p->noe_support == 1) { 450 /* Enable the Notification on Event in this controller */ 451 if (CPQARY3_SUCCESS == 452 cpqary3_send_NOE_command(cpqary3p, 453 NULL, CPQARY3_NOE_INIT)) { 454 cleanstatus |= CPQARY3_NOE_INIT_DONE; 455 } else { 456 cmn_err(CE_CONT, "CPQary3 : Failed to initialize " 457 "NOTIFICATION ON EVENT \n"); 458 } 459 } 460 /* NOE */ 461 462 /* Report that an Instance of the Driver is Attached Successfully */ 463 ddi_report_dev(dip); 464 465 /* 466 * Now update the num_ctlr 467 * This is required for the agents 468 */ 469 470 gdriver_info.num_ctlr++; 471 472 return (DDI_SUCCESS); 473 474 } 475 476 /* 477 * Function : cpqary3_detach 478 * Description : This routine removes the state associated with a 479 * given instance of a device node prior to the 480 * removal of that instance from the system 481 * Called By : kernel 482 * Parameters : dip, command for detach 483 * Return Values: DDI_SUCCESS / DDI_FAILURE 484 * [failure ONLY if the command sent with this function 485 * as a paramter is not DETACH] 486 */ 487 int 488 cpqary3_detach(dev_info_t *dip, ddi_detach_cmd_t detach_cmd) 489 { 490 cpqary3_t *cpqary3p; 491 scsi_hba_tran_t *hba_tran; 492 493 /* Return failure, If Command is not DDI_DETACH */ 494 495 if (DDI_DETACH != detach_cmd) 496 return (DDI_FAILURE); 497 498 /* 499 * Get scsi_hba_tran structure. 500 * Get per controller structure. 501 */ 502 503 hba_tran = (scsi_hba_tran_t *)ddi_get_driver_private(dip); 504 cpqary3p = (cpqary3_t *)hba_tran->tran_hba_private; 505 506 /* Flush the cache */ 507 508 cpqary3_flush_cache(cpqary3p); 509 510 /* Undo cpqary3_attach */ 511 512 cpqary3_cleanup(cpqary3p, CPQARY3_CLEAN_ALL); 513 514 return (DDI_SUCCESS); 515 516 } 517 518 /* 519 * Function : cpary3_ioctl 520 * Description : This routine services ioctl requests. 521 * Called By : kernel 522 * Parameters : Too many to list. Please look below !!! 523 * Return Values: 0 / EINVAL / EFAULT / 524 * [0 on normal successful completion of the ioctl 525 * request] 526 */ 527 int 528 cpqary3_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 529 int *retvaluep) 530 { 531 minor_t cpqary3_minor_num; 532 cpqary3_t *cpqary3p; 533 int instance; 534 535 /* 536 * Get the soft state structure for this instance 537 * Return ENODEV if the structure does not exist. 538 */ 539 540 /* 541 * minor() call used in cpqary3_ioctl() returns minor number of the 542 * device which are in the 543 * range 0-255. if the minor number of the device is greater than 255, 544 * data will get truncated. so we are now using getminor(), 545 * instead of minor() 546 */ 547 548 if (EINVAL == (cpqary3_minor_num = getminor(dev))) { 549 *retvaluep = ENODEV; 550 return (*retvaluep); 551 } 552 553 /* HPQacucli Changes */ 554 555 /* get instance */ 556 instance = MINOR2INST(cpqary3_minor_num); 557 558 cpqary3p = (cpqary3_t *)ddi_get_soft_state(cpqary3_state, instance); 559 560 /* HPQacucli Changes */ 561 562 if (!cpqary3p) { 563 *retvaluep = ENODEV; 564 return (*retvaluep); 565 } 566 567 /* HPQacucli Changes */ 568 569 /* check which interface is being requested */ 570 if (CPQARY3_MINOR2INTERFACE(cpqary3_minor_num) != CPQARY3_MINOR) { 571 /* defer to SCSA */ 572 return (scsi_hba_ioctl(dev, cmd, arg, mode, credp, retvaluep)); 573 } 574 575 /* HPQacucli Changes */ 576 577 switch (cmd) { 578 case CPQARY3_IOCTL_DRIVER_INFO: 579 *retvaluep = 580 cpqary3_ioctl_driver_info(arg, mode); 581 break; 582 583 case CPQARY3_IOCTL_CTLR_INFO: 584 *retvaluep = 585 cpqary3_ioctl_ctlr_info(arg, cpqary3p, mode); 586 break; 587 588 case CPQARY3_IOCTL_BMIC_PASS: 589 *retvaluep = 590 cpqary3_ioctl_bmic_pass(arg, cpqary3p, mode); 591 break; 592 593 case CPQARY3_IOCTL_SCSI_PASS: 594 *retvaluep = 595 cpqary3_ioctl_scsi_pass(arg, cpqary3p, mode); 596 break; 597 598 default: 599 *retvaluep = EINVAL; 600 break; 601 } 602 return (*retvaluep); 603 604 605 } 606 607 608 /* 609 * Function : cqpary3_cleanup 610 * Description : This routine frees all allocated resources. 611 * Called By : kernel 612 * Parameters : per-controller, bit-map(stating what all to clean) 613 * Return Values: None 614 */ 615 static void 616 cpqary3_cleanup(cpqary3_t *cpqary3p, uint32_t status) 617 { 618 int8_t node_name[10]; 619 clock_t cpqary3_lbolt; 620 uint32_t targ; 621 622 ASSERT(cpqary3p != NULL); 623 624 /* 625 * Disable the NOE command 626 * Free the Command Memory Pool 627 * destroy all conditional variables 628 */ 629 630 /* 631 * We have removed NOE functionality from the 632 * driver. So commenting the below piece of code 633 */ 634 635 if (status & CPQARY3_NOE_INIT_DONE) { 636 if (CPQARY3_SUCCESS == cpqary3_disable_NOE_command(cpqary3p)) { 637 mutex_enter(&cpqary3p->hw_mutex); 638 cpqary3_lbolt = ddi_get_lbolt(); 639 if (DDI_FAILURE == 640 cv_timedwait_sig(&cpqary3p->cv_noe_wait, 641 &cpqary3p->hw_mutex, 642 cpqary3_lbolt + drv_usectohz(3000000))) { 643 cmn_err(CE_NOTE, 644 "CPQary3: Resume signal for disable NOE " 645 "command not received \n"); 646 } 647 mutex_exit(&cpqary3p->hw_mutex); 648 } 649 } 650 651 /* 652 * Detach the device 653 * Free / Release / Destroy the following entities/resources: 654 * transport layer 655 * h/w & s/w interrupt handlers 656 * all mutex 657 * timeout handler 658 * target structure 659 * minor node 660 * soft state 661 * any register/memory mapping 662 */ 663 664 if (status & CPQARY3_INTR_HDLR_SET) 665 ddi_remove_intr(cpqary3p->dip, 0, cpqary3p->hw_iblock_cookie); 666 667 if (status & CPQARY3_SW_INTR_HDLR_SET) 668 ddi_remove_softintr(cpqary3p->cpqary3_softintr_id); 669 670 if ((status & CPQARY3_TICK_TMOUT_REGD) && cpqary3p->tick_tmout_id) { 671 VERIFY(untimeout(cpqary3p->tick_tmout_id) >= 0); 672 cpqary3p->tick_tmout_id = NULL; 673 } 674 675 if (status & CPQARY3_CREATE_MINOR_NODE) { 676 (void) sprintf(node_name, "cpqary3%d", cpqary3p->instance); 677 ddi_remove_minor_node(cpqary3p->dip, node_name); 678 } 679 680 if (status & CPQARY3_HBA_TRAN_ATTACH_DONE) 681 (void) scsi_hba_detach(cpqary3p->dip); 682 683 if (status & CPQARY3_HBA_TRAN_ALLOC_DONE) 684 scsi_hba_tran_free(cpqary3p->hba_tran); 685 686 if (status & CPQARY3_CTLR_CONFIG_DONE) { 687 mutex_enter(&cpqary3p->hw_mutex); 688 689 cv_destroy(&cpqary3p->cv_abort_wait); 690 cv_destroy(&cpqary3p->cv_flushcache_wait); 691 cv_destroy(&cpqary3p->cv_noe_wait); 692 cv_destroy(&cpqary3p->cv_immediate_wait); 693 cv_destroy(&cpqary3p->cv_ioctl_wait); 694 695 for (targ = 0; targ < CPQARY3_MAX_TGT; targ++) { 696 if (cpqary3p->cpqary3_tgtp[targ] == NULL) 697 continue; 698 MEM_SFREE(cpqary3p->cpqary3_tgtp[targ], 699 sizeof (cpqary3_tgt_t)); 700 } 701 702 mutex_exit(&cpqary3p->hw_mutex); 703 704 cpqary3_memfini(cpqary3p, CPQARY3_MEMLIST_DONE | 705 CPQARY3_PHYCTGS_DONE | CPQARY3_CMDMEM_DONE); 706 } 707 708 if (status & CPQARY3_SW_MUTEX_INIT_DONE) 709 mutex_destroy(&cpqary3p->sw_mutex); 710 711 if (status & CPQARY3_MUTEX_INIT_DONE) 712 mutex_destroy(&cpqary3p->hw_mutex); 713 714 /* 715 * If this flag is set, free all mapped registers 716 */ 717 if (status & CPQARY3_MEM_MAPPED) { 718 if (cpqary3p->idr_handle) 719 ddi_regs_map_free(&cpqary3p->idr_handle); 720 if (cpqary3p->isr_handle) 721 ddi_regs_map_free(&cpqary3p->isr_handle); 722 if (cpqary3p->imr_handle) 723 ddi_regs_map_free(&cpqary3p->imr_handle); 724 if (cpqary3p->ipq_handle) 725 ddi_regs_map_free(&cpqary3p->ipq_handle); 726 if (cpqary3p->opq_handle) 727 ddi_regs_map_free(&cpqary3p->opq_handle); 728 if (cpqary3p->ct_handle) 729 ddi_regs_map_free(&cpqary3p->ct_handle); 730 } 731 732 if (status & CPQARY3_SOFTSTATE_ALLOC_DONE) { 733 ddi_soft_state_free(cpqary3_state, 734 ddi_get_instance(cpqary3p->dip)); 735 } 736 } 737 738 /* 739 * Function : cpqary3_update_ctlrdetails 740 * Description : Performs Sanity check of the hw, Updates PCI Config 741 * Information, Verifies the supported board-id and 742 * Sets up a mapping for the Primary I2O Memory BAR and 743 * the Primary DRAM 1 BAR to access Host Interface 744 * registers and the Transport Configuration table. 745 * Called By : cpqary3_attach() 746 * Parameters : per-controller, bitmap (used for cleaning operations) 747 * Return Values: SUCCESS / FAILURE 748 * [Success / failure depending upon the outcome of all 749 * checks and mapping. If any of them fail, a failure is 750 * sent back] 751 */ 752 static uint8_t 753 cpqary3_update_ctlrdetails(cpqary3_t *cpqary3p, uint32_t *cleanstatus) 754 { 755 int8_t retvalue; 756 uint8_t mem_bar0_set = 0; 757 uint8_t mem_64_bar0_set = 0; 758 uint8_t mem_bar1_set = 0; 759 uint8_t mem_64_bar1_set = 0; 760 int32_t reglen; 761 uint32_t *regp; 762 uint32_t mem_bar0 = 0; 763 uint32_t mem_64_bar0; 764 uint32_t mem_bar1 = 0; 765 uint32_t mem_64_bar1 = 0; 766 uint32_t ct_mem_bar = 0; 767 uint32_t ct_cfgmem_val = 0; 768 uint32_t ct_memoff_val = 0; 769 uint32_t ct_cfg_bar = 0; 770 uint32_t ct_mem_len = 0; 771 offset_t map_len = 0; 772 uint32_t regset_index; 773 ddi_acc_handle_t pci_handle; 774 uint32_t *ct_cfg_offset; 775 ddi_acc_handle_t ct_cfgoff_handle; 776 uint32_t *ct_mem_offset; 777 ddi_acc_handle_t ct_memoff_handle; 778 779 RETURN_FAILURE_IF_NULL(cpqary3p); 780 781 /* 782 * Check if the bus, or part of the bus that the device is installed 783 * on, permits the device to become a DMA master. 784 * If our device is not permitted to become master, return 785 */ 786 if (ddi_slaveonly(cpqary3p->dip) == DDI_SUCCESS) 787 return (CPQARY3_FAILURE); 788 789 /* 790 * Get the HW Configuration 791 * Get Bus #, Dev # and Func # for this device 792 * Free the memory that regp points towards after the 793 * ddi_getlongprop() call 794 */ 795 if (ddi_getlongprop(DDI_DEV_T_NONE, cpqary3p->dip, DDI_PROP_DONTPASS, 796 "reg", (caddr_t)®p, ®len) != DDI_PROP_SUCCESS) 797 return (CPQARY3_FAILURE); 798 799 cpqary3p->bus = PCI_REG_BUS_G(*regp); 800 cpqary3p->dev = PCI_REG_DEV_G(*regp); 801 cpqary3p->fun = PCI_REG_FUNC_G(*regp); 802 803 for (regset_index = 0; regset_index < reglen / 20; regset_index ++) { 804 if (PCI_REG_ADDR_G(*(regp + regset_index * 5)) == 0x2) { 805 if (!mem_bar0_set) { 806 mem_bar0 = regset_index; 807 mem_bar0_set = 1; 808 } else if (!mem_bar1_set) { 809 mem_bar1 = regset_index; 810 mem_bar1_set = 1; 811 } 812 } 813 } 814 815 mem_64_bar0 = mem_bar0; 816 mem_64_bar1 = mem_bar1; 817 818 for (regset_index = 0; regset_index < reglen / 20; regset_index ++) { 819 if (PCI_REG_ADDR_G(*(regp + regset_index * 5)) == 0x3) { 820 if (!mem_64_bar0_set) { 821 mem_64_bar0 = regset_index; 822 mem_64_bar0_set = 1; 823 } else if (!mem_64_bar1_set) { 824 mem_64_bar1 = regset_index; 825 mem_64_bar1_set = 1; 826 } 827 } 828 } 829 830 mem_bar0 = mem_64_bar0; 831 mem_bar1 = mem_64_bar1; 832 833 MEM_SFREE(regp, reglen); 834 835 /* 836 * Setup resources to access the Local PCI Bus 837 * If unsuccessful, return. 838 * Else, read the following from the PCI space: 839 * Sub-System Vendor ID 840 * Sub-System Device ID 841 * Interrupt Line 842 * Command Register 843 * Free the just allocated resources. 844 */ 845 if (pci_config_setup(cpqary3p->dip, &pci_handle) != DDI_SUCCESS) 846 return (CPQARY3_FAILURE); 847 848 cpqary3p->irq = pci_config_get8(pci_handle, PCI_CONF_ILINE); 849 cpqary3p->board_id = 850 (pci_config_get16(pci_handle, PCI_CONF_SUBVENID) << 16) 851 | pci_config_get16(pci_handle, PCI_CONF_SUBSYSID); 852 853 pci_config_teardown(&pci_handle); 854 855 /* 856 * Verify Board Id 857 * If unsupported boards are detected, return. 858 * Update name for controller for driver use. 859 */ 860 cpqary3p->bddef = cpqary3_bd_getbybid(cpqary3p->board_id); 861 if (cpqary3p->bddef == NULL) { 862 cmn_err(CE_WARN, 863 "CPQary3: <Bid 0x%X> Controller NOT Supported", 864 cpqary3p->board_id); 865 return (CPQARY3_FAILURE); 866 } 867 map_len = cpqary3p->bddef->bd_maplen; 868 (void) strcpy(cpqary3p->hba_name, cpqary3p->bddef->bd_dispname); 869 870 /* 871 * Set up a mapping for the following registers: 872 * Inbound Doorbell 873 * Outbound List Status 874 * Outbound Interrupt Mask 875 * Host Inbound Queue 876 * Host Outbound Queue 877 * Host Transport Configuration Table 878 * Mapping of the above has been done in that order. 879 */ 880 retvalue = ddi_regs_map_setup(cpqary3p->dip, 881 mem_bar0, /* INDEX_PCI_BASE0, */ 882 (caddr_t *)&cpqary3p->idr, (offset_t)I2O_IBDB_SET, map_len, 883 &cpqary3_dev_attributes, &cpqary3p->idr_handle); 884 885 if (retvalue != DDI_SUCCESS) { 886 if (DDI_REGS_ACC_CONFLICT == retvalue) { 887 cmn_err(CE_WARN, 888 "CPQary3 : Registers Mapping Conflict"); 889 } 890 cmn_err(CE_WARN, "CPQary3 : Inbound Doorbell " 891 "Register Mapping Failed"); 892 return (CPQARY3_FAILURE); 893 } 894 895 /* PERF */ 896 retvalue = ddi_regs_map_setup(cpqary3p->dip, 897 mem_bar0, /* INDEX_PCI_BASE0, */ 898 (caddr_t *)&cpqary3p->odr, (offset_t)I2O_OBDB_STATUS, map_len, 899 &cpqary3_dev_attributes, &cpqary3p->odr_handle); 900 901 if (retvalue != DDI_SUCCESS) { 902 if (DDI_REGS_ACC_CONFLICT == retvalue) { 903 cmn_err(CE_WARN, 904 "CPQary3 : Registers Mapping Conflict"); 905 } 906 cmn_err(CE_WARN, 907 "CPQary3 : Outbound Doorbell Register Mapping Failed"); 908 return (CPQARY3_FAILURE); 909 } 910 911 retvalue = ddi_regs_map_setup(cpqary3p->dip, 912 mem_bar0, /* INDEX_PCI_BASE0, */ 913 (caddr_t *)&cpqary3p->odr_cl, (offset_t)I2O_OBDB_CLEAR, map_len, 914 &cpqary3_dev_attributes, &cpqary3p->odr_cl_handle); 915 916 if (retvalue != DDI_SUCCESS) { 917 if (DDI_REGS_ACC_CONFLICT == retvalue) { 918 cmn_err(CE_WARN, 919 "CPQary3 : Registers Mapping Conflict"); 920 } 921 cmn_err(CE_WARN, "CPQary3 : Outbound Doorbell " 922 "Register Clear Mapping Failed"); 923 return (CPQARY3_FAILURE); 924 } 925 926 /* LOCKUP CODE */ 927 retvalue = ddi_regs_map_setup(cpqary3p->dip, 928 mem_bar0, /* INDEX_PCI_BASE0, */ 929 (caddr_t *)&cpqary3p->spr0, (offset_t)I2O_CTLR_INIT, map_len, 930 &cpqary3_dev_attributes, &cpqary3p->spr0_handle); 931 932 if (retvalue != DDI_SUCCESS) { 933 if (DDI_REGS_ACC_CONFLICT == retvalue) { 934 cmn_err(CE_WARN, 935 "CPQary3 : Registers Mapping Conflict"); 936 } 937 cmn_err(CE_WARN, 938 "CPQary3 : Scratch Pad register zero Mapping Failed"); 939 return (CPQARY3_FAILURE); 940 } 941 /* LOCKUP CODE */ 942 /* PERF */ 943 944 *cleanstatus |= CPQARY3_MEM_MAPPED; 945 946 retvalue = ddi_regs_map_setup(cpqary3p->dip, 947 mem_bar0, /* INDEX_PCI_BASE0, */ 948 (caddr_t *)&cpqary3p->isr, (offset_t)I2O_INT_STATUS, map_len, 949 &cpqary3_dev_attributes, &cpqary3p->isr_handle); 950 951 if (retvalue != DDI_SUCCESS) { 952 if (retvalue == DDI_REGS_ACC_CONFLICT) { 953 cmn_err(CE_WARN, 954 "CPQary3 : Registers Mapping Conflict"); 955 } 956 cmn_err(CE_WARN, 957 "CPQary3 : Interrupt Status Register Mapping Failed"); 958 return (CPQARY3_FAILURE); 959 } 960 961 retvalue = ddi_regs_map_setup(cpqary3p->dip, 962 mem_bar0, /* INDEX_PCI_BASE0, */ 963 (caddr_t *)&cpqary3p->imr, (offset_t)I2O_INT_MASK, map_len, 964 &cpqary3_dev_attributes, &cpqary3p->imr_handle); 965 966 if (retvalue != DDI_SUCCESS) { 967 if (retvalue == DDI_REGS_ACC_CONFLICT) { 968 cmn_err(CE_WARN, 969 "CPQary3 : Registers Mapping Conflict"); 970 } 971 cmn_err(CE_WARN, 972 "CPQary3 : Interrupt Mask Register Mapping Failed"); 973 return (CPQARY3_FAILURE); 974 } 975 976 retvalue = ddi_regs_map_setup(cpqary3p->dip, 977 mem_bar0, /* INDEX_PCI_BASE0, */ 978 (caddr_t *)&cpqary3p->ipq, (offset_t)I2O_IBPOST_Q, map_len, 979 &cpqary3_dev_attributes, &cpqary3p->ipq_handle); 980 981 if (retvalue != DDI_SUCCESS) { 982 if (retvalue == DDI_REGS_ACC_CONFLICT) { 983 cmn_err(CE_WARN, 984 "CPQary3 : Registers Mapping Conflict"); 985 } 986 cmn_err(CE_WARN, 987 "CPQary3 : Inbound Queue Register Mapping Failed"); 988 return (CPQARY3_FAILURE); 989 } 990 991 retvalue = ddi_regs_map_setup(cpqary3p->dip, 992 mem_bar0, /* INDEX_PCI_BASE0, */ (caddr_t *)&cpqary3p->opq, 993 (offset_t)I2O_OBPOST_Q, map_len, &cpqary3_dev_attributes, 994 &cpqary3p->opq_handle); 995 996 if (retvalue != DDI_SUCCESS) { 997 if (retvalue == DDI_REGS_ACC_CONFLICT) { 998 cmn_err(CE_WARN, 999 "CPQary3 : Registers Mapping Conflict"); 1000 } 1001 cmn_err(CE_WARN, "CPQary3 : Outbound Post Queue " 1002 "Register Mapping Failed"); 1003 return (CPQARY3_FAILURE); 1004 } 1005 1006 1007 /* 1008 * The config offset and memory offset have to be obtained in order to 1009 * locate the config table. 1010 */ 1011 retvalue = ddi_regs_map_setup(cpqary3p->dip, 1012 mem_bar0, /* INDEX_PCI_BASE0, */ (caddr_t *)&ct_cfg_offset, 1013 (offset_t)CT_CFG_OFFSET, map_len, &cpqary3_dev_attributes, 1014 &ct_cfgoff_handle); 1015 1016 if (retvalue != DDI_SUCCESS) { 1017 if (retvalue == DDI_REGS_ACC_CONFLICT) { 1018 cmn_err(CE_WARN, 1019 "CPQary3 : Registers Mapping Conflict"); 1020 } 1021 cmn_err(CE_WARN, "CPQary3 : Configuration Table " 1022 "Register Mapping Failed"); 1023 return (CPQARY3_FAILURE); 1024 } 1025 1026 retvalue = ddi_regs_map_setup(cpqary3p->dip, 1027 mem_bar0, /* INDEX_PCI_BASE0, */ 1028 (caddr_t *)&ct_mem_offset, (offset_t)CT_MEM_OFFSET, map_len, 1029 &cpqary3_dev_attributes, &ct_memoff_handle); 1030 1031 if (retvalue != DDI_SUCCESS) { 1032 if (retvalue == DDI_REGS_ACC_CONFLICT) { 1033 cmn_err(CE_WARN, 1034 "CPQary3 : Registers Mapping Conflict"); 1035 } 1036 cmn_err(CE_WARN, "CPQary3 : Configuration Table " 1037 "Register Mapping Failed"); 1038 return (CPQARY3_FAILURE); 1039 } 1040 1041 ct_cfgmem_val = (uint32_t)ddi_get32(ct_cfgoff_handle, ct_cfg_offset); 1042 ct_memoff_val = (uint32_t)ddi_get32(ct_memoff_handle, ct_mem_offset); 1043 1044 ddi_regs_map_free(&ct_cfgoff_handle); 1045 ddi_regs_map_free(&ct_memoff_handle); 1046 1047 ct_cfg_bar = (ct_cfgmem_val & 0x0000ffff); 1048 ct_mem_len = (ct_cfgmem_val & 0xffff0000); 1049 ct_mem_len = (ct_mem_len >> 16); 1050 1051 if (ct_cfg_bar == 0x10) { 1052 if (ct_mem_len) { 1053 ct_mem_bar = mem_64_bar0; 1054 } else { 1055 ct_mem_bar = mem_bar0; 1056 } 1057 1058 } else if (ct_cfg_bar == 0x14) { 1059 if (ct_mem_len) { 1060 ct_mem_bar = mem_64_bar1; 1061 } else { 1062 ct_mem_bar = mem_bar1; 1063 } 1064 } else { 1065 return (CPQARY3_FAILURE); 1066 } 1067 1068 1069 /* 1070 * The Configuration Table(CT) shall be mapped in the form of a 1071 * structure since several members in the CT need to be accessed 1072 * to read and write. 1073 */ 1074 retvalue = ddi_regs_map_setup(cpqary3p->dip, 1075 ct_mem_bar, /* INDEX_PCI_BASE0/1, */ 1076 (caddr_t *)&cpqary3p->ct, (offset_t)ct_memoff_val, 1077 sizeof (CfgTable_t), &cpqary3_dev_attributes, &cpqary3p->ct_handle); 1078 1079 if (retvalue != DDI_SUCCESS) { 1080 if (retvalue == DDI_REGS_ACC_CONFLICT) { 1081 cmn_err(CE_WARN, 1082 "CPQary3 : Registers Mapping Conflict"); 1083 } 1084 cmn_err(CE_WARN, "CPQary3 : Configuration Table " 1085 "Register Mapping Failed"); 1086 return (CPQARY3_FAILURE); 1087 } 1088 1089 /* PERF */ 1090 1091 retvalue = ddi_regs_map_setup(cpqary3p->dip, 1092 ct_mem_bar, /* INDEX_PCI_BASE0/1, */ 1093 (caddr_t *)&cpqary3p->cp, 1094 (offset_t)(ct_memoff_val + cpqary3p->ct->TransportMethodOffset), 1095 sizeof (CfgTrans_Perf_t), &cpqary3_dev_attributes, 1096 &cpqary3p->cp_handle); 1097 1098 if (retvalue != DDI_SUCCESS) { 1099 if (retvalue == DDI_REGS_ACC_CONFLICT) 1100 cmn_err(CE_WARN, 1101 "CPQary3 : Registers Mapping Conflict"); 1102 cmn_err(CE_WARN, "CPQary3 : Performant Transport Method Table " 1103 "Mapping Failed"); 1104 return (CPQARY3_FAILURE); 1105 } 1106 1107 /* PERF */ 1108 1109 return (CPQARY3_SUCCESS); 1110 }