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 we need to reset the ioc
1200          * but we can't do it here as it's most likely we were called from
1201          * the taskq that mptsas_restart_ioc()->mptsas_flush_hba() needs to
1202          * wait for. So set a flag for mptsas_watch().
1203          */
1204         if (rval == FALSE) {
1205                 mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1206                     "schedule reset in watch!");
1207                 mpt->m_softstate |= MPTSAS_SS_RESET_INWATCH;
1208         }
1209         
1210         return (rval);
1211 }
1212 
1213 /*
1214  * Complete firmware download frame for v2.0 cards.
1215  */
1216 static void
1217 mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,
1218     ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1219     ddi_dma_cookie_t flsh_cookie)
1220 {
1221         pMpi2FWDownloadTCSGE_t  tcsge;
1222         pMpi2SGESimple64_t      sge;
1223         uint32_t                flagslength;
1224 
1225         ddi_put8(acc_hdl, &fwdownload->Function,
1226             MPI2_FUNCTION_FW_DOWNLOAD);
1227         ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1228         ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1229             MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1230         ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1231 
1232         tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1233         ddi_put8(acc_hdl, &tcsge->ContextSize, 0);
1234         ddi_put8(acc_hdl, &tcsge->DetailsLength, 12);
1235         ddi_put8(acc_hdl, &tcsge->Flags, 0);
1236         ddi_put32(acc_hdl, &tcsge->ImageOffset, 0);
1237         ddi_put32(acc_hdl, &tcsge->ImageSize, size);
1238 
1239         sge = (pMpi2SGESimple64_t)(tcsge + 1);
1240         flagslength = size;
1241         flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1242             MPI2_SGE_FLAGS_END_OF_BUFFER |
1243             MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1244             MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1245             MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1246             MPI2_SGE_FLAGS_HOST_TO_IOC |
1247             MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1248         ddi_put32(acc_hdl, &sge->FlagsLength, flagslength);
1249         ddi_put32(acc_hdl, &sge->Address.Low,
1250             flsh_cookie.dmac_address);
1251         ddi_put32(acc_hdl, &sge->Address.High,
1252             (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1253 }
1254 
1255 /*
1256  * Complete firmware download frame for v2.5 cards.
1257  */
1258 static void
1259 mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,
1260     ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1261     ddi_dma_cookie_t flsh_cookie)
1262 {
1263         pMpi2IeeeSgeSimple64_t  sge;
1264         uint8_t                 flags;
1265 
1266         ddi_put8(acc_hdl, &fwdownload->Function,
1267             MPI2_FUNCTION_FW_DOWNLOAD);
1268         ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1269         ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1270             MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1271         ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1272 
1273         ddi_put32(acc_hdl, &fwdownload->ImageOffset, 0);
1274         ddi_put32(acc_hdl, &fwdownload->ImageSize, size);
1275 
1276         sge = (pMpi2IeeeSgeSimple64_t)&fwdownload->SGL;
1277         flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
1278             MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
1279             MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
1280         ddi_put8(acc_hdl, &sge->Flags, flags);
1281         ddi_put32(acc_hdl, &sge->Length, size);
1282         ddi_put32(acc_hdl, &sge->Address.Low,
1283             flsh_cookie.dmac_address);
1284         ddi_put32(acc_hdl, &sge->Address.High,
1285             (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1286 }
1287 
1288 static int mptsas_enable_mpi25_flashupdate = 0;
1289 
1290 int
1291 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1292     uint8_t type, int mode)
1293 {
1294 
1295         /*
1296          * In order to avoid allocating variables on the stack,
1297          * we make use of the pre-existing mptsas_cmd_t and
1298          * scsi_pkt which are included in the mptsas_t which
1299          * is passed to this routine.
1300          */
1301 
1302         ddi_dma_attr_t          flsh_dma_attrs;
1303         ddi_dma_cookie_t        flsh_cookie;
1304         ddi_dma_handle_t        flsh_dma_handle;
1305         ddi_acc_handle_t        flsh_accessp;
1306         caddr_t                 memp, flsh_memp;
1307         mptsas_cmd_t            *cmd;
1308         struct scsi_pkt         *pkt;
1309         int                     i;
1310         int                     rvalue = 0;
1311         uint64_t                request_desc;
1312 
1313         if (mpt->m_MPI25 && !mptsas_enable_mpi25_flashupdate) {
1314                 /*
1315                  * The code is there but not tested yet.
1316                  * User has to know there are risks here.
1317                  */
1318                 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1319                     "Updating firmware through MPI 2.5 has not been "
1320                     "tested yet!\n"
1321                     "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
1322                 return (-1);
1323         } /* Otherwise, you pay your money and you take your chances. */
1324 
1325         if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1326                 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1327                     "failed. event ack command pool is full\n");
1328                 return (rvalue);
1329         }
1330 
1331         bzero((caddr_t)cmd, sizeof (*cmd));
1332         bzero((caddr_t)pkt, scsi_pkt_size());
1333         cmd->ioc_cmd_slot = (uint32_t)rvalue;
1334 
1335         /*
1336          * dynamically create a customized dma attribute structure
1337          * that describes the flash file.
1338          */
1339         flsh_dma_attrs = mpt->m_msg_dma_attr;
1340         flsh_dma_attrs.dma_attr_sgllen = 1;
1341 
1342         if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1343             &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1344                 mptsas_log(mpt, CE_WARN,
1345                     "(unable to allocate dma resource.");
1346                 mptsas_return_to_pool(mpt, cmd);
1347                 return (-1);
1348         }
1349 
1350         bzero(flsh_memp, size);
1351 
1352         for (i = 0; i < size; i++) {
1353                 (void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
1354         }
1355         (void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
1356 
1357         /*
1358          * form a cmd/pkt to store the fw download message
1359          */
1360         pkt->pkt_cdbp                = (opaque_t)&cmd->cmd_cdb[0];
1361         pkt->pkt_scbp                = (opaque_t)&cmd->cmd_scb;
1362         pkt->pkt_ha_private  = (opaque_t)cmd;
1363         pkt->pkt_flags               = FLAG_HEAD;
1364         pkt->pkt_time                = 60;
1365         cmd->cmd_pkt         = pkt;
1366         cmd->cmd_scblen              = 1;
1367         cmd->cmd_flags               = CFLAG_CMDIOC | CFLAG_FW_CMD;
1368 
1369         /*
1370          * Save the command in a slot
1371          */
1372         if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1373                 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1374                 mptsas_return_to_pool(mpt, cmd);
1375                 return (-1);
1376         }
1377 
1378         /*
1379          * Fill in fw download message
1380          */
1381         ASSERT(cmd->cmd_slot != 0);
1382         memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1383         bzero(memp, mpt->m_req_frame_size);
1384 
1385         if (mpt->m_MPI25)
1386                 mptsas_uflash25((pMpi25FWDownloadRequest)memp,
1387                     mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1388         else
1389                 mptsas_uflash2((pMpi2FWDownloadRequest)memp,
1390                     mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1391 
1392         /*
1393          * Start command
1394          */
1395         (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1396             DDI_DMA_SYNC_FORDEV);
1397         request_desc = (cmd->cmd_slot << 16) +
1398             MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1399         cmd->cmd_rfm = NULL;
1400         MPTSAS_START_CMD(mpt, request_desc);
1401 
1402         rvalue = 0;
1403         (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1404             drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1405         if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1406                 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1407                 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1408                         mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1409                 }
1410                 rvalue = -1;
1411         }
1412         mptsas_remove_cmd(mpt, cmd);
1413         mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1414 
1415         return (rvalue);
1416 }
1417 
1418 static int
1419 mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1420     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1421     va_list ap)
1422 {
1423 #ifndef __lock_lint
1424         _NOTE(ARGUNUSED(ap))
1425 #endif
1426         pMpi2SasDevicePage0_t   sasdevpage;
1427         int                     rval = DDI_SUCCESS, i;
1428         uint8_t                 *sas_addr = NULL;
1429         uint8_t                 tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1430         uint16_t                *devhdl, *bay_num, *enclosure;
1431         uint64_t                *sas_wwn;
1432         uint32_t                *dev_info;
1433         uint8_t                 *physport, *phynum;
1434         uint16_t                *pdevhdl, *io_flags;
1435         uint32_t                page_address;
1436 
1437         if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1438             (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1439                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1440                     "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1441                     iocstatus, iocloginfo);
1442                 rval = DDI_FAILURE;
1443                 return (rval);
1444         }
1445         page_address = va_arg(ap, uint32_t);
1446         /*
1447          * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1448          * are no more pages.  If everything is OK up to this point but the
1449          * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
1450          * signal that device traversal is complete.
1451          */
1452         if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1453                 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1454                     MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1455                         mpt->m_done_traverse_dev = 1;
1456                 }
1457                 rval = DDI_FAILURE;
1458                 return (rval);
1459         }
1460         devhdl = va_arg(ap, uint16_t *);
1461         sas_wwn = va_arg(ap, uint64_t *);
1462         dev_info = va_arg(ap, uint32_t *);
1463         physport = va_arg(ap, uint8_t *);
1464         phynum = va_arg(ap, uint8_t *);
1465         pdevhdl = va_arg(ap, uint16_t *);
1466         bay_num = va_arg(ap, uint16_t *);
1467         enclosure = va_arg(ap, uint16_t *);
1468         io_flags = va_arg(ap, uint16_t *);
1469 
1470         sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1471 
1472         *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1473         *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1474         sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1475         for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1476                 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1477         }
1478         bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1479         *sas_wwn = LE_64(*sas_wwn);
1480         *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1481         *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1482         *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1483         *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1484         *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1485         *io_flags = ddi_get16(accessp, &sasdevpage->Flags);
1486 
1487         if (*io_flags & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
1488                 /*
1489                  * Leave a messages about FP cabability in the log.
1490                  */
1491                 mptsas_log(mpt, CE_CONT,
1492                     "!w%016"PRIx64" FastPath Capable%s", *sas_wwn,
1493                     (*io_flags &
1494                     MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)?
1495                     " and Enabled":" but Disabled");
1496         }
1497 
1498         return (rval);
1499 }
1500 
1501 /*
1502  * Request MPI configuration page SAS device page 0 to get DevHandle, device
1503  * info and SAS address.
1504  */
1505 int
1506 mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1507     uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1508     uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1509     uint16_t *bay_num, uint16_t *enclosure, uint16_t *io_flags)
1510 {
1511         int rval = DDI_SUCCESS;
1512 
1513         ASSERT(mutex_owned(&mpt->m_mutex));
1514 
1515         /*
1516          * Get the header and config page.  reply contains the reply frame,
1517          * which holds status info for the request.
1518          */
1519         rval = mptsas_access_config_page(mpt,
1520             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1521             MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1522             mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1523             dev_info, physport, phynum, pdev_handle,
1524             bay_num, enclosure, io_flags);
1525 
1526         return (rval);
1527 }
1528 
1529 static int
1530 mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1531     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1532     va_list ap)
1533 {
1534 #ifndef __lock_lint
1535         _NOTE(ARGUNUSED(ap))
1536 #endif
1537         pMpi2ExpanderPage0_t    expddevpage;
1538         int                     rval = DDI_SUCCESS, i;
1539         uint8_t                 *sas_addr = NULL;
1540         uint8_t                 tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1541         uint16_t                *devhdl;
1542         uint64_t                *sas_wwn;
1543         uint8_t                 physport;
1544         mptsas_phymask_t        *phymask;
1545         uint16_t                *pdevhdl;
1546         uint32_t                page_address;
1547 
1548         if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1549             (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1550                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
1551                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1552                     iocstatus, iocloginfo);
1553                 rval = DDI_FAILURE;
1554                 return (rval);
1555         }
1556         page_address = va_arg(ap, uint32_t);
1557         /*
1558          * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1559          * are no more pages.  If everything is OK up to this point but the
1560          * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
1561          * signal that device traversal is complete.
1562          */
1563         if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1564                 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
1565                     MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
1566                         mpt->m_done_traverse_smp = 1;
1567                 }
1568                 rval = DDI_FAILURE;
1569                 return (rval);
1570         }
1571         devhdl = va_arg(ap, uint16_t *);
1572         sas_wwn = va_arg(ap, uint64_t *);
1573         phymask = va_arg(ap, mptsas_phymask_t *);
1574         pdevhdl = va_arg(ap, uint16_t *);
1575 
1576         expddevpage = (pMpi2ExpanderPage0_t)page_memp;
1577 
1578         *devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
1579         physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
1580         *phymask = mptsas_physport_to_phymask(mpt, physport);
1581         *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
1582         sas_addr = (uint8_t *)(&expddevpage->SASAddress);
1583         for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1584                 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1585         }
1586         bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1587         *sas_wwn = LE_64(*sas_wwn);
1588 
1589         return (rval);
1590 }
1591 
1592 /*
1593  * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1594  * and SAS address.
1595  */
1596 int
1597 mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
1598     mptsas_smp_t *info)
1599 {
1600         int                     rval = DDI_SUCCESS;
1601 
1602         ASSERT(mutex_owned(&mpt->m_mutex));
1603 
1604         /*
1605          * Get the header and config page.  reply contains the reply frame,
1606          * which holds status info for the request.
1607          */
1608         rval = mptsas_access_config_page(mpt,
1609             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1610             MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
1611             mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
1612             &info->m_addr.mta_wwn, &info->m_addr.mta_phymask, &info->m_pdevhdl);
1613 
1614         return (rval);
1615 }
1616 
1617 static int
1618 mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1619     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1620     va_list ap)
1621 {
1622 #ifndef __lock_lint
1623         _NOTE(ARGUNUSED(ap))
1624 #endif
1625         int     rval = DDI_SUCCESS, i;
1626         uint8_t *sas_addr = NULL;
1627         uint64_t *sas_wwn;
1628         uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1629         uint8_t *portwidth;
1630         pMpi2SasPortPage0_t sasportpage;
1631 
1632         if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1633                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
1634                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1635                     iocstatus, iocloginfo);
1636                 rval = DDI_FAILURE;
1637                 return (rval);
1638         }
1639         sas_wwn = va_arg(ap, uint64_t *);
1640         portwidth = va_arg(ap, uint8_t *);
1641 
1642         sasportpage = (pMpi2SasPortPage0_t)page_memp;
1643         sas_addr = (uint8_t *)(&sasportpage->SASAddress);
1644         for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1645                 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1646         }
1647         bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1648         *sas_wwn = LE_64(*sas_wwn);
1649         *portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
1650         return (rval);
1651 }
1652 
1653 /*
1654  * Request MPI configuration page SAS port page 0 to get initiator SAS address
1655  * and port width.
1656  */
1657 int
1658 mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
1659     uint64_t *sas_wwn, uint8_t *portwidth)
1660 {
1661         int rval = DDI_SUCCESS;
1662 
1663         ASSERT(mutex_owned(&mpt->m_mutex));
1664 
1665         /*
1666          * Get the header and config page.  reply contains the reply frame,
1667          * which holds status info for the request.
1668          */
1669         rval = mptsas_access_config_page(mpt,
1670             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1671             MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
1672             mptsas_sasportpage_0_cb, sas_wwn, portwidth);
1673 
1674         return (rval);
1675 }
1676 
1677 static int
1678 mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
1679     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1680     va_list ap)
1681 {
1682 #ifndef __lock_lint
1683         _NOTE(ARGUNUSED(ap))
1684 #endif
1685         int rval = DDI_SUCCESS;
1686         pMpi2SasIOUnitPage0_t sasioupage0;
1687         int i, num_phys;
1688         uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1689         uint8_t port_flags;
1690 
1691         if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1692                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1693                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1694                     iocstatus, iocloginfo);
1695                 rval = DDI_FAILURE;
1696                 return (rval);
1697         }
1698         readpage1 = va_arg(ap, uint32_t *);
1699         retrypage0 = va_arg(ap, uint32_t *);
1700 
1701         sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1702 
1703         num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1704         /*
1705          * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1706          * was initially set.  This should never change throughout the life of
1707          * the driver.
1708          */
1709         ASSERT(num_phys == mpt->m_num_phys);
1710         for (i = 0; i < num_phys; i++) {
1711                 cpdi[i] = ddi_get32(accessp,
1712                     &sasioupage0->PhyData[i].
1713                     ControllerPhyDeviceInfo);
1714                 port_flags = ddi_get8(accessp,
1715                     &sasioupage0->PhyData[i].PortFlags);
1716                 mpt->m_phy_info[i].port_num =
1717                     ddi_get8(accessp,
1718                     &sasioupage0->PhyData[i].Port);
1719                 mpt->m_phy_info[i].ctrl_devhdl =
1720                     ddi_get16(accessp, &sasioupage0->
1721                     PhyData[i].ControllerDevHandle);
1722                 mpt->m_phy_info[i].attached_devhdl =
1723                     ddi_get16(accessp, &sasioupage0->
1724                     PhyData[i].AttachedDevHandle);
1725                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1726                 mpt->m_phy_info[i].port_flags = port_flags;
1727 
1728                 if (port_flags & DISCOVERY_IN_PROGRESS) {
1729                         *retrypage0 = *retrypage0 + 1;
1730                         break;
1731                 } else {
1732                         *retrypage0 = 0;
1733                 }
1734                 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
1735                         /*
1736                          * some PHY configuration described in
1737                          * SAS IO Unit Page1
1738                          */
1739                         *readpage1 = 1;
1740                 }
1741         }
1742 
1743         return (rval);
1744 }
1745 
1746 static int
1747 mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
1748     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1749     va_list ap)
1750 {
1751 #ifndef __lock_lint
1752         _NOTE(ARGUNUSED(ap))
1753 #endif
1754         int rval = DDI_SUCCESS;
1755         pMpi2SasIOUnitPage1_t sasioupage1;
1756         int i, num_phys;
1757         uint32_t cpdi[MPTSAS_MAX_PHYS];
1758         uint8_t port_flags;
1759 
1760         if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1761                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1762                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1763                     iocstatus, iocloginfo);
1764                 rval = DDI_FAILURE;
1765                 return (rval);
1766         }
1767 
1768         sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1769         num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1770         /*
1771          * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
1772          * was initially set.  This should never change throughout the life of
1773          * the driver.
1774          */
1775         ASSERT(num_phys == mpt->m_num_phys);
1776         for (i = 0; i < num_phys; i++) {
1777                 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1778                     ControllerPhyDeviceInfo);
1779                 port_flags = ddi_get8(accessp,
1780                     &sasioupage1->PhyData[i].PortFlags);
1781                 mpt->m_phy_info[i].port_num =
1782                     ddi_get8(accessp,
1783                     &sasioupage1->PhyData[i].Port);
1784                 mpt->m_phy_info[i].port_flags = port_flags;
1785                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1786         }
1787         return (rval);
1788 }
1789 
1790 /*
1791  * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1792  * page1 to update the PHY information.  This is the message passing method of
1793  * this function which should be called except during initialization.
1794  */
1795 int
1796 mptsas_get_sas_io_unit_page(mptsas_t *mpt)
1797 {
1798         int rval = DDI_SUCCESS, state;
1799         uint32_t readpage1 = 0, retrypage0 = 0;
1800 
1801         ASSERT(mutex_owned(&mpt->m_mutex));
1802 
1803         /*
1804          * Now we cycle through the state machine.  Here's what happens:
1805          * 1. Read IO unit page 0 and set phy information
1806          * 2. See if Read IO unit page1 is needed because of port configuration
1807          * 3. Read IO unit page 1 and update phy information.
1808          */
1809         state = IOUC_READ_PAGE0;
1810         while (state != IOUC_DONE) {
1811                 if (state == IOUC_READ_PAGE0) {
1812                         rval = mptsas_access_config_page(mpt,
1813                             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1814                             MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
1815                             mptsas_sasiou_page_0_cb, &readpage1,
1816                             &retrypage0);
1817                 } else if (state == IOUC_READ_PAGE1) {
1818                         rval = mptsas_access_config_page(mpt,
1819                             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1820                             MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
1821                             mptsas_sasiou_page_1_cb);
1822                 }
1823 
1824                 if (rval == DDI_SUCCESS) {
1825                         switch (state) {
1826                         case IOUC_READ_PAGE0:
1827                                 /*
1828                                  * retry 30 times if discovery is in process
1829                                  */
1830                                 if (retrypage0 && (retrypage0 < 30)) {
1831                                         drv_usecwait(1000 * 100);
1832                                         state = IOUC_READ_PAGE0;
1833                                         break;
1834                                 } else if (retrypage0 == 30) {
1835                                         mptsas_log(mpt, CE_WARN,
1836                                             "!Discovery in progress, can't "
1837                                             "verify IO unit config, then "
1838                                             "after 30 times retry, give "
1839                                             "up!");
1840                                         state = IOUC_DONE;
1841                                         rval = DDI_FAILURE;
1842                                         break;
1843                                 }
1844 
1845                                 if (readpage1 == 0) {
1846                                         state = IOUC_DONE;
1847                                         rval = DDI_SUCCESS;
1848                                         break;
1849                                 }
1850 
1851                                 state = IOUC_READ_PAGE1;
1852                                 break;
1853 
1854                         case IOUC_READ_PAGE1:
1855                                 state = IOUC_DONE;
1856                                 rval = DDI_SUCCESS;
1857                                 break;
1858                         }
1859                 } else {
1860                         return (rval);
1861                 }
1862         }
1863 
1864         return (rval);
1865 }
1866 
1867 static int
1868 mptsas_biospage_3_cb(mptsas_t *mpt, caddr_t page_memp,
1869     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1870     va_list ap)
1871 {
1872 #ifndef __lock_lint
1873         _NOTE(ARGUNUSED(ap))
1874 #endif
1875         pMpi2BiosPage3_t        sasbiospage;
1876         int                     rval = DDI_SUCCESS;
1877         uint32_t                *bios_version;
1878 
1879         if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1880             (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1881                 mptsas_log(mpt, CE_WARN, "mptsas_get_bios_page3 header: "
1882                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, iocloginfo);
1883                 rval = DDI_FAILURE;
1884                 return (rval);
1885         }
1886         bios_version = va_arg(ap, uint32_t *);
1887         sasbiospage = (pMpi2BiosPage3_t)page_memp;
1888         *bios_version = ddi_get32(accessp, &sasbiospage->BiosVersion);
1889 
1890         return (rval);
1891 }
1892 
1893 /*
1894  * Request MPI configuration page BIOS page 3 to get BIOS version.  Since all
1895  * other information in this page is not needed, just ignore it.
1896  */
1897 int
1898 mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version)
1899 {
1900         int rval = DDI_SUCCESS;
1901 
1902         ASSERT(mutex_owned(&mpt->m_mutex));
1903 
1904         /*
1905          * Get the header and config page.  reply contains the reply frame,
1906          * which holds status info for the request.
1907          */
1908         rval = mptsas_access_config_page(mpt,
1909             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, MPI2_CONFIG_PAGETYPE_BIOS, 3,
1910             0, mptsas_biospage_3_cb, bios_version);
1911 
1912         return (rval);
1913 }
1914 
1915 /*
1916  * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1917  * page1 to update the PHY information.  This is the handshaking version of
1918  * this function, which should be called during initialization only.
1919  */
1920 int
1921 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1922 {
1923         ddi_dma_attr_t          recv_dma_attrs, page_dma_attrs;
1924         ddi_dma_cookie_t        page_cookie;
1925         ddi_dma_handle_t        recv_dma_handle, page_dma_handle;
1926         ddi_acc_handle_t        recv_accessp, page_accessp;
1927         pMpi2ConfigReply_t      configreply;
1928         pMpi2SasIOUnitPage0_t   sasioupage0;
1929         pMpi2SasIOUnitPage1_t   sasioupage1;
1930         int                     recv_numbytes;
1931         caddr_t                 recv_memp, page_memp;
1932         int                     i, num_phys, start_phy = 0;
1933         int                     page0_size =
1934             sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1935             (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1936         int                     page1_size =
1937             sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1938             (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1939         uint32_t                flags_length;
1940         uint32_t                cpdi[MPTSAS_MAX_PHYS];
1941         uint32_t                readpage1 = 0, retrypage0 = 0;
1942         uint16_t                iocstatus;
1943         uint8_t                 port_flags, page_number, action;
1944         uint32_t                reply_size = 256; /* Big enough for any page */
1945         uint_t                  state;
1946         int                     rval = DDI_FAILURE;
1947         boolean_t               free_recv = B_FALSE, free_page = B_FALSE;
1948 
1949         /*
1950          * Initialize our "state machine".  This is a bit convoluted,
1951          * but it keeps us from having to do the ddi allocations numerous
1952          * times.
1953          */
1954 
1955         NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1956         ASSERT(mutex_owned(&mpt->m_mutex));
1957         state = IOUC_READ_PAGE0;
1958 
1959         /*
1960          * dynamically create a customized dma attribute structure
1961          * that describes mpt's config reply page request structure.
1962          */
1963         recv_dma_attrs = mpt->m_msg_dma_attr;
1964         recv_dma_attrs.dma_attr_sgllen = 1;
1965         recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
1966 
1967         if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
1968             &recv_dma_handle, &recv_accessp, &recv_memp,
1969             (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
1970                 mptsas_log(mpt, CE_WARN,
1971                     "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1972                 goto cleanup;
1973         }
1974         /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
1975         free_recv = B_TRUE;
1976 
1977         page_dma_attrs = mpt->m_msg_dma_attr;
1978         page_dma_attrs.dma_attr_sgllen = 1;
1979         page_dma_attrs.dma_attr_granular = reply_size;
1980 
1981         if (mptsas_dma_addr_create(mpt, page_dma_attrs,
1982             &page_dma_handle, &page_accessp, &page_memp,
1983             reply_size, &page_cookie) == FALSE) {
1984                 mptsas_log(mpt, CE_WARN,
1985                     "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
1986                 goto cleanup;
1987         }
1988         /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
1989         free_page = B_TRUE;
1990 
1991         /*
1992          * Now we cycle through the state machine.  Here's what happens:
1993          * 1. Read IO unit page 0 and set phy information
1994          * 2. See if Read IO unit page1 is needed because of port configuration
1995          * 3. Read IO unit page 1 and update phy information.
1996          */
1997 
1998         sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1999         sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
2000 
2001         while (state != IOUC_DONE) {
2002                 switch (state) {
2003                 case IOUC_READ_PAGE0:
2004                         page_number = 0;
2005                         action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2006                         flags_length = (uint32_t)page0_size;
2007                         flags_length |= ((uint32_t)(
2008                             MPI2_SGE_FLAGS_LAST_ELEMENT |
2009                             MPI2_SGE_FLAGS_END_OF_BUFFER |
2010                             MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2011                             MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2012                             MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2013                             MPI2_SGE_FLAGS_IOC_TO_HOST |
2014                             MPI2_SGE_FLAGS_END_OF_LIST) <<
2015                             MPI2_SGE_FLAGS_SHIFT);
2016 
2017                         break;
2018 
2019                 case IOUC_READ_PAGE1:
2020                         page_number = 1;
2021                         action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2022                         flags_length = (uint32_t)page1_size;
2023                         flags_length |= ((uint32_t)(
2024                             MPI2_SGE_FLAGS_LAST_ELEMENT |
2025                             MPI2_SGE_FLAGS_END_OF_BUFFER |
2026                             MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2027                             MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2028                             MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2029                             MPI2_SGE_FLAGS_IOC_TO_HOST |
2030                             MPI2_SGE_FLAGS_END_OF_LIST) <<
2031                             MPI2_SGE_FLAGS_SHIFT);
2032 
2033                         break;
2034                 default:
2035                         break;
2036                 }
2037 
2038                 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2039                 configreply = (pMpi2ConfigReply_t)recv_memp;
2040                 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2041 
2042                 if (mptsas_send_extended_config_request_msg(mpt,
2043                     MPI2_CONFIG_ACTION_PAGE_HEADER,
2044                     MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
2045                     0, page_number, 0, 0, 0, 0)) {
2046                         goto cleanup;
2047                 }
2048 
2049                 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2050                     recv_accessp)) {
2051                         goto cleanup;
2052                 }
2053 
2054                 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2055                 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2056 
2057                 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2058                         mptsas_log(mpt, CE_WARN,
2059                             "mptsas_get_sas_io_unit_page_hndshk: read page "
2060                             "header iocstatus = 0x%x", iocstatus);
2061                         goto cleanup;
2062                 }
2063 
2064                 if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
2065                         bzero(page_memp, reply_size);
2066                 }
2067 
2068                 if (mptsas_send_extended_config_request_msg(mpt, action,
2069                     MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
2070                     ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2071                     ddi_get16(recv_accessp, &configreply->ExtPageLength),
2072                     flags_length, page_cookie.dmac_laddress)) {
2073                         goto cleanup;
2074                 }
2075 
2076                 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2077                     recv_accessp)) {
2078                         goto cleanup;
2079                 }
2080 
2081                 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2082                 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2083 
2084                 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2085                         mptsas_log(mpt, CE_WARN,
2086                             "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2087                             "config failed for action %d, iocstatus = 0x%x",
2088                             action, iocstatus);
2089                         goto cleanup;
2090                 }
2091 
2092                 switch (state) {
2093                 case IOUC_READ_PAGE0:
2094                         if ((ddi_dma_sync(page_dma_handle, 0, 0,
2095                             DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2096                                 goto cleanup;
2097                         }
2098 
2099                         num_phys = ddi_get8(page_accessp,
2100                             &sasioupage0->NumPhys);
2101                         ASSERT(num_phys == mpt->m_num_phys);
2102                         if (num_phys > MPTSAS_MAX_PHYS) {
2103                                 mptsas_log(mpt, CE_WARN, "Number of phys "
2104                                     "supported by HBA (%d) is more than max "
2105                                     "supported by driver (%d).  Driver will "
2106                                     "not attach.", num_phys,
2107                                     MPTSAS_MAX_PHYS);
2108                                 rval = DDI_FAILURE;
2109                                 goto cleanup;
2110                         }
2111                         for (i = start_phy; i < num_phys; i++, start_phy = i) {
2112                                 cpdi[i] = ddi_get32(page_accessp,
2113                                     &sasioupage0->PhyData[i].
2114                                     ControllerPhyDeviceInfo);
2115                                 port_flags = ddi_get8(page_accessp,
2116                                     &sasioupage0->PhyData[i].PortFlags);
2117 
2118                                 mpt->m_phy_info[i].port_num =
2119                                     ddi_get8(page_accessp,
2120                                     &sasioupage0->PhyData[i].Port);
2121                                 mpt->m_phy_info[i].ctrl_devhdl =
2122                                     ddi_get16(page_accessp, &sasioupage0->
2123                                     PhyData[i].ControllerDevHandle);
2124                                 mpt->m_phy_info[i].attached_devhdl =
2125                                     ddi_get16(page_accessp, &sasioupage0->
2126                                     PhyData[i].AttachedDevHandle);
2127                                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2128                                 mpt->m_phy_info[i].port_flags = port_flags;
2129 
2130                                 if (port_flags & DISCOVERY_IN_PROGRESS) {
2131                                         retrypage0++;
2132                                         NDBG20(("Discovery in progress, can't "
2133                                             "verify IO unit config, then NO.%d"
2134                                             " times retry", retrypage0));
2135                                         break;
2136                                 } else {
2137                                         retrypage0 = 0;
2138                                 }
2139                                 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
2140                                         /*
2141                                          * some PHY configuration described in
2142                                          * SAS IO Unit Page1
2143                                          */
2144                                         readpage1 = 1;
2145                                 }
2146                         }
2147 
2148                         /*
2149                          * retry 30 times if discovery is in process
2150                          */
2151                         if (retrypage0 && (retrypage0 < 30)) {
2152                                 drv_usecwait(1000 * 100);
2153                                 state = IOUC_READ_PAGE0;
2154                                 break;
2155                         } else if (retrypage0 == 30) {
2156                                 mptsas_log(mpt, CE_WARN,
2157                                     "!Discovery in progress, can't "
2158                                     "verify IO unit config, then after"
2159                                     " 30 times retry, give up!");
2160                                 state = IOUC_DONE;
2161                                 rval = DDI_FAILURE;
2162                                 break;
2163                         }
2164 
2165                         if (readpage1 == 0) {
2166                                 state = IOUC_DONE;
2167                                 rval = DDI_SUCCESS;
2168                                 break;
2169                         }
2170 
2171                         state = IOUC_READ_PAGE1;
2172                         break;
2173 
2174                 case IOUC_READ_PAGE1:
2175                         if ((ddi_dma_sync(page_dma_handle, 0, 0,
2176                             DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2177                                 goto cleanup;
2178                         }
2179 
2180                         num_phys = ddi_get8(page_accessp,
2181                             &sasioupage1->NumPhys);
2182                         ASSERT(num_phys == mpt->m_num_phys);
2183                         if (num_phys > MPTSAS_MAX_PHYS) {
2184                                 mptsas_log(mpt, CE_WARN, "Number of phys "
2185                                     "supported by HBA (%d) is more than max "
2186                                     "supported by driver (%d).  Driver will "
2187                                     "not attach.", num_phys,
2188                                     MPTSAS_MAX_PHYS);
2189                                 rval = DDI_FAILURE;
2190                                 goto cleanup;
2191                         }
2192                         for (i = 0; i < num_phys; i++) {
2193                                 cpdi[i] = ddi_get32(page_accessp,
2194                                     &sasioupage1->PhyData[i].
2195                                     ControllerPhyDeviceInfo);
2196                                 port_flags = ddi_get8(page_accessp,
2197                                     &sasioupage1->PhyData[i].PortFlags);
2198                                 mpt->m_phy_info[i].port_num =
2199                                     ddi_get8(page_accessp,
2200                                     &sasioupage1->PhyData[i].Port);
2201                                 mpt->m_phy_info[i].port_flags = port_flags;
2202                                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2203 
2204                         }
2205 
2206                         state = IOUC_DONE;
2207                         rval = DDI_SUCCESS;
2208                         break;
2209                 }
2210         }
2211         if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2212             (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2213                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2214                 rval = DDI_FAILURE;
2215                 goto cleanup;
2216         }
2217         if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2218             (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2219                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2220                 rval = DDI_FAILURE;
2221                 goto cleanup;
2222         }
2223 
2224 cleanup:
2225         if (free_recv)
2226                 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2227         if (free_page)
2228                 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2229         if (rval != DDI_SUCCESS) {
2230                 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2231                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2232         }
2233         return (rval);
2234 }
2235 
2236 /*
2237  * mptsas_get_manufacture_page5
2238  *
2239  * This function will retrieve the base WWID from the adapter.  Since this
2240  * function is only called during the initialization process, use handshaking.
2241  */
2242 int
2243 mptsas_get_manufacture_page5(mptsas_t *mpt)
2244 {
2245         ddi_dma_attr_t                  recv_dma_attrs, page_dma_attrs;
2246         ddi_dma_cookie_t                page_cookie;
2247         ddi_dma_handle_t                recv_dma_handle, page_dma_handle;
2248         ddi_acc_handle_t                recv_accessp, page_accessp;
2249         pMpi2ConfigReply_t              configreply;
2250         caddr_t                         recv_memp, page_memp;
2251         int                             recv_numbytes;
2252         pMpi2ManufacturingPage5_t       m5;
2253         uint32_t                        flagslength;
2254         int                             rval = DDI_SUCCESS;
2255         uint_t                          iocstatus;
2256         boolean_t               free_recv = B_FALSE, free_page = B_FALSE;
2257 
2258         MPTSAS_DISABLE_INTR(mpt);
2259 
2260         if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2261             MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2262                 rval = DDI_FAILURE;
2263                 goto done;
2264         }
2265 
2266         /*
2267          * dynamically create a customized dma attribute structure
2268          * that describes the MPT's config reply page request structure.
2269          */
2270         recv_dma_attrs = mpt->m_msg_dma_attr;
2271         recv_dma_attrs.dma_attr_sgllen = 1;
2272         recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2273 
2274         if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2275             &recv_dma_handle, &recv_accessp, &recv_memp,
2276             (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2277                 rval = DDI_FAILURE;
2278                 goto done;
2279         }
2280         /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2281         free_recv = B_TRUE;
2282 
2283         bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2284         configreply = (pMpi2ConfigReply_t)recv_memp;
2285         recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2286 
2287         /*
2288          * get config reply message
2289          */
2290         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2291             recv_accessp)) {
2292                 rval = DDI_FAILURE;
2293                 goto done;
2294         }
2295 
2296         if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2297                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2298                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2299                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2300                 goto done;
2301         }
2302 
2303         /*
2304          * dynamically create a customized dma attribute structure
2305          * that describes the MPT's config page structure.
2306          */
2307         page_dma_attrs = mpt->m_msg_dma_attr;
2308         page_dma_attrs.dma_attr_sgllen = 1;
2309         page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2310 
2311         if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2312             &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2313             &page_cookie) == FALSE) {
2314                 rval = DDI_FAILURE;
2315                 goto done;
2316         }
2317         /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2318         free_page = B_TRUE;
2319 
2320         bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2321         m5 = (pMpi2ManufacturingPage5_t)page_memp;
2322         NDBG20(("mptsas_get_manufacture_page5: paddr 0x%p",
2323             (void *)(uintptr_t)page_cookie.dmac_laddress));
2324 
2325         /*
2326          * Give reply address to IOC to store config page in and send
2327          * config request out.
2328          */
2329 
2330         flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2331         flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2332             MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2333             MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2334             MPI2_SGE_FLAGS_IOC_TO_HOST |
2335             MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2336 
2337         if (mptsas_send_config_request_msg(mpt,
2338             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2339             MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2340             ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2341             ddi_get8(recv_accessp, &configreply->Header.PageLength),
2342             flagslength, page_cookie.dmac_laddress)) {
2343                 rval = DDI_FAILURE;
2344                 goto done;
2345         }
2346 
2347         /*
2348          * get reply view handshake
2349          */
2350         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2351             recv_accessp)) {
2352                 rval = DDI_FAILURE;
2353                 goto done;
2354         }
2355 
2356         if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2357                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2358                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2359                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2360                 goto done;
2361         }
2362 
2363         (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2364 
2365         /*
2366          * Fusion-MPT stores fields in little-endian format.  This is
2367          * why the low-order 32 bits are stored first.
2368          */
2369         mpt->un.sasaddr.m_base_wwid_lo =
2370             ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2371         mpt->un.sasaddr.m_base_wwid_hi =
2372             ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2373 
2374         if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2375             "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2376                 NDBG2(("%s%d: failed to create base-wwid property",
2377                     ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2378         }
2379 
2380         /*
2381          * Set the number of PHYs present.
2382          */
2383         mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2384 
2385         if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2386             "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2387                 NDBG2(("%s%d: failed to create num-phys property",
2388                     ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2389         }
2390 
2391         mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2392             mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2393             (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2394 
2395         if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2396             (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2397                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2398                 rval = DDI_FAILURE;
2399                 goto done;
2400         }
2401         if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2402             (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2403                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2404                 rval = DDI_FAILURE;
2405         }
2406 done:
2407         /*
2408          * free up memory
2409          */
2410         if (free_recv)
2411                 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2412         if (free_page)
2413                 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2414         MPTSAS_ENABLE_INTR(mpt);
2415 
2416         return (rval);
2417 }
2418 
2419 static int
2420 mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2421     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2422     va_list ap)
2423 {
2424 #ifndef __lock_lint
2425         _NOTE(ARGUNUSED(ap))
2426 #endif
2427         pMpi2SasPhyPage0_t      sasphypage;
2428         int                     rval = DDI_SUCCESS;
2429         uint16_t                *owner_devhdl, *attached_devhdl;
2430         uint8_t                 *attached_phy_identify;
2431         uint32_t                *attached_phy_info;
2432         uint8_t                 *programmed_link_rate;
2433         uint8_t                 *hw_link_rate;
2434         uint8_t                 *change_count;
2435         uint32_t                *phy_info;
2436         uint8_t                 *negotiated_link_rate;
2437         uint32_t                page_address;
2438 
2439         if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2440             (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2441                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
2442                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2443                     iocstatus, iocloginfo);
2444                 rval = DDI_FAILURE;
2445                 return (rval);
2446         }
2447         page_address = va_arg(ap, uint32_t);
2448         /*
2449          * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2450          * are no more pages.  If everything is OK up to this point but the
2451          * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
2452          * signal that device traversal is complete.
2453          */
2454         if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2455                 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2456                     MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2457                         mpt->m_done_traverse_smp = 1;
2458                 }
2459                 rval = DDI_FAILURE;
2460                 return (rval);
2461         }
2462         owner_devhdl = va_arg(ap, uint16_t *);
2463         attached_devhdl = va_arg(ap, uint16_t *);
2464         attached_phy_identify = va_arg(ap, uint8_t *);
2465         attached_phy_info = va_arg(ap, uint32_t *);
2466         programmed_link_rate = va_arg(ap, uint8_t *);
2467         hw_link_rate = va_arg(ap, uint8_t *);
2468         change_count = va_arg(ap, uint8_t *);
2469         phy_info = va_arg(ap, uint32_t *);
2470         negotiated_link_rate = va_arg(ap, uint8_t *);
2471 
2472         sasphypage = (pMpi2SasPhyPage0_t)page_memp;
2473 
2474         *owner_devhdl =
2475             ddi_get16(accessp, &sasphypage->OwnerDevHandle);
2476         *attached_devhdl =
2477             ddi_get16(accessp, &sasphypage->AttachedDevHandle);
2478         *attached_phy_identify =
2479             ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
2480         *attached_phy_info =
2481             ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
2482         *programmed_link_rate =
2483             ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
2484         *hw_link_rate =
2485             ddi_get8(accessp, &sasphypage->HwLinkRate);
2486         *change_count =
2487             ddi_get8(accessp, &sasphypage->ChangeCount);
2488         *phy_info =
2489             ddi_get32(accessp, &sasphypage->PhyInfo);
2490         *negotiated_link_rate =
2491             ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
2492 
2493         return (rval);
2494 }
2495 
2496 /*
2497  * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2498  * and SAS address.
2499  */
2500 int
2501 mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
2502     smhba_info_t *info)
2503 {
2504         int                     rval = DDI_SUCCESS;
2505 
2506         ASSERT(mutex_owned(&mpt->m_mutex));
2507 
2508         /*
2509          * Get the header and config page.  reply contains the reply frame,
2510          * which holds status info for the request.
2511          */
2512         rval = mptsas_access_config_page(mpt,
2513             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2514             MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
2515             mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
2516             &info->attached_devhdl, &info->attached_phy_identify,
2517             &info->attached_phy_info, &info->programmed_link_rate,
2518             &info->hw_link_rate, &info->change_count,
2519             &info->phy_info, &info->negotiated_link_rate);
2520 
2521         return (rval);
2522 }
2523 
2524 static int
2525 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2526     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2527     va_list ap)
2528 {
2529 #ifndef __lock_lint
2530         _NOTE(ARGUNUSED(ap))
2531 #endif
2532         pMpi2SasPhyPage1_t      sasphypage;
2533         int                     rval = DDI_SUCCESS;
2534 
2535         uint32_t                *invalid_dword_count;
2536         uint32_t                *running_disparity_error_count;
2537         uint32_t                *loss_of_dword_sync_count;
2538         uint32_t                *phy_reset_problem_count;
2539         uint32_t                page_address;
2540 
2541         if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2542             (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2543                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
2544                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2545                     iocstatus, iocloginfo);
2546                 rval = DDI_FAILURE;
2547                 return (rval);
2548         }
2549         page_address = va_arg(ap, uint32_t);
2550         /*
2551          * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2552          * are no more pages.  If everything is OK up to this point but the
2553          * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
2554          * signal that device traversal is complete.
2555          */
2556         if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2557                 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2558                     MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2559                         mpt->m_done_traverse_smp = 1;
2560                 }
2561                 rval = DDI_FAILURE;
2562                 return (rval);
2563         }
2564 
2565         invalid_dword_count = va_arg(ap, uint32_t *);
2566         running_disparity_error_count = va_arg(ap, uint32_t *);
2567         loss_of_dword_sync_count = va_arg(ap, uint32_t *);
2568         phy_reset_problem_count = va_arg(ap, uint32_t *);
2569 
2570         sasphypage = (pMpi2SasPhyPage1_t)page_memp;
2571 
2572         *invalid_dword_count =
2573             ddi_get32(accessp, &sasphypage->InvalidDwordCount);
2574         *running_disparity_error_count =
2575             ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
2576         *loss_of_dword_sync_count =
2577             ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
2578         *phy_reset_problem_count =
2579             ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
2580 
2581         return (rval);
2582 }
2583 
2584 /*
2585  * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2586  * and SAS address.
2587  */
2588 int
2589 mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
2590     smhba_info_t *info)
2591 {
2592         int                     rval = DDI_SUCCESS;
2593 
2594         ASSERT(mutex_owned(&mpt->m_mutex));
2595 
2596         /*
2597          * Get the header and config page.  reply contains the reply frame,
2598          * which holds status info for the request.
2599          */
2600         rval = mptsas_access_config_page(mpt,
2601             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2602             MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
2603             mptsas_sasphypage_1_cb, page_address,
2604             &info->invalid_dword_count,
2605             &info->running_disparity_error_count,
2606             &info->loss_of_dword_sync_count,
2607             &info->phy_reset_problem_count);
2608 
2609         return (rval);
2610 }
2611 /*
2612  * mptsas_get_manufacture_page0
2613  *
2614  * This function will retrieve the base
2615  * Chip name, Board Name,Board Trace number from the adapter.
2616  * Since this function is only called during the
2617  * initialization process, use handshaking.
2618  */
2619 int
2620 mptsas_get_manufacture_page0(mptsas_t *mpt)
2621 {
2622         ddi_dma_attr_t                  recv_dma_attrs, page_dma_attrs;
2623         ddi_dma_cookie_t                page_cookie;
2624         ddi_dma_handle_t                recv_dma_handle, page_dma_handle;
2625         ddi_acc_handle_t                recv_accessp, page_accessp;
2626         pMpi2ConfigReply_t              configreply;
2627         caddr_t                         recv_memp, page_memp;
2628         int                             recv_numbytes;
2629         pMpi2ManufacturingPage0_t       m0;
2630         uint32_t                        flagslength;
2631         int                             rval = DDI_SUCCESS;
2632         uint_t                          iocstatus;
2633         uint8_t                         i = 0;
2634         boolean_t               free_recv = B_FALSE, free_page = B_FALSE;
2635 
2636         MPTSAS_DISABLE_INTR(mpt);
2637 
2638         if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2639             MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2640                 rval = DDI_FAILURE;
2641                 goto done;
2642         }
2643 
2644         /*
2645          * dynamically create a customized dma attribute structure
2646          * that describes the MPT's config reply page request structure.
2647          */
2648         recv_dma_attrs = mpt->m_msg_dma_attr;
2649         recv_dma_attrs.dma_attr_sgllen = 1;
2650         recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2651 
2652         if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2653             &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2654             NULL) == FALSE) {
2655                 rval = DDI_FAILURE;
2656                 goto done;
2657         }
2658         /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2659         free_recv = B_TRUE;
2660 
2661         bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2662         configreply = (pMpi2ConfigReply_t)recv_memp;
2663         recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2664 
2665         /*
2666          * get config reply message
2667          */
2668         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2669             recv_accessp)) {
2670                 rval = DDI_FAILURE;
2671                 goto done;
2672         }
2673 
2674         if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2675                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2676                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2677                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2678                 goto done;
2679         }
2680 
2681         /*
2682          * dynamically create a customized dma attribute structure
2683          * that describes the MPT's config page structure.
2684          */
2685         page_dma_attrs = mpt->m_msg_dma_attr;
2686         page_dma_attrs.dma_attr_sgllen = 1;
2687         page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2688 
2689         if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2690             &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2691             &page_cookie) == FALSE) {
2692                 rval = DDI_FAILURE;
2693                 goto done;
2694         }
2695         /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2696         free_page = B_TRUE;
2697 
2698         bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2699         m0 = (pMpi2ManufacturingPage0_t)page_memp;
2700 
2701         /*
2702          * Give reply address to IOC to store config page in and send
2703          * config request out.
2704          */
2705 
2706         flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2707         flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2708             MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2709             MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2710             MPI2_SGE_FLAGS_IOC_TO_HOST |
2711             MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2712 
2713         if (mptsas_send_config_request_msg(mpt,
2714             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2715             MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2716             ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2717             ddi_get8(recv_accessp, &configreply->Header.PageLength),
2718             flagslength, page_cookie.dmac_laddress)) {
2719                 rval = DDI_FAILURE;
2720                 goto done;
2721         }
2722 
2723         /*
2724          * get reply view handshake
2725          */
2726         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2727             recv_accessp)) {
2728                 rval = DDI_FAILURE;
2729                 goto done;
2730         }
2731 
2732         if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2733                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2734                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2735                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2736                 goto done;
2737         }
2738 
2739         (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2740 
2741         /*
2742          * Fusion-MPT stores fields in little-endian format.  This is
2743          * why the low-order 32 bits are stored first.
2744          */
2745 
2746         for (i = 0; i < 16; i++) {
2747                 mpt->m_MANU_page0.ChipName[i] =
2748                     ddi_get8(page_accessp,
2749                     (uint8_t *)(void *)&m0->ChipName[i]);
2750         }
2751 
2752         for (i = 0; i < 8; i++) {
2753                 mpt->m_MANU_page0.ChipRevision[i] =
2754                     ddi_get8(page_accessp,
2755                     (uint8_t *)(void *)&m0->ChipRevision[i]);
2756         }
2757 
2758         for (i = 0; i < 16; i++) {
2759                 mpt->m_MANU_page0.BoardName[i] =
2760                     ddi_get8(page_accessp,
2761                     (uint8_t *)(void *)&m0->BoardName[i]);
2762         }
2763 
2764         for (i = 0; i < 16; i++) {
2765                 mpt->m_MANU_page0.BoardAssembly[i] =
2766                     ddi_get8(page_accessp,
2767                     (uint8_t *)(void *)&m0->BoardAssembly[i]);
2768         }
2769 
2770         for (i = 0; i < 16; i++) {
2771                 mpt->m_MANU_page0.BoardTracerNumber[i] =
2772                     ddi_get8(page_accessp,
2773                     (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2774         }
2775 
2776         if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2777             (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2778                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2779                 rval = DDI_FAILURE;
2780                 goto done;
2781         }
2782         if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2783             (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2784                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2785                 rval = DDI_FAILURE;
2786         }
2787 done:
2788         /*
2789          * free up memory
2790          */
2791         if (free_recv)
2792                 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2793         if (free_page)
2794                 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2795         MPTSAS_ENABLE_INTR(mpt);
2796 
2797         return (rval);
2798 }