Print this page
    
9048 mpt_sas should not require targets to send SEP messages
Reviewed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Approved by: Gordon Ross <gwr@nexenta.com>
NEX-17006 backport mpt_sas tri-mode parts support change
9044 Need support for mpt_sas tri-mode parts
9045 Clean up mpt_sas compiler warnings
9046 mptsas_handle_topo_change can return without its locks held
9047 workaround SAS3408 firmware issue
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@joyent.com>
Reviewed by: Albert Lee <trisk@forkgnu.org>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
Approved by: Richard Lowe <richlowe@richlowe.net>
NEX-16174 scsi error messages should go to system log only
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-14838 Support 24 port version of SAS adapters
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-1774 mptsas error stats are always zero
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
NEX-2103 12G mpt_sas needs additional minor enhancements
NEX-2157 mpt_sas firmware update minor regression
NEX-1889 mpt_sas should support 12G HBAs
4500 mptsas_hash_traverse() is unsafe, leads to missing devices
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Approved by: Albert Lee <trisk@nexenta.com>
backout 4500 mptsas_hash_traverse() is unsafe, leads to missing devices
4403 mpt_sas panic when pulling a drive
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Reviewed by: Albert Lee <trisk@nexenta.com>
Reviewed by: Andy Giles <illumos@ang.homedns.org>
Approved by: Robert Mustacchi <rm@joyent.com>
4500 mptsas_hash_traverse() is unsafe, leads to missing devices
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Approved by: Albert Lee <trisk@nexenta.com>
re #9636 rb2836 - mpt_sas should attempt an MUR reset at attach time.
--HG--
branch : stable-4.0
re #9636 rb2836 - mpt_sas should attempt an MUR reset at attach time.
re #6530 mpt_sas crash when more than 1 Initiator involved - ie HA
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
          +++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24      - * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
       24 + * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
  25   25   * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
  26   26   * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  27   27   * Copyright (c) 2017, Joyent, Inc.
  28   28   */
  29   29  
  30   30  /*
  31   31   * Copyright (c) 2000 to 2010, LSI Corporation.
  32   32   * All rights reserved.
  33   33   *
  34   34   * Redistribution and use in source and binary forms of all code within
  35   35   * this file that is exclusively owned by LSI, with or without
  36   36   * modification, is permitted provided that, in addition to the CDDL 1.0
  37   37   * License requirements, the following conditions are met:
  38   38   *
  39   39   *    Neither the name of the author nor the names of its contributors may be
  40   40   *    used to endorse or promote products derived from this software without
  41   41   *    specific prior written permission.
  42   42   *
  43   43   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  44   44   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  45   45   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  46   46   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  47   47   * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  48   48   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  49   49   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  50   50   * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  51   51   * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  52   52   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  53   53   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  54   54   * DAMAGE.
  55   55   */
  56   56  
  57   57  /*
  58   58   * mptsas_impl - This file contains all the basic functions for communicating
  59   59   * to MPT based hardware.
  60   60   */
  61   61  
  62   62  #if defined(lint) || defined(DEBUG)
  63   63  #define MPTSAS_DEBUG
  64   64  #endif
  65   65  
  66   66  /*
  67   67   * standard header files
  68   68   */
  69   69  #include <sys/note.h>
  70   70  #include <sys/scsi/scsi.h>
  71   71  #include <sys/pci.h>
  72   72  
  73   73  #pragma pack(1)
  74   74  #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
  75   75  #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
  76   76  #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
  77   77  #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
  78   78  #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
  79   79  #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
  80   80  #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
  81   81  #pragma pack()
  82   82  
  83   83  /*
  84   84   * private header files.
  85   85   */
  86   86  #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
  87   87  #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
  88   88  
  89   89  /*
  90   90   * FMA header files.
  91   91   */
  92   92  #include <sys/fm/io/ddi.h>
  93   93  
  94   94  /*
  95   95   *  prototypes
  96   96   */
  97   97  static void mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd);
  98   98  static void mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd);
  99   99  static m_event_struct_t *mptsas_ioc_event_find_by_cmd(mptsas_t *mpt,
 100  100      struct mptsas_cmd *cmd);
 101  101  
 102  102  /*
 103  103   * add ioc evnet cmd into the queue
 104  104   */
 105  105  static void
 106  106  mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd)
 107  107  {
 108  108          if ((cmd->m_event_linkp = mpt->m_ioc_event_cmdq) == NULL) {
 109  109                  mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
 110  110                  mpt->m_ioc_event_cmdq = cmd;
 111  111          } else {
 112  112                  cmd->m_event_linkp = NULL;
 113  113                  *(mpt->m_ioc_event_cmdtail) = cmd;
 114  114                  mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
 115  115          }
 116  116  }
 117  117  
 118  118  /*
 119  119   * remove specified cmd from the ioc event queue
 120  120   */
 121  121  static void
 122  122  mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd)
 123  123  {
 124  124          m_event_struct_t        *prev = mpt->m_ioc_event_cmdq;
 125  125          if (prev == cmd) {
 126  126                  if ((mpt->m_ioc_event_cmdq = cmd->m_event_linkp) == NULL) {
 127  127                          mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq;
 128  128                  }
 129  129                  cmd->m_event_linkp = NULL;
 130  130                  return;
 131  131          }
 132  132          while (prev != NULL) {
 133  133                  if (prev->m_event_linkp == cmd) {
 134  134                          prev->m_event_linkp = cmd->m_event_linkp;
 135  135                          if (cmd->m_event_linkp == NULL) {
 136  136                                  mpt->m_ioc_event_cmdtail = &prev->m_event_linkp;
 137  137                          }
 138  138  
 139  139                          cmd->m_event_linkp = NULL;
 140  140                          return;
 141  141                  }
 142  142                  prev = prev->m_event_linkp;
 143  143          }
 144  144  }
 145  145  
 146  146  static m_event_struct_t *
 147  147  mptsas_ioc_event_find_by_cmd(mptsas_t *mpt, struct mptsas_cmd *cmd)
 148  148  {
 149  149          m_event_struct_t        *ioc_cmd = NULL;
 150  150  
 151  151          ioc_cmd = mpt->m_ioc_event_cmdq;
 152  152          while (ioc_cmd != NULL) {
 153  153                  if (&(ioc_cmd->m_event_cmd) == cmd) {
 154  154                          return (ioc_cmd);
 155  155                  }
 156  156                  ioc_cmd = ioc_cmd->m_event_linkp;
 157  157          }
 158  158          ioc_cmd = NULL;
 159  159          return (ioc_cmd);
 160  160  }
 161  161  
 162  162  void
 163  163  mptsas_destroy_ioc_event_cmd(mptsas_t *mpt)
 164  164  {
 165  165          m_event_struct_t        *ioc_cmd = NULL;
 166  166          m_event_struct_t        *ioc_cmd_tmp = NULL;
 167  167          ioc_cmd = mpt->m_ioc_event_cmdq;
 168  168  
 169  169          /*
 170  170           * because the IOC event queue is resource of per instance for driver,
 171  171           * it's not only ACK event commands used it, but also some others used
 172  172           * it. We need destroy all ACK event commands when IOC reset, but can't
 173  173           * disturb others.So we use filter to clear the ACK event cmd in ioc
 174  174           * event queue, and other requests should be reserved, and they would
 175  175           * be free by its owner.
 176  176           */
 177  177          while (ioc_cmd != NULL) {
 178  178                  if (ioc_cmd->m_event_cmd.cmd_flags & CFLAG_CMDACK) {
 179  179                          NDBG20(("destroy!! remove Ack Flag ioc_cmd\n"));
 180  180                          if ((mpt->m_ioc_event_cmdq =
 181  181                              ioc_cmd->m_event_linkp) == NULL)
 182  182                                  mpt->m_ioc_event_cmdtail =
 183  183                                      &mpt->m_ioc_event_cmdq;
 184  184                          ioc_cmd_tmp = ioc_cmd;
 185  185                          ioc_cmd = ioc_cmd->m_event_linkp;
 186  186                          kmem_free(ioc_cmd_tmp, M_EVENT_STRUCT_SIZE);
 187  187                  } else {
 188  188                          /*
 189  189                           * it's not ack cmd, so continue to check next one
 190  190                           */
 191  191  
 192  192                          NDBG20(("destroy!! it's not Ack Flag, continue\n"));
 193  193                          ioc_cmd = ioc_cmd->m_event_linkp;
 194  194                  }
 195  195  
 196  196          }
 197  197  }
 198  198  
 199  199  void
 200  200  mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd)
 201  201  {
 202  202          pMpi2ConfigRequest_t    request;
 203  203          pMpi2SGESimple64_t      sge;
 204  204          struct scsi_pkt         *pkt = cmd->cmd_pkt;
 205  205          mptsas_config_request_t *config = pkt->pkt_ha_private;
 206  206          uint8_t                 direction;
 207  207          uint32_t                length, flagslength;
 208  208          uint64_t                request_desc;
 209  209  
 210  210          ASSERT(mutex_owned(&mpt->m_mutex));
 211  211  
 212  212          /*
 213  213           * Point to the correct message and clear it as well as the global
 214  214           * config page memory.
 215  215           */
 216  216          request = (pMpi2ConfigRequest_t)(mpt->m_req_frame +
 217  217              (mpt->m_req_frame_size * cmd->cmd_slot));
 218  218          bzero(request, mpt->m_req_frame_size);
 219  219  
 220  220          /*
 221  221           * Form the request message.
 222  222           */
 223  223          ddi_put8(mpt->m_acc_req_frame_hdl, &request->Function,
 224  224              MPI2_FUNCTION_CONFIG);
 225  225          ddi_put8(mpt->m_acc_req_frame_hdl, &request->Action, config->action);
 226  226          direction = MPI2_SGE_FLAGS_IOC_TO_HOST;
 227  227          length = 0;
 228  228          sge = (pMpi2SGESimple64_t)&request->PageBufferSGE;
 229  229          if (config->action == MPI2_CONFIG_ACTION_PAGE_HEADER) {
 230  230                  if (config->page_type > MPI2_CONFIG_PAGETYPE_MASK) {
 231  231                          ddi_put8(mpt->m_acc_req_frame_hdl,
 232  232                              &request->Header.PageType,
 233  233                              MPI2_CONFIG_PAGETYPE_EXTENDED);
 234  234                          ddi_put8(mpt->m_acc_req_frame_hdl,
 235  235                              &request->ExtPageType, config->page_type);
 236  236                  } else {
 237  237                          ddi_put8(mpt->m_acc_req_frame_hdl,
 238  238                              &request->Header.PageType, config->page_type);
 239  239                  }
 240  240          } else {
 241  241                  ddi_put8(mpt->m_acc_req_frame_hdl, &request->ExtPageType,
 242  242                      config->ext_page_type);
 243  243                  ddi_put16(mpt->m_acc_req_frame_hdl, &request->ExtPageLength,
 244  244                      config->ext_page_length);
 245  245                  ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageType,
 246  246                      config->page_type);
 247  247                  ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageLength,
 248  248                      config->page_length);
 249  249                  ddi_put8(mpt->m_acc_req_frame_hdl,
 250  250                      &request->Header.PageVersion, config->page_version);
 251  251                  if ((config->page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
 252  252                      MPI2_CONFIG_PAGETYPE_EXTENDED) {
 253  253                          length = config->ext_page_length * 4;
 254  254                  } else {
 255  255                          length = config->page_length * 4;
 256  256                  }
 257  257  
 258  258                  if (config->action == MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
 259  259                          direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
 260  260                  }
 261  261                  ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
 262  262                      (uint32_t)cmd->cmd_dma_addr);
 263  263                  ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
 264  264                      (uint32_t)(cmd->cmd_dma_addr >> 32));
 265  265          }
 266  266          ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageNumber,
 267  267              config->page_number);
 268  268          ddi_put32(mpt->m_acc_req_frame_hdl, &request->PageAddress,
 269  269              config->page_address);
 270  270          flagslength = ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
 271  271              MPI2_SGE_FLAGS_END_OF_BUFFER |
 272  272              MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
 273  273              MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
 274  274              MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
 275  275              direction |
 276  276              MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
 277  277          flagslength |= length;
 278  278          ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
 279  279  
 280  280          (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
 281  281              DDI_DMA_SYNC_FORDEV);
 282  282          request_desc = (cmd->cmd_slot << 16) +
 283  283              MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 284  284          cmd->cmd_rfm = NULL;
 285  285          MPTSAS_START_CMD(mpt, request_desc);
 286  286          if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
 287  287              DDI_SUCCESS) ||
 288  288              (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
 289  289              DDI_SUCCESS)) {
 290  290                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
 291  291          }
 292  292  }
 293  293  
 294  294  int
 295  295  mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
 296  296      uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
 297  297      caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...)
 298  298  {
 299  299          va_list                 ap;
 300  300          ddi_dma_attr_t          attrs;
 301  301          ddi_dma_cookie_t        cookie;
 302  302          ddi_acc_handle_t        accessp;
 303  303          size_t                  len = 0;
 304  304          mptsas_config_request_t config;
 305  305          int                     rval = DDI_SUCCESS, config_flags = 0;
 306  306          mptsas_cmd_t            *cmd;
 307  307          struct scsi_pkt         *pkt;
 308  308          pMpi2ConfigReply_t      reply;
 309  309          uint16_t                iocstatus = 0;
 310  310          uint32_t                iocloginfo;
 311  311          caddr_t                 page_memp;
 312  312          boolean_t               free_dma = B_FALSE;
 313  313  
 314  314          va_start(ap, callback);
 315  315          ASSERT(mutex_owned(&mpt->m_mutex));
 316  316  
 317  317          /*
 318  318           * Get a command from the pool.
 319  319           */
 320  320          if ((rval = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
 321  321                  mptsas_log(mpt, CE_NOTE, "command pool is full for config "
 322  322                      "page request");
 323  323                  rval = DDI_FAILURE;
 324  324                  goto page_done;
 325  325          }
 326  326          config_flags |= MPTSAS_REQUEST_POOL_CMD;
 327  327  
 328  328          bzero((caddr_t)cmd, sizeof (*cmd));
 329  329          bzero((caddr_t)pkt, scsi_pkt_size());
 330  330          bzero((caddr_t)&config, sizeof (config));
 331  331  
 332  332          /*
 333  333           * Save the data for this request to be used in the call to start the
 334  334           * config header request.
 335  335           */
 336  336          config.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
 337  337          config.page_type = page_type;
 338  338          config.page_number = page_number;
 339  339          config.page_address = page_address;
 340  340  
 341  341          /*
 342  342           * Form a blank cmd/pkt to store the acknowledgement message
 343  343           */
 344  344          pkt->pkt_ha_private     = (opaque_t)&config;
 345  345          pkt->pkt_flags          = FLAG_HEAD;
 346  346          pkt->pkt_time           = 60;
 347  347          cmd->cmd_pkt            = pkt;
 348  348          cmd->cmd_flags          = CFLAG_CMDIOC | CFLAG_CONFIG;
 349  349  
 350  350          /*
 351  351           * Save the config header request message in a slot.
 352  352           */
 353  353          if (mptsas_save_cmd(mpt, cmd) == TRUE) {
 354  354                  cmd->cmd_flags |= CFLAG_PREPARED;
 355  355                  mptsas_start_config_page_access(mpt, cmd);
 356  356          } else {
 357  357                  mptsas_waitq_add(mpt, cmd);
 358  358          }
 359  359  
 360  360          /*
 361  361           * If this is a request for a RAID info page, or any page called during
 362  362           * the RAID info page request, poll because these config page requests
 363  363           * are nested.  Poll to avoid data corruption due to one page's data
 364  364           * overwriting the outer page request's data.  This can happen when
 365  365           * the mutex is released in cv_wait.
 366  366           */
 367  367          if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
 368  368              (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
 369  369              (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
 370  370                  (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
 371  371          } else {
 372  372                  while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
 373  373                          cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
 374  374                  }
 375  375          }
 376  376  
 377  377          /*
 378  378           * Check if the header request completed without timing out
 379  379           */
 380  380          if (cmd->cmd_flags & CFLAG_TIMEOUT) {
 381  381                  mptsas_log(mpt, CE_WARN, "config header request timeout");
 382  382                  rval = DDI_FAILURE;
 383  383                  goto page_done;
 384  384          }
 385  385  
 386  386          /*
 387  387           * cmd_rfm points to the reply message if a reply was given.  Check the
 388  388           * IOCStatus to make sure everything went OK with the header request.
 389  389           */
 390  390          if (cmd->cmd_rfm) {
 391  391                  config_flags |= MPTSAS_ADDRESS_REPLY;
 392  392                  (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
 393  393                      DDI_DMA_SYNC_FORCPU);
 394  394                  reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
 395  395                      - (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
 396  396                  config.page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
 397  397                      &reply->Header.PageType);
 398  398                  config.page_number = ddi_get8(mpt->m_acc_reply_frame_hdl,
 399  399                      &reply->Header.PageNumber);
 400  400                  config.page_length = ddi_get8(mpt->m_acc_reply_frame_hdl,
 401  401                      &reply->Header.PageLength);
 402  402                  config.page_version = ddi_get8(mpt->m_acc_reply_frame_hdl,
 403  403                      &reply->Header.PageVersion);
 404  404                  config.ext_page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
 405  405                      &reply->ExtPageType);
 406  406                  config.ext_page_length = ddi_get16(mpt->m_acc_reply_frame_hdl,
 407  407                      &reply->ExtPageLength);
 408  408  
 409  409                  iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
 410  410                      &reply->IOCStatus);
 411  411                  iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
 412  412                      &reply->IOCLogInfo);
 413  413  
 414  414                  if (iocstatus) {
 415  415                          NDBG13(("mptsas_access_config_page header: "
 416  416                              "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
 417  417                              iocloginfo));
 418  418                          rval = DDI_FAILURE;
 419  419                          goto page_done;
 420  420                  }
 421  421  
 422  422                  if ((config.page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
 423  423                      MPI2_CONFIG_PAGETYPE_EXTENDED)
 424  424                          len = (config.ext_page_length * 4);
 425  425                  else
 426  426                          len = (config.page_length * 4);
 427  427  
 428  428          }
 429  429  
 430  430          if (pkt->pkt_reason == CMD_RESET) {
 431  431                  mptsas_log(mpt, CE_WARN, "ioc reset abort config header "
 432  432                      "request");
 433  433                  rval = DDI_FAILURE;
 434  434                  goto page_done;
 435  435          }
 436  436  
 437  437          /*
 438  438           * Put the reply frame back on the free queue, increment the free
 439  439           * index, and write the new index to the free index register.  But only
 440  440           * if this reply is an ADDRESS reply.
 441  441           */
 442  442          if (config_flags & MPTSAS_ADDRESS_REPLY) {
 443  443                  ddi_put32(mpt->m_acc_free_queue_hdl,
 444  444                      &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
 445  445                      cmd->cmd_rfm);
 446  446                  (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
 447  447                      DDI_DMA_SYNC_FORDEV);
 448  448                  if (++mpt->m_free_index == mpt->m_free_queue_depth) {
 449  449                          mpt->m_free_index = 0;
 450  450                  }
 451  451                  ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
 452  452                      mpt->m_free_index);
 453  453                  config_flags &= (~MPTSAS_ADDRESS_REPLY);
 454  454          }
 455  455  
 456  456          /*
 457  457           * Allocate DMA buffer here.  Store the info regarding this buffer in
 458  458           * the cmd struct so that it can be used for this specific command and
 459  459           * de-allocated after the command completes.  The size of the reply
 460  460           * will not be larger than the reply frame size.
 461  461           */
 462  462          attrs = mpt->m_msg_dma_attr;
 463  463          attrs.dma_attr_sgllen = 1;
 464  464          attrs.dma_attr_granular = (uint32_t)len;
 465  465  
 466  466          if (mptsas_dma_addr_create(mpt, attrs,
 467  467              &cmd->cmd_dmahandle, &accessp, &page_memp,
 468  468              len, &cookie) == FALSE) {
 469  469                  rval = DDI_FAILURE;
 470  470                  mptsas_log(mpt, CE_WARN,
 471  471                      "mptsas_dma_addr_create(len=0x%x) failed", (int)len);
 472  472                  goto page_done;
 473  473          }
 474  474          /* NOW we can safely call mptsas_dma_addr_destroy(). */
 475  475          free_dma = B_TRUE;
 476  476  
 477  477          cmd->cmd_dma_addr = cookie.dmac_laddress;
 478  478          bzero(page_memp, len);
 479  479  
 480  480          /*
 481  481           * Save the data for this request to be used in the call to start the
 482  482           * config page read
 483  483           */
 484  484          config.action = action;
 485  485          config.page_address = page_address;
 486  486  
 487  487          /*
 488  488           * Re-use the cmd that was used to get the header.  Reset some of the
 489  489           * values.
 490  490           */
 491  491          bzero((caddr_t)pkt, scsi_pkt_size());
 492  492          pkt->pkt_ha_private     = (opaque_t)&config;
 493  493          pkt->pkt_flags          = FLAG_HEAD;
 494  494          pkt->pkt_time           = 60;
 495  495          cmd->cmd_flags          = CFLAG_PREPARED | CFLAG_CMDIOC | CFLAG_CONFIG;
 496  496  
 497  497          /*
 498  498           * Send the config page request.  cmd is re-used from header request.
 499  499           */
 500  500          mptsas_start_config_page_access(mpt, cmd);
 501  501  
 502  502          /*
 503  503           * If this is a request for a RAID info page, or any page called during
 504  504           * the RAID info page request, poll because these config page requests
 505  505           * are nested.  Poll to avoid data corruption due to one page's data
 506  506           * overwriting the outer page request's data.  This can happen when
 507  507           * the mutex is released in cv_wait.
 508  508           */
 509  509          if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
 510  510              (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
 511  511              (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
 512  512                  (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
 513  513          } else {
 514  514                  while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
 515  515                          cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
 516  516                  }
 517  517          }
 518  518  
 519  519          /*
 520  520           * Check if the request completed without timing out
 521  521           */
 522  522          if (cmd->cmd_flags & CFLAG_TIMEOUT) {
 523  523                  mptsas_log(mpt, CE_WARN, "config page request timeout");
 524  524                  rval = DDI_FAILURE;
 525  525                  goto page_done;
 526  526          }
 527  527  
 528  528          /*
 529  529           * cmd_rfm points to the reply message if a reply was given.  The reply
 530  530           * frame and the config page are returned from this function in the
 531  531           * param list.
 532  532           */
 533  533          if (cmd->cmd_rfm) {
 534  534                  config_flags |= MPTSAS_ADDRESS_REPLY;
 535  535                  (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
 536  536                      DDI_DMA_SYNC_FORCPU);
 537  537                  (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
  
    | 
      ↓ open down ↓ | 
    503 lines elided | 
    
      ↑ open up ↑ | 
  
 538  538                      DDI_DMA_SYNC_FORCPU);
 539  539                  reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
 540  540                      - (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
 541  541                  iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
 542  542                      &reply->IOCStatus);
 543  543                  iocstatus = MPTSAS_IOCSTATUS(iocstatus);
 544  544                  iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
 545  545                      &reply->IOCLogInfo);
 546  546          }
 547  547  
 548      -        if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)) {
      548 +        if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)
      549 +            != DDI_SUCCESS) {
 549  550                  rval = DDI_FAILURE;
 550  551                  goto page_done;
 551  552          }
 552  553  
 553  554          mptsas_fma_check(mpt, cmd);
 554  555          /*
 555  556           * Check the DMA/ACC handles and then free the DMA buffer.
 556  557           */
 557  558          if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
 558  559              (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
 559  560                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
 560  561                  rval = DDI_FAILURE;
 561  562          }
 562  563  
 563  564          if (pkt->pkt_reason == CMD_TRAN_ERR) {
 564  565                  mptsas_log(mpt, CE_WARN, "config fma error");
 565  566                  rval = DDI_FAILURE;
 566  567                  goto page_done;
 567  568          }
 568  569          if (pkt->pkt_reason == CMD_RESET) {
 569  570                  mptsas_log(mpt, CE_WARN, "ioc reset abort config request");
 570  571                  rval = DDI_FAILURE;
 571  572                  goto page_done;
 572  573          }
 573  574  
 574  575  page_done:
 575  576          va_end(ap);
 576  577          /*
 577  578           * Put the reply frame back on the free queue, increment the free
 578  579           * index, and write the new index to the free index register.  But only
 579  580           * if this reply is an ADDRESS reply.
 580  581           */
 581  582          if (config_flags & MPTSAS_ADDRESS_REPLY) {
 582  583                  ddi_put32(mpt->m_acc_free_queue_hdl,
 583  584                      &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
 584  585                      cmd->cmd_rfm);
 585  586                  (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
 586  587                      DDI_DMA_SYNC_FORDEV);
 587  588                  if (++mpt->m_free_index == mpt->m_free_queue_depth) {
 588  589                          mpt->m_free_index = 0;
 589  590                  }
 590  591                  ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
 591  592                      mpt->m_free_index);
 592  593          }
 593  594  
 594  595          if (free_dma)
 595  596                  mptsas_dma_addr_destroy(&cmd->cmd_dmahandle, &accessp);
 596  597  
 597  598          if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
 598  599                  mptsas_remove_cmd(mpt, cmd);
 599  600                  config_flags &= (~MPTSAS_REQUEST_POOL_CMD);
 600  601          }
 601  602          if (config_flags & MPTSAS_REQUEST_POOL_CMD)
 602  603                  mptsas_return_to_pool(mpt, cmd);
 603  604  
 604  605          if (config_flags & MPTSAS_CMD_TIMEOUT) {
 605  606                  mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
 606  607                  if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
 607  608                          mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
 608  609                  }
 609  610          }
 610  611  
 611  612          return (rval);
 612  613  }
 613  614  
 614  615  int
 615  616  mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action, uint8_t pagetype,
 616  617      uint32_t pageaddress, uint8_t pagenumber, uint8_t pageversion,
 617  618      uint8_t pagelength, uint32_t SGEflagslength, uint64_t SGEaddress)
 618  619  {
 619  620          pMpi2ConfigRequest_t    config;
 620  621          int                     send_numbytes;
 621  622  
 622  623          bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
 623  624          config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
 624  625          ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
 625  626          ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
 626  627          ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
 627  628          ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType, pagetype);
 628  629          ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
 629  630          ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
 630  631          ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageLength, pagelength);
 631  632          ddi_put32(mpt->m_hshk_acc_hdl,
 632  633              &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
 633  634          ddi_put32(mpt->m_hshk_acc_hdl,
 634  635              &config->PageBufferSGE.MpiSimple.u.Address64.Low, SGEaddress);
 635  636          ddi_put32(mpt->m_hshk_acc_hdl,
 636  637              &config->PageBufferSGE.MpiSimple.u.Address64.High,
 637  638              SGEaddress >> 32);
 638  639          send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
 639  640  
 640  641          /*
 641  642           * Post message via handshake
 642  643           */
 643  644          if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
 644  645              mpt->m_hshk_acc_hdl)) {
 645  646                  return (-1);
 646  647          }
 647  648          return (0);
 648  649  }
 649  650  
 650  651  int
 651  652  mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
 652  653      uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
 653  654      uint8_t pageversion, uint16_t extpagelength,
 654  655      uint32_t SGEflagslength, uint64_t SGEaddress)
 655  656  {
 656  657          pMpi2ConfigRequest_t    config;
 657  658          int                     send_numbytes;
 658  659  
 659  660          bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
 660  661          config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
 661  662          ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
 662  663          ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
 663  664          ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
 664  665          ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType,
 665  666              MPI2_CONFIG_PAGETYPE_EXTENDED);
 666  667          ddi_put8(mpt->m_hshk_acc_hdl, &config->ExtPageType, extpagetype);
 667  668          ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
 668  669          ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
 669  670          ddi_put16(mpt->m_hshk_acc_hdl, &config->ExtPageLength, extpagelength);
 670  671          ddi_put32(mpt->m_hshk_acc_hdl,
 671  672              &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
 672  673          ddi_put32(mpt->m_hshk_acc_hdl,
 673  674              &config->PageBufferSGE.MpiSimple.u.Address64.Low, SGEaddress);
 674  675          ddi_put32(mpt->m_hshk_acc_hdl,
 675  676              &config->PageBufferSGE.MpiSimple.u.Address64.High,
 676  677              SGEaddress >> 32);
 677  678          send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
 678  679  
 679  680          /*
 680  681           * Post message via handshake
 681  682           */
 682  683          if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
 683  684              mpt->m_hshk_acc_hdl)) {
 684  685                  return (-1);
 685  686          }
 686  687          return (0);
 687  688  }
 688  689  
 689  690  int
 690  691  mptsas_ioc_wait_for_response(mptsas_t *mpt)
 691  692  {
 692  693          int     polls = 0;
 693  694  
 694  695          while ((ddi_get32(mpt->m_datap,
 695  696              &mpt->m_reg->HostInterruptStatus) & MPI2_HIS_IOP_DOORBELL_STATUS)) {
 696  697                  drv_usecwait(1000);
 697  698                  if (polls++ > 60000) {
 698  699                          return (-1);
 699  700                  }
 700  701          }
 701  702          return (0);
 702  703  }
 703  704  
 704  705  int
 705  706  mptsas_ioc_wait_for_doorbell(mptsas_t *mpt)
 706  707  {
 707  708          int     polls = 0;
 708  709  
 709  710          while ((ddi_get32(mpt->m_datap,
 710  711              &mpt->m_reg->HostInterruptStatus) & MPI2_HIM_DIM) == 0) {
 711  712                  drv_usecwait(1000);
 712  713                  if (polls++ > 300000) {
 713  714                          return (-1);
 714  715                  }
 715  716          }
 716  717          return (0);
 717  718  }
 718  719  
 719  720  int
 720  721  mptsas_send_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
 721  722      ddi_acc_handle_t accessp)
 722  723  {
 723  724          int     i;
 724  725  
 725  726          /*
 726  727           * clean pending doorbells
 727  728           */
 728  729          ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
 729  730          ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
 730  731              ((MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) |
 731  732              ((numbytes / 4) << MPI2_DOORBELL_ADD_DWORDS_SHIFT)));
 732  733  
 733  734          if (mptsas_ioc_wait_for_doorbell(mpt)) {
 734  735                  NDBG19(("mptsas_send_handshake failed.  Doorbell not ready\n"));
 735  736                  return (-1);
 736  737          }
 737  738  
 738  739          /*
 739  740           * clean pending doorbells again
 740  741           */
 741  742          ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
 742  743  
 743  744          if (mptsas_ioc_wait_for_response(mpt)) {
 744  745                  NDBG19(("mptsas_send_handshake failed.  Doorbell not "
 745  746                      "cleared\n"));
 746  747                  return (-1);
 747  748          }
 748  749  
 749  750          /*
 750  751           * post handshake message
 751  752           */
 752  753          for (i = 0; (i < numbytes / 4); i++, memp += 4) {
 753  754                  ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
 754  755                      ddi_get32(accessp, (uint32_t *)((void *)(memp))));
 755  756                  if (mptsas_ioc_wait_for_response(mpt)) {
 756  757                          NDBG19(("mptsas_send_handshake failed posting "
 757  758                              "message\n"));
 758  759                          return (-1);
 759  760                  }
 760  761          }
 761  762  
 762  763          if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
 763  764                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
 764  765                  ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
 765  766                  return (-1);
 766  767          }
 767  768  
 768  769          return (0);
 769  770  }
 770  771  
 771  772  int
 772  773  mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
 773  774      ddi_acc_handle_t accessp)
 774  775  {
 775  776          int             i, totalbytes, bytesleft;
 776  777          uint16_t        val;
 777  778  
 778  779          /*
 779  780           * wait for doorbell
 780  781           */
 781  782          if (mptsas_ioc_wait_for_doorbell(mpt)) {
 782  783                  NDBG19(("mptsas_get_handshake failed.  Doorbell not ready\n"));
 783  784                  return (-1);
 784  785          }
 785  786  
 786  787          /*
 787  788           * get first 2 bytes of handshake message to determine how much
 788  789           * data we will be getting
 789  790           */
 790  791          for (i = 0; i < 2; i++, memp += 2) {
 791  792                  val = (ddi_get32(mpt->m_datap,
 792  793                      &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
 793  794                  ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
 794  795                  if (mptsas_ioc_wait_for_doorbell(mpt)) {
 795  796                          NDBG19(("mptsas_get_handshake failure getting initial"
 796  797                              " data\n"));
 797  798                          return (-1);
 798  799                  }
 799  800                  ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
 800  801                  if (i == 1) {
 801  802                          totalbytes = (val & 0xFF) * 2;
 802  803                  }
 803  804          }
 804  805  
 805  806          /*
 806  807           * If we are expecting less bytes than the message wants to send
 807  808           * we simply save as much as we expected and then throw out the rest
 808  809           * later
 809  810           */
 810  811          if (totalbytes > (numbytes / 2)) {
 811  812                  bytesleft = ((numbytes / 2) - 2);
 812  813          } else {
 813  814                  bytesleft = (totalbytes - 2);
 814  815          }
 815  816  
 816  817          /*
 817  818           * Get the rest of the data
 818  819           */
 819  820          for (i = 0; i < bytesleft; i++, memp += 2) {
 820  821                  val = (ddi_get32(mpt->m_datap,
 821  822                      &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
 822  823                  ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
 823  824                  if (mptsas_ioc_wait_for_doorbell(mpt)) {
 824  825                          NDBG19(("mptsas_get_handshake failure getting"
 825  826                              " main data\n"));
 826  827                          return (-1);
 827  828                  }
 828  829                  ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
 829  830          }
 830  831  
 831  832          /*
 832  833           * Sometimes the device will send more data than is expected
 833  834           * This data is not used by us but needs to be cleared from
 834  835           * ioc doorbell.  So we just read the values and throw
 835  836           * them out.
 836  837           */
 837  838          if (totalbytes > (numbytes / 2)) {
 838  839                  for (i = (numbytes / 2); i < totalbytes; i++) {
 839  840                          val = (ddi_get32(mpt->m_datap,
 840  841                              &mpt->m_reg->Doorbell) &
 841  842                              MPI2_DOORBELL_DATA_MASK);
 842  843                          ddi_put32(mpt->m_datap,
 843  844                              &mpt->m_reg->HostInterruptStatus, 0);
 844  845                          if (mptsas_ioc_wait_for_doorbell(mpt)) {
 845  846                                  NDBG19(("mptsas_get_handshake failure getting "
 846  847                                      "extra garbage data\n"));
 847  848                                  return (-1);
 848  849                          }
 849  850                  }
 850  851          }
 851  852  
 852  853          ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
 853  854  
 854  855          if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
 855  856                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
 856  857                  ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
 857  858                  return (-1);
 858  859          }
 859  860  
 860  861          return (0);
 861  862  }
 862  863  
 863  864  int
 864  865  mptsas_kick_start(mptsas_t *mpt)
 865  866  {
 866  867          int             polls = 0;
 867  868          uint32_t        diag_reg, ioc_state, saved_HCB_size;
 868  869  
 869  870          /*
 870  871           * Start a hard reset.  Write magic number and wait 500 mSeconds.
 871  872           */
 872  873          MPTSAS_ENABLE_DRWE(mpt);
 873  874          drv_usecwait(500000);
 874  875  
 875  876          /*
 876  877           * Read the current Diag Reg and save the Host Controlled Boot size.
 877  878           */
 878  879          diag_reg = ddi_get32(mpt->m_datap, &mpt->m_reg->HostDiagnostic);
 879  880          saved_HCB_size = ddi_get32(mpt->m_datap, &mpt->m_reg->HCBSize);
 880  881  
 881  882          /*
 882  883           * Set Reset Adapter bit and wait 50 mSeconds.
 883  884           */
 884  885          diag_reg |= MPI2_DIAG_RESET_ADAPTER;
 885  886          ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
 886  887          drv_usecwait(50000);
 887  888  
 888  889          /*
 889  890           * Poll, waiting for Reset Adapter bit to clear.  300 Seconds max
 890  891           * (600000 * 500 = 300,000,000 uSeconds, 300 seconds).
 891  892           * If no more adapter (all FF's), just return failure.
 892  893           */
 893  894          for (polls = 0; polls < 600000; polls++) {
 894  895                  diag_reg = ddi_get32(mpt->m_datap,
 895  896                      &mpt->m_reg->HostDiagnostic);
 896  897                  if (diag_reg == 0xFFFFFFFF) {
 897  898                          mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
 898  899                          ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
 899  900                          return (DDI_FAILURE);
 900  901                  }
 901  902                  if (!(diag_reg & MPI2_DIAG_RESET_ADAPTER)) {
 902  903                          break;
 903  904                  }
 904  905                  drv_usecwait(500);
 905  906          }
 906  907          if (polls == 600000) {
 907  908                  mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
 908  909                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
 909  910                  return (DDI_FAILURE);
 910  911          }
 911  912  
 912  913          /*
 913  914           * Check if adapter is in Host Boot Mode.  If so, restart adapter
 914  915           * assuming the HCB points to good FW.
 915  916           * Set BootDeviceSel to HCDW (Host Code and Data Window).
 916  917           */
 917  918          if (diag_reg & MPI2_DIAG_HCB_MODE) {
 918  919                  diag_reg &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
 919  920                  diag_reg |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
 920  921                  ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
 921  922  
 922  923                  /*
 923  924                   * Re-enable the HCDW.
 924  925                   */
 925  926                  ddi_put32(mpt->m_datap, &mpt->m_reg->HCBSize,
 926  927                      (saved_HCB_size | MPI2_HCB_SIZE_HCB_ENABLE));
 927  928          }
 928  929  
 929  930          /*
 930  931           * Restart the adapter.
 931  932           */
 932  933          diag_reg &= ~MPI2_DIAG_HOLD_IOC_RESET;
 933  934          ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
 934  935  
 935  936          /*
 936  937           * Disable writes to the Host Diag register.
 937  938           */
 938  939          ddi_put32(mpt->m_datap, &mpt->m_reg->WriteSequence,
 939  940              MPI2_WRSEQ_FLUSH_KEY_VALUE);
 940  941  
 941  942          /*
 942  943           * Wait 60 seconds max for FW to come to ready state.
 943  944           */
 944  945          for (polls = 0; polls < 60000; polls++) {
 945  946                  ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
 946  947                  if (ioc_state == 0xFFFFFFFF) {
 947  948                          mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
 948  949                          ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
 949  950                          return (DDI_FAILURE);
 950  951                  }
 951  952                  if ((ioc_state & MPI2_IOC_STATE_MASK) ==
 952  953                      MPI2_IOC_STATE_READY) {
 953  954                          break;
 954  955                  }
 955  956                  drv_usecwait(1000);
 956  957          }
 957  958          if (polls == 60000) {
 958  959                  mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
 959  960                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
 960  961                  return (DDI_FAILURE);
 961  962          }
 962  963  
 963  964          /*
 964  965           * Clear the ioc ack events queue.
 965  966           */
 966  967          mptsas_destroy_ioc_event_cmd(mpt);
 967  968  
 968  969          return (DDI_SUCCESS);
 969  970  }
 970  971  
 971  972  int
 972  973  mptsas_ioc_reset(mptsas_t *mpt, int first_time)
 973  974  {
 974  975          int             polls = 0;
 975  976          uint32_t        reset_msg;
 976  977          uint32_t        ioc_state;
 977  978  
 978  979          ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
 979  980          /*
 980  981           * If chip is already in ready state then there is nothing to do.
 981  982           */
 982  983          if (ioc_state == MPI2_IOC_STATE_READY) {
 983  984                  return (MPTSAS_NO_RESET);
 984  985          }
 985  986          /*
 986  987           * If the chip is already operational, we just need to send
 987  988           * it a message unit reset to put it back in the ready state
 988  989           */
 989  990          if (ioc_state & MPI2_IOC_STATE_OPERATIONAL) {
 990  991                  /*
 991  992                   * If the first time, try MUR anyway, because we haven't even
 992  993                   * queried the card for m_event_replay and other capabilities.
 993  994                   * Other platforms do it this way, we can still do a hard
 994  995                   * reset if we need to, MUR takes less time than a full
 995  996                   * adapter reset, and there are reports that some HW
 996  997                   * combinations will lock up when receiving a hard reset.
 997  998                   */
 998  999                  if ((first_time || mpt->m_event_replay) &&
 999 1000                      (mpt->m_softstate & MPTSAS_SS_MSG_UNIT_RESET)) {
1000 1001                          mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1001 1002                          reset_msg = MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET;
1002 1003                          ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
1003 1004                              (reset_msg << MPI2_DOORBELL_FUNCTION_SHIFT));
1004 1005                          if (mptsas_ioc_wait_for_response(mpt)) {
1005 1006                                  NDBG19(("mptsas_ioc_reset failure sending "
1006 1007                                      "message_unit_reset\n"));
1007 1008                                  goto hard_reset;
1008 1009                          }
1009 1010  
1010 1011                          /*
1011 1012                           * Wait no more than 60 seconds for chip to become
1012 1013                           * ready.
1013 1014                           */
1014 1015                          while ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell) &
1015 1016                              MPI2_IOC_STATE_READY) == 0x0) {
1016 1017                                  drv_usecwait(1000);
1017 1018                                  if (polls++ > 60000) {
1018 1019                                          goto hard_reset;
1019 1020                                  }
1020 1021                          }
1021 1022  
1022 1023                          /*
1023 1024                           * Save the last reset mode done on IOC which will be
1024 1025                           * helpful while resuming from suspension.
1025 1026                           */
1026 1027                          mpt->m_softstate |= MPTSAS_DID_MSG_UNIT_RESET;
1027 1028  
1028 1029                          /*
1029 1030                           * the message unit reset would do reset operations
1030 1031                           * clear reply and request queue, so we should clear
1031 1032                           * ACK event cmd.
1032 1033                           */
1033 1034                          mptsas_destroy_ioc_event_cmd(mpt);
1034 1035                          return (MPTSAS_SUCCESS_MUR);
1035 1036                  }
1036 1037          }
1037 1038  hard_reset:
1038 1039          mpt->m_softstate &= ~MPTSAS_DID_MSG_UNIT_RESET;
1039 1040          if (mptsas_kick_start(mpt) == DDI_FAILURE) {
1040 1041                  mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
1041 1042                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
1042 1043                  return (MPTSAS_RESET_FAIL);
1043 1044          }
1044 1045          return (MPTSAS_SUCCESS_HARDRESET);
1045 1046  }
1046 1047  
1047 1048  
1048 1049  int
1049 1050  mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
1050 1051      struct scsi_pkt **pkt)
1051 1052  {
1052 1053          m_event_struct_t        *ioc_cmd = NULL;
1053 1054  
1054 1055          ioc_cmd = kmem_zalloc(M_EVENT_STRUCT_SIZE, KM_SLEEP);
1055 1056          if (ioc_cmd == NULL) {
1056 1057                  return (DDI_FAILURE);
1057 1058          }
1058 1059          ioc_cmd->m_event_linkp = NULL;
1059 1060          mptsas_ioc_event_cmdq_add(mpt, ioc_cmd);
1060 1061          *cmd = &(ioc_cmd->m_event_cmd);
1061 1062          *pkt = &(ioc_cmd->m_event_pkt);
1062 1063  
1063 1064          return (DDI_SUCCESS);
1064 1065  }
1065 1066  
1066 1067  void
1067 1068  mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd)
1068 1069  {
1069 1070          m_event_struct_t        *ioc_cmd = NULL;
1070 1071  
1071 1072          ioc_cmd = mptsas_ioc_event_find_by_cmd(mpt, cmd);
1072 1073          if (ioc_cmd == NULL) {
1073 1074                  return;
1074 1075          }
1075 1076  
1076 1077          mptsas_ioc_event_cmdq_delete(mpt, ioc_cmd);
1077 1078          kmem_free(ioc_cmd, M_EVENT_STRUCT_SIZE);
1078 1079          ioc_cmd = NULL;
1079 1080  }
1080 1081  
1081 1082  /*
1082 1083   * NOTE: We should be able to queue TM requests in the controller to make this
1083 1084   * a lot faster.  If resetting all targets, for example, we can load the hi
1084 1085   * priority queue with its limit and the controller will reply as they are
1085 1086   * completed.  This way, we don't have to poll for one reply at a time.
1086 1087   * Think about enhancing this later.
1087 1088   */
1088 1089  int
1089 1090  mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
1090 1091      int lun, uint8_t *reply, uint32_t reply_size, int mode)
1091 1092  {
1092 1093          /*
1093 1094           * In order to avoid allocating variables on the stack,
1094 1095           * we make use of the pre-existing mptsas_cmd_t and
1095 1096           * scsi_pkt which are included in the mptsas_t which
1096 1097           * is passed to this routine.
1097 1098           */
1098 1099  
1099 1100          pMpi2SCSITaskManagementRequest_t        task;
1100 1101          int                                     rval = FALSE;
1101 1102          mptsas_cmd_t                            *cmd;
  
    | 
      ↓ open down ↓ | 
    543 lines elided | 
    
      ↑ open up ↑ | 
  
1102 1103          struct scsi_pkt                         *pkt;
1103 1104          mptsas_slots_t                          *slots = mpt->m_active;
1104 1105          uint64_t                                request_desc, i;
1105 1106          pMPI2DefaultReply_t                     reply_msg;
1106 1107  
1107 1108          /*
1108 1109           * Can't start another task management routine.
1109 1110           */
1110 1111          if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1111 1112                  mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1112      -                    " command at a time\n");
     1113 +                    " command at a time");
