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)&regp, &reglen) != 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 }