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 /*
  17  * This module contains routines that program the controller. All
  18  * operations  viz.,  initialization of  controller,  submision &
  19  * retrieval  of  commands, enabling &  disabling of  interrupts,
  20  * checking interrupt status are performed here.
  21  */
  22 
  23 #include <sys/sdt.h>
  24 #include "cpqary3.h"
  25 
  26 /*
  27  * Local Functions Definitions
  28  */
  29 uint8_t cpqary3_check_simple_ctlr_intr(cpqary3_t *cpqary3p);
  30 uint8_t cpqary3_check_perf_ctlr_intr(cpqary3_t *cpqary3p);
  31 uint8_t cpqary3_check_perf_e200_intr(cpqary3_t *cpqary3p);
  32 uint8_t cpqary3_check_ctlr_init(cpqary3_t *);
  33 
  34 /*
  35  * Function     :       cpqary3_check_simple_ctlr_intr
  36  * Description  :       This routine determines if the controller did interrupt.
  37  * Called By    :       cpqary3_hw_isr()
  38  * Parameters   :       per-controller
  39  * Calls        :       None
  40  * Return Values:       SUCCESS : This controller did interrupt.
  41  *                      FAILURE : It did not.
  42  */
  43 uint8_t
  44 cpqary3_check_simple_ctlr_intr(cpqary3_t *cpqary3p)
  45 {
  46         uint32_t        intr_pending_mask = 0;
  47 
  48         /*
  49          * Read the Interrupt Status Register and
  50          * if bit 3 is set, it indicates that we have completed commands
  51          * in the controller
  52          */
  53         intr_pending_mask = cpqary3p->bddef->bd_intrpendmask;
  54 
  55         if (intr_pending_mask &
  56             (ddi_get32(cpqary3p->isr_handle, (uint32_t *)cpqary3p->isr)))
  57                 return (CPQARY3_SUCCESS);
  58 
  59         return (CPQARY3_FAILURE);
  60 }
  61 
  62 /*
  63  * Function     :       cpqary3_check_perf_ctlr_intr
  64  * Description  :       This routine determines if the
  65  *                      controller did interrupt.
  66  * Called By    :       cpqary3_hw_isr()
  67  * Parameters   :       per-controller
  68  * Calls        :       None
  69  * Return Values:       SUCCESS : This controller did interrupt.
  70  *                      FAILURE : It did not.
  71  */
  72 uint8_t
  73 cpqary3_check_perf_ctlr_intr(cpqary3_t *cpqary3p)
  74 {
  75         /*
  76          * Read the Interrupt Status Register and
  77          * if bit 3 is set, it indicates that we have completed commands
  78          * in the controller
  79          */
  80         if (0x1 & (ddi_get32(cpqary3p->isr_handle,
  81             (uint32_t *)cpqary3p->isr))) {
  82                 return (CPQARY3_SUCCESS);
  83         }
  84 
  85         return (CPQARY3_FAILURE);
  86 }
  87 
  88 /*
  89  * Function     :       cpqary3_check_perf_e200_intr
  90  * Description  :       This routine determines if the controller
  91  *                      did interrupt.
  92  * Called By    :       cpqary3_hw_isr()
  93  * Parameters   :       per-controller
  94  * Calls        :       None
  95  * Return Values:       SUCCESS : This controller did interrupt.
  96  *                      FAILURE : It did not.
  97  */
  98 uint8_t
  99 cpqary3_check_perf_e200_intr(cpqary3_t *cpqary3p)
 100 {
 101         /*
 102          * Read the Interrupt Status Register and
 103          * if bit 3 is set, it indicates that we have completed commands
 104          * in the controller
 105          */
 106         if (0x4 & (ddi_get32(cpqary3p->isr_handle,
 107             (uint32_t *)cpqary3p->isr))) {
 108                 return (CPQARY3_SUCCESS);
 109         }
 110 
 111         return (CPQARY3_FAILURE);
 112 }
 113 
 114 
 115 /*
 116  * Function     :       cpqary3_retrieve
 117  * Description  :       This routine retrieves the completed command from the
 118  *                      controller reply queue.
 119  *                      and processes the completed commands.
 120  * Called By    :       cpqary3_sw_isr(), cpqary3_handle_flag_nointr()
 121  * Parameters   :       per-controller
 122  * Calls        :       packet completion routines
 123  * Return Values:       SUCCESS : A completed command has been retrieved
 124  *                      and processed.
 125  *                      FAILURE : No completed command was in the controller.
 126  */
 127 uint8_t
 128 cpqary3_retrieve(cpqary3_t *cpqary3p)
 129 {
 130         uint32_t                        tag;
 131         uint32_t                        CmdsOutMax;
 132         cpqary3_cmdpvt_t                *cpqary3_cmdpvtp;
 133         cpqary3_drvr_replyq_t           *replyq_ptr;
 134 
 135         /*
 136          * Get the Reply Command List Addr
 137          * Update the returned Tag in that particular command structure.
 138          * If a valid one, de-q that from the SUBMITTED Q and
 139          * enqueue that to the RETRIEVED Q.
 140          */
 141 
 142         RETURN_FAILURE_IF_NULL(cpqary3p);
 143 
 144         /* PERF */
 145         replyq_ptr = (cpqary3_drvr_replyq_t *)cpqary3p->drvr_replyq;
 146         CmdsOutMax = cpqary3p->ctlr_maxcmds;
 147 
 148         while ((replyq_ptr->replyq_headptr[0] & 0x01) ==
 149             replyq_ptr->cyclic_indicator) {
 150                 /* command has completed */
 151                 /* Get the tag */
 152 
 153                 tag = replyq_ptr->replyq_headptr[0];
 154                 if ((tag >> CPQARY3_GET_MEM_TAG) >= (CmdsOutMax / 3) * 3) {
 155                         cmn_err(CE_WARN,
 156                             "CPQary3 : HBA returned Spurious Tag");
 157                         return (CPQARY3_FAILURE);
 158                 }
 159 
 160                 cpqary3_cmdpvtp = &cpqary3p->cmdmemlistp->pool[
 161                     tag >> CPQARY3_GET_MEM_TAG];
 162                 cpqary3_cmdpvtp->cmdlist_memaddr->
 163                     Header.Tag.drvinfo_n_err = (tag & 0xF) >> 1;
 164                 mutex_enter(&cpqary3p->sw_mutex);
 165                 cpqary3_cmdpvtp->complete(cpqary3_cmdpvtp);
 166                 mutex_exit(&cpqary3p->sw_mutex);
 167 
 168                 /* Traverse to the next command in reply queue */
 169 
 170                 ++replyq_ptr->index;
 171                 if (replyq_ptr->index == replyq_ptr->max_index) {
 172                         replyq_ptr->index = 0;
 173                         /* Toggle at wraparound */
 174                         replyq_ptr->cyclic_indicator =
 175                             (replyq_ptr->cyclic_indicator == 0) ? 1 : 0;
 176                         replyq_ptr->replyq_headptr =
 177                             /* LINTED: alignment */
 178                             (uint32_t *)(replyq_ptr->replyq_start_addr);
 179                 } else {
 180                         replyq_ptr->replyq_headptr += 2;
 181                 }
 182         }
 183         /* PERF */
 184 
 185         return (CPQARY3_SUCCESS);
 186 }
 187 
 188 
 189 /*
 190  * Function     :  cpqary3_poll_retrieve
 191  * Description  :  This routine retrieves the completed command from the
 192  *                      controller reply queue in poll mode.
 193  *                      and processes the completed commands.
 194  * Called By    :  cpqary3_poll
 195  * Parameters   :  per-controller
 196  * Calls        :  packet completion routines
 197  * Return Values:  If the polled command is completed, send back a success.
 198  *                      If not return failure.
 199  */
 200 uint8_t
 201 cpqary3_poll_retrieve(cpqary3_t *cpqary3p, uint32_t poll_tag)
 202 {
 203         uint32_t                        tag;
 204         uint32_t                        CmdsOutMax;
 205         cpqary3_cmdpvt_t                *cpqary3_cmdpvtp;
 206         cpqary3_drvr_replyq_t           *replyq_ptr;
 207         uint32_t                        temp_tag;
 208         uint8_t                         tag_flag = 0;
 209 
 210         RETURN_FAILURE_IF_NULL(cpqary3p);
 211 
 212         /* PERF */
 213         replyq_ptr = (cpqary3_drvr_replyq_t *)cpqary3p->drvr_replyq;
 214         CmdsOutMax = cpqary3p->cmdmemlistp->max_memcnt;
 215 
 216         if (!(cpqary3p->bddef->bd_flags & SA_BD_SAS)) {
 217                 while ((tag = ddi_get32(cpqary3p->opq_handle,
 218                     (uint32_t *)cpqary3p->opq)) != 0xFFFFFFFF) {
 219                         cpqary3_cmdpvtp = &cpqary3p->cmdmemlistp->pool[
 220                             tag >> CPQARY3_GET_MEM_TAG];
 221                         cpqary3_cmdpvtp->cmdlist_memaddr->
 222                             Header.Tag.drvinfo_n_err = (tag & 0xF) >> 1;
 223                         temp_tag = cpqary3_cmdpvtp->tag.tag_value;
 224 
 225                         if (temp_tag == poll_tag)
 226                                 tag_flag = 1;
 227                         cpqary3_cmdpvtp->complete(cpqary3_cmdpvtp);
 228                 }
 229         } else {
 230                 while ((replyq_ptr->replyq_headptr[0] & 0x01) ==
 231                     replyq_ptr->cyclic_indicator) {
 232                         /* command has completed */
 233                         /* Get the tag */
 234                         tag = replyq_ptr->replyq_headptr[0];
 235 
 236                         if ((tag >> CPQARY3_GET_MEM_TAG) >= (CmdsOutMax/3)*3) {
 237                                 cmn_err(CE_WARN,
 238                                     "CPQary3 : HBA returned Spurious Tag");
 239                                 return (CPQARY3_FAILURE);
 240                         }
 241 
 242                         cpqary3_cmdpvtp = &cpqary3p->cmdmemlistp->pool[
 243                             tag >> CPQARY3_GET_MEM_TAG];
 244                         cpqary3_cmdpvtp->cmdlist_memaddr->
 245                             Header.Tag.drvinfo_n_err = (tag & 0xF) >> 1;
 246                         temp_tag = cpqary3_cmdpvtp->tag.tag_value;
 247 
 248                         if (temp_tag == poll_tag)
 249                                 tag_flag = 1;
 250 
 251                         cpqary3_cmdpvtp->complete(cpqary3_cmdpvtp);
 252 
 253                         /* Traverse to the next command in reply queue */
 254                         ++replyq_ptr->index;
 255                         if (replyq_ptr->index == replyq_ptr->max_index) {
 256                                 replyq_ptr->index = 0;
 257                                 /* Toggle at wraparound */
 258                                 replyq_ptr->cyclic_indicator =
 259                                     (replyq_ptr->cyclic_indicator == 0) ? 1 : 0;
 260                                 replyq_ptr->replyq_headptr =
 261                                     /* LINTED: alignment */
 262                                     (uint32_t *)(replyq_ptr->replyq_start_addr);
 263                         } else {
 264                                 replyq_ptr->replyq_headptr += 2;
 265                         }
 266                 }
 267         }
 268         /* PERF */
 269         if (tag_flag) {
 270                 return (CPQARY3_SUCCESS);
 271         }
 272 
 273         return (CPQARY3_FAILURE);
 274 }
 275 
 276 /*
 277  * Function     :       cpqary3_submit
 278  * Description  :       This routine submits the command to the Inbound Post Q.
 279  * Called By    :       cpqary3_transport(), cpqary3_send_NOE_command(),
 280  *                      cpqary3_disable_NOE_command(),
 281  *                      cpqary3_handle_flag_nointr(),
 282  *                      cpqary3_tick_hdlr(), cpqary3_synccmd_send()
 283  * Parameters   :       per-controller, physical address
 284  * Calls        :       None
 285  * Return Values:       None
 286  */
 287 int32_t
 288 cpqary3_submit(cpqary3_t *cpqary3p, uint32_t cmd_phyaddr)
 289 {
 290         uint32_t                phys_addr = 0;
 291         uint8_t                 retval  = 0;
 292 
 293         /*
 294          * Write the Physical Address of the command-to-be-submitted
 295          * into the Controller's Inbound Post Q.
 296          */
 297 
 298         ASSERT(cpqary3p != NULL);
 299 
 300 #ifdef AMD64_DEBUG
 301         {
 302         char            debug_char;
 303         uint32_t        tmp_cmd_phyaddr;
 304 
 305         tmp_cmd_phyaddr = (uint32_t)(cmd_phyaddr & 0XFFFFFFFF);
 306 
 307         cmn_err(CE_WARN, "CPQary3: cmd_phyaddr = %lX\n tmp_cmd_phyaddr = %lX",
 308             cmd_phyaddr, tmp_cmd_phyaddr);
 309 
 310         debug_enter(&debug_char);
 311         ddi_put32(cpqary3p->ipq_handle, (uint32_t *)cpqary3p->ipq, cmd_phyaddr);
 312         }
 313 #endif
 314 
 315 
 316         /* CONTROLLER_LOCKUP */
 317         if (cpqary3p->controller_lockup == CPQARY3_TRUE) {
 318                 retval = EIO;
 319                 return (retval);
 320         }
 321         /* CONTROLLER_LOCKUP */
 322 
 323         if (!(cpqary3p->bddef->bd_flags & SA_BD_SAS)) {
 324                 ddi_put32(cpqary3p->ipq_handle,
 325                     (uint32_t *)cpqary3p->ipq, cmd_phyaddr);
 326         } else {
 327                 /* The driver always uses the 0th block fetch count always */
 328                 phys_addr = cmd_phyaddr | 0 | 0x1;
 329                 ddi_put32(cpqary3p->ipq_handle,
 330                     (uint32_t *)cpqary3p->ipq, phys_addr);
 331         }
 332 
 333         /* PERF */
 334 
 335         /*
 336          * Command submission can NEVER FAIL since the number of commands that
 337          * can reside in the controller at any time is 1024 and our memory
 338          * allocation is for 225 commands ONLY. Thus, at any given time the
 339          * maximum number of commands in the controller is 225.
 340          */
 341 
 342         /* CONTROLLER_LOCKUP */
 343         return (retval);
 344         /* CONTROLLER_LOCKUP */
 345 
 346 }
 347 
 348 
 349 /*
 350  * Function     :       cpqary3_intr_onoff
 351  * Description  :       This routine enables/disables the HBA interrupt.
 352  * Called By    :       cpqary3_attach(), ry3_handle_flag_nointr(),
 353  *                      cpqary3_tick_hdlr(), cpqary3_init_ctlr_resource()
 354  * Parameters   :       per-controller, flag stating enable/disable
 355  * Calls        :       None
 356  * Return Values:       None
 357  */
 358 void
 359 cpqary3_intr_onoff(cpqary3_t *cpqary3p, uint8_t flag)
 360 {
 361         uint32_t        intr = 0;
 362         uint32_t        intr_mask = 0;
 363 
 364         /*
 365          * Enable or disable the interrupt based on the flag
 366          * Read the Interrupt Mask Register first and then update it
 367          * accordingly
 368          */
 369 
 370         ASSERT(cpqary3p != NULL);
 371 
 372         intr = ddi_get32(cpqary3p->imr_handle, (uint32_t *)cpqary3p->imr);
 373         intr_mask = cpqary3p->bddef->bd_intrmask;
 374 
 375         if (flag == CPQARY3_INTR_ENABLE) {
 376                 ddi_put32(cpqary3p->imr_handle,
 377                     (uint32_t *)cpqary3p->imr, intr & ~(intr_mask));
 378         } else {
 379                 ddi_put32(cpqary3p->imr_handle,
 380                     (uint32_t *)cpqary3p->imr, (intr | intr_mask));
 381         }
 382 }
 383 
 384 
 385 /*
 386  * Function     :       cpqary3_lockup_intr_onoff
 387  * Description  :       This routine enables/disables the lockup interrupt.
 388  * Called By    :       cpqary3_attach(), cpqary3_handle_flag_nointr(),
 389  *                      cpqary3_tick_hdlr(), cpqary3_hw_isr,
 390  *                      cpqary3_init_ctlr_resource()
 391  * Parameters   :       per-controller, flag stating enable/disable
 392  * Calls        :       None
 393  * Return Values:       None
 394  */
 395 void
 396 cpqary3_lockup_intr_onoff(cpqary3_t *cpqary3p, uint8_t flag)
 397 {
 398         uint32_t        intr = 0;
 399         uint32_t        intr_lockup_mask = 0;
 400 
 401         /*
 402          * Enable or disable the interrupt based on the flag
 403          * Read the Interrupt Mask Register first and then update it
 404          * accordingly
 405          */
 406 
 407         ASSERT(cpqary3p != NULL);
 408 
 409         intr = ddi_get32(cpqary3p->imr_handle, (uint32_t *)cpqary3p->imr);
 410         intr_lockup_mask = cpqary3p->bddef->bd_lockup_intrmask;
 411 
 412         if (flag == CPQARY3_INTR_ENABLE) {
 413                 ddi_put32(cpqary3p->imr_handle,
 414                     (uint32_t *)cpqary3p->imr, intr & ~(intr_lockup_mask));
 415         } else {
 416                 ddi_put32(cpqary3p->imr_handle,
 417                     (uint32_t *)cpqary3p->imr, (intr | intr_lockup_mask));
 418         }
 419 }
 420 
 421 /*
 422  * Function     :       cpqary3_init_ctlr
 423  * Description  :       This routine initialises the HBA to Simple Transport
 424  *                      Method. Refer to CISS for more information.
 425  *                      It checks the readiness of the HBA.
 426  * Called By    :       cpqary3_init_ctlr_resource()
 427  * Parameters   :       per-controller(), physical address()
 428  * Calls        :       cpqary3_check_ctlr_init
 429  * Return Values:       SUCCESS / FAILURE
 430  *                      [Shall return failure if the initialization of the
 431  *                      controller to the Simple Transport Method fails]
 432  */
 433 uint8_t
 434 cpqary3_init_ctlr(cpqary3_t *cpqary3p)
 435 {
 436         uint8_t                         cntr;
 437         uint8_t                         signature[4] = { 'C', 'I', 'S', 'S' };
 438         volatile CfgTable_t             *ctp;
 439         volatile CfgTrans_Perf_t        *perf_cfg;
 440         cpqary3_phyctg_t                *cpqary3_phyctgp;
 441         uint32_t                        phy_addr;
 442         size_t                          cmd_size;
 443         uint32_t                        queue_depth;
 444         uint32_t                        CmdsOutMax;
 445         uint32_t                        BlockFetchCnt[8];
 446         caddr_t                         replyq_start_addr = NULL;
 447         /* SG */
 448         uint32_t                        max_blk_fetch_cnt = 0;
 449         uint32_t                        max_sg_cnt = 0;
 450         uint32_t                        optimal_sg = 0;
 451         uint32_t                        optimal_sg_size = 0;
 452         /* Header + Request + Error */
 453         uint32_t                        size_of_HRE = 0;
 454         uint32_t                        size_of_cmdlist = 0;
 455         /* SG */
 456 
 457         RETURN_FAILURE_IF_NULL(cpqary3p);
 458         ctp = (CfgTable_t *)cpqary3p->ct;
 459         perf_cfg = (CfgTrans_Perf_t *)cpqary3p->cp;
 460 
 461         /* QUEUE CHANGES */
 462         cpqary3p->drvr_replyq =
 463             (cpqary3_drvr_replyq_t *)MEM_ZALLOC(sizeof (cpqary3_drvr_replyq_t));
 464         /* QUEUE CHANGES */
 465 
 466         if (!cpqary3_check_ctlr_init(cpqary3p))
 467                 return (CPQARY3_FAILURE);
 468 
 469         DTRACE_PROBE1(ctlr_init_start, CfgTable_t *, ctp);
 470 
 471         /*
 472          * Validate the signature - should be "CISS"
 473          * Use of cntr in the for loop does not suggest a counter - it just
 474          * saves declaration of another variable.
 475          */
 476 
 477         for (cntr = 0; cntr < 4; cntr++) {
 478                 if (DDI_GET8(cpqary3p, &ctp->Signature[cntr]) !=
 479                     signature[cntr]) {
 480                         cmn_err(CE_WARN, "CPQary3 : Controller NOT ready");
 481                         cmn_err(CE_WARN, "CPQary3 : _cpqary3_init_ctlr : "
 482                             "Signature not stamped");
 483                         return (CPQARY3_FAILURE);
 484                 }
 485         }
 486 
 487 
 488         if (!(cpqary3p->bddef->bd_flags & SA_BD_SAS)) {
 489                 CmdsOutMax = DDI_GET32(cpqary3p, &ctp->CmdsOutMax);
 490 
 491                 if (CmdsOutMax == 0) {
 492                         cmn_err(CE_CONT, "CPQary3 : HBA Maximum Outstanding "
 493                             "Commands set to Zero\n");
 494                         cmn_err(CE_CONT, "CPQary3 : Cannot continue driver "
 495                             "initialization \n");
 496                         return (CPQARY3_FAILURE);
 497                 }
 498 
 499                 cpqary3p->ctlr_maxcmds = CmdsOutMax;
 500                 cpqary3p->sg_cnt = CPQARY3_SG_CNT;
 501 
 502                 queue_depth = cpqary3p->ctlr_maxcmds;
 503                 cmd_size = (8 * queue_depth);
 504                 /* QUEUE CHANGES */
 505                 cpqary3p->drvr_replyq->cyclic_indicator =
 506                     CPQARY3_REPLYQ_INIT_CYCLIC_IND;
 507                 cpqary3p->drvr_replyq->simple_cyclic_indicator =
 508                     CPQARY3_REPLYQ_INIT_CYCLIC_IND;
 509                 cpqary3p->drvr_replyq->max_index = cpqary3p->ctlr_maxcmds;
 510                 cpqary3p->drvr_replyq->simple_index = 0;
 511                 replyq_start_addr = MEM_ZALLOC(cmd_size);
 512                 bzero(replyq_start_addr, cmd_size);
 513                 cpqary3p->drvr_replyq->replyq_headptr =
 514                     /* LINTED: alignment */
 515                     (uint32_t *)replyq_start_addr;
 516                 cpqary3p->drvr_replyq->replyq_simple_ptr =
 517                     /* LINTED: alignment */
 518                     (uint32_t *)replyq_start_addr;
 519                 cpqary3p->drvr_replyq->replyq_start_addr = replyq_start_addr;
 520 
 521                 /* PERF */
 522 
 523                 /*
 524                  * Check for support of SIMPLE Transport Method
 525                  */
 526                 if (!(DDI_GET32(cpqary3p, &ctp->TransportSupport) &
 527                     CFGTBL_XPORT_SIMPLE)) {
 528                         cmn_err(CE_WARN, "CPQary3 : Controller "
 529                             "NOT YET INITIALIZED");
 530                         cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, "
 531                             "try again later \n");
 532                         return (CPQARY3_FAILURE);
 533                 }
 534 
 535                 /*
 536                  * Configuration Table Initialization
 537                  * Set bit 0 of InBound Door Bell Reg to inform the controller
 538                  * about the changes related to the Configuration table
 539                  */
 540                 DTRACE_PROBE(cfgtable_init_start);
 541 
 542                 DDI_PUT32(cpqary3p, &ctp->HostWrite.TransportRequest,
 543                     CFGTBL_XPORT_SIMPLE);
 544                 ddi_put32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr,
 545                     ddi_get32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr) |
 546                     CFGTBL_CHANGE_REQ);
 547 
 548                 /*
 549                  * Check whether the controller is  ready
 550                  */
 551 
 552                 cntr = 0;
 553                 while (ddi_get32(cpqary3p->idr_handle,
 554                     (uint32_t *)cpqary3p->idr) & CFGTBL_ACC_CMDS) {
 555                         drv_usecwait(1000000); /* Wait for 1 Sec. */
 556                         cntr++;
 557 
 558                         /*
 559                          * Wait for a maximum of 90 seconds. No f/w should take
 560                          * more than 90 secs to initialize. If the controller
 561                          * is not ready even after 90 secs, it suggests that
 562                          * something is wrong
 563                          * (wrt the controller, what else) !!!
 564                          */
 565 
 566                         if (cntr > CISS_INIT_TIME) /* 1.30 Mins */ {
 567                                 cmn_err(CE_CONT, "CPQary3 : Controller "
 568                                     "Initialization Failed \n");
 569                                 return (CPQARY3_FAILURE);
 570                         }
 571                 }
 572 
 573                 DTRACE_PROBE(cfgtable_init_done);
 574 
 575                 /*
 576                  * Check whether controller accepts the requested method of
 577                  * transport
 578                  */
 579                 if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) &
 580                     CFGTBL_XPORT_SIMPLE)) {
 581                         cmn_err(CE_CONT, "CPQary3 : Failed to Initialize "
 582                             "Controller \n");
 583                         cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, "
 584                             "try again later\n");
 585                         return (CPQARY3_FAILURE);
 586                 }
 587 
 588                 DTRACE_PROBE(ctlr_init_simple);
 589 
 590                 /*
 591                  * Check if Controller is ready to accept Commands
 592                  */
 593 
 594                 if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) &
 595                     CFGTBL_ACC_CMDS)) {
 596                         cmn_err(CE_CONT, "CPQary3: Controller NOT ready to "
 597                             "accept Commands \n");
 598                         return (CPQARY3_FAILURE);
 599                 }
 600 
 601                 DTRACE_PROBE(ctlr_init_ready);
 602 
 603                 /*
 604                  * Check if the maximum number of oustanding commands for the
 605                  * initialized controller is something greater than Zero.
 606                  */
 607 
 608                 CmdsOutMax = DDI_GET32(cpqary3p, &ctp->CmdsOutMax);
 609 
 610                 if (CmdsOutMax == 0) {
 611                         cmn_err(CE_CONT, "CPQary3 : HBA Maximum Outstanding "
 612                             "Commands set to Zero\n");
 613                         cmn_err(CE_CONT, "CPQary3 : Cannot continue driver "
 614                             "initialization \n");
 615                         return (CPQARY3_FAILURE);
 616                 }
 617                 cpqary3p->ctlr_maxcmds = CmdsOutMax;
 618 
 619                 /*
 620                  * Zero the Upper 32 Address in the Controller
 621                  */
 622 
 623                 DDI_PUT32(cpqary3p, &ctp->HostWrite.Upper32Addr, 0x00000000);
 624                 cpqary3p->heartbeat = DDI_GET32(cpqary3p, &ctp->HeartBeat);
 625 
 626                 /* Set the controller interrupt check routine */
 627                 cpqary3p->check_ctlr_intr = cpqary3_check_simple_ctlr_intr;
 628 
 629                 cpqary3p->host_support =
 630                     DDI_GET32(cpqary3p, &ctp->HostDrvrSupport);
 631                 DDI_PUT32(cpqary3p, &ctp->HostDrvrSupport,
 632                     (cpqary3p->host_support | 0x4));
 633                 cpqary3p->host_support =
 634                     DDI_GET32(cpqary3p, &ctp->HostDrvrSupport);
 635 
 636                 cpqary3p->lockup_logged = CPQARY3_FALSE;
 637         } else {
 638         /* PERF */
 639 
 640                 /*
 641                  * Check for support of PERF Transport Method
 642                  */
 643                 if (!(DDI_GET32(cpqary3p, &ctp->TransportSupport)
 644                     & CFGTBL_XPORT_PERFORMANT)) {
 645                         cmn_err(CE_WARN, "CPQary3 : Controller "
 646                             "NOT YET INITIALIZED");
 647                         cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, "
 648                             "try again later \n");
 649                         return (CPQARY3_FAILURE);
 650                 }
 651 
 652                 CmdsOutMax = DDI_GET32(cpqary3p, &ctp->MaxPerfModeCmdsOutMax);
 653                 if (CmdsOutMax == 0)
 654                         CmdsOutMax = DDI_GET32(cpqary3p, &ctp->CmdsOutMax);
 655                 if (CmdsOutMax == 0) {
 656                         cmn_err(CE_CONT, "CPQary3 : HBA Maximum Outstanding "
 657                             "Commands set to Zero\n");
 658                         cmn_err(CE_CONT, "CPQary3 : Cannot continue driver "
 659                             "initialization \n");
 660                         return (CPQARY3_FAILURE);
 661                 }
 662 
 663                 cpqary3p->ctlr_maxcmds = CmdsOutMax;
 664 
 665 
 666                 /* Initialize the Performant Method Transport Method Table */
 667 
 668                 queue_depth = cpqary3p->ctlr_maxcmds;
 669 
 670                 DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQSize, queue_depth);
 671                 DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQCount, 1);
 672                 DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQCntrAddrLow32, 0);
 673                 DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQCntrAddrHigh32, 0);
 674 
 675                 cpqary3_phyctgp =
 676                     (cpqary3_phyctg_t *)MEM_ZALLOC(sizeof (cpqary3_phyctg_t));
 677 
 678                 if (!cpqary3_phyctgp) {
 679                         cmn_err(CE_NOTE,
 680                             "CPQary3: Initial mem zalloc failed");
 681                         return (CPQARY3_FAILURE);
 682                 }
 683                 cmd_size = (8 * queue_depth);
 684                 phy_addr = 0;
 685                 replyq_start_addr = cpqary3_alloc_phyctgs_mem(cpqary3p,
 686                     cmd_size, &phy_addr, cpqary3_phyctgp);
 687 
 688                 if (!replyq_start_addr) {
 689                         cmn_err(CE_WARN, "MEMALLOC returned failure");
 690                         return (CPQARY3_FAILURE);
 691                 }
 692 
 693                 bzero(replyq_start_addr, cmd_size);
 694                 cpqary3p->drvr_replyq->replyq_headptr =
 695                     /* LINTED: alignment */
 696                     (uint32_t *)replyq_start_addr;
 697                 cpqary3p->drvr_replyq->index = 0;
 698                 cpqary3p->drvr_replyq->max_index = queue_depth;
 699                 cpqary3p->drvr_replyq->replyq_start_addr = replyq_start_addr;
 700                 cpqary3p->drvr_replyq->cyclic_indicator =
 701                     CPQARY3_REPLYQ_INIT_CYCLIC_IND;
 702                 cpqary3p->drvr_replyq->replyq_start_paddr = phy_addr;
 703 
 704                 DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQAddr0Low32, phy_addr);
 705                 DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQAddr0High32, 0);
 706 
 707                 max_blk_fetch_cnt =
 708                     DDI_GET32(cpqary3p, &ctp->MaxBlockFetchCount);
 709 
 710                 /*
 711                  * For non-proton FW controllers, max_blk_fetch_count is not
 712                  * implemented in the firmware
 713                  */
 714 
 715                 /*
 716                  * When blk fetch count is 0, FW auto fetches 564 bytes
 717                  * corresponding to an optimal S/G of 31
 718                  */
 719                 if (max_blk_fetch_cnt == 0) {
 720                         BlockFetchCnt[0] = 35;
 721                 } else {
 722                         /*
 723                          * With MAX_PERF_SG_CNT set to 64, block fetch count
 724                          * is got by:(sizeof (CommandList_t) + 15)/16
 725                          */
 726                         if (max_blk_fetch_cnt > 68)
 727                                 BlockFetchCnt[0] = 68;
 728                         else
 729                                 BlockFetchCnt[0] = max_blk_fetch_cnt;
 730                 }
 731 
 732                 DDI_PUT32_CP(cpqary3p, &perf_cfg->BlockFetchCnt[0],
 733                     BlockFetchCnt[0]);
 734                 DDI_PUT32(cpqary3p, &ctp->HostWrite.TransportRequest,
 735                     CFGTBL_XPORT_PERFORMANT);
 736                 ddi_put32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr,
 737                     ddi_get32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr) |
 738                     CFGTBL_CHANGE_REQ);
 739 
 740                 /*
 741                  * Check whether the controller is  ready
 742                  */
 743 
 744                 cntr = 0;
 745                 while (ddi_get32(cpqary3p->idr_handle,
 746                     (uint32_t *)cpqary3p->idr) & CFGTBL_ACC_CMDS) {
 747                         drv_usecwait(1000000); /* Wait for 1 Sec. */
 748                         cntr++;
 749 
 750 
 751                         /*
 752                          * Wait for a maximum of 90 seconds. No f/w should take
 753                          * more than 90 secs to initialize. If the controller
 754                          * is not ready even after 90 secs, it suggests that
 755                          * something is wrong
 756                          * (wrt the controller, what else) !!!
 757                          */
 758 
 759                         if (cntr > CISS_INIT_TIME) /* 1.30 Mins */ {
 760                                 cmn_err(CE_CONT, "CPQary3 : Controller "
 761                                     "Initialization Failed \n");
 762                                 return (CPQARY3_FAILURE);
 763                         }
 764                 }
 765 
 766                 /*
 767                  * Check whether controller accepts the requested method of
 768                  * transport
 769                  */
 770 
 771                 if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) &
 772                     CFGTBL_XPORT_PERFORMANT)) {
 773                         cmn_err(CE_NOTE, "CPQary3 : Failed to Initialize "
 774                             "Controller");
 775                         cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, "
 776                             "try again later\n");
 777                         DTRACE_PROBE1(ctlr_init_perf_fail, CfgTable_t *, ctp);
 778                         return (CPQARY3_FAILURE);
 779                 }
 780 
 781                 DTRACE_PROBE(ctlr_init_simple);
 782 
 783                 /*
 784                  * Check if Controller is ready to accept Commands
 785                  */
 786 
 787                 if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) &
 788                     CFGTBL_ACC_CMDS)) {
 789                         cmn_err(CE_NOTE, "CPQary3: Controller NOT ready to "
 790                             "accept Commands");
 791                         return (CPQARY3_FAILURE);
 792                 }
 793 
 794                 /*
 795                  * Check if the maximum number of oustanding commands for the
 796                  * initialized controller is something greater than Zero.
 797                  */
 798 
 799                 CmdsOutMax = DDI_GET32(cpqary3p, &ctp->MaxPerfModeCmdsOutMax);
 800                 if (CmdsOutMax == 0)
 801                         CmdsOutMax = DDI_GET32(cpqary3p, &ctp->CmdsOutMax);
 802 
 803                 if (CmdsOutMax == 0) {
 804                         cmn_err(CE_NOTE, "CPQary3 : HBA Maximum Outstanding "
 805                             "Commands set to Zero");
 806                         cmn_err(CE_NOTE, "CPQary3 : Cannot continue driver "
 807                             "initialization");
 808                         return (CPQARY3_FAILURE);
 809                 }
 810 
 811                 cpqary3p->ctlr_maxcmds = CmdsOutMax;
 812 
 813                 /* SG */
 814                 max_sg_cnt = DDI_GET32(cpqary3p, &ctp->MaxSGElements);
 815                 max_blk_fetch_cnt =
 816                     DDI_GET32(cpqary3p, &ctp->MaxBlockFetchCount);
 817 
 818                 /* 32 byte aligned - size_of_cmdlist */
 819                 size_of_cmdlist = ((sizeof (CommandList_t) + 31) / 32) * 32;
 820                 size_of_HRE  = size_of_cmdlist -
 821                     (sizeof (SGDescriptor_t) * CISS_MAXSGENTRIES);
 822 
 823                 if ((max_blk_fetch_cnt == 0) || (max_sg_cnt == 0) ||
 824                     ((max_blk_fetch_cnt * 16) <= size_of_HRE)) {
 825                         cpqary3p->sg_cnt = CPQARY3_PERF_SG_CNT;
 826                 } else {
 827                         /*
 828                          * Get the optimal_sg - no of the SG's that will fit
 829                          * into the max_blk_fetch_cnt
 830                          */
 831 
 832                         optimal_sg_size =
 833                             (max_blk_fetch_cnt * 16) - size_of_HRE;
 834 
 835                         if (optimal_sg_size < sizeof (SGDescriptor_t)) {
 836                                 optimal_sg = CPQARY3_PERF_SG_CNT;
 837                         } else {
 838                                 optimal_sg =
 839                                     optimal_sg_size / sizeof (SGDescriptor_t);
 840                         }
 841 
 842                         cpqary3p->sg_cnt = MIN(max_sg_cnt, optimal_sg);
 843 
 844                         if (cpqary3p->sg_cnt > MAX_PERF_SG_CNT)
 845                                 cpqary3p->sg_cnt = MAX_PERF_SG_CNT;
 846                 }
 847 
 848                 /* SG */
 849 
 850                 /*
 851                  * Zero the Upper 32 Address in the Controller
 852                  */
 853 
 854                 DDI_PUT32(cpqary3p, &ctp->HostWrite.Upper32Addr, 0x00000000);
 855                 cpqary3p->heartbeat = DDI_GET32(cpqary3p, &ctp->HeartBeat);
 856 
 857                 /* Set the controller interrupt check routine */
 858 
 859                 if (cpqary3p->bddef->bd_is_e200) {
 860                         cpqary3p->check_ctlr_intr =
 861                             cpqary3_check_perf_e200_intr;
 862                 } else {
 863                         cpqary3p->check_ctlr_intr =
 864                             cpqary3_check_perf_ctlr_intr;
 865                 }
 866 
 867                 if ((!cpqary3p->bddef->bd_is_e200) &&
 868                     (!cpqary3p->bddef->bd_is_ssll)) {
 869                         cpqary3p->host_support =
 870                             DDI_GET32(cpqary3p, &ctp->HostDrvrSupport);
 871                         DDI_PUT32(cpqary3p, &ctp->HostDrvrSupport,
 872                             (cpqary3p->host_support | 0x4));
 873                 }
 874                 cpqary3p->host_support =
 875                     DDI_GET32(cpqary3p, &ctp->HostDrvrSupport);
 876                 cpqary3p->lockup_logged = CPQARY3_FALSE;
 877         }
 878 
 879         return (CPQARY3_SUCCESS);
 880 }
 881 
 882 /*
 883  * Function     :       cpqary3_check_ctlr_init
 884  * Description  :       This routine checks to see if the HBA is initialized.
 885  * Called By    :       cpqary3_init_ctlr()
 886  * Parameters   :       per-controller
 887  * Calls        :       None
 888  * Return Values:       SUCCESS / FAILURE
 889  */
 890 uint8_t
 891 cpqary3_check_ctlr_init(cpqary3_t *cpqary3p)
 892 {
 893         int8_t                          retvalue;
 894         uint16_t                        i;
 895         uint32_t                        *ctlr_init;
 896         ddi_acc_handle_t                ctlr_init_handle;
 897         extern ddi_device_acc_attr_t    cpqary3_dev_attributes;
 898 
 899         RETURN_FAILURE_IF_NULL(cpqary3p);
 900 
 901         /*
 902          * Set up the mapping for a Register at offset 0xB0 from I2O Bar
 903          * The value 0xB0 taken from the CONFIGM utility.
 904          * It should read 0xffff0000 if the controller is initialized.
 905          * if not yet initialized, read it every second for 300 secs.
 906          * If not set even after 300 secs, return FAILURE.
 907          * If set, free the mapping and continue
 908          */
 909         retvalue = ddi_regs_map_setup(cpqary3p->dip, INDEX_PCI_BASE0,
 910             (caddr_t *)&ctlr_init, (offset_t)I2O_CTLR_INIT, 4,
 911             &cpqary3_dev_attributes, &ctlr_init_handle);
 912 
 913         if (retvalue != DDI_SUCCESS) {
 914                 if (DDI_REGS_ACC_CONFLICT == retvalue)
 915                         cmn_err(CE_WARN,
 916                             "CPQary3 : HBA Init Register Mapping Conflict");
 917                 cmn_err(CE_WARN,
 918                     "CPQary3 : HBA Init Regsiter Mapping Failed");
 919                 return (CPQARY3_FAILURE);
 920         }
 921 
 922         for (i = 0; i < 300; i++) {  /* loop for 300 seconds */
 923                 if (CISS_CTLR_INIT == ddi_get32(ctlr_init_handle, ctlr_init)) {
 924                         DTRACE_PROBE(ctlr_init_check_ready);
 925                         ddi_regs_map_free(&ctlr_init_handle);
 926                         break;
 927                 } else {
 928                         DTRACE_PROBE(ctlr_init_check_notready);
 929                         delay(drv_sectohz(1));
 930                 }
 931         }
 932 
 933         if (i >= 300) {      /* HBA not initialized even after 300 seconds !!! */
 934                 ddi_regs_map_free(&ctlr_init_handle);
 935                 cmn_err(CE_WARN, "CPQary3 : %s NOT initialized !!! HBA may not "
 936                     "function properly. Please replace the hardware or check "
 937                     "the connections", cpqary3p->hba_name);
 938                 return (CPQARY3_FAILURE);
 939         }
 940 
 941         return (CPQARY3_SUCCESS);
 942 }