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