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