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