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