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