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