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