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