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