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