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