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