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