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