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