1113 1114                  return (FALSE);
1114 1115          }
1115 1116  
1116 1117          cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1117 1118          pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1118 1119  
1119 1120          bzero((caddr_t)cmd, sizeof (*cmd));
1120 1121          bzero((caddr_t)pkt, scsi_pkt_size());
1121 1122  
1122 1123          pkt->pkt_cdbp           = (opaque_t)&cmd->cmd_cdb[0];
1123 1124          pkt->pkt_scbp           = (opaque_t)&cmd->cmd_scb;
1124 1125          pkt->pkt_ha_private     = (opaque_t)cmd;
1125 1126          pkt->pkt_flags          = (FLAG_NOINTR | FLAG_HEAD);
1126 1127          pkt->pkt_time           = 60;
1127 1128          pkt->pkt_address.a_target = dev_handle;
1128 1129          pkt->pkt_address.a_lun = (uchar_t)lun;
1129 1130          cmd->cmd_pkt            = pkt;
1130 1131          cmd->cmd_scblen         = 1;
1131 1132          cmd->cmd_flags          = CFLAG_TM_CMD;
1132 1133          cmd->cmd_slot           = MPTSAS_TM_SLOT(mpt);
1133 1134  
1134 1135          slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
1135 1136  
1136 1137          /*
1137 1138           * Store the TM message in memory location corresponding to the TM slot
1138 1139           * number.
1139 1140           */
1140 1141          task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
1141 1142              (mpt->m_req_frame_size * cmd->cmd_slot));
1142 1143          bzero(task, mpt->m_req_frame_size);
1143 1144  
1144 1145          /*
1145 1146           * form message for requested task
1146 1147           */
1147 1148          mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
1148 1149              MPI2_FUNCTION_SCSI_TASK_MGMT);
1149 1150  
1150 1151          /*
1151 1152           * Set the task type
1152 1153           */
1153 1154          ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
1154 1155  
1155 1156          /*
1156 1157           * Send TM request using High Priority Queue.
1157 1158           */
1158 1159          (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1159 1160              DDI_DMA_SYNC_FORDEV);
1160 1161          request_desc = (cmd->cmd_slot << 16) +
1161 1162              MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1162 1163          MPTSAS_START_CMD(mpt, request_desc);
1163 1164          rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
1164 1165  
1165 1166          if (pkt->pkt_reason == CMD_INCOMPLETE)
1166 1167                  rval = FALSE;
1167 1168  
1168 1169          /*
1169 1170           * If a reply frame was used and there is a reply buffer to copy the
1170 1171           * reply data into, copy it.  If this fails, log a message, but don't
1171 1172           * fail the TM request.
1172 1173           */
1173 1174          if (cmd->cmd_rfm && reply) {
1174 1175                  (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
1175 1176                      DDI_DMA_SYNC_FORCPU);
1176 1177                  reply_msg = (pMPI2DefaultReply_t)
1177 1178                      (mpt->m_reply_frame + (cmd->cmd_rfm -
1178 1179                      (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
1179 1180                  if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
1180 1181                          reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
1181 1182                  }
1182 1183                  mutex_exit(&mpt->m_mutex);
1183 1184                  for (i = 0; i < reply_size; i++) {
1184 1185                          if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
1185 1186                              mode)) {
1186 1187                                  mptsas_log(mpt, CE_WARN, "failed to copy out "
1187 1188                                      "reply data for TM request");
1188 1189                                  break;
1189 1190                          }
1190 1191                  }
1191 1192                  mutex_enter(&mpt->m_mutex);
1192 1193          }
1193 1194  
1194 1195          /*
1195 1196           * clear the TM slot before returning
1196 1197           */
1197 1198          slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
1198 1199  
1199 1200          /*
1200 1201           * If we lost our task management command
1201 1202           * we need to reset the ioc
1202 1203           */
1203 1204          if (rval == FALSE) {
1204 1205                  mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1205 1206                      "try to reset ioc to recovery!");
1206 1207                  mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1207 1208                  if (mptsas_restart_ioc(mpt)) {
1208 1209                          mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1209 1210                          rval = FAILED;
1210 1211                  }
1211 1212          }
1212 1213  
1213 1214          return (rval);
1214 1215  }
1215 1216  
1216 1217  /*
1217 1218   * Complete firmware download frame for v2.0 cards.
1218 1219   */
1219 1220  static void
1220 1221  mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,
1221 1222      ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1222 1223      ddi_dma_cookie_t flsh_cookie)
1223 1224  {
1224 1225          pMpi2FWDownloadTCSGE_t  tcsge;
1225 1226          pMpi2SGESimple64_t      sge;
1226 1227          uint32_t                flagslength;
1227 1228  
1228 1229          ddi_put8(acc_hdl, &fwdownload->Function,
1229 1230              MPI2_FUNCTION_FW_DOWNLOAD);
1230 1231          ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1231 1232          ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1232 1233              MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1233 1234          ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1234 1235  
1235 1236          tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1236 1237          ddi_put8(acc_hdl, &tcsge->ContextSize, 0);
1237 1238          ddi_put8(acc_hdl, &tcsge->DetailsLength, 12);
1238 1239          ddi_put8(acc_hdl, &tcsge->Flags, 0);
1239 1240          ddi_put32(acc_hdl, &tcsge->ImageOffset, 0);
1240 1241          ddi_put32(acc_hdl, &tcsge->ImageSize, size);
1241 1242  
1242 1243          sge = (pMpi2SGESimple64_t)(tcsge + 1);
1243 1244          flagslength = size;
1244 1245          flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1245 1246              MPI2_SGE_FLAGS_END_OF_BUFFER |
1246 1247              MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1247 1248              MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1248 1249              MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1249 1250              MPI2_SGE_FLAGS_HOST_TO_IOC |
1250 1251              MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1251 1252          ddi_put32(acc_hdl, &sge->FlagsLength, flagslength);
1252 1253          ddi_put32(acc_hdl, &sge->Address.Low,
1253 1254              flsh_cookie.dmac_address);
1254 1255          ddi_put32(acc_hdl, &sge->Address.High,
1255 1256              (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1256 1257  }
1257 1258  
1258 1259  /*
1259 1260   * Complete firmware download frame for v2.5 cards.
1260 1261   */
1261 1262  static void
1262 1263  mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,
1263 1264      ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1264 1265      ddi_dma_cookie_t flsh_cookie)
1265 1266  {
1266 1267          pMpi2IeeeSgeSimple64_t  sge;
1267 1268          uint8_t                 flags;
1268 1269  
1269 1270          ddi_put8(acc_hdl, &fwdownload->Function,
1270 1271              MPI2_FUNCTION_FW_DOWNLOAD);
1271 1272          ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1272 1273          ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1273 1274              MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1274 1275          ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1275 1276  
1276 1277          ddi_put32(acc_hdl, &fwdownload->ImageOffset, 0);
1277 1278          ddi_put32(acc_hdl, &fwdownload->ImageSize, size);
1278 1279  
1279 1280          sge = (pMpi2IeeeSgeSimple64_t)&fwdownload->SGL;
1280 1281          flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
1281 1282              MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
1282 1283              MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
1283 1284          ddi_put8(acc_hdl, &sge->Flags, flags);
1284 1285          ddi_put32(acc_hdl, &sge->Length, size);
1285 1286          ddi_put32(acc_hdl, &sge->Address.Low,
1286 1287              flsh_cookie.dmac_address);
1287 1288          ddi_put32(acc_hdl, &sge->Address.High,
1288 1289              (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1289 1290  }
1290 1291  
1291 1292  static int mptsas_enable_mpi25_flashupdate = 0;
1292 1293  
1293 1294  int
1294 1295  mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1295 1296      uint8_t type, int mode)
1296 1297  {
1297 1298  
1298 1299          /*
1299 1300           * In order to avoid allocating variables on the stack,
1300 1301           * we make use of the pre-existing mptsas_cmd_t and
1301 1302           * scsi_pkt which are included in the mptsas_t which
1302 1303           * is passed to this routine.
1303 1304           */
1304 1305  
1305 1306          ddi_dma_attr_t          flsh_dma_attrs;
1306 1307          ddi_dma_cookie_t        flsh_cookie;
1307 1308          ddi_dma_handle_t        flsh_dma_handle;
1308 1309          ddi_acc_handle_t        flsh_accessp;
1309 1310          caddr_t                 memp, flsh_memp;
1310 1311          mptsas_cmd_t            *cmd;
1311 1312          struct scsi_pkt         *pkt;
1312 1313          int                     i;
  
    | 
      ↓ open down ↓ | 
    190 lines elided | 
    
      ↑ open up ↑ | 
  
1313 1314          int                     rvalue = 0;
1314 1315          uint64_t                request_desc;
1315 1316  
1316 1317          if (mpt->m_MPI25 && !mptsas_enable_mpi25_flashupdate) {
1317 1318                  /*
1318 1319                   * The code is there but not tested yet.
1319 1320                   * User has to know there are risks here.
1320 1321                   */
1321 1322                  mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1322 1323                      "Updating firmware through MPI 2.5 has not been "
1323      -                    "tested yet!\n"
1324      -                    "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
     1324 +                    "tested yet!  "
     1325 +                    "To enable set mptsas_enable_mpi25_flashupdate to 1.");
1325 1326                  return (-1);
1326 1327          } /* Otherwise, you pay your money and you take your chances. */
1327 1328  
1328 1329          if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1329 1330                  mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1330      -                    "failed. event ack command pool is full\n");
     1331 +                    "failed. event ack command pool is full");
