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 */ 26 27 /* 28 * Copyright (c) 2000 to 2009, 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_init - This file contains all the functions used to initialize 56 * MPT2.0 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 69 #pragma pack(1) 70 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h> 71 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h> 72 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h> 73 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h> 74 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h> 75 #pragma pack() 76 /* 77 * private header files. 78 */ 79 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h> 80 81 static int mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var, 82 ddi_acc_handle_t accessp); 83 static int mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var, 84 ddi_acc_handle_t accessp); 85 static int mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var, 86 ddi_acc_handle_t accessp); 87 static int mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp, 88 int var, ddi_acc_handle_t accessp); 89 static int mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var, 90 ddi_acc_handle_t accessp); 91 static int mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var, 92 ddi_acc_handle_t accessp); 93 static int mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp, 94 int var, ddi_acc_handle_t accessp); 95 static int mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt, 96 caddr_t memp, int var, ddi_acc_handle_t accessp); 97 static int mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var, 98 ddi_acc_handle_t accessp); 99 static int mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var, 100 ddi_acc_handle_t accessp); 101 102 static const char * 103 mptsas_product_type_string(mptsas_t *mpt) 104 { 105 switch (mpt->m_productid & MPI2_FW_HEADER_PID_PROD_MASK) { 106 107 case MPI2_FW_HEADER_PID_PROD_A: 108 return ("A"); 109 default: 110 return ("?"); 111 } 112 } 113 114 int 115 mptsas_ioc_get_facts(mptsas_t *mpt) 116 { 117 /* 118 * Send get facts messages 119 */ 120 if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REQUEST), NULL, 121 mptsas_ioc_do_get_facts)) { 122 return (DDI_FAILURE); 123 } 124 125 /* 126 * Get facts reply messages 127 */ 128 if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REPLY), NULL, 129 mptsas_ioc_do_get_facts_reply)) { 130 return (DDI_FAILURE); 131 } 132 133 return (DDI_SUCCESS); 134 } 135 136 static int 137 mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var, 138 ddi_acc_handle_t accessp) 139 { 140 #ifndef __lock_lint 141 _NOTE(ARGUNUSED(var)) 142 #endif 143 pMpi2IOCFactsRequest_t facts; 144 int numbytes; 145 146 bzero(memp, sizeof (*facts)); 147 facts = (void *)memp; 148 ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_IOC_FACTS); 149 numbytes = sizeof (*facts); 150 151 /* 152 * Post message via handshake 153 */ 154 if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) { 155 return (DDI_FAILURE); 156 } 157 158 return (DDI_SUCCESS); 159 } 160 161 static int 162 mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var, 163 ddi_acc_handle_t accessp) 164 { 165 #ifndef __lock_lint 166 _NOTE(ARGUNUSED(var)) 167 #endif 168 169 pMpi2IOCFactsReply_t factsreply; 170 int numbytes; 171 uint_t iocstatus; 172 char buf[32]; 173 uint16_t numReplyFrames; 174 uint16_t queueSize, queueDiff; 175 int simple_sge_main; 176 int simple_sge_next; 177 178 bzero(memp, sizeof (*factsreply)); 179 factsreply = (void *)memp; 180 numbytes = sizeof (*factsreply); 181 182 /* 183 * get ioc facts reply message 184 */ 185 if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) { 186 return (DDI_FAILURE); 187 } 188 189 if (iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) { 190 mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_facts_reply: " 191 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, 192 ddi_get32(accessp, &factsreply->IOCLogInfo)); 193 return (DDI_FAILURE); 194 } 195 196 /* 197 * store key values from reply to mpt structure 198 */ 199 mpt->m_fwversion = ddi_get32(accessp, &factsreply->FWVersion.Word); 200 mpt->m_productid = ddi_get16(accessp, &factsreply->ProductID); 201 202 203 (void) sprintf(buf, "%u.%u.%u.%u", 204 ddi_get8(accessp, &factsreply->FWVersion.Struct.Major), 205 ddi_get8(accessp, &factsreply->FWVersion.Struct.Minor), 206 ddi_get8(accessp, &factsreply->FWVersion.Struct.Unit), 207 ddi_get8(accessp, &factsreply->FWVersion.Struct.Dev)); 208 mptsas_log(mpt, CE_NOTE, "?mpt%d Firmware version v%s (%s)\n", 209 mpt->m_instance, buf, mptsas_product_type_string(mpt)); 210 (void) ddi_prop_update_string(DDI_DEV_T_NONE, mpt->m_dip, 211 "firmware-version", buf); 212 213 /* 214 * Set up request info. 215 */ 216 mpt->m_max_requests = ddi_get16(accessp, 217 &factsreply->RequestCredit) - 1; 218 mpt->m_req_frame_size = ddi_get16(accessp, 219 &factsreply->IOCRequestFrameSize) * 4; 220 221 /* 222 * Size of reply free queue should be the number of requests 223 * plus some additional for events (32). Make sure number of 224 * reply frames is not a multiple of 16 so that the queue sizes 225 * are calculated correctly later to be a multiple of 16. 226 */ 227 mpt->m_reply_frame_size = ddi_get8(accessp, 228 &factsreply->ReplyFrameSize) * 4; 229 numReplyFrames = mpt->m_max_requests + 32; 230 if (!(numReplyFrames % 16)) { 231 numReplyFrames--; 232 } 233 mpt->m_max_replies = numReplyFrames; 234 queueSize = numReplyFrames; 235 queueSize += 16 - (queueSize % 16); 236 mpt->m_free_queue_depth = queueSize; 237 238 /* 239 * Size of reply descriptor post queue should be the number of 240 * request frames + the number of reply frames + 1 and needs to 241 * be a multiple of 16. This size can be no larger than 242 * MaxReplyDescriptorPostQueueDepth from IOCFacts. If the 243 * calculated queue size is larger than allowed, subtract a 244 * multiple of 16 from m_max_requests, m_max_replies, and 245 * m_reply_free_depth. 246 */ 247 queueSize = mpt->m_max_requests + numReplyFrames + 1; 248 if (queueSize % 16) { 249 queueSize += 16 - (queueSize % 16); 250 } 251 mpt->m_post_queue_depth = ddi_get16(accessp, 252 &factsreply->MaxReplyDescriptorPostQueueDepth); 253 if (queueSize > mpt->m_post_queue_depth) { 254 queueDiff = queueSize - mpt->m_post_queue_depth; 255 if (queueDiff % 16) { 256 queueDiff += 16 - (queueDiff % 16); 257 } 258 mpt->m_max_requests -= queueDiff; 259 mpt->m_max_replies -= queueDiff; 260 mpt->m_free_queue_depth -= queueDiff; 261 queueSize -= queueDiff; 262 } 263 mpt->m_post_queue_depth = queueSize; 264 265 /* 266 * Set up other stuff. 267 */ 268 mpt->m_max_chain_depth = ddi_get8(accessp, 269 &factsreply->MaxChainDepth); 270 mpt->m_ioc_capabilities = ddi_get32(accessp, 271 &factsreply->IOCCapabilities); 272 273 /* 274 * Calculate max frames per request based on DMA S/G length. 275 */ 276 277 simple_sge_main = MPTSAS_MAX_FRAME_SGES64(mpt) - 1; 278 simple_sge_next = mpt->m_req_frame_size / 279 sizeof (MPI2_SGE_SIMPLE64) - 1; 280 281 mpt->m_max_request_frames = (MPTSAS_MAX_DMA_SEGS - 282 simple_sge_main) / simple_sge_next + 1; 283 if (((MPTSAS_MAX_DMA_SEGS - simple_sge_main) % 284 simple_sge_next) > 1) { 285 mpt->m_max_request_frames++; 286 } 287 288 return (DDI_SUCCESS); 289 } 290 291 int 292 mptsas_ioc_get_port_facts(mptsas_t *mpt, int port) 293 { 294 /* 295 * Send get port facts message 296 */ 297 if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REQUEST), port, 298 mptsas_ioc_do_get_port_facts)) { 299 return (DDI_FAILURE); 300 } 301 302 /* 303 * Get port facts reply message 304 */ 305 if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REPLY), port, 306 mptsas_ioc_do_get_port_facts_reply)) { 307 return (DDI_FAILURE); 308 } 309 310 return (DDI_SUCCESS); 311 } 312 313 static int 314 mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var, 315 ddi_acc_handle_t accessp) 316 { 317 pMpi2PortFactsRequest_t facts; 318 int numbytes; 319 320 bzero(memp, sizeof (*facts)); 321 facts = (void *)memp; 322 ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_PORT_FACTS); 323 ddi_put8(accessp, &facts->PortNumber, var); 324 numbytes = sizeof (*facts); 325 326 /* 327 * Send port facts message via handshake 328 */ 329 if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) { 330 return (DDI_FAILURE); 331 } 332 333 return (DDI_SUCCESS); 334 } 335 336 static int 337 mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp, int var, 338 ddi_acc_handle_t accessp) 339 { 340 #ifndef __lock_lint 341 _NOTE(ARGUNUSED(var)) 342 #endif 343 pMpi2PortFactsReply_t factsreply; 344 int numbytes; 345 uint_t iocstatus; 346 347 bzero(memp, sizeof (*factsreply)); 348 factsreply = (void *)memp; 349 numbytes = sizeof (*factsreply); 350 351 /* 352 * Get port facts reply message via handshake 353 */ 354 if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) { 355 return (DDI_FAILURE); 356 } 357 358 if (iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) { 359 mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_port_facts_reply: " 360 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, 361 ddi_get32(accessp, &factsreply->IOCLogInfo)); 362 return (DDI_FAILURE); 363 } 364 365 return (DDI_SUCCESS); 366 } 367 368 int 369 mptsas_ioc_enable_port(mptsas_t *mpt) 370 { 371 /* 372 * Send enable port message 373 */ 374 if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REQUEST), 0, 375 mptsas_ioc_do_enable_port)) { 376 return (DDI_FAILURE); 377 } 378 379 /* 380 * Get enable port reply message 381 */ 382 if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REPLY), 0, 383 mptsas_ioc_do_enable_port_reply)) { 384 return (DDI_FAILURE); 385 } 386 387 return (DDI_SUCCESS); 388 } 389 390 static int 391 mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var, 392 ddi_acc_handle_t accessp) 393 { 394 #ifndef __lock_lint 395 _NOTE(ARGUNUSED(var)) 396 #endif 397 pMpi2PortEnableRequest_t enable; 398 int numbytes; 399 400 bzero(memp, sizeof (*enable)); 401 enable = (void *)memp; 402 ddi_put8(accessp, &enable->Function, MPI2_FUNCTION_PORT_ENABLE); 403 numbytes = sizeof (*enable); 404 405 /* 406 * Send message via handshake 407 */ 408 if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) { 409 return (DDI_FAILURE); 410 } 411 412 return (DDI_SUCCESS); 413 } 414 415 static int 416 mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var, 417 ddi_acc_handle_t accessp) 418 { 419 #ifndef __lock_lint 420 _NOTE(ARGUNUSED(var)) 421 #endif 422 423 int numbytes; 424 uint_t iocstatus; 425 pMpi2PortEnableReply_t portreply; 426 427 numbytes = sizeof (MPI2_PORT_ENABLE_REPLY); 428 bzero(memp, numbytes); 429 portreply = (void *)memp; 430 431 /* 432 * Get message via handshake 433 */ 434 if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) { 435 return (DDI_FAILURE); 436 } 437 438 if (iocstatus = ddi_get16(accessp, &portreply->IOCStatus)) { 439 mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_enable_port_reply: " 440 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, 441 ddi_get32(accessp, &portreply->IOCLogInfo)); 442 return (DDI_FAILURE); 443 } 444 445 return (DDI_SUCCESS); 446 } 447 448 int 449 mptsas_ioc_enable_event_notification(mptsas_t *mpt) 450 { 451 ASSERT(mutex_owned(&mpt->m_mutex)); 452 453 /* 454 * Send enable event notification message 455 */ 456 if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REQUEST), NULL, 457 mptsas_ioc_do_enable_event_notification)) { 458 return (DDI_FAILURE); 459 } 460 461 /* 462 * Get enable event reply message 463 */ 464 if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REPLY), NULL, 465 mptsas_ioc_do_enable_event_notification_reply)) { 466 return (DDI_FAILURE); 467 } 468 469 return (DDI_SUCCESS); 470 } 471 472 static int 473 mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp, int var, 474 ddi_acc_handle_t accessp) 475 { 476 #ifndef __lock_lint 477 _NOTE(ARGUNUSED(var)) 478 #endif 479 480 pMpi2EventNotificationRequest_t event; 481 int numbytes; 482 483 bzero(memp, sizeof (*event)); 484 event = (void *)memp; 485 ddi_put8(accessp, &event->Function, MPI2_FUNCTION_EVENT_NOTIFICATION); 486 numbytes = sizeof (*event); 487 488 /* 489 * Send message via handshake 490 */ 491 if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) { 492 return (DDI_FAILURE); 493 } 494 495 return (DDI_SUCCESS); 496 } 497 498 static int 499 mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt, caddr_t memp, 500 int var, ddi_acc_handle_t accessp) 501 { 502 #ifndef __lock_lint 503 _NOTE(ARGUNUSED(var)) 504 #endif 505 int numbytes; 506 uint_t iocstatus; 507 pMpi2EventNotificationReply_t eventsreply; 508 509 numbytes = sizeof (MPI2_EVENT_NOTIFICATION_REPLY); 510 bzero(memp, numbytes); 511 eventsreply = (void *)memp; 512 513 /* 514 * Get message via handshake 515 */ 516 if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) { 517 return (DDI_FAILURE); 518 } 519 520 if (iocstatus = ddi_get16(accessp, &eventsreply->IOCStatus)) { 521 mptsas_log(mpt, CE_WARN, 522 "mptsas_ioc_do_enable_event_notification_reply: " 523 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, 524 ddi_get32(accessp, &eventsreply->IOCLogInfo)); 525 return (DDI_FAILURE); 526 } 527 528 return (DDI_SUCCESS); 529 } 530 531 int 532 mptsas_ioc_init(mptsas_t *mpt) 533 { 534 /* 535 * Send ioc init message 536 */ 537 if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REQUEST), NULL, 538 mptsas_do_ioc_init)) { 539 return (DDI_FAILURE); 540 } 541 542 /* 543 * Get ioc init reply message 544 */ 545 if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REPLY), NULL, 546 mptsas_do_ioc_init_reply)) { 547 return (DDI_FAILURE); 548 } 549 550 return (DDI_SUCCESS); 551 } 552 553 static int 554 mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var, 555 ddi_acc_handle_t accessp) 556 { 557 #ifndef __lock_lint 558 _NOTE(ARGUNUSED(var)) 559 #endif 560 561 pMpi2IOCInitRequest_t init; 562 int numbytes; 563 564 bzero(memp, sizeof (*init)); 565 init = (void *)memp; 566 ddi_put8(accessp, &init->Function, MPI2_FUNCTION_IOC_INIT); 567 ddi_put8(accessp, &init->WhoInit, MPI2_WHOINIT_HOST_DRIVER); 568 ddi_put16(accessp, &init->MsgVersion, MPI2_VERSION); 569 ddi_put16(accessp, &init->HeaderVersion, MPI2_HEADER_VERSION); 570 ddi_put16(accessp, &init->SystemRequestFrameSize, 571 mpt->m_req_frame_size / 4); 572 ddi_put16(accessp, &init->ReplyDescriptorPostQueueDepth, 573 mpt->m_post_queue_depth); 574 ddi_put16(accessp, &init->ReplyFreeQueueDepth, 575 mpt->m_free_queue_depth); 576 577 /* 578 * These addresses are set using the DMA cookie addresses from when the 579 * memory was allocated. Sense buffer hi address should be 0. 580 */ 581 ddi_put32(accessp, &init->SenseBufferAddressHigh, 0); 582 ddi_put32(accessp, &init->SystemReplyAddressHigh, 583 (uint32_t)(mpt->m_reply_frame_dma_addr >> 32)); 584 ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.High, 585 (uint32_t)(mpt->m_req_frame_dma_addr >> 32)); 586 ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.Low, 587 (uint32_t)mpt->m_req_frame_dma_addr); 588 ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.High, 589 (uint32_t)(mpt->m_post_queue_dma_addr >> 32)); 590 ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.Low, 591 (uint32_t)mpt->m_post_queue_dma_addr); 592 ddi_put32(accessp, &init->ReplyFreeQueueAddress.High, 593 (uint32_t)(mpt->m_free_queue_dma_addr >> 32)); 594 ddi_put32(accessp, &init->ReplyFreeQueueAddress.Low, 595 (uint32_t)mpt->m_free_queue_dma_addr); 596 597 numbytes = sizeof (*init); 598 599 /* 600 * Post message via handshake 601 */ 602 if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) { 603 return (DDI_FAILURE); 604 } 605 606 return (DDI_SUCCESS); 607 } 608 609 static int 610 mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var, 611 ddi_acc_handle_t accessp) 612 { 613 #ifndef __lock_lint 614 _NOTE(ARGUNUSED(var)) 615 #endif 616 617 pMpi2IOCInitReply_t initreply; 618 int numbytes; 619 uint_t iocstatus; 620 621 numbytes = sizeof (MPI2_IOC_INIT_REPLY); 622 bzero(memp, numbytes); 623 initreply = (void *)memp; 624 625 /* 626 * Get reply message via handshake 627 */ 628 if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) { 629 return (DDI_FAILURE); 630 } 631 632 if (iocstatus = ddi_get16(accessp, &initreply->IOCStatus)) { 633 mptsas_log(mpt, CE_WARN, "mptsas_do_ioc_init_reply: " 634 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, 635 ddi_get32(accessp, &initreply->IOCLogInfo)); 636 return (DDI_FAILURE); 637 } 638 639 if ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell)) & 640 MPI2_IOC_STATE_OPERATIONAL) { 641 mptsas_log(mpt, CE_NOTE, 642 "?mpt%d: IOC Operational.\n", mpt->m_instance); 643 } else { 644 return (DDI_FAILURE); 645 } 646 647 return (DDI_SUCCESS); 648 } 649