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 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  26  * Copyright (c) 2017, Joyent, Inc.
  27  */
  28 
  29 /*
  30  * Copyright (c) 2000 to 2009, LSI Corporation.
  31  * All rights reserved.
  32  *
  33  * Redistribution and use in source and binary forms of all code within
  34  * this file that is exclusively owned by LSI, with or without
  35  * modification, is permitted provided that, in addition to the CDDL 1.0
  36  * License requirements, the following conditions are met:
  37  *
  38  *    Neither the name of the author nor the names of its contributors may be
  39  *    used to endorse or promote products derived from this software without
  40  *    specific prior written permission.
  41  *
  42  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  43  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  44  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  45  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  46  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  47  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  48  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  49  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  50  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  51  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  52  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  53  * DAMAGE.
  54  */
  55 
  56 /*
  57  * mptsas_init - This file contains all the functions used to initialize
  58  * MPT2.0 based hardware.
  59  */
  60 
  61 #if defined(lint) || defined(DEBUG)
  62 #define MPTSAS_DEBUG
  63 #endif
  64 
  65 /*
  66  * standard header files
  67  */
  68 #include <sys/note.h>
  69 #include <sys/scsi/scsi.h>
  70 
  71 #pragma pack(1)
  72 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
  73 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
  74 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
  75 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
  76 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
  77 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
  78 #pragma pack()
  79 /*
  80  * private header files.
  81  */
  82 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
  83 
  84 static int mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var,
  85         ddi_acc_handle_t accessp);
  86 static int mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
  87         ddi_acc_handle_t accessp);
  88 static int mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var,
  89         ddi_acc_handle_t accessp);
  90 static int mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp,
  91     int var, ddi_acc_handle_t accessp);
  92 static int mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var,
  93         ddi_acc_handle_t accessp);
  94 static int mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var,
  95         ddi_acc_handle_t accessp);
  96 static int mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp,
  97         int var, ddi_acc_handle_t accessp);
  98 static int mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt,
  99     caddr_t memp, int var, ddi_acc_handle_t accessp);
 100 static int mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var,
 101         ddi_acc_handle_t accessp);
 102 static int mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var,
 103         ddi_acc_handle_t accessp);
 104 
 105 static const char *
 106 mptsas_devid_type_string(mptsas_t *mpt)
 107 {
 108         switch (mpt->m_devid) {
 109         case MPI2_MFGPAGE_DEVID_SAS2008:
 110                 return ("SAS2008");
 111         case MPI2_MFGPAGE_DEVID_SAS2004:
 112                 return ("SAS2004");
 113         case MPI2_MFGPAGE_DEVID_SAS2108_1:
 114         case MPI2_MFGPAGE_DEVID_SAS2108_2:
 115         case MPI2_MFGPAGE_DEVID_SAS2108_3:
 116                 return ("SAS2108");
 117         case MPI2_MFGPAGE_DEVID_SAS2116_1:
 118         case MPI2_MFGPAGE_DEVID_SAS2116_2:
 119                 return ("SAS2116");
 120         case MPI2_MFGPAGE_DEVID_SAS2208_1:
 121         case MPI2_MFGPAGE_DEVID_SAS2208_2:
 122         case MPI2_MFGPAGE_DEVID_SAS2208_3:
 123         case MPI2_MFGPAGE_DEVID_SAS2208_4:
 124         case MPI2_MFGPAGE_DEVID_SAS2208_5:
 125         case MPI2_MFGPAGE_DEVID_SAS2208_6:
 126                 return ("SAS2208");
 127         case MPI2_MFGPAGE_DEVID_SAS2308_1:
 128         case MPI2_MFGPAGE_DEVID_SAS2308_2:
 129         case MPI2_MFGPAGE_DEVID_SAS2308_3:
 130                 return ("SAS2308");
 131         case MPI25_MFGPAGE_DEVID_SAS3004:
 132                 return ("SAS3004");
 133         case MPI25_MFGPAGE_DEVID_SAS3008:
 134                 return ("SAS3008");
 135         case MPI25_MFGPAGE_DEVID_SAS3108_1:
 136         case MPI25_MFGPAGE_DEVID_SAS3108_2:
 137         case MPI25_MFGPAGE_DEVID_SAS3108_5:
 138         case MPI25_MFGPAGE_DEVID_SAS3108_6:
 139                 return ("SAS3108");
 140         default:
 141                 return ("?");
 142         }
 143 }
 144 
 145 int
 146 mptsas_ioc_get_facts(mptsas_t *mpt)
 147 {
 148         /*
 149          * Send get facts messages
 150          */
 151         if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REQUEST), NULL,
 152             mptsas_ioc_do_get_facts)) {
 153                 return (DDI_FAILURE);
 154         }
 155 
 156         /*
 157          * Get facts reply messages
 158          */
 159         if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REPLY), NULL,
 160             mptsas_ioc_do_get_facts_reply)) {
 161                 return (DDI_FAILURE);
 162         }
 163 
 164         return (DDI_SUCCESS);
 165 }
 166 
 167 static int
 168 mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var,
 169     ddi_acc_handle_t accessp)
 170 {
 171 #ifndef __lock_lint
 172         _NOTE(ARGUNUSED(var))
 173 #endif
 174         pMpi2IOCFactsRequest_t  facts;
 175         int                     numbytes;
 176 
 177         bzero(memp, sizeof (*facts));
 178         facts = (void *)memp;
 179         ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_IOC_FACTS);
 180         numbytes = sizeof (*facts);
 181 
 182         /*
 183          * Post message via handshake
 184          */
 185         if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
 186                 return (DDI_FAILURE);
 187         }
 188 
 189         return (DDI_SUCCESS);
 190 }
 191 
 192 static int
 193 mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
 194     ddi_acc_handle_t accessp)
 195 {
 196 #ifndef __lock_lint
 197         _NOTE(ARGUNUSED(var))
 198 #endif
 199 
 200         pMpi2IOCFactsReply_t    factsreply;
 201         int                     numbytes;
 202         uint_t                  iocstatus;
 203         char                    buf[32];
 204         uint16_t                numReplyFrames;
 205         uint16_t                queueSize, queueDiff;
 206         int                     simple_sge_main;
 207         int                     simple_sge_next;
 208         uint32_t                capabilities;
 209         uint16_t                msgversion;
 210 
 211         bzero(memp, sizeof (*factsreply));
 212         factsreply = (void *)memp;
 213         numbytes = sizeof (*factsreply);
 214 
 215         /*
 216          * get ioc facts reply message
 217          */
 218         if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
 219                 return (DDI_FAILURE);
 220         }
 221 
 222         if (iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) {
 223                 mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_facts_reply: "
 224                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
 225                     ddi_get32(accessp, &factsreply->IOCLogInfo));
 226                 return (DDI_FAILURE);
 227         }
 228 
 229         /*
 230          * store key values from reply to mpt structure
 231          */
 232         mpt->m_fwversion = ddi_get32(accessp, &factsreply->FWVersion.Word);
 233         mpt->m_productid = ddi_get16(accessp, &factsreply->ProductID);
 234 
 235 
 236         (void) sprintf(buf, "%u.%u.%u.%u",
 237             ddi_get8(accessp, &factsreply->FWVersion.Struct.Major),
 238             ddi_get8(accessp, &factsreply->FWVersion.Struct.Minor),
 239             ddi_get8(accessp, &factsreply->FWVersion.Struct.Unit),
 240             ddi_get8(accessp, &factsreply->FWVersion.Struct.Dev));
 241         mptsas_log(mpt, CE_NOTE, "?MPT Firmware version v%s (%s)\n",
 242             buf, mptsas_devid_type_string(mpt));
 243         (void) ddi_prop_update_string(DDI_DEV_T_NONE, mpt->m_dip,
 244             "firmware-version", buf);
 245 
 246         /*
 247          * Set up request info.
 248          */
 249         mpt->m_max_requests = ddi_get16(accessp,
 250             &factsreply->RequestCredit) - 1;
 251         mpt->m_req_frame_size = ddi_get16(accessp,
 252             &factsreply->IOCRequestFrameSize) * 4;
 253 
 254         /*
 255          * Size of reply free queue should be the number of requests
 256          * plus some additional for events (32).  Make sure number of
 257          * reply frames is not a multiple of 16 so that the queue sizes
 258          * are calculated correctly later to be a multiple of 16.
 259          */
 260         mpt->m_reply_frame_size = ddi_get8(accessp,
 261             &factsreply->ReplyFrameSize) * 4;
 262         numReplyFrames = mpt->m_max_requests + 32;
 263         if (!(numReplyFrames % 16)) {
 264                 numReplyFrames--;
 265         }
 266         mpt->m_max_replies = numReplyFrames;
 267         queueSize = numReplyFrames;
 268         queueSize += 16 - (queueSize % 16);
 269         mpt->m_free_queue_depth = queueSize;
 270 
 271         /*
 272          * Size of reply descriptor post queue should be the number of
 273          * request frames + the number of reply frames + 1 and needs to
 274          * be a multiple of 16.  This size can be no larger than
 275          * MaxReplyDescriptorPostQueueDepth from IOCFacts.  If the
 276          * calculated queue size is larger than allowed, subtract a
 277          * multiple of 16 from m_max_requests, m_max_replies, and
 278          * m_reply_free_depth.
 279          */
 280         queueSize = mpt->m_max_requests + numReplyFrames + 1;
 281         if (queueSize % 16) {
 282                 queueSize += 16 - (queueSize % 16);
 283         }
 284         mpt->m_post_queue_depth = ddi_get16(accessp,
 285             &factsreply->MaxReplyDescriptorPostQueueDepth);
 286         if (queueSize > mpt->m_post_queue_depth) {
 287                 queueDiff = queueSize - mpt->m_post_queue_depth;
 288                 if (queueDiff % 16) {
 289                         queueDiff += 16 - (queueDiff % 16);
 290                 }
 291                 mpt->m_max_requests -= queueDiff;
 292                 mpt->m_max_replies -= queueDiff;
 293                 mpt->m_free_queue_depth -= queueDiff;
 294                 queueSize -= queueDiff;
 295         }
 296         mpt->m_post_queue_depth = queueSize;
 297 
 298         /*
 299          * Set up max chain depth.
 300          */
 301         mpt->m_max_chain_depth = ddi_get8(accessp,
 302             &factsreply->MaxChainDepth);
 303         mpt->m_ioc_capabilities = ddi_get32(accessp,
 304             &factsreply->IOCCapabilities);
 305 
 306         /*
 307          * Set flag to check for SAS3 support.
 308          */
 309         msgversion = ddi_get16(accessp, &factsreply->MsgVersion);
 310         if (msgversion >= MPI2_VERSION_02_05) {
 311                 mptsas_log(mpt, CE_NOTE, "?mpt_sas%d SAS 3 Supported\n",
 312                     mpt->m_instance);
 313                 mpt->m_MPI25 = TRUE;
 314         } else {
 315                 mptsas_log(mpt, CE_NOTE, "?mpt_sas%d MPI Version 0x%x\n",
 316                     mpt->m_instance, msgversion);
 317         }
 318 
 319         /*
 320          * Calculate max frames per request based on DMA S/G length.
 321          */
 322         simple_sge_main = MPTSAS_MAX_FRAME_SGES64(mpt) - 1;
 323         simple_sge_next = mpt->m_req_frame_size / MPTSAS_SGE_SIZE(mpt) - 1;
 324 
 325         mpt->m_max_request_frames = (MPTSAS_MAX_DMA_SEGS -
 326             simple_sge_main) / simple_sge_next + 1;
 327         if (((MPTSAS_MAX_DMA_SEGS - simple_sge_main) %
 328             simple_sge_next) > 1) {
 329                 mpt->m_max_request_frames++;
 330         }
 331 
 332         /*
 333          * Check if controller supports FW diag buffers and set flag to enable
 334          * each type.
 335          */
 336         capabilities = ddi_get32(accessp, &factsreply->IOCCapabilities);
 337         if (capabilities & MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
 338                 mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE].enabled =
 339                     TRUE;
 340         }
 341         if (capabilities & MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) {
 342                 mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT].
 343                     enabled = TRUE;
 344         }
 345         if (capabilities & MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) {
 346                 mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED].
 347                     enabled = TRUE;
 348         }
 349 
 350         /*
 351          * Check if controller supports replaying events when issuing Message
 352          * Unit Reset and set flag to enable MUR.
 353          */
 354         if (capabilities & MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) {
 355                 mpt->m_event_replay = TRUE;
 356         }
 357 
 358         /*
 359          * Check if controller supports IR.
 360          */
 361         if (capabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
 362                 mpt->m_ir_capable = TRUE;
 363         }
 364 
 365         return (DDI_SUCCESS);
 366 }
 367 
 368 int
 369 mptsas_ioc_get_port_facts(mptsas_t *mpt, int port)
 370 {
 371         /*
 372          * Send get port facts message
 373          */
 374         if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REQUEST), port,
 375             mptsas_ioc_do_get_port_facts)) {
 376                 return (DDI_FAILURE);
 377         }
 378 
 379         /*
 380          * Get port facts reply message
 381          */
 382         if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REPLY), port,
 383             mptsas_ioc_do_get_port_facts_reply)) {
 384                 return (DDI_FAILURE);
 385         }
 386 
 387         return (DDI_SUCCESS);
 388 }
 389 
 390 static int
 391 mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var,
 392     ddi_acc_handle_t accessp)
 393 {
 394         pMpi2PortFactsRequest_t facts;
 395         int                     numbytes;
 396 
 397         bzero(memp, sizeof (*facts));
 398         facts = (void *)memp;
 399         ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_PORT_FACTS);
 400         ddi_put8(accessp, &facts->PortNumber, var);
 401         numbytes = sizeof (*facts);
 402 
 403         /*
 404          * Send port facts message via handshake
 405          */
 406         if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
 407                 return (DDI_FAILURE);
 408         }
 409 
 410         return (DDI_SUCCESS);
 411 }
 412 
 413 static int
 414 mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
 415     ddi_acc_handle_t accessp)
 416 {
 417 #ifndef __lock_lint
 418         _NOTE(ARGUNUSED(var))
 419 #endif
 420         pMpi2PortFactsReply_t   factsreply;
 421         int                     numbytes;
 422         uint_t                  iocstatus;
 423 
 424         bzero(memp, sizeof (*factsreply));
 425         factsreply = (void *)memp;
 426         numbytes = sizeof (*factsreply);
 427 
 428         /*
 429          * Get port facts reply message via handshake
 430          */
 431         if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
 432                 return (DDI_FAILURE);
 433         }
 434 
 435         if (iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) {
 436                 mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_port_facts_reply: "
 437                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
 438                     ddi_get32(accessp, &factsreply->IOCLogInfo));
 439                 return (DDI_FAILURE);
 440         }
 441 
 442         return (DDI_SUCCESS);
 443 }
 444 
 445 int
 446 mptsas_ioc_enable_port(mptsas_t *mpt)
 447 {
 448         /*
 449          * Send enable port message
 450          */
 451         if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REQUEST), 0,
 452             mptsas_ioc_do_enable_port)) {
 453                 return (DDI_FAILURE);
 454         }
 455 
 456         /*
 457          * Get enable port reply message
 458          */
 459         if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REPLY), 0,
 460             mptsas_ioc_do_enable_port_reply)) {
 461                 return (DDI_FAILURE);
 462         }
 463 
 464         return (DDI_SUCCESS);
 465 }
 466 
 467 static int
 468 mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var,
 469     ddi_acc_handle_t accessp)
 470 {
 471 #ifndef __lock_lint
 472         _NOTE(ARGUNUSED(var))
 473 #endif
 474         pMpi2PortEnableRequest_t        enable;
 475         int                             numbytes;
 476 
 477         bzero(memp, sizeof (*enable));
 478         enable = (void *)memp;
 479         ddi_put8(accessp, &enable->Function, MPI2_FUNCTION_PORT_ENABLE);
 480         numbytes = sizeof (*enable);
 481 
 482         /*
 483          * Send message via handshake
 484          */
 485         if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
 486                 return (DDI_FAILURE);
 487         }
 488 
 489         return (DDI_SUCCESS);
 490 }
 491 
 492 static int
 493 mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var,
 494     ddi_acc_handle_t accessp)
 495 {
 496 #ifndef __lock_lint
 497         _NOTE(ARGUNUSED(var))
 498 #endif
 499 
 500         int                     numbytes;
 501         uint_t                  iocstatus;
 502         pMpi2PortEnableReply_t  portreply;
 503 
 504         numbytes = sizeof (MPI2_PORT_ENABLE_REPLY);
 505         bzero(memp, numbytes);
 506         portreply = (void *)memp;
 507 
 508         /*
 509          * Get message via handshake
 510          */
 511         if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
 512                 return (DDI_FAILURE);
 513         }
 514 
 515         if (iocstatus = ddi_get16(accessp, &portreply->IOCStatus)) {
 516                 mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_enable_port_reply: "
 517                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
 518                     ddi_get32(accessp, &portreply->IOCLogInfo));
 519                 return (DDI_FAILURE);
 520         }
 521 
 522         return (DDI_SUCCESS);
 523 }
 524 
 525 int
 526 mptsas_ioc_enable_event_notification(mptsas_t *mpt)
 527 {
 528         ASSERT(mutex_owned(&mpt->m_mutex));
 529 
 530         /*
 531          * Send enable event notification message
 532          */
 533         if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REQUEST), NULL,
 534             mptsas_ioc_do_enable_event_notification)) {
 535                 return (DDI_FAILURE);
 536         }
 537 
 538         /*
 539          * Get enable event reply message
 540          */
 541         if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REPLY), NULL,
 542             mptsas_ioc_do_enable_event_notification_reply)) {
 543                 return (DDI_FAILURE);
 544         }
 545 
 546         return (DDI_SUCCESS);
 547 }
 548 
 549 static int
 550 mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp, int var,
 551     ddi_acc_handle_t accessp)
 552 {
 553 #ifndef __lock_lint
 554         _NOTE(ARGUNUSED(var))
 555 #endif
 556 
 557         pMpi2EventNotificationRequest_t event;
 558         int                             numbytes;
 559 
 560         bzero(memp, sizeof (*event));
 561         event = (void *)memp;
 562         ddi_put8(accessp, &event->Function, MPI2_FUNCTION_EVENT_NOTIFICATION);
 563         numbytes = sizeof (*event);
 564 
 565         /*
 566          * Send message via handshake
 567          */
 568         if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
 569                 return (DDI_FAILURE);
 570         }
 571 
 572         return (DDI_SUCCESS);
 573 }
 574 
 575 static int
 576 mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt, caddr_t memp,
 577     int var, ddi_acc_handle_t accessp)
 578 {
 579 #ifndef __lock_lint
 580         _NOTE(ARGUNUSED(var))
 581 #endif
 582         int                             numbytes;
 583         uint_t                          iocstatus;
 584         pMpi2EventNotificationReply_t   eventsreply;
 585 
 586         numbytes = sizeof (MPI2_EVENT_NOTIFICATION_REPLY);
 587         bzero(memp, numbytes);
 588         eventsreply = (void *)memp;
 589 
 590         /*
 591          * Get message via handshake
 592          */
 593         if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
 594                 return (DDI_FAILURE);
 595         }
 596 
 597         if (iocstatus = ddi_get16(accessp, &eventsreply->IOCStatus)) {
 598                 mptsas_log(mpt, CE_WARN,
 599                     "mptsas_ioc_do_enable_event_notification_reply: "
 600                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
 601                     ddi_get32(accessp, &eventsreply->IOCLogInfo));
 602                 return (DDI_FAILURE);
 603         }
 604 
 605         return (DDI_SUCCESS);
 606 }
 607 
 608 int
 609 mptsas_ioc_init(mptsas_t *mpt)
 610 {
 611         /*
 612          * Send ioc init message
 613          */
 614         if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REQUEST), NULL,
 615             mptsas_do_ioc_init)) {
 616                 return (DDI_FAILURE);
 617         }
 618 
 619         /*
 620          * Get ioc init reply message
 621          */
 622         if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REPLY), NULL,
 623             mptsas_do_ioc_init_reply)) {
 624                 return (DDI_FAILURE);
 625         }
 626 
 627         return (DDI_SUCCESS);
 628 }
 629 
 630 static int
 631 mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var,
 632     ddi_acc_handle_t accessp)
 633 {
 634 #ifndef __lock_lint
 635         _NOTE(ARGUNUSED(var))
 636 #endif
 637 
 638         pMpi2IOCInitRequest_t   init;
 639         int                     numbytes;
 640         timespec_t              time;
 641         uint64_t                mSec;
 642 
 643         bzero(memp, sizeof (*init));
 644         init = (void *)memp;
 645         ddi_put8(accessp, &init->Function, MPI2_FUNCTION_IOC_INIT);
 646         ddi_put8(accessp, &init->WhoInit, MPI2_WHOINIT_HOST_DRIVER);
 647         ddi_put16(accessp, &init->MsgVersion, MPI2_VERSION);
 648         ddi_put16(accessp, &init->HeaderVersion, MPI2_HEADER_VERSION);
 649         ddi_put16(accessp, &init->SystemRequestFrameSize,
 650             mpt->m_req_frame_size / 4);
 651         ddi_put16(accessp, &init->ReplyDescriptorPostQueueDepth,
 652             mpt->m_post_queue_depth);
 653         ddi_put16(accessp, &init->ReplyFreeQueueDepth,
 654             mpt->m_free_queue_depth);
 655 
 656         /*
 657          * These addresses are set using the DMA cookie addresses from when the
 658          * memory was allocated.  Sense buffer hi address should be 0.
 659          */
 660         ddi_put32(accessp, &init->SenseBufferAddressHigh,
 661             (uint32_t)(mpt->m_req_sense_dma_addr >> 32));
 662         ddi_put32(accessp, &init->SystemReplyAddressHigh,
 663             (uint32_t)(mpt->m_reply_frame_dma_addr >> 32));
 664         ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.High,
 665             (uint32_t)(mpt->m_req_frame_dma_addr >> 32));
 666         ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.Low,
 667             (uint32_t)mpt->m_req_frame_dma_addr);
 668         ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.High,
 669             (uint32_t)(mpt->m_post_queue_dma_addr >> 32));
 670         ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.Low,
 671             (uint32_t)mpt->m_post_queue_dma_addr);
 672         ddi_put32(accessp, &init->ReplyFreeQueueAddress.High,
 673             (uint32_t)(mpt->m_free_queue_dma_addr >> 32));
 674         ddi_put32(accessp, &init->ReplyFreeQueueAddress.Low,
 675             (uint32_t)mpt->m_free_queue_dma_addr);
 676 
 677         /*
 678          * Fill in the timestamp with the number of milliseconds since midnight
 679          * of January 1, 1970 UT (Greenwich Mean Time).  Time is returned in
 680          * seconds and nanoseconds.  Translate both to milliseconds and add
 681          * them together to get total milliseconds.
 682          */
 683         gethrestime(&time);
 684         mSec = time.tv_sec * MILLISEC;
 685         mSec += (time.tv_nsec / MICROSEC);
 686         ddi_put32(accessp, &init->TimeStamp.High, (uint32_t)(mSec >> 32));
 687         ddi_put32(accessp, &init->TimeStamp.Low, (uint32_t)mSec);
 688 
 689         numbytes = sizeof (*init);
 690 
 691         /*
 692          * Post message via handshake
 693          */
 694         if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
 695                 return (DDI_FAILURE);
 696         }
 697 
 698         return (DDI_SUCCESS);
 699 }
 700 
 701 static int
 702 mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var,
 703     ddi_acc_handle_t accessp)
 704 {
 705 #ifndef __lock_lint
 706         _NOTE(ARGUNUSED(var))
 707 #endif
 708 
 709         pMpi2IOCInitReply_t     initreply;
 710         int                     numbytes;
 711         uint_t                  iocstatus;
 712 
 713         numbytes = sizeof (MPI2_IOC_INIT_REPLY);
 714         bzero(memp, numbytes);
 715         initreply = (void *)memp;
 716 
 717         /*
 718          * Get reply message via handshake
 719          */
 720         if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
 721                 return (DDI_FAILURE);
 722         }
 723 
 724         if (iocstatus = ddi_get16(accessp, &initreply->IOCStatus)) {
 725                 mptsas_log(mpt, CE_WARN, "mptsas_do_ioc_init_reply: "
 726                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
 727                     ddi_get32(accessp, &initreply->IOCLogInfo));
 728                 return (DDI_FAILURE);
 729         }
 730 
 731         if ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell)) &
 732             MPI2_IOC_STATE_OPERATIONAL) {
 733                 mptsas_log(mpt, CE_NOTE,
 734                     "?mpt%d: IOC Operational.\n", mpt->m_instance);
 735         } else {
 736                 return (DDI_FAILURE);
 737         }
 738 
 739         return (DDI_SUCCESS);
 740 }