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