1331 1332                  return (rvalue);
1332 1333          }
1333 1334  
1334 1335          bzero((caddr_t)cmd, sizeof (*cmd));
1335 1336          bzero((caddr_t)pkt, scsi_pkt_size());
1336 1337          cmd->ioc_cmd_slot = (uint32_t)rvalue;
1337 1338  
1338 1339          /*
1339 1340           * dynamically create a customized dma attribute structure
1340 1341           * that describes the flash file.
1341 1342           */
1342 1343          flsh_dma_attrs = mpt->m_msg_dma_attr;
1343 1344          flsh_dma_attrs.dma_attr_sgllen = 1;
1344 1345  
1345 1346          if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1346 1347              &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1347 1348                  mptsas_log(mpt, CE_WARN,
1348 1349                      "(unable to allocate dma resource.");
1349 1350                  mptsas_return_to_pool(mpt, cmd);
1350 1351                  return (-1);
1351 1352          }
1352 1353  
1353 1354          bzero(flsh_memp, size);
1354 1355  
1355 1356          for (i = 0; i < size; i++) {
1356 1357                  (void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
1357 1358          }
1358 1359          (void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
1359 1360  
1360 1361          /*
1361 1362           * form a cmd/pkt to store the fw download message
1362 1363           */
1363 1364          pkt->pkt_cdbp           = (opaque_t)&cmd->cmd_cdb[0];
1364 1365          pkt->pkt_scbp           = (opaque_t)&cmd->cmd_scb;
1365 1366          pkt->pkt_ha_private     = (opaque_t)cmd;
1366 1367          pkt->pkt_flags          = FLAG_HEAD;
1367 1368          pkt->pkt_time           = 60;
1368 1369          cmd->cmd_pkt            = pkt;
1369 1370          cmd->cmd_scblen         = 1;
1370 1371          cmd->cmd_flags          = CFLAG_CMDIOC | CFLAG_FW_CMD;
1371 1372  
1372 1373          /*
1373 1374           * Save the command in a slot
1374 1375           */
1375 1376          if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1376 1377                  mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1377 1378                  mptsas_return_to_pool(mpt, cmd);
1378 1379                  return (-1);
1379 1380          }
1380 1381  
1381 1382          /*
1382 1383           * Fill in fw download message
1383 1384           */
1384 1385          ASSERT(cmd->cmd_slot != 0);
1385 1386          memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1386 1387          bzero(memp, mpt->m_req_frame_size);
1387 1388  
1388 1389          if (mpt->m_MPI25)
1389 1390                  mptsas_uflash25((pMpi25FWDownloadRequest)memp,
1390 1391                      mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1391 1392          else
1392 1393                  mptsas_uflash2((pMpi2FWDownloadRequest)memp,
1393 1394                      mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1394 1395  
1395 1396          /*
1396 1397           * Start command
1397 1398           */
1398 1399          (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1399 1400              DDI_DMA_SYNC_FORDEV);
1400 1401          request_desc = (cmd->cmd_slot << 16) +
1401 1402              MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1402 1403          cmd->cmd_rfm = NULL;
1403 1404          MPTSAS_START_CMD(mpt, request_desc);
1404 1405  
1405 1406          rvalue = 0;
1406 1407          (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1407 1408              drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1408 1409          if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1409 1410                  mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1410 1411                  if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1411 1412                          mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1412 1413                  }
1413 1414                  rvalue = -1;
1414 1415          }
1415 1416          mptsas_remove_cmd(mpt, cmd);
1416 1417          mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1417 1418  
1418 1419          return (rvalue);
1419 1420  }
1420 1421  
1421 1422  static int
1422 1423  mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1423 1424      ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1424 1425      va_list ap)
1425 1426  {
1426 1427  #ifndef __lock_lint
1427 1428          _NOTE(ARGUNUSED(ap))
1428 1429  #endif
1429 1430          pMpi2SasDevicePage0_t   sasdevpage;
1430 1431          int                     rval = DDI_SUCCESS, i;
1431 1432          uint8_t                 *sas_addr = NULL;
1432 1433          uint8_t                 tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1433 1434          uint16_t                *devhdl, *bay_num, *enclosure;
1434 1435          uint64_t                *sas_wwn;
1435 1436          uint32_t                *dev_info;
1436 1437          uint8_t                 *physport, *phynum;
1437 1438          uint16_t                *pdevhdl, *io_flags;
1438 1439          uint32_t                page_address;
1439 1440  
1440 1441          if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1441 1442              (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1442 1443                  mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1443 1444                      "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1444 1445                      iocstatus, iocloginfo);
1445 1446                  rval = DDI_FAILURE;
1446 1447                  return (rval);
1447 1448          }
1448 1449          page_address = va_arg(ap, uint32_t);
1449 1450          /*
1450 1451           * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1451 1452           * are no more pages.  If everything is OK up to this point but the
1452 1453           * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
1453 1454           * signal that device traversal is complete.
1454 1455           */
1455 1456          if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1456 1457                  if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1457 1458                      MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1458 1459                          mpt->m_done_traverse_dev = 1;
1459 1460                  }
1460 1461                  rval = DDI_FAILURE;
1461 1462                  return (rval);
1462 1463          }
1463 1464          devhdl = va_arg(ap, uint16_t *);
1464 1465          sas_wwn = va_arg(ap, uint64_t *);
1465 1466          dev_info = va_arg(ap, uint32_t *);
1466 1467          physport = va_arg(ap, uint8_t *);
1467 1468          phynum = va_arg(ap, uint8_t *);
1468 1469          pdevhdl = va_arg(ap, uint16_t *);
1469 1470          bay_num = va_arg(ap, uint16_t *);
1470 1471          enclosure = va_arg(ap, uint16_t *);
1471 1472          io_flags = va_arg(ap, uint16_t *);
1472 1473  
1473 1474          sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1474 1475  
1475 1476          *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1476 1477          *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1477 1478          sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1478 1479          for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1479 1480                  tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1480 1481          }
1481 1482          bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1482 1483          *sas_wwn = LE_64(*sas_wwn);
1483 1484          *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1484 1485          *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1485 1486          *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1486 1487          *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1487 1488          *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1488 1489          *io_flags = ddi_get16(accessp, &sasdevpage->Flags);
1489 1490  
1490 1491          if (*io_flags & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
1491 1492                  /*
1492 1493                   * Leave a messages about FP cabability in the log.
1493 1494                   */
1494 1495                  mptsas_log(mpt, CE_CONT,
1495 1496                      "!w%016"PRIx64" FastPath Capable%s", *sas_wwn,
1496 1497                      (*io_flags &
1497 1498                      MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)?
1498 1499                      " and Enabled":" but Disabled");
1499 1500          }
1500 1501  
1501 1502          return (rval);
1502 1503  }
1503 1504  
1504 1505  /*
1505 1506   * Request MPI configuration page SAS device page 0 to get DevHandle, device
1506 1507   * info and SAS address.
1507 1508   */
1508 1509  int
1509 1510  mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1510 1511      uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1511 1512      uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1512 1513      uint16_t *bay_num, uint16_t *enclosure, uint16_t *io_flags)
1513 1514  {
1514 1515          int rval = DDI_SUCCESS;
1515 1516  
1516 1517          ASSERT(mutex_owned(&mpt->m_mutex));
1517 1518  
1518 1519          /*
1519 1520           * Get the header and config page.  reply contains the reply frame,
1520 1521           * which holds status info for the request.
1521 1522           */
1522 1523          rval = mptsas_access_config_page(mpt,
1523 1524              MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1524 1525              MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1525 1526              mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1526 1527              dev_info, physport, phynum, pdev_handle,
1527 1528              bay_num, enclosure, io_flags);
1528 1529  
1529 1530          return (rval);
1530 1531  }
1531 1532  
1532 1533  static int
1533 1534  mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1534 1535      ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1535 1536      va_list ap)
1536 1537  {
1537 1538  #ifndef __lock_lint
1538 1539          _NOTE(ARGUNUSED(ap))
1539 1540  #endif
1540 1541          pMpi2ExpanderPage0_t    expddevpage;
1541 1542          int                     rval = DDI_SUCCESS, i;
1542 1543          uint8_t                 *sas_addr = NULL;
1543 1544          uint8_t                 tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1544 1545          uint16_t                *devhdl;
1545 1546          uint64_t                *sas_wwn;
1546 1547          uint8_t                 physport;
1547 1548          mptsas_phymask_t        *phymask;
1548 1549          uint16_t                *pdevhdl;
1549 1550          uint32_t                page_address;
1550 1551  
1551 1552          if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1552 1553              (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1553 1554                  mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
1554 1555                      "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1555 1556                      iocstatus, iocloginfo);
1556 1557                  rval = DDI_FAILURE;
1557 1558                  return (rval);
1558 1559          }
1559 1560          page_address = va_arg(ap, uint32_t);
1560 1561          /*
1561 1562           * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1562 1563           * are no more pages.  If everything is OK up to this point but the
1563 1564           * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
1564 1565           * signal that device traversal is complete.
1565 1566           */
1566 1567          if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1567 1568                  if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
1568 1569                      MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
1569 1570                          mpt->m_done_traverse_smp = 1;
1570 1571                  }
1571 1572                  rval = DDI_FAILURE;
1572 1573                  return (rval);
1573 1574          }
1574 1575          devhdl = va_arg(ap, uint16_t *);
1575 1576          sas_wwn = va_arg(ap, uint64_t *);
1576 1577          phymask = va_arg(ap, mptsas_phymask_t *);
1577 1578          pdevhdl = va_arg(ap, uint16_t *);
1578 1579  
1579 1580          expddevpage = (pMpi2ExpanderPage0_t)page_memp;
1580 1581  
1581 1582          *devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
1582 1583          physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
1583 1584          *phymask = mptsas_physport_to_phymask(mpt, physport);
1584 1585          *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
1585 1586          sas_addr = (uint8_t *)(&expddevpage->SASAddress);
1586 1587          for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1587 1588                  tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1588 1589          }
1589 1590          bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1590 1591          *sas_wwn = LE_64(*sas_wwn);
1591 1592  
1592 1593          return (rval);
1593 1594  }
1594 1595  
1595 1596  /*
1596 1597   * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1597 1598   * and SAS address.
1598 1599   */
1599 1600  int
1600 1601  mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
1601 1602      mptsas_smp_t *info)
1602 1603  {
1603 1604          int                     rval = DDI_SUCCESS;
1604 1605  
1605 1606          ASSERT(mutex_owned(&mpt->m_mutex));
1606 1607  
1607 1608          /*
1608 1609           * Get the header and config page.  reply contains the reply frame,
1609 1610           * which holds status info for the request.
1610 1611           */
1611 1612          rval = mptsas_access_config_page(mpt,
1612 1613              MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1613 1614              MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
1614 1615              mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
1615 1616              &info->m_addr.mta_wwn, &info->m_addr.mta_phymask, &info->m_pdevhdl);
1616 1617  
1617 1618          return (rval);
1618 1619  }
1619 1620  
1620 1621  static int
1621 1622  mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1622 1623      ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1623 1624      va_list ap)
1624 1625  {
1625 1626  #ifndef __lock_lint
1626 1627          _NOTE(ARGUNUSED(ap))
1627 1628  #endif
1628 1629          int     rval = DDI_SUCCESS, i;
1629 1630          uint8_t *sas_addr = NULL;
1630 1631          uint64_t *sas_wwn;
1631 1632          uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1632 1633          uint8_t *portwidth;
1633 1634          pMpi2SasPortPage0_t sasportpage;
1634 1635  
1635 1636          if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1636 1637                  mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
1637 1638                      "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1638 1639                      iocstatus, iocloginfo);
1639 1640                  rval = DDI_FAILURE;
1640 1641                  return (rval);
1641 1642          }
1642 1643          sas_wwn = va_arg(ap, uint64_t *);
1643 1644          portwidth = va_arg(ap, uint8_t *);
1644 1645  
1645 1646          sasportpage = (pMpi2SasPortPage0_t)page_memp;
1646 1647          sas_addr = (uint8_t *)(&sasportpage->SASAddress);
1647 1648          for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1648 1649                  tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1649 1650          }
1650 1651          bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1651 1652          *sas_wwn = LE_64(*sas_wwn);
1652 1653          *portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
1653 1654          return (rval);
1654 1655  }
1655 1656  
1656 1657  /*
1657 1658   * Request MPI configuration page SAS port page 0 to get initiator SAS address
1658 1659   * and port width.
1659 1660   */
1660 1661  int
1661 1662  mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
1662 1663      uint64_t *sas_wwn, uint8_t *portwidth)
1663 1664  {
1664 1665          int rval = DDI_SUCCESS;
1665 1666  
1666 1667          ASSERT(mutex_owned(&mpt->m_mutex));
1667 1668  
1668 1669          /*
1669 1670           * Get the header and config page.  reply contains the reply frame,
1670 1671           * which holds status info for the request.
1671 1672           */
1672 1673          rval = mptsas_access_config_page(mpt,
1673 1674              MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1674 1675              MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
1675 1676              mptsas_sasportpage_0_cb, sas_wwn, portwidth);
1676 1677  
1677 1678          return (rval);
1678 1679  }
1679 1680  
1680 1681  static int
1681 1682  mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
1682 1683      ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1683 1684      va_list ap)
1684 1685  {
1685 1686  #ifndef __lock_lint
1686 1687          _NOTE(ARGUNUSED(ap))
1687 1688  #endif
1688 1689          int rval = DDI_SUCCESS;
1689 1690          pMpi2SasIOUnitPage0_t sasioupage0;
1690 1691          int i, num_phys;
1691 1692          uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1692 1693          uint8_t port_flags;
1693 1694  
1694 1695          if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1695 1696                  mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1696 1697                      "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1697 1698                      iocstatus, iocloginfo);
1698 1699                  rval = DDI_FAILURE;
1699 1700                  return (rval);
  
    | 
      ↓ open down ↓ | 
    359 lines elided | 
    
      ↑ open up ↑ | 
  
1700 1701          }
1701 1702          readpage1 = va_arg(ap, uint32_t *);
1702 1703          retrypage0 = va_arg(ap, uint32_t *);
1703 1704  
1704 1705          sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1705 1706  
1706 1707          num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1707 1708          /*
1708 1709           * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1709 1710           * was initially set.  This should never change throughout the life of
1710      -         * the driver.
     1711 +         * the driver.  Note, due to cases where we've seen page zero have more
     1712 +         * phys than the reported manufacturing information, we limit the number
     1713 +         * of phys here to what we got from the manufacturing information.
1711 1714           */
1712      -        ASSERT(num_phys == mpt->m_num_phys);
     1715 +        ASSERT3U(num_phys, >=, mpt->m_num_phys);
     1716 +        num_phys = mpt->m_num_phys;
