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