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