1713 1717          for (i = 0; i < num_phys; i++) {
1714 1718                  cpdi[i] = ddi_get32(accessp,
1715 1719                      &sasioupage0->PhyData[i].
1716 1720                      ControllerPhyDeviceInfo);
1717 1721                  port_flags = ddi_get8(accessp,
1718 1722                      &sasioupage0->PhyData[i].PortFlags);
1719 1723                  mpt->m_phy_info[i].port_num =
1720 1724                      ddi_get8(accessp,
1721 1725                      &sasioupage0->PhyData[i].Port);
1722 1726                  mpt->m_phy_info[i].ctrl_devhdl =
1723 1727                      ddi_get16(accessp, &sasioupage0->
1724 1728                      PhyData[i].ControllerDevHandle);
1725 1729                  mpt->m_phy_info[i].attached_devhdl =
1726 1730                      ddi_get16(accessp, &sasioupage0->
1727 1731                      PhyData[i].AttachedDevHandle);
1728 1732                  mpt->m_phy_info[i].phy_device_type = cpdi[i];
1729 1733                  mpt->m_phy_info[i].port_flags = port_flags;
1730 1734  
1731 1735                  if (port_flags & DISCOVERY_IN_PROGRESS) {
1732 1736                          *retrypage0 = *retrypage0 + 1;
1733 1737                          break;
1734 1738                  } else {
1735 1739                          *retrypage0 = 0;
1736 1740                  }
1737 1741                  if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
1738 1742                          /*
1739 1743                           * some PHY configuration described in
1740 1744                           * SAS IO Unit Page1
1741 1745                           */
1742 1746                          *readpage1 = 1;
1743 1747                  }
1744 1748          }
1745 1749  
1746 1750          return (rval);
1747 1751  }
1748 1752  
1749 1753  static int
1750 1754  mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
1751 1755      ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1752 1756      va_list ap)
1753 1757  {
1754 1758  #ifndef __lock_lint
1755 1759          _NOTE(ARGUNUSED(ap))
1756 1760  #endif
1757 1761          int rval = DDI_SUCCESS;
1758 1762          pMpi2SasIOUnitPage1_t sasioupage1;
1759 1763          int i, num_phys;
1760 1764          uint32_t cpdi[MPTSAS_MAX_PHYS];
1761 1765          uint8_t port_flags;
1762 1766  
1763 1767          if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
  
    | 
      ↓ open down ↓ | 
    41 lines elided | 
    
      ↑ open up ↑ | 
  
1764 1768                  mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1765 1769                      "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1766 1770                      iocstatus, iocloginfo);
1767 1771                  rval = DDI_FAILURE;
1768 1772                  return (rval);
1769 1773          }
1770 1774  
1771 1775          sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1772 1776          num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1773 1777          /*
1774      -         * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
     1778 +         * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1775 1779           * was initially set.  This should never change throughout the life of
1776      -         * the driver.
     1780 +         * the driver.  Note, due to cases where we've seen page zero have more
     1781 +         * phys than the reported manufacturing information, we limit the number
     1782 +         * of phys here to what we got from the manufacturing information.
1777 1783           */
1778      -        ASSERT(num_phys == mpt->m_num_phys);
     1784 +        ASSERT3U(num_phys, >=, mpt->m_num_phys);
     1785 +        num_phys = mpt->m_num_phys;
