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