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