1779 1786          for (i = 0; i < num_phys; i++) {
1780 1787                  cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1781 1788                      ControllerPhyDeviceInfo);
1782 1789                  port_flags = ddi_get8(accessp,
1783 1790                      &sasioupage1->PhyData[i].PortFlags);
1784 1791                  mpt->m_phy_info[i].port_num =
1785 1792                      ddi_get8(accessp,
1786 1793                      &sasioupage1->PhyData[i].Port);
1787 1794                  mpt->m_phy_info[i].port_flags = port_flags;
1788 1795                  mpt->m_phy_info[i].phy_device_type = cpdi[i];
1789 1796          }
1790 1797          return (rval);
1791 1798  }
1792 1799  
1793 1800  /*
1794 1801   * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1795 1802   * page1 to update the PHY information.  This is the message passing method of
1796 1803   * this function which should be called except during initialization.
1797 1804   */
1798 1805  int
1799 1806  mptsas_get_sas_io_unit_page(mptsas_t *mpt)
1800 1807  {
1801 1808          int rval = DDI_SUCCESS, state;
1802 1809          uint32_t readpage1 = 0, retrypage0 = 0;
1803 1810  
1804 1811          ASSERT(mutex_owned(&mpt->m_mutex));
1805 1812  
1806 1813          /*
1807 1814           * Now we cycle through the state machine.  Here's what happens:
1808 1815           * 1. Read IO unit page 0 and set phy information
1809 1816           * 2. See if Read IO unit page1 is needed because of port configuration
1810 1817           * 3. Read IO unit page 1 and update phy information.
1811 1818           */
1812 1819          state = IOUC_READ_PAGE0;
1813 1820          while (state != IOUC_DONE) {
1814 1821                  if (state == IOUC_READ_PAGE0) {
1815 1822                          rval = mptsas_access_config_page(mpt,
1816 1823                              MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1817 1824                              MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
1818 1825                              mptsas_sasiou_page_0_cb, &readpage1,
1819 1826                              &retrypage0);
1820 1827                  } else if (state == IOUC_READ_PAGE1) {
1821 1828                          rval = mptsas_access_config_page(mpt,
1822 1829                              MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1823 1830                              MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
1824 1831                              mptsas_sasiou_page_1_cb);
1825 1832                  }
1826 1833  
1827 1834                  if (rval == DDI_SUCCESS) {
1828 1835                          switch (state) {
1829 1836                          case IOUC_READ_PAGE0:
1830 1837                                  /*
1831 1838                                   * retry 30 times if discovery is in process
1832 1839                                   */
1833 1840                                  if (retrypage0 && (retrypage0 < 30)) {
1834 1841                                          drv_usecwait(1000 * 100);
1835 1842                                          state = IOUC_READ_PAGE0;
1836 1843                                          break;
1837 1844                                  } else if (retrypage0 == 30) {
1838 1845                                          mptsas_log(mpt, CE_WARN,
1839 1846                                              "!Discovery in progress, can't "
1840 1847                                              "verify IO unit config, then "
1841 1848                                              "after 30 times retry, give "
1842 1849                                              "up!");
1843 1850                                          state = IOUC_DONE;
1844 1851                                          rval = DDI_FAILURE;
1845 1852                                          break;
1846 1853                                  }
1847 1854  
1848 1855                                  if (readpage1 == 0) {
1849 1856                                          state = IOUC_DONE;
1850 1857                                          rval = DDI_SUCCESS;
1851 1858                                          break;
1852 1859                                  }
1853 1860  
1854 1861                                  state = IOUC_READ_PAGE1;
1855 1862                                  break;
1856 1863  
1857 1864                          case IOUC_READ_PAGE1:
1858 1865                                  state = IOUC_DONE;
1859 1866                                  rval = DDI_SUCCESS;
1860 1867                                  break;
1861 1868                          }
1862 1869                  } else {
1863 1870                          return (rval);
1864 1871                  }
1865 1872          }
1866 1873  
1867 1874          return (rval);
1868 1875  }
1869 1876  
1870 1877  static int
1871 1878  mptsas_biospage_3_cb(mptsas_t *mpt, caddr_t page_memp,
1872 1879      ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1873 1880      va_list ap)
1874 1881  {
1875 1882  #ifndef __lock_lint
1876 1883          _NOTE(ARGUNUSED(ap))
1877 1884  #endif
1878 1885          pMpi2BiosPage3_t        sasbiospage;
1879 1886          int                     rval = DDI_SUCCESS;
1880 1887          uint32_t                *bios_version;
1881 1888  
1882 1889          if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1883 1890              (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1884 1891                  mptsas_log(mpt, CE_WARN, "mptsas_get_bios_page3 header: "
1885 1892                      "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, iocloginfo);
1886 1893                  rval = DDI_FAILURE;
1887 1894                  return (rval);
1888 1895          }
1889 1896          bios_version = va_arg(ap, uint32_t *);
1890 1897          sasbiospage = (pMpi2BiosPage3_t)page_memp;
1891 1898          *bios_version = ddi_get32(accessp, &sasbiospage->BiosVersion);
1892 1899  
1893 1900          return (rval);
1894 1901  }
1895 1902  
1896 1903  /*
1897 1904   * Request MPI configuration page BIOS page 3 to get BIOS version.  Since all
1898 1905   * other information in this page is not needed, just ignore it.
1899 1906   */
1900 1907  int
1901 1908  mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version)
1902 1909  {
1903 1910          int rval = DDI_SUCCESS;
1904 1911  
1905 1912          ASSERT(mutex_owned(&mpt->m_mutex));
1906 1913  
1907 1914          /*
1908 1915           * Get the header and config page.  reply contains the reply frame,
1909 1916           * which holds status info for the request.
1910 1917           */
1911 1918          rval = mptsas_access_config_page(mpt,
1912 1919              MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, MPI2_CONFIG_PAGETYPE_BIOS, 3,
1913 1920              0, mptsas_biospage_3_cb, bios_version);
1914 1921  
1915 1922          return (rval);
1916 1923  }
1917 1924  
1918 1925  /*
1919 1926   * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1920 1927   * page1 to update the PHY information.  This is the handshaking version of
1921 1928   * this function, which should be called during initialization only.
1922 1929   */
1923 1930  int
1924 1931  mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
  
    | 
      ↓ open down ↓ | 
    136 lines elided | 
    
      ↑ open up ↑ | 
  
