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