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