1925 1932  {
1926 1933          ddi_dma_attr_t          recv_dma_attrs, page_dma_attrs;
1927 1934          ddi_dma_cookie_t        page_cookie;
1928 1935          ddi_dma_handle_t        recv_dma_handle, page_dma_handle;
1929 1936          ddi_acc_handle_t        recv_accessp, page_accessp;
1930 1937          pMpi2ConfigReply_t      configreply;
1931 1938          pMpi2SasIOUnitPage0_t   sasioupage0;
1932 1939          pMpi2SasIOUnitPage1_t   sasioupage1;
1933 1940          int                     recv_numbytes;
1934 1941          caddr_t                 recv_memp, page_memp;
1935      -        int                     i, num_phys, start_phy = 0;
     1942 +        uint_t                  i, num_phys, start_phy = 0;
1936 1943          int                     page0_size =
1937 1944              sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1938 1945              (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1939 1946          int                     page1_size =
1940 1947              sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1941 1948              (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1942 1949          uint32_t                flags_length;
1943 1950          uint32_t                cpdi[MPTSAS_MAX_PHYS];
1944 1951          uint32_t                readpage1 = 0, retrypage0 = 0;
1945 1952          uint16_t                iocstatus;
1946 1953          uint8_t                 port_flags, page_number, action;
1947 1954          uint32_t                reply_size;
1948 1955          uint_t                  state;
1949 1956          int                     rval = DDI_FAILURE;
1950 1957          boolean_t               free_recv = B_FALSE, free_page = B_FALSE;
1951 1958  
1952 1959          /*
1953 1960           * We want to find a reply_size that's large enough for the page0 and
1954 1961           * page1 sizes and resistant to increase in the number of phys.
1955 1962           */
1956 1963          reply_size = MAX(page0_size, page1_size);
1957 1964          if (P2ROUNDUP(reply_size, 256) <= reply_size) {
1958 1965                  mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page_hndsk: "
1959 1966                      "cannot size reply size");
1960 1967                  goto cleanup;
1961 1968          }
1962 1969  
1963 1970          /*
1964 1971           * Initialize our "state machine".  This is a bit convoluted,
1965 1972           * but it keeps us from having to do the ddi allocations numerous
1966 1973           * times.
1967 1974           */
1968 1975  
1969 1976          NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1970 1977          ASSERT(mutex_owned(&mpt->m_mutex));
1971 1978          state = IOUC_READ_PAGE0;
1972 1979  
1973 1980          /*
1974 1981           * dynamically create a customized dma attribute structure
1975 1982           * that describes mpt's config reply page request structure.
1976 1983           */
1977 1984          recv_dma_attrs = mpt->m_msg_dma_attr;
1978 1985          recv_dma_attrs.dma_attr_sgllen = 1;
1979 1986          recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
1980 1987  
1981 1988          if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
1982 1989              &recv_dma_handle, &recv_accessp, &recv_memp,
1983 1990              (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
1984 1991                  mptsas_log(mpt, CE_WARN,
1985 1992                      "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1986 1993                  goto cleanup;
1987 1994          }
1988 1995          /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
1989 1996          free_recv = B_TRUE;
1990 1997  
1991 1998          page_dma_attrs = mpt->m_msg_dma_attr;
1992 1999          page_dma_attrs.dma_attr_sgllen = 1;
1993 2000          page_dma_attrs.dma_attr_granular = reply_size;
1994 2001  
1995 2002          if (mptsas_dma_addr_create(mpt, page_dma_attrs,
1996 2003              &page_dma_handle, &page_accessp, &page_memp,
1997 2004              reply_size, &page_cookie) == FALSE) {
1998 2005                  mptsas_log(mpt, CE_WARN,
1999 2006                      "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
2000 2007                  goto cleanup;
2001 2008          }
2002 2009          /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2003 2010          free_page = B_TRUE;
2004 2011  
2005 2012          /*
2006 2013           * Now we cycle through the state machine.  Here's what happens:
2007 2014           * 1. Read IO unit page 0 and set phy information
2008 2015           * 2. See if Read IO unit page1 is needed because of port configuration
2009 2016           * 3. Read IO unit page 1 and update phy information.
2010 2017           */
2011 2018  
2012 2019          sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
2013 2020          sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
2014 2021  
2015 2022          while (state != IOUC_DONE) {
2016 2023                  switch (state) {
2017 2024                  case IOUC_READ_PAGE0:
2018 2025                          page_number = 0;
2019 2026                          action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2020 2027                          flags_length = (uint32_t)page0_size;
2021 2028                          flags_length |= ((uint32_t)(
2022 2029                              MPI2_SGE_FLAGS_LAST_ELEMENT |
2023 2030                              MPI2_SGE_FLAGS_END_OF_BUFFER |
2024 2031                              MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2025 2032                              MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2026 2033                              MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2027 2034                              MPI2_SGE_FLAGS_IOC_TO_HOST |
2028 2035                              MPI2_SGE_FLAGS_END_OF_LIST) <<
2029 2036                              MPI2_SGE_FLAGS_SHIFT);
2030 2037  
2031 2038                          break;
2032 2039  
2033 2040                  case IOUC_READ_PAGE1:
2034 2041                          page_number = 1;
2035 2042                          action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2036 2043                          flags_length = (uint32_t)page1_size;
2037 2044                          flags_length |= ((uint32_t)(
2038 2045                              MPI2_SGE_FLAGS_LAST_ELEMENT |
2039 2046                              MPI2_SGE_FLAGS_END_OF_BUFFER |
2040 2047                              MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2041 2048                              MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2042 2049                              MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2043 2050                              MPI2_SGE_FLAGS_IOC_TO_HOST |
2044 2051                              MPI2_SGE_FLAGS_END_OF_LIST) <<
2045 2052                              MPI2_SGE_FLAGS_SHIFT);
2046 2053  
2047 2054                          break;
2048 2055                  default:
2049 2056                          break;
2050 2057                  }
2051 2058  
2052 2059                  bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2053 2060                  configreply = (pMpi2ConfigReply_t)recv_memp;
2054 2061                  recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2055 2062  
2056 2063                  if (mptsas_send_extended_config_request_msg(mpt,
2057 2064                      MPI2_CONFIG_ACTION_PAGE_HEADER,
2058 2065                      MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
2059 2066                      0, page_number, 0, 0, 0, 0)) {
2060 2067                          goto cleanup;
2061 2068                  }
2062 2069  
2063 2070                  if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2064 2071                      recv_accessp)) {
2065 2072                          goto cleanup;
2066 2073                  }
2067 2074  
2068 2075                  iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2069 2076                  iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2070 2077  
2071 2078                  if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2072 2079                          mptsas_log(mpt, CE_WARN,
2073 2080                              "mptsas_get_sas_io_unit_page_hndshk: read page "
2074 2081                              "header iocstatus = 0x%x", iocstatus);
2075 2082                          goto cleanup;
2076 2083                  }
2077 2084  
2078 2085                  if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
2079 2086                          bzero(page_memp, reply_size);
2080 2087                  }
2081 2088  
2082 2089                  if (mptsas_send_extended_config_request_msg(mpt, action,
2083 2090                      MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
2084 2091                      ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2085 2092                      ddi_get16(recv_accessp, &configreply->ExtPageLength),
2086 2093                      flags_length, page_cookie.dmac_laddress)) {
2087 2094                          goto cleanup;
2088 2095                  }
2089 2096  
2090 2097                  if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2091 2098                      recv_accessp)) {
2092 2099                          goto cleanup;
2093 2100                  }
2094 2101  
2095 2102                  iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2096 2103                  iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2097 2104  
2098 2105                  if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2099 2106                          mptsas_log(mpt, CE_WARN,
2100 2107                              "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2101 2108                              "config failed for action %d, iocstatus = 0x%x",
2102 2109                              action, iocstatus);
2103 2110                          goto cleanup;
2104 2111                  }
  
    | 
      ↓ open down ↓ | 
    159 lines elided | 
    
      ↑ open up ↑ | 
  
