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