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