2105 2112  
2106 2113                  switch (state) {
2107 2114                  case IOUC_READ_PAGE0:
2108 2115                          if ((ddi_dma_sync(page_dma_handle, 0, 0,
2109 2116                              DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2110 2117                                  goto cleanup;
2111 2118                          }
2112 2119  
2113 2120                          num_phys = ddi_get8(page_accessp,
2114 2121                              &sasioupage0->NumPhys);
2115      -                        ASSERT(num_phys == mpt->m_num_phys);
2116 2122                          if (num_phys > MPTSAS_MAX_PHYS) {
2117 2123                                  mptsas_log(mpt, CE_WARN, "Number of phys "
2118 2124                                      "supported by HBA (%d) is more than max "
2119 2125                                      "supported by driver (%d).  Driver will "
2120 2126                                      "not attach.", num_phys,
2121 2127                                      MPTSAS_MAX_PHYS);
2122 2128                                  rval = DDI_FAILURE;
2123 2129                                  goto cleanup;
2124 2130                          }
     2131 +                        if (num_phys > mpt->m_num_phys) {
     2132 +                                mptsas_log(mpt, CE_WARN, "Number of phys "
     2133 +                                    "reported by HBA SAS IO Unit Page 0 (%u) "
     2134 +                                    "is greater than that reported by the "
     2135 +                                    "manufacturing information (%u). Driver "
     2136 +                                    "phy count limited to %u. Please contact "
     2137 +                                    "the firmware vendor about this.", num_phys,
     2138 +                                    mpt->m_num_phys, mpt->m_num_phys);
     2139 +                                num_phys = mpt->m_num_phys;
     2140 +                        } else if (num_phys < mpt->m_num_phys) {
     2141 +                                mptsas_log(mpt, CE_WARN, "Number of phys "
     2142 +                                    "reported by HBA SAS IO Unit Page 0 (%u) "
     2143 +                                    "is less than that reported by the "
     2144 +                                    "manufacturing information (%u). Driver "
     2145 +                                    "will not attach. Please contact the "
     2146 +                                    "firmware vendor about this.", num_phys,
     2147 +                                    mpt->m_num_phys);
     2148 +                                rval = DDI_FAILURE;
     2149 +                                goto cleanup;
     2150 +                        }
2125 2151                          for (i = start_phy; i < num_phys; i++, start_phy = i) {
2126 2152                                  cpdi[i] = ddi_get32(page_accessp,
2127 2153                                      &sasioupage0->PhyData[i].
2128 2154                                      ControllerPhyDeviceInfo);
2129 2155                                  port_flags = ddi_get8(page_accessp,
2130 2156                                      &sasioupage0->PhyData[i].PortFlags);
2131 2157  
2132 2158                                  mpt->m_phy_info[i].port_num =
2133 2159                                      ddi_get8(page_accessp,
2134 2160                                      &sasioupage0->PhyData[i].Port);
2135 2161                                  mpt->m_phy_info[i].ctrl_devhdl =
2136 2162                                      ddi_get16(page_accessp, &sasioupage0->
2137 2163                                      PhyData[i].ControllerDevHandle);
2138 2164                                  mpt->m_phy_info[i].attached_devhdl =
2139 2165                                      ddi_get16(page_accessp, &sasioupage0->
2140 2166                                      PhyData[i].AttachedDevHandle);
2141 2167                                  mpt->m_phy_info[i].phy_device_type = cpdi[i];
2142 2168                                  mpt->m_phy_info[i].port_flags = port_flags;
2143 2169  
2144 2170                                  if (port_flags & DISCOVERY_IN_PROGRESS) {
2145 2171                                          retrypage0++;
2146 2172                                          NDBG20(("Discovery in progress, can't "
2147 2173                                              "verify IO unit config, then NO.%d"
2148 2174                                              " times retry", retrypage0));
2149 2175                                          break;
2150 2176                                  } else {
2151 2177                                          retrypage0 = 0;
2152 2178                                  }
2153 2179                                  if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
2154 2180                                          /*
2155 2181                                           * some PHY configuration described in
2156 2182                                           * SAS IO Unit Page1
2157 2183                                           */
2158 2184                                          readpage1 = 1;
2159 2185                                  }
2160 2186                          }
2161 2187  
2162 2188                          /*
2163 2189                           * retry 30 times if discovery is in process
2164 2190                           */
2165 2191                          if (retrypage0 && (retrypage0 < 30)) {
2166 2192                                  drv_usecwait(1000 * 100);
2167 2193                                  state = IOUC_READ_PAGE0;
2168 2194                                  break;
2169 2195                          } else if (retrypage0 == 30) {
2170 2196                                  mptsas_log(mpt, CE_WARN,
2171 2197                                      "!Discovery in progress, can't "
2172 2198                                      "verify IO unit config, then after"
2173 2199                                      " 30 times retry, give up!");
2174 2200                                  state = IOUC_DONE;
2175 2201                                  rval = DDI_FAILURE;
2176 2202                                  break;
2177 2203                          }
2178 2204  
2179 2205                          if (readpage1 == 0) {
2180 2206                                  state = IOUC_DONE;
2181 2207                                  rval = DDI_SUCCESS;
2182 2208                                  break;
2183 2209                          }
2184 2210  
2185 2211                          state = IOUC_READ_PAGE1;
  
    | 
      ↓ open down ↓ | 
    51 lines elided | 
    
      ↑ open up ↑ | 
  
2186 2212                          break;
2187 2213  
2188 2214                  case IOUC_READ_PAGE1:
2189 2215                          if ((ddi_dma_sync(page_dma_handle, 0, 0,
2190 2216                              DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2191 2217                                  goto cleanup;
2192 2218                          }
2193 2219  
2194 2220                          num_phys = ddi_get8(page_accessp,
2195 2221                              &sasioupage1->NumPhys);
2196      -                        ASSERT(num_phys == mpt->m_num_phys);
2197 2222                          if (num_phys > MPTSAS_MAX_PHYS) {
2198 2223                                  mptsas_log(mpt, CE_WARN, "Number of phys "
2199 2224                                      "supported by HBA (%d) is more than max "
2200 2225                                      "supported by driver (%d).  Driver will "
2201 2226                                      "not attach.", num_phys,
2202 2227                                      MPTSAS_MAX_PHYS);
2203 2228                                  rval = DDI_FAILURE;
2204 2229                                  goto cleanup;
2205 2230                          }
     2231 +                        if (num_phys > mpt->m_num_phys) {
     2232 +                                mptsas_log(mpt, CE_WARN, "Number of phys "
     2233 +                                    "reported by HBA SAS IO Unit Page 1 (%u) "
     2234 +                                    "is greater than that reported by the "
     2235 +                                    "manufacturing information (%u). Limiting "
     2236 +                                    "phy count to %u. Please contact the "
     2237 +                                    "firmware vendor about this.", num_phys,
     2238 +                                    mpt->m_num_phys, mpt->m_num_phys);
     2239 +                                num_phys = mpt->m_num_phys;
     2240 +                        } else if (num_phys < mpt->m_num_phys) {
     2241 +                                mptsas_log(mpt, CE_WARN, "Number of phys "
     2242 +                                    "reported by HBA SAS IO Unit Page 1 (%u) "
     2243 +                                    "is less than that reported by the "
     2244 +                                    "manufacturing information (%u). Driver "
     2245 +                                    "will not attach. Please contact the "
     2246 +                                    "firmware vendor about this.", num_phys,
     2247 +                                    mpt->m_num_phys);
     2248 +                                rval = DDI_FAILURE;
     2249 +                                goto cleanup;
     2250 +                        }
2206 2251                          for (i = 0; i < num_phys; i++) {
2207 2252                                  cpdi[i] = ddi_get32(page_accessp,
2208 2253                                      &sasioupage1->PhyData[i].
2209 2254                                      ControllerPhyDeviceInfo);
2210 2255                                  port_flags = ddi_get8(page_accessp,
2211 2256                                      &sasioupage1->PhyData[i].PortFlags);
2212 2257                                  mpt->m_phy_info[i].port_num =
2213 2258                                      ddi_get8(page_accessp,
2214 2259                                      &sasioupage1->PhyData[i].Port);
2215 2260                                  mpt->m_phy_info[i].port_flags = port_flags;
2216 2261                                  mpt->m_phy_info[i].phy_device_type = cpdi[i];
2217 2262  
2218 2263                          }
2219 2264  
2220 2265                          state = IOUC_DONE;
2221 2266                          rval = DDI_SUCCESS;
2222 2267                          break;
2223 2268                  }
2224 2269          }
2225 2270          if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2226 2271              (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2227 2272                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2228 2273                  rval = DDI_FAILURE;
2229 2274                  goto cleanup;
2230 2275          }
2231 2276          if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2232 2277              (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2233 2278                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2234 2279                  rval = DDI_FAILURE;
2235 2280                  goto cleanup;
2236 2281          }
2237 2282  
2238 2283  cleanup:
2239 2284          if (free_recv)
2240 2285                  mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2241 2286          if (free_page)
2242 2287                  mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2243 2288          if (rval != DDI_SUCCESS) {
2244 2289                  mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2245 2290                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2246 2291          }
2247 2292          return (rval);
2248 2293  }
2249 2294  
2250 2295  /*
2251 2296   * mptsas_get_manufacture_page5
2252 2297   *
2253 2298   * This function will retrieve the base WWID from the adapter.  Since this
2254 2299   * function is only called during the initialization process, use handshaking.
2255 2300   */
2256 2301  int
2257 2302  mptsas_get_manufacture_page5(mptsas_t *mpt)
2258 2303  {
2259 2304          ddi_dma_attr_t                  recv_dma_attrs, page_dma_attrs;
2260 2305          ddi_dma_cookie_t                page_cookie;
2261 2306          ddi_dma_handle_t                recv_dma_handle, page_dma_handle;
2262 2307          ddi_acc_handle_t                recv_accessp, page_accessp;
2263 2308          pMpi2ConfigReply_t              configreply;
2264 2309          caddr_t                         recv_memp, page_memp;
2265 2310          int                             recv_numbytes;
2266 2311          pMpi2ManufacturingPage5_t       m5;
2267 2312          uint32_t                        flagslength;
2268 2313          int                             rval = DDI_SUCCESS;
2269 2314          uint_t                          iocstatus;
2270 2315          boolean_t               free_recv = B_FALSE, free_page = B_FALSE;
2271 2316  
2272 2317          MPTSAS_DISABLE_INTR(mpt);
2273 2318  
2274 2319          if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2275 2320              MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2276 2321                  rval = DDI_FAILURE;
2277 2322                  goto done;
2278 2323          }
2279 2324  
2280 2325          /*
2281 2326           * dynamically create a customized dma attribute structure
2282 2327           * that describes the MPT's config reply page request structure.
2283 2328           */
2284 2329          recv_dma_attrs = mpt->m_msg_dma_attr;
2285 2330          recv_dma_attrs.dma_attr_sgllen = 1;
2286 2331          recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2287 2332  
2288 2333          if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2289 2334              &recv_dma_handle, &recv_accessp, &recv_memp,
2290 2335              (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2291 2336                  rval = DDI_FAILURE;
2292 2337                  goto done;
2293 2338          }
2294 2339          /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2295 2340          free_recv = B_TRUE;
2296 2341  
2297 2342          bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2298 2343          configreply = (pMpi2ConfigReply_t)recv_memp;
2299 2344          recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
  
    | 
      ↓ open down ↓ | 
    84 lines elided | 
    
      ↑ open up ↑ | 
  
2300 2345  
2301 2346          /*
2302 2347           * get config reply message
2303 2348           */
2304 2349          if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2305 2350              recv_accessp)) {
2306 2351                  rval = DDI_FAILURE;
2307 2352                  goto done;
2308 2353          }
2309 2354  
2310      -        if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
     2355 +        if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
     2356 +            0) {
2311 2357                  mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2312 2358                      "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2313 2359                      ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2314 2360                  goto done;
2315 2361          }
2316 2362  
2317 2363          /*
2318 2364           * dynamically create a customized dma attribute structure
2319 2365           * that describes the MPT's config page structure.
2320 2366           */
2321 2367          page_dma_attrs = mpt->m_msg_dma_attr;
2322 2368          page_dma_attrs.dma_attr_sgllen = 1;
2323 2369          page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2324 2370  
2325 2371          if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2326 2372              &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2327 2373              &page_cookie) == FALSE) {
2328 2374                  rval = DDI_FAILURE;
2329 2375                  goto done;
2330 2376          }
2331 2377          /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2332 2378          free_page = B_TRUE;
2333 2379  
2334 2380          bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2335 2381          m5 = (pMpi2ManufacturingPage5_t)page_memp;
2336 2382          NDBG20(("mptsas_get_manufacture_page5: paddr 0x%p",
2337 2383              (void *)(uintptr_t)page_cookie.dmac_laddress));
2338 2384  
2339 2385          /*
2340 2386           * Give reply address to IOC to store config page in and send
2341 2387           * config request out.
2342 2388           */
2343 2389  
2344 2390          flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2345 2391          flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2346 2392              MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2347 2393              MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2348 2394              MPI2_SGE_FLAGS_IOC_TO_HOST |
2349 2395              MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2350 2396  
2351 2397          if (mptsas_send_config_request_msg(mpt,
2352 2398              MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2353 2399              MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2354 2400              ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2355 2401              ddi_get8(recv_accessp, &configreply->Header.PageLength),
2356 2402              flagslength, page_cookie.dmac_laddress)) {
2357 2403                  rval = DDI_FAILURE;
2358 2404                  goto done;
2359 2405          }
  
    | 
      ↓ open down ↓ | 
    39 lines elided | 
    
      ↑ open up ↑ | 
  
2360 2406  
2361 2407          /*
2362 2408           * get reply view handshake
2363 2409           */
2364 2410          if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2365 2411              recv_accessp)) {
2366 2412                  rval = DDI_FAILURE;
2367 2413                  goto done;
2368 2414          }
2369 2415  
2370      -        if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
     2416 +        if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
     2417 +            0) {
2371 2418                  mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2372 2419                      "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2373 2420                      ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2374 2421                  goto done;
2375 2422          }
2376 2423  
2377 2424          (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2378 2425  
2379 2426          /*
2380 2427           * Fusion-MPT stores fields in little-endian format.  This is
2381 2428           * why the low-order 32 bits are stored first.
2382 2429           */
2383 2430          mpt->un.sasaddr.m_base_wwid_lo =
2384 2431              ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2385 2432          mpt->un.sasaddr.m_base_wwid_hi =
2386 2433              ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2387 2434  
2388 2435          if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2389 2436              "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2390 2437                  NDBG2(("%s%d: failed to create base-wwid property",
2391 2438                      ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2392 2439          }
2393 2440  
2394 2441          /*
  
    | 
      ↓ open down ↓ | 
    14 lines elided | 
    
      ↑ open up ↑ | 
  
2395 2442           * Set the number of PHYs present.
2396 2443           */
2397 2444          mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2398 2445  
2399 2446          if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2400 2447              "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2401 2448                  NDBG2(("%s%d: failed to create num-phys property",
2402 2449                      ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2403 2450          }
2404 2451  
2405      -        mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2406      -            mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
     2452 +        mptsas_log(mpt, CE_NOTE, "Initiator WWNs: 0x%016llx-0x%016llx",
     2453 +            (unsigned long long)mpt->un.m_base_wwid,
2407 2454              (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2408 2455  
2409 2456          if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2410 2457              (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2411 2458                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2412 2459                  rval = DDI_FAILURE;
2413 2460                  goto done;
2414 2461          }
2415 2462          if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2416 2463              (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2417 2464                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2418 2465                  rval = DDI_FAILURE;
2419 2466          }
2420 2467  done:
2421 2468          /*
2422 2469           * free up memory
2423 2470           */
2424 2471          if (free_recv)
2425 2472                  mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2426 2473          if (free_page)
2427 2474                  mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2428 2475          MPTSAS_ENABLE_INTR(mpt);
2429 2476  
2430 2477          return (rval);
2431 2478  }
2432 2479  
2433 2480  static int
2434 2481  mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2435 2482      ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2436 2483      va_list ap)
2437 2484  {
2438 2485  #ifndef __lock_lint
2439 2486          _NOTE(ARGUNUSED(ap))
2440 2487  #endif
2441 2488          pMpi2SasPhyPage0_t      sasphypage;
2442 2489          int                     rval = DDI_SUCCESS;
2443 2490          uint16_t                *owner_devhdl, *attached_devhdl;
2444 2491          uint8_t                 *attached_phy_identify;
2445 2492          uint32_t                *attached_phy_info;
2446 2493          uint8_t                 *programmed_link_rate;
2447 2494          uint8_t                 *hw_link_rate;
2448 2495          uint8_t                 *change_count;
2449 2496          uint32_t                *phy_info;
2450 2497          uint8_t                 *negotiated_link_rate;
2451 2498          uint32_t                page_address;
2452 2499  
2453 2500          if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2454 2501              (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2455 2502                  mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
2456 2503                      "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2457 2504                      iocstatus, iocloginfo);
2458 2505                  rval = DDI_FAILURE;
2459 2506                  return (rval);
2460 2507          }
2461 2508          page_address = va_arg(ap, uint32_t);
2462 2509          /*
2463 2510           * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2464 2511           * are no more pages.  If everything is OK up to this point but the
2465 2512           * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
2466 2513           * signal that device traversal is complete.
2467 2514           */
2468 2515          if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2469 2516                  if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2470 2517                      MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2471 2518                          mpt->m_done_traverse_smp = 1;
2472 2519                  }
2473 2520                  rval = DDI_FAILURE;
2474 2521                  return (rval);
2475 2522          }
2476 2523          owner_devhdl = va_arg(ap, uint16_t *);
2477 2524          attached_devhdl = va_arg(ap, uint16_t *);
2478 2525          attached_phy_identify = va_arg(ap, uint8_t *);
2479 2526          attached_phy_info = va_arg(ap, uint32_t *);
2480 2527          programmed_link_rate = va_arg(ap, uint8_t *);
2481 2528          hw_link_rate = va_arg(ap, uint8_t *);
2482 2529          change_count = va_arg(ap, uint8_t *);
2483 2530          phy_info = va_arg(ap, uint32_t *);
2484 2531          negotiated_link_rate = va_arg(ap, uint8_t *);
2485 2532  
2486 2533          sasphypage = (pMpi2SasPhyPage0_t)page_memp;
2487 2534  
2488 2535          *owner_devhdl =
2489 2536              ddi_get16(accessp, &sasphypage->OwnerDevHandle);
2490 2537          *attached_devhdl =
2491 2538              ddi_get16(accessp, &sasphypage->AttachedDevHandle);
2492 2539          *attached_phy_identify =
2493 2540              ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
2494 2541          *attached_phy_info =
2495 2542              ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
2496 2543          *programmed_link_rate =
2497 2544              ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
2498 2545          *hw_link_rate =
2499 2546              ddi_get8(accessp, &sasphypage->HwLinkRate);
2500 2547          *change_count =
2501 2548              ddi_get8(accessp, &sasphypage->ChangeCount);
2502 2549          *phy_info =
2503 2550              ddi_get32(accessp, &sasphypage->PhyInfo);
2504 2551          *negotiated_link_rate =
2505 2552              ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
2506 2553  
2507 2554          return (rval);
2508 2555  }
2509 2556  
2510 2557  /*
2511 2558   * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2512 2559   * and SAS address.
2513 2560   */
2514 2561  int
2515 2562  mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
2516 2563      smhba_info_t *info)
2517 2564  {
2518 2565          int                     rval = DDI_SUCCESS;
2519 2566  
2520 2567          ASSERT(mutex_owned(&mpt->m_mutex));
2521 2568  
2522 2569          /*
2523 2570           * Get the header and config page.  reply contains the reply frame,
2524 2571           * which holds status info for the request.
2525 2572           */
2526 2573          rval = mptsas_access_config_page(mpt,
2527 2574              MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2528 2575              MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
2529 2576              mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
2530 2577              &info->attached_devhdl, &info->attached_phy_identify,
2531 2578              &info->attached_phy_info, &info->programmed_link_rate,
2532 2579              &info->hw_link_rate, &info->change_count,
2533 2580              &info->phy_info, &info->negotiated_link_rate);
2534 2581  
2535 2582          return (rval);
2536 2583  }
2537 2584  
2538 2585  static int
2539 2586  mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2540 2587      ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2541 2588      va_list ap)
2542 2589  {
2543 2590  #ifndef __lock_lint
2544 2591          _NOTE(ARGUNUSED(ap))
2545 2592  #endif
2546 2593          pMpi2SasPhyPage1_t      sasphypage;
  
    | 
      ↓ open down ↓ | 
    130 lines elided | 
    
      ↑ open up ↑ | 
  
2547 2594          int                     rval = DDI_SUCCESS;
2548 2595  
2549 2596          uint32_t                *invalid_dword_count;
2550 2597          uint32_t                *running_disparity_error_count;
2551 2598          uint32_t                *loss_of_dword_sync_count;
2552 2599          uint32_t                *phy_reset_problem_count;
2553 2600          uint32_t                page_address;
2554 2601  
2555 2602          if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2556 2603              (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2557      -                mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
     2604 +                mptsas_log(mpt, CE_WARN, "%s "
2558 2605                      "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2559      -                    iocstatus, iocloginfo);
     2606 +                    __func__, iocstatus, iocloginfo);
2560 2607                  rval = DDI_FAILURE;
2561 2608                  return (rval);
2562 2609          }
2563 2610          page_address = va_arg(ap, uint32_t);
2564 2611          /*
2565 2612           * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2566 2613           * are no more pages.  If everything is OK up to this point but the
2567 2614           * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
2568 2615           * signal that device traversal is complete.
2569 2616           */
2570 2617          if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2571 2618                  if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2572 2619                      MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2573 2620                          mpt->m_done_traverse_smp = 1;
2574 2621                  }
2575 2622                  rval = DDI_FAILURE;
2576 2623                  return (rval);
2577 2624          }
2578 2625  
2579 2626          invalid_dword_count = va_arg(ap, uint32_t *);
2580 2627          running_disparity_error_count = va_arg(ap, uint32_t *);
2581 2628          loss_of_dword_sync_count = va_arg(ap, uint32_t *);
2582 2629          phy_reset_problem_count = va_arg(ap, uint32_t *);
2583 2630  
2584 2631          sasphypage = (pMpi2SasPhyPage1_t)page_memp;
2585 2632  
2586 2633          *invalid_dword_count =
2587 2634              ddi_get32(accessp, &sasphypage->InvalidDwordCount);
2588 2635          *running_disparity_error_count =
2589 2636              ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
2590 2637          *loss_of_dword_sync_count =
2591 2638              ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
2592 2639          *phy_reset_problem_count =
2593 2640              ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
2594 2641  
2595 2642          return (rval);
2596 2643  }
2597 2644  
2598 2645  /*
2599 2646   * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2600 2647   * and SAS address.
2601 2648   */
2602 2649  int
2603 2650  mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
2604 2651      smhba_info_t *info)
2605 2652  {
2606 2653          int                     rval = DDI_SUCCESS;
2607 2654  
2608 2655          ASSERT(mutex_owned(&mpt->m_mutex));
2609 2656  
2610 2657          /*
2611 2658           * Get the header and config page.  reply contains the reply frame,
2612 2659           * which holds status info for the request.
2613 2660           */
2614 2661          rval = mptsas_access_config_page(mpt,
2615 2662              MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2616 2663              MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
2617 2664              mptsas_sasphypage_1_cb, page_address,
2618 2665              &info->invalid_dword_count,
2619 2666              &info->running_disparity_error_count,
2620 2667              &info->loss_of_dword_sync_count,
2621 2668              &info->phy_reset_problem_count);
2622 2669  
2623 2670          return (rval);
2624 2671  }
2625 2672  /*
2626 2673   * mptsas_get_manufacture_page0
2627 2674   *
2628 2675   * This function will retrieve the base
2629 2676   * Chip name, Board Name,Board Trace number from the adapter.
2630 2677   * Since this function is only called during the
2631 2678   * initialization process, use handshaking.
2632 2679   */
2633 2680  int
2634 2681  mptsas_get_manufacture_page0(mptsas_t *mpt)
2635 2682  {
2636 2683          ddi_dma_attr_t                  recv_dma_attrs, page_dma_attrs;
2637 2684          ddi_dma_cookie_t                page_cookie;
2638 2685          ddi_dma_handle_t                recv_dma_handle, page_dma_handle;
2639 2686          ddi_acc_handle_t                recv_accessp, page_accessp;
2640 2687          pMpi2ConfigReply_t              configreply;
2641 2688          caddr_t                         recv_memp, page_memp;
2642 2689          int                             recv_numbytes;
2643 2690          pMpi2ManufacturingPage0_t       m0;
2644 2691          uint32_t                        flagslength;
2645 2692          int                             rval = DDI_SUCCESS;
2646 2693          uint_t                          iocstatus;
2647 2694          uint8_t                         i = 0;
2648 2695          boolean_t               free_recv = B_FALSE, free_page = B_FALSE;
2649 2696  
2650 2697          MPTSAS_DISABLE_INTR(mpt);
2651 2698  
2652 2699          if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2653 2700              MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2654 2701                  rval = DDI_FAILURE;
2655 2702                  goto done;
2656 2703          }
2657 2704  
2658 2705          /*
2659 2706           * dynamically create a customized dma attribute structure
2660 2707           * that describes the MPT's config reply page request structure.
2661 2708           */
2662 2709          recv_dma_attrs = mpt->m_msg_dma_attr;
2663 2710          recv_dma_attrs.dma_attr_sgllen = 1;
2664 2711          recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2665 2712  
2666 2713          if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2667 2714              &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2668 2715              NULL) == FALSE) {
2669 2716                  rval = DDI_FAILURE;
2670 2717                  goto done;
2671 2718          }
2672 2719          /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2673 2720          free_recv = B_TRUE;
2674 2721  
2675 2722          bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2676 2723          configreply = (pMpi2ConfigReply_t)recv_memp;
2677 2724          recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
  
    | 
      ↓ open down ↓ | 
    108 lines elided | 
    
      ↑ open up ↑ | 
  
