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