2678 2725  
2679 2726          /*
2680 2727           * get config reply message
2681 2728           */
2682 2729          if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2683 2730              recv_accessp)) {
2684 2731                  rval = DDI_FAILURE;
2685 2732                  goto done;
2686 2733          }
2687 2734  
2688      -        if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
     2735 +        if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
     2736 +            0) {
2689 2737                  mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2690 2738                      "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2691 2739                      ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2692 2740                  goto done;
2693 2741          }
2694 2742  
2695 2743          /*
2696 2744           * dynamically create a customized dma attribute structure
2697 2745           * that describes the MPT's config page structure.
2698 2746           */
2699 2747          page_dma_attrs = mpt->m_msg_dma_attr;
2700 2748          page_dma_attrs.dma_attr_sgllen = 1;
2701 2749          page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2702 2750  
2703 2751          if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2704 2752              &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2705 2753              &page_cookie) == FALSE) {
2706 2754                  rval = DDI_FAILURE;
2707 2755                  goto done;
2708 2756          }
2709 2757          /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2710 2758          free_page = B_TRUE;
2711 2759  
2712 2760          bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2713 2761          m0 = (pMpi2ManufacturingPage0_t)page_memp;
2714 2762  
2715 2763          /*
2716 2764           * Give reply address to IOC to store config page in and send
2717 2765           * config request out.
2718 2766           */
2719 2767  
2720 2768          flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2721 2769          flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2722 2770              MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2723 2771              MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2724 2772              MPI2_SGE_FLAGS_IOC_TO_HOST |
2725 2773              MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2726 2774  
2727 2775          if (mptsas_send_config_request_msg(mpt,
2728 2776              MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2729 2777              MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2730 2778              ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2731 2779              ddi_get8(recv_accessp, &configreply->Header.PageLength),
2732 2780              flagslength, page_cookie.dmac_laddress)) {
2733 2781                  rval = DDI_FAILURE;
2734 2782                  goto done;
2735 2783          }
  
    | 
      ↓ open down ↓ | 
    37 lines elided | 
    
      ↑ open up ↑ | 
  
2736 2784  
2737 2785          /*
2738 2786           * get reply view handshake
2739 2787           */
2740 2788          if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2741 2789              recv_accessp)) {
2742 2790                  rval = DDI_FAILURE;
2743 2791                  goto done;
2744 2792          }
2745 2793  
2746      -        if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
     2794 +        if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
     2795 +            0) {
2747 2796                  mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2748 2797                      "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2749 2798                      ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2750 2799                  goto done;
2751 2800          }
2752 2801  
2753 2802          (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2754 2803  
2755 2804          /*
2756 2805           * Fusion-MPT stores fields in little-endian format.  This is
2757 2806           * why the low-order 32 bits are stored first.
2758 2807           */
2759 2808  
2760 2809          for (i = 0; i < 16; i++) {
2761 2810                  mpt->m_MANU_page0.ChipName[i] =
2762 2811                      ddi_get8(page_accessp,
2763 2812                      (uint8_t *)(void *)&m0->ChipName[i]);
2764 2813          }
2765 2814  
2766 2815          for (i = 0; i < 8; i++) {
2767 2816                  mpt->m_MANU_page0.ChipRevision[i] =
2768 2817                      ddi_get8(page_accessp,
2769 2818                      (uint8_t *)(void *)&m0->ChipRevision[i]);
2770 2819          }
2771 2820  
2772 2821          for (i = 0; i < 16; i++) {
2773 2822                  mpt->m_MANU_page0.BoardName[i] =
2774 2823                      ddi_get8(page_accessp,
2775 2824                      (uint8_t *)(void *)&m0->BoardName[i]);
2776 2825          }
2777 2826  
2778 2827          for (i = 0; i < 16; i++) {
2779 2828                  mpt->m_MANU_page0.BoardAssembly[i] =
2780 2829                      ddi_get8(page_accessp,
2781 2830                      (uint8_t *)(void *)&m0->BoardAssembly[i]);
2782 2831          }
2783 2832  
2784 2833          for (i = 0; i < 16; i++) {
2785 2834                  mpt->m_MANU_page0.BoardTracerNumber[i] =
2786 2835                      ddi_get8(page_accessp,
2787 2836                      (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2788 2837          }
2789 2838  
2790 2839          if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2791 2840              (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2792 2841                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2793 2842                  rval = DDI_FAILURE;
2794 2843                  goto done;
2795 2844          }
2796 2845          if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2797 2846              (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2798 2847                  ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2799 2848                  rval = DDI_FAILURE;
2800 2849          }
2801 2850  done:
2802 2851          /*
2803 2852           * free up memory
2804 2853           */
2805 2854          if (free_recv)
2806 2855                  mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2807 2856          if (free_page)
2808 2857                  mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2809 2858          MPTSAS_ENABLE_INTR(mpt);
2810 2859  
2811 2860          return (rval);
2812 2861  }
2813 2862  
2814 2863  static int
2815 2864  mptsas_enclosurepage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2816 2865      ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2817 2866      va_list ap)
2818 2867  {
2819 2868          uint32_t                        page_address;
2820 2869          pMpi2SasEnclosurePage0_t        encpage, encout;
2821 2870  
2822 2871          if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2823 2872              (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2824 2873                  mptsas_log(mpt, CE_WARN, "mptsas_get_enclsourepage0 "
2825 2874                      "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
2826 2875                      iocstatus, iocloginfo);
2827 2876                  return (DDI_FAILURE);
2828 2877          }
2829 2878  
2830 2879          page_address = va_arg(ap, uint32_t);
2831 2880          encout = va_arg(ap, pMpi2SasEnclosurePage0_t);
2832 2881          encpage = (pMpi2SasEnclosurePage0_t)page_memp;
2833 2882  
2834 2883          /*
2835 2884           * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2836 2885           * are no more pages.  If everything is OK up to this point but the
2837 2886           * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
2838 2887           * signal that enclosure traversal is complete.
2839 2888           */
2840 2889          if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2841 2890                  if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
2842 2891                      MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
2843 2892                          mpt->m_done_traverse_enc = 1;
2844 2893                  }
2845 2894                  return (DDI_FAILURE);
2846 2895          }
2847 2896  
2848 2897          encout->Header.PageVersion = ddi_get8(accessp,
2849 2898              &encpage->Header.PageVersion);
2850 2899          encout->Header.PageNumber = ddi_get8(accessp,
2851 2900              &encpage->Header.PageNumber);
2852 2901          encout->Header.PageType = ddi_get8(accessp, &encpage->Header.PageType);
2853 2902          encout->Header.ExtPageLength = ddi_get16(accessp,
2854 2903              &encpage->Header.ExtPageLength);
2855 2904          encout->Header.ExtPageType = ddi_get8(accessp,
2856 2905              &encpage->Header.ExtPageType);
2857 2906  
2858 2907          encout->EnclosureLogicalID.Low = ddi_get32(accessp,
2859 2908              &encpage->EnclosureLogicalID.Low);
2860 2909          encout->EnclosureLogicalID.High = ddi_get32(accessp,
2861 2910              &encpage->EnclosureLogicalID.High);
2862 2911          encout->Flags = ddi_get16(accessp, &encpage->Flags);
2863 2912          encout->EnclosureHandle = ddi_get16(accessp, &encpage->EnclosureHandle);
2864 2913          encout->NumSlots = ddi_get16(accessp, &encpage->NumSlots);
2865 2914          encout->StartSlot = ddi_get16(accessp, &encpage->StartSlot);
2866 2915          encout->EnclosureLevel = ddi_get8(accessp, &encpage->EnclosureLevel);
2867 2916          encout->SEPDevHandle = ddi_get16(accessp, &encpage->SEPDevHandle);
2868 2917  
2869 2918          return (DDI_SUCCESS);
2870 2919  }
2871 2920  
2872 2921  /*
2873 2922   * Request information about the SES enclosures.
2874 2923   */
2875 2924  int
2876 2925  mptsas_get_enclosure_page0(mptsas_t *mpt, uint32_t page_address,
2877 2926      mptsas_enclosure_t *mep)
2878 2927  {
2879 2928          int rval = DDI_SUCCESS;
2880 2929          Mpi2SasEnclosurePage0_t encpage;
2881 2930  
2882 2931          ASSERT(MUTEX_HELD(&mpt->m_mutex));
  
    | 
      ↓ open down ↓ | 
    126 lines elided | 
    
      ↑ open up ↑ | 
  
2883 2932  
2884 2933          bzero(&encpage, sizeof (encpage));
2885 2934          rval = mptsas_access_config_page(mpt,
2886 2935              MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2887 2936              MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE, 0, page_address,
2888 2937              mptsas_enclosurepage_0_cb, page_address, &encpage);
2889 2938  
2890 2939          if (rval == DDI_SUCCESS) {
2891 2940                  mep->me_enchdl = encpage.EnclosureHandle;
2892 2941                  mep->me_flags = encpage.Flags;
     2942 +                mep->me_nslots = encpage.NumSlots;
     2943 +                mep->me_fslot = encpage.StartSlot;
     2944 +                mep->me_slotleds = NULL;
2893 2945          }
2894 2946  
2895 2947          return (rval);
2896 2948  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX