Merge commit '9276b3991ba20d5a5660887ba81b0bc7bed25a0c'
[unleashed.git] / usr / src / uts / common / io / scsi / adapters / mpt_sas / mptsas_impl.c
blob0e84fbd80d7b5f30ea83dcac4d7c7a3815f5199b
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
26 * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
27 * Copyright (c) 2017, Joyent, Inc.
31 * Copyright (c) 2000 to 2010, LSI Corporation.
32 * All rights reserved.
34 * Redistribution and use in source and binary forms of all code within
35 * this file that is exclusively owned by LSI, with or without
36 * modification, is permitted provided that, in addition to the CDDL 1.0
37 * License requirements, the following conditions are met:
39 * Neither the name of the author nor the names of its contributors may be
40 * used to endorse or promote products derived from this software without
41 * specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
46 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
47 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
48 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
49 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
50 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
51 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
52 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
53 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
54 * DAMAGE.
58 * mptsas_impl - This file contains all the basic functions for communicating
59 * to MPT based hardware.
62 #if defined(DEBUG)
63 #define MPTSAS_DEBUG
64 #endif
67 * standard header files
69 #include <sys/note.h>
70 #include <sys/scsi/scsi.h>
71 #include <sys/pci.h>
73 #pragma pack(1)
74 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
75 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
76 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
77 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
78 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
79 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
80 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
81 #pragma pack()
84 * private header files.
86 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
87 #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
90 * FMA header files.
92 #include <sys/fm/io/ddi.h>
95 * prototypes
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);
103 * add ioc evnet cmd into the queue
105 static void
106 mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd)
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;
119 * remove specified cmd from the ioc event queue
121 static void
122 mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd)
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;
129 cmd->m_event_linkp = NULL;
130 return;
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;
139 cmd->m_event_linkp = NULL;
140 return;
142 prev = prev->m_event_linkp;
146 static m_event_struct_t *
147 mptsas_ioc_event_find_by_cmd(mptsas_t *mpt, struct mptsas_cmd *cmd)
149 m_event_struct_t *ioc_cmd = NULL;
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);
156 ioc_cmd = ioc_cmd->m_event_linkp;
158 ioc_cmd = NULL;
159 return (ioc_cmd);
162 void
163 mptsas_destroy_ioc_event_cmd(mptsas_t *mpt)
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;
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.
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 {
189 * it's not ack cmd, so continue to check next one
192 NDBG20(("destroy!! it's not Ack Flag, continue\n"));
193 ioc_cmd = ioc_cmd->m_event_linkp;
199 void
200 mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd)
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;
208 uint64_t request_desc;
210 ASSERT(mutex_owned(&mpt->m_mutex));
213 * Point to the correct message and clear it as well as the global
214 * config page memory.
216 request = (pMpi2ConfigRequest_t)(mpt->m_req_frame +
217 (mpt->m_req_frame_size * cmd->cmd_slot));
218 bzero(request, mpt->m_req_frame_size);
221 * Form the request message.
223 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Function,
224 MPI2_FUNCTION_CONFIG);
225 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Action, config->action);
226 direction = MPI2_SGE_FLAGS_IOC_TO_HOST;
227 length = 0;
228 sge = (pMpi2SGESimple64_t)&request->PageBufferSGE;
229 if (config->action == MPI2_CONFIG_ACTION_PAGE_HEADER) {
230 if (config->page_type > MPI2_CONFIG_PAGETYPE_MASK) {
231 ddi_put8(mpt->m_acc_req_frame_hdl,
232 &request->Header.PageType,
233 MPI2_CONFIG_PAGETYPE_EXTENDED);
234 ddi_put8(mpt->m_acc_req_frame_hdl,
235 &request->ExtPageType, config->page_type);
236 } else {
237 ddi_put8(mpt->m_acc_req_frame_hdl,
238 &request->Header.PageType, config->page_type);
240 } else {
241 ddi_put8(mpt->m_acc_req_frame_hdl, &request->ExtPageType,
242 config->ext_page_type);
243 ddi_put16(mpt->m_acc_req_frame_hdl, &request->ExtPageLength,
244 config->ext_page_length);
245 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageType,
246 config->page_type);
247 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageLength,
248 config->page_length);
249 ddi_put8(mpt->m_acc_req_frame_hdl,
250 &request->Header.PageVersion, config->page_version);
251 if ((config->page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
252 MPI2_CONFIG_PAGETYPE_EXTENDED) {
253 length = config->ext_page_length * 4;
254 } else {
255 length = config->page_length * 4;
258 if (config->action == MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
259 direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
261 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
262 (uint32_t)cmd->cmd_dma_addr);
263 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
264 (uint32_t)(cmd->cmd_dma_addr >> 32));
266 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageNumber,
267 config->page_number);
268 ddi_put32(mpt->m_acc_req_frame_hdl, &request->PageAddress,
269 config->page_address);
270 flagslength = ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
271 MPI2_SGE_FLAGS_END_OF_BUFFER |
272 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
273 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
274 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
275 direction |
276 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
277 flagslength |= length;
278 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
280 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
281 DDI_DMA_SYNC_FORDEV);
282 request_desc = (cmd->cmd_slot << 16) +
283 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
284 cmd->cmd_rfm = 0;
285 MPTSAS_START_CMD(mpt, request_desc);
286 if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
287 DDI_SUCCESS) ||
288 (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
289 DDI_SUCCESS)) {
290 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
295 mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
296 uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
297 caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...)
299 va_list ap;
300 ddi_dma_attr_t attrs;
301 ddi_dma_cookie_t cookie;
302 ddi_acc_handle_t accessp;
303 size_t len = 0;
304 mptsas_config_request_t config;
305 int rval = DDI_SUCCESS, config_flags = 0;
306 mptsas_cmd_t *cmd;
307 struct scsi_pkt *pkt;
308 pMpi2ConfigReply_t reply;
309 uint16_t iocstatus = 0;
310 uint32_t iocloginfo;
311 caddr_t page_memp;
312 boolean_t free_dma = B_FALSE;
314 va_start(ap, callback);
315 ASSERT(mutex_owned(&mpt->m_mutex));
318 * Get a command from the pool.
320 if ((rval = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
321 mptsas_log(mpt, CE_NOTE, "command pool is full for config "
322 "page request");
323 rval = DDI_FAILURE;
324 goto page_done;
326 config_flags |= MPTSAS_REQUEST_POOL_CMD;
328 bzero((caddr_t)cmd, sizeof (*cmd));
329 bzero((caddr_t)pkt, scsi_pkt_size());
330 bzero((caddr_t)&config, sizeof (config));
333 * Save the data for this request to be used in the call to start the
334 * config header request.
336 config.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
337 config.page_type = page_type;
338 config.page_number = page_number;
339 config.page_address = page_address;
342 * Form a blank cmd/pkt to store the acknowledgement message
344 pkt->pkt_ha_private = (opaque_t)&config;
345 pkt->pkt_flags = FLAG_HEAD;
346 pkt->pkt_time = 60;
347 cmd->cmd_pkt = pkt;
348 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_CONFIG;
351 * Save the config header request message in a slot.
353 if (mptsas_save_cmd(mpt, cmd) == TRUE) {
354 cmd->cmd_flags |= CFLAG_PREPARED;
355 mptsas_start_config_page_access(mpt, cmd);
356 } else {
357 mptsas_waitq_add(mpt, cmd);
361 * If this is a request for a RAID info page, or any page called during
362 * the RAID info page request, poll because these config page requests
363 * are nested. Poll to avoid data corruption due to one page's data
364 * overwriting the outer page request's data. This can happen when
365 * the mutex is released in cv_wait.
367 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
368 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
369 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
370 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
371 } else {
372 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
373 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
378 * Check if the header request completed without timing out
380 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
381 mptsas_log(mpt, CE_WARN, "config header request timeout");
382 rval = DDI_FAILURE;
383 goto page_done;
387 * cmd_rfm points to the reply message if a reply was given. Check the
388 * IOCStatus to make sure everything went OK with the header request.
390 if (cmd->cmd_rfm) {
391 config_flags |= MPTSAS_ADDRESS_REPLY;
392 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
393 DDI_DMA_SYNC_FORCPU);
394 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
395 - (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
396 config.page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
397 &reply->Header.PageType);
398 config.page_number = ddi_get8(mpt->m_acc_reply_frame_hdl,
399 &reply->Header.PageNumber);
400 config.page_length = ddi_get8(mpt->m_acc_reply_frame_hdl,
401 &reply->Header.PageLength);
402 config.page_version = ddi_get8(mpt->m_acc_reply_frame_hdl,
403 &reply->Header.PageVersion);
404 config.ext_page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
405 &reply->ExtPageType);
406 config.ext_page_length = ddi_get16(mpt->m_acc_reply_frame_hdl,
407 &reply->ExtPageLength);
409 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
410 &reply->IOCStatus);
411 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
412 &reply->IOCLogInfo);
414 if (iocstatus) {
415 NDBG13(("mptsas_access_config_page header: "
416 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
417 iocloginfo));
418 rval = DDI_FAILURE;
419 goto page_done;
422 if ((config.page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
423 MPI2_CONFIG_PAGETYPE_EXTENDED)
424 len = (config.ext_page_length * 4);
425 else
426 len = (config.page_length * 4);
430 if (pkt->pkt_reason == CMD_RESET) {
431 mptsas_log(mpt, CE_WARN, "ioc reset abort config header "
432 "request");
433 rval = DDI_FAILURE;
434 goto page_done;
438 * Put the reply frame back on the free queue, increment the free
439 * index, and write the new index to the free index register. But only
440 * if this reply is an ADDRESS reply.
442 if (config_flags & MPTSAS_ADDRESS_REPLY) {
443 ddi_put32(mpt->m_acc_free_queue_hdl,
444 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
445 cmd->cmd_rfm);
446 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
447 DDI_DMA_SYNC_FORDEV);
448 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
449 mpt->m_free_index = 0;
451 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
452 mpt->m_free_index);
453 config_flags &= (~MPTSAS_ADDRESS_REPLY);
457 * Allocate DMA buffer here. Store the info regarding this buffer in
458 * the cmd struct so that it can be used for this specific command and
459 * de-allocated after the command completes. The size of the reply
460 * will not be larger than the reply frame size.
462 attrs = mpt->m_msg_dma_attr;
463 attrs.dma_attr_sgllen = 1;
464 attrs.dma_attr_granular = (uint32_t)len;
466 if (mptsas_dma_addr_create(mpt, attrs,
467 &cmd->cmd_dmahandle, &accessp, &page_memp,
468 len, &cookie) == FALSE) {
469 rval = DDI_FAILURE;
470 mptsas_log(mpt, CE_WARN,
471 "mptsas_dma_addr_create(len=0x%x) failed", (int)len);
472 goto page_done;
474 /* NOW we can safely call mptsas_dma_addr_destroy(). */
475 free_dma = B_TRUE;
477 cmd->cmd_dma_addr = cookie.dmac_laddress;
478 bzero(page_memp, len);
481 * Save the data for this request to be used in the call to start the
482 * config page read
484 config.action = action;
485 config.page_address = page_address;
488 * Re-use the cmd that was used to get the header. Reset some of the
489 * values.
491 bzero((caddr_t)pkt, scsi_pkt_size());
492 pkt->pkt_ha_private = (opaque_t)&config;
493 pkt->pkt_flags = FLAG_HEAD;
494 pkt->pkt_time = 60;
495 cmd->cmd_flags = CFLAG_PREPARED | CFLAG_CMDIOC | CFLAG_CONFIG;
498 * Send the config page request. cmd is re-used from header request.
500 mptsas_start_config_page_access(mpt, cmd);
503 * If this is a request for a RAID info page, or any page called during
504 * the RAID info page request, poll because these config page requests
505 * are nested. Poll to avoid data corruption due to one page's data
506 * overwriting the outer page request's data. This can happen when
507 * the mutex is released in cv_wait.
509 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
510 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
511 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
512 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
513 } else {
514 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
515 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
520 * Check if the request completed without timing out
522 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
523 mptsas_log(mpt, CE_WARN, "config page request timeout");
524 rval = DDI_FAILURE;
525 goto page_done;
529 * cmd_rfm points to the reply message if a reply was given. The reply
530 * frame and the config page are returned from this function in the
531 * param list.
533 if (cmd->cmd_rfm) {
534 config_flags |= MPTSAS_ADDRESS_REPLY;
535 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
536 DDI_DMA_SYNC_FORCPU);
537 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
538 DDI_DMA_SYNC_FORCPU);
539 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
540 - (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
541 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
542 &reply->IOCStatus);
543 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
544 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
545 &reply->IOCLogInfo);
548 if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)) {
549 rval = DDI_FAILURE;
550 goto page_done;
553 mptsas_fma_check(mpt, cmd);
555 * Check the DMA/ACC handles and then free the DMA buffer.
557 if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
558 (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
559 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
560 rval = DDI_FAILURE;
563 if (pkt->pkt_reason == CMD_TRAN_ERR) {
564 mptsas_log(mpt, CE_WARN, "config fma error");
565 rval = DDI_FAILURE;
566 goto page_done;
568 if (pkt->pkt_reason == CMD_RESET) {
569 mptsas_log(mpt, CE_WARN, "ioc reset abort config request");
570 rval = DDI_FAILURE;
571 goto page_done;
574 page_done:
575 va_end(ap);
577 * Put the reply frame back on the free queue, increment the free
578 * index, and write the new index to the free index register. But only
579 * if this reply is an ADDRESS reply.
581 if (config_flags & MPTSAS_ADDRESS_REPLY) {
582 ddi_put32(mpt->m_acc_free_queue_hdl,
583 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
584 cmd->cmd_rfm);
585 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
586 DDI_DMA_SYNC_FORDEV);
587 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
588 mpt->m_free_index = 0;
590 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
591 mpt->m_free_index);
594 if (free_dma)
595 mptsas_dma_addr_destroy(&cmd->cmd_dmahandle, &accessp);
597 if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
598 mptsas_remove_cmd(mpt, cmd);
599 config_flags &= (~MPTSAS_REQUEST_POOL_CMD);
601 if (config_flags & MPTSAS_REQUEST_POOL_CMD)
602 mptsas_return_to_pool(mpt, cmd);
604 if (config_flags & MPTSAS_CMD_TIMEOUT) {
605 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
606 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
607 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
611 return (rval);
615 mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action, uint8_t pagetype,
616 uint32_t pageaddress, uint8_t pagenumber, uint8_t pageversion,
617 uint8_t pagelength, uint32_t SGEflagslength, uint64_t SGEaddress)
619 pMpi2ConfigRequest_t config;
620 int send_numbytes;
622 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
623 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
624 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
625 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
626 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
627 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType, pagetype);
628 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
629 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
630 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageLength, pagelength);
631 ddi_put32(mpt->m_hshk_acc_hdl,
632 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
633 ddi_put32(mpt->m_hshk_acc_hdl,
634 &config->PageBufferSGE.MpiSimple.u.Address64.Low, SGEaddress);
635 ddi_put32(mpt->m_hshk_acc_hdl,
636 &config->PageBufferSGE.MpiSimple.u.Address64.High,
637 SGEaddress >> 32);
638 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
641 * Post message via handshake
643 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
644 mpt->m_hshk_acc_hdl)) {
645 return (-1);
647 return (0);
651 mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
652 uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
653 uint8_t pageversion, uint16_t extpagelength,
654 uint32_t SGEflagslength, uint64_t SGEaddress)
656 pMpi2ConfigRequest_t config;
657 int send_numbytes;
659 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
660 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
661 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
662 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
663 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
664 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType,
665 MPI2_CONFIG_PAGETYPE_EXTENDED);
666 ddi_put8(mpt->m_hshk_acc_hdl, &config->ExtPageType, extpagetype);
667 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
668 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
669 ddi_put16(mpt->m_hshk_acc_hdl, &config->ExtPageLength, extpagelength);
670 ddi_put32(mpt->m_hshk_acc_hdl,
671 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
672 ddi_put32(mpt->m_hshk_acc_hdl,
673 &config->PageBufferSGE.MpiSimple.u.Address64.Low, SGEaddress);
674 ddi_put32(mpt->m_hshk_acc_hdl,
675 &config->PageBufferSGE.MpiSimple.u.Address64.High,
676 SGEaddress >> 32);
677 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
680 * Post message via handshake
682 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
683 mpt->m_hshk_acc_hdl)) {
684 return (-1);
686 return (0);
690 mptsas_ioc_wait_for_response(mptsas_t *mpt)
692 int polls = 0;
694 while ((ddi_get32(mpt->m_datap,
695 &mpt->m_reg->HostInterruptStatus) & MPI2_HIS_IOP_DOORBELL_STATUS)) {
696 drv_usecwait(1000);
697 if (polls++ > 60000) {
698 return (-1);
701 return (0);
705 mptsas_ioc_wait_for_doorbell(mptsas_t *mpt)
707 int polls = 0;
709 while ((ddi_get32(mpt->m_datap,
710 &mpt->m_reg->HostInterruptStatus) & MPI2_HIM_DIM) == 0) {
711 drv_usecwait(1000);
712 if (polls++ > 300000) {
713 return (-1);
716 return (0);
720 mptsas_send_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
721 ddi_acc_handle_t accessp)
723 int i;
726 * clean pending doorbells
728 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
729 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
730 ((MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) |
731 ((numbytes / 4) << MPI2_DOORBELL_ADD_DWORDS_SHIFT)));
733 if (mptsas_ioc_wait_for_doorbell(mpt)) {
734 NDBG19(("mptsas_send_handshake failed. Doorbell not ready\n"));
735 return (-1);
739 * clean pending doorbells again
741 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
743 if (mptsas_ioc_wait_for_response(mpt)) {
744 NDBG19(("mptsas_send_handshake failed. Doorbell not "
745 "cleared\n"));
746 return (-1);
750 * post handshake message
752 for (i = 0; (i < numbytes / 4); i++, memp += 4) {
753 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
754 ddi_get32(accessp, (uint32_t *)((void *)(memp))));
755 if (mptsas_ioc_wait_for_response(mpt)) {
756 NDBG19(("mptsas_send_handshake failed posting "
757 "message\n"));
758 return (-1);
762 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
763 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
764 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
765 return (-1);
768 return (0);
772 mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
773 ddi_acc_handle_t accessp)
775 int i, totalbytes, bytesleft;
776 uint16_t val;
779 * wait for doorbell
781 if (mptsas_ioc_wait_for_doorbell(mpt)) {
782 NDBG19(("mptsas_get_handshake failed. Doorbell not ready\n"));
783 return (-1);
787 * get first 2 bytes of handshake message to determine how much
788 * data we will be getting
790 for (i = 0; i < 2; i++, memp += 2) {
791 val = (ddi_get32(mpt->m_datap,
792 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
793 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
794 if (mptsas_ioc_wait_for_doorbell(mpt)) {
795 NDBG19(("mptsas_get_handshake failure getting initial"
796 " data\n"));
797 return (-1);
799 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
800 if (i == 1) {
801 totalbytes = (val & 0xFF) * 2;
806 * If we are expecting less bytes than the message wants to send
807 * we simply save as much as we expected and then throw out the rest
808 * later
810 if (totalbytes > (numbytes / 2)) {
811 bytesleft = ((numbytes / 2) - 2);
812 } else {
813 bytesleft = (totalbytes - 2);
817 * Get the rest of the data
819 for (i = 0; i < bytesleft; i++, memp += 2) {
820 val = (ddi_get32(mpt->m_datap,
821 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
822 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
823 if (mptsas_ioc_wait_for_doorbell(mpt)) {
824 NDBG19(("mptsas_get_handshake failure getting"
825 " main data\n"));
826 return (-1);
828 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
832 * Sometimes the device will send more data than is expected
833 * This data is not used by us but needs to be cleared from
834 * ioc doorbell. So we just read the values and throw
835 * them out.
837 if (totalbytes > (numbytes / 2)) {
838 for (i = (numbytes / 2); i < totalbytes; i++) {
839 val = (ddi_get32(mpt->m_datap,
840 &mpt->m_reg->Doorbell) &
841 MPI2_DOORBELL_DATA_MASK);
842 ddi_put32(mpt->m_datap,
843 &mpt->m_reg->HostInterruptStatus, 0);
844 if (mptsas_ioc_wait_for_doorbell(mpt)) {
845 NDBG19(("mptsas_get_handshake failure getting "
846 "extra garbage data\n"));
847 return (-1);
852 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
854 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
855 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
856 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
857 return (-1);
860 return (0);
864 mptsas_kick_start(mptsas_t *mpt)
866 int polls = 0;
867 uint32_t diag_reg, ioc_state, saved_HCB_size;
870 * Start a hard reset. Write magic number and wait 500 mSeconds.
872 MPTSAS_ENABLE_DRWE(mpt);
873 drv_usecwait(500000);
876 * Read the current Diag Reg and save the Host Controlled Boot size.
878 diag_reg = ddi_get32(mpt->m_datap, &mpt->m_reg->HostDiagnostic);
879 saved_HCB_size = ddi_get32(mpt->m_datap, &mpt->m_reg->HCBSize);
882 * Set Reset Adapter bit and wait 50 mSeconds.
884 diag_reg |= MPI2_DIAG_RESET_ADAPTER;
885 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
886 drv_usecwait(50000);
889 * Poll, waiting for Reset Adapter bit to clear. 300 Seconds max
890 * (600000 * 500 = 300,000,000 uSeconds, 300 seconds).
891 * If no more adapter (all FF's), just return failure.
893 for (polls = 0; polls < 600000; polls++) {
894 diag_reg = ddi_get32(mpt->m_datap,
895 &mpt->m_reg->HostDiagnostic);
896 if (diag_reg == 0xFFFFFFFF) {
897 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
898 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
899 return (DDI_FAILURE);
901 if (!(diag_reg & MPI2_DIAG_RESET_ADAPTER)) {
902 break;
904 drv_usecwait(500);
906 if (polls == 600000) {
907 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
908 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
909 return (DDI_FAILURE);
913 * Check if adapter is in Host Boot Mode. If so, restart adapter
914 * assuming the HCB points to good FW.
915 * Set BootDeviceSel to HCDW (Host Code and Data Window).
917 if (diag_reg & MPI2_DIAG_HCB_MODE) {
918 diag_reg &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
919 diag_reg |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
920 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
923 * Re-enable the HCDW.
925 ddi_put32(mpt->m_datap, &mpt->m_reg->HCBSize,
926 (saved_HCB_size | MPI2_HCB_SIZE_HCB_ENABLE));
930 * Restart the adapter.
932 diag_reg &= ~MPI2_DIAG_HOLD_IOC_RESET;
933 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
936 * Disable writes to the Host Diag register.
938 ddi_put32(mpt->m_datap, &mpt->m_reg->WriteSequence,
939 MPI2_WRSEQ_FLUSH_KEY_VALUE);
942 * Wait 60 seconds max for FW to come to ready state.
944 for (polls = 0; polls < 60000; polls++) {
945 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
946 if (ioc_state == 0xFFFFFFFF) {
947 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
948 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
949 return (DDI_FAILURE);
951 if ((ioc_state & MPI2_IOC_STATE_MASK) ==
952 MPI2_IOC_STATE_READY) {
953 break;
955 drv_usecwait(1000);
957 if (polls == 60000) {
958 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
959 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
960 return (DDI_FAILURE);
964 * Clear the ioc ack events queue.
966 mptsas_destroy_ioc_event_cmd(mpt);
968 return (DDI_SUCCESS);
972 mptsas_ioc_reset(mptsas_t *mpt, int first_time)
974 int polls = 0;
975 uint32_t reset_msg;
976 uint32_t ioc_state;
978 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
980 * If chip is already in ready state then there is nothing to do.
982 if (ioc_state == MPI2_IOC_STATE_READY) {
983 return (MPTSAS_NO_RESET);
986 * If the chip is already operational, we just need to send
987 * it a message unit reset to put it back in the ready state
989 if (ioc_state & MPI2_IOC_STATE_OPERATIONAL) {
991 * If the first time, try MUR anyway, because we haven't even
992 * queried the card for m_event_replay and other capabilities.
993 * Other platforms do it this way, we can still do a hard
994 * reset if we need to, MUR takes less time than a full
995 * adapter reset, and there are reports that some HW
996 * combinations will lock up when receiving a hard reset.
998 if ((first_time || mpt->m_event_replay) &&
999 (mpt->m_softstate & MPTSAS_SS_MSG_UNIT_RESET)) {
1000 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1001 reset_msg = MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET;
1002 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
1003 (reset_msg << MPI2_DOORBELL_FUNCTION_SHIFT));
1004 if (mptsas_ioc_wait_for_response(mpt)) {
1005 NDBG19(("mptsas_ioc_reset failure sending "
1006 "message_unit_reset\n"));
1007 goto hard_reset;
1011 * Wait no more than 60 seconds for chip to become
1012 * ready.
1014 while ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell) &
1015 MPI2_IOC_STATE_READY) == 0x0) {
1016 drv_usecwait(1000);
1017 if (polls++ > 60000) {
1018 goto hard_reset;
1023 * Save the last reset mode done on IOC which will be
1024 * helpful while resuming from suspension.
1026 mpt->m_softstate |= MPTSAS_DID_MSG_UNIT_RESET;
1029 * the message unit reset would do reset operations
1030 * clear reply and request queue, so we should clear
1031 * ACK event cmd.
1033 mptsas_destroy_ioc_event_cmd(mpt);
1034 return (MPTSAS_SUCCESS_MUR);
1037 hard_reset:
1038 mpt->m_softstate &= ~MPTSAS_DID_MSG_UNIT_RESET;
1039 if (mptsas_kick_start(mpt) == DDI_FAILURE) {
1040 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
1041 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
1042 return (MPTSAS_RESET_FAIL);
1044 return (MPTSAS_SUCCESS_HARDRESET);
1049 mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
1050 struct scsi_pkt **pkt)
1052 m_event_struct_t *ioc_cmd = NULL;
1054 ioc_cmd = kmem_zalloc(M_EVENT_STRUCT_SIZE, KM_SLEEP);
1055 if (ioc_cmd == NULL) {
1056 return (DDI_FAILURE);
1058 ioc_cmd->m_event_linkp = NULL;
1059 mptsas_ioc_event_cmdq_add(mpt, ioc_cmd);
1060 *cmd = &(ioc_cmd->m_event_cmd);
1061 *pkt = &(ioc_cmd->m_event_pkt);
1063 return (DDI_SUCCESS);
1066 void
1067 mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd)
1069 m_event_struct_t *ioc_cmd = NULL;
1071 ioc_cmd = mptsas_ioc_event_find_by_cmd(mpt, cmd);
1072 if (ioc_cmd == NULL) {
1073 return;
1076 mptsas_ioc_event_cmdq_delete(mpt, ioc_cmd);
1077 kmem_free(ioc_cmd, M_EVENT_STRUCT_SIZE);
1078 ioc_cmd = NULL;
1082 * NOTE: We should be able to queue TM requests in the controller to make this
1083 * a lot faster. If resetting all targets, for example, we can load the hi
1084 * priority queue with its limit and the controller will reply as they are
1085 * completed. This way, we don't have to poll for one reply at a time.
1086 * Think about enhancing this later.
1089 mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
1090 int lun, uint8_t *reply, uint32_t reply_size, int mode)
1093 * In order to avoid allocating variables on the stack,
1094 * we make use of the pre-existing mptsas_cmd_t and
1095 * scsi_pkt which are included in the mptsas_t which
1096 * is passed to this routine.
1099 pMpi2SCSITaskManagementRequest_t task;
1100 int rval = FALSE;
1101 mptsas_cmd_t *cmd;
1102 struct scsi_pkt *pkt;
1103 mptsas_slots_t *slots = mpt->m_active;
1104 uint64_t request_desc, i;
1105 pMPI2DefaultReply_t reply_msg;
1108 * Can't start another task management routine.
1110 if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1111 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1112 " command at a time\n");
1113 return (FALSE);
1116 cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1117 pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1119 bzero((caddr_t)cmd, sizeof (*cmd));
1120 bzero((caddr_t)pkt, scsi_pkt_size());
1122 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1123 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1124 pkt->pkt_ha_private = (opaque_t)cmd;
1125 pkt->pkt_flags = (FLAG_NOINTR | FLAG_HEAD);
1126 pkt->pkt_time = 60;
1127 pkt->pkt_address.a_target = dev_handle;
1128 pkt->pkt_address.a_lun = (uchar_t)lun;
1129 cmd->cmd_pkt = pkt;
1130 cmd->cmd_scblen = 1;
1131 cmd->cmd_flags = CFLAG_TM_CMD;
1132 cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
1134 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
1137 * Store the TM message in memory location corresponding to the TM slot
1138 * number.
1140 task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
1141 (mpt->m_req_frame_size * cmd->cmd_slot));
1142 bzero(task, mpt->m_req_frame_size);
1145 * form message for requested task
1147 mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
1148 MPI2_FUNCTION_SCSI_TASK_MGMT);
1151 * Set the task type
1153 ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
1156 * Send TM request using High Priority Queue.
1158 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1159 DDI_DMA_SYNC_FORDEV);
1160 request_desc = (cmd->cmd_slot << 16) +
1161 MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1162 MPTSAS_START_CMD(mpt, request_desc);
1163 rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
1165 if (pkt->pkt_reason == CMD_INCOMPLETE)
1166 rval = FALSE;
1169 * If a reply frame was used and there is a reply buffer to copy the
1170 * reply data into, copy it. If this fails, log a message, but don't
1171 * fail the TM request.
1173 if (cmd->cmd_rfm && reply) {
1174 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
1175 DDI_DMA_SYNC_FORCPU);
1176 reply_msg = (pMPI2DefaultReply_t)
1177 (mpt->m_reply_frame + (cmd->cmd_rfm -
1178 (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
1179 if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
1180 reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
1182 mutex_exit(&mpt->m_mutex);
1183 for (i = 0; i < reply_size; i++) {
1184 if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
1185 mode)) {
1186 mptsas_log(mpt, CE_WARN, "failed to copy out "
1187 "reply data for TM request");
1188 break;
1191 mutex_enter(&mpt->m_mutex);
1195 * clear the TM slot before returning
1197 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
1200 * If we lost our task management command
1201 * we need to reset the ioc
1203 if (rval == FALSE) {
1204 mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1205 "try to reset ioc to recovery!");
1206 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1207 if (mptsas_restart_ioc(mpt)) {
1208 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1209 rval = FAILED;
1213 return (rval);
1217 * Complete firmware download frame for v2.0 cards.
1219 static void
1220 mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,
1221 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1222 ddi_dma_cookie_t flsh_cookie)
1224 pMpi2FWDownloadTCSGE_t tcsge;
1225 pMpi2SGESimple64_t sge;
1226 uint32_t flagslength;
1228 ddi_put8(acc_hdl, &fwdownload->Function,
1229 MPI2_FUNCTION_FW_DOWNLOAD);
1230 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1231 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1232 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1233 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1235 tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1236 ddi_put8(acc_hdl, &tcsge->ContextSize, 0);
1237 ddi_put8(acc_hdl, &tcsge->DetailsLength, 12);
1238 ddi_put8(acc_hdl, &tcsge->Flags, 0);
1239 ddi_put32(acc_hdl, &tcsge->ImageOffset, 0);
1240 ddi_put32(acc_hdl, &tcsge->ImageSize, size);
1242 sge = (pMpi2SGESimple64_t)(tcsge + 1);
1243 flagslength = size;
1244 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1245 MPI2_SGE_FLAGS_END_OF_BUFFER |
1246 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1247 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1248 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1249 MPI2_SGE_FLAGS_HOST_TO_IOC |
1250 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1251 ddi_put32(acc_hdl, &sge->FlagsLength, flagslength);
1252 ddi_put32(acc_hdl, &sge->Address.Low,
1253 flsh_cookie.dmac_address);
1254 ddi_put32(acc_hdl, &sge->Address.High,
1255 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1259 * Complete firmware download frame for v2.5 cards.
1261 static void
1262 mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,
1263 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1264 ddi_dma_cookie_t flsh_cookie)
1266 pMpi2IeeeSgeSimple64_t sge;
1267 uint8_t flags;
1269 ddi_put8(acc_hdl, &fwdownload->Function,
1270 MPI2_FUNCTION_FW_DOWNLOAD);
1271 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1272 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1273 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1274 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1276 ddi_put32(acc_hdl, &fwdownload->ImageOffset, 0);
1277 ddi_put32(acc_hdl, &fwdownload->ImageSize, size);
1279 sge = (pMpi2IeeeSgeSimple64_t)&fwdownload->SGL;
1280 flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
1281 MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
1282 MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
1283 ddi_put8(acc_hdl, &sge->Flags, flags);
1284 ddi_put32(acc_hdl, &sge->Length, size);
1285 ddi_put32(acc_hdl, &sge->Address.Low,
1286 flsh_cookie.dmac_address);
1287 ddi_put32(acc_hdl, &sge->Address.High,
1288 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1291 static int mptsas_enable_mpi25_flashupdate = 0;
1294 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1295 uint8_t type, int mode)
1299 * In order to avoid allocating variables on the stack,
1300 * we make use of the pre-existing mptsas_cmd_t and
1301 * scsi_pkt which are included in the mptsas_t which
1302 * is passed to this routine.
1305 ddi_dma_attr_t flsh_dma_attrs;
1306 ddi_dma_cookie_t flsh_cookie;
1307 ddi_dma_handle_t flsh_dma_handle;
1308 ddi_acc_handle_t flsh_accessp;
1309 caddr_t memp, flsh_memp;
1310 mptsas_cmd_t *cmd;
1311 struct scsi_pkt *pkt;
1312 int i;
1313 int rvalue = 0;
1314 uint64_t request_desc;
1316 if (mpt->m_MPI25 && !mptsas_enable_mpi25_flashupdate) {
1318 * The code is there but not tested yet.
1319 * User has to know there are risks here.
1321 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1322 "Updating firmware through MPI 2.5 has not been "
1323 "tested yet!\n"
1324 "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
1325 return (-1);
1326 } /* Otherwise, you pay your money and you take your chances. */
1328 if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1329 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1330 "failed. event ack command pool is full\n");
1331 return (rvalue);
1334 bzero((caddr_t)cmd, sizeof (*cmd));
1335 bzero((caddr_t)pkt, scsi_pkt_size());
1336 cmd->ioc_cmd_slot = (uint32_t)rvalue;
1339 * dynamically create a customized dma attribute structure
1340 * that describes the flash file.
1342 flsh_dma_attrs = mpt->m_msg_dma_attr;
1343 flsh_dma_attrs.dma_attr_sgllen = 1;
1345 if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1346 &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1347 mptsas_log(mpt, CE_WARN,
1348 "(unable to allocate dma resource.");
1349 mptsas_return_to_pool(mpt, cmd);
1350 return (-1);
1353 bzero(flsh_memp, size);
1355 for (i = 0; i < size; i++) {
1356 (void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
1358 (void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
1361 * form a cmd/pkt to store the fw download message
1363 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1364 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1365 pkt->pkt_ha_private = (opaque_t)cmd;
1366 pkt->pkt_flags = FLAG_HEAD;
1367 pkt->pkt_time = 60;
1368 cmd->cmd_pkt = pkt;
1369 cmd->cmd_scblen = 1;
1370 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_FW_CMD;
1373 * Save the command in a slot
1375 if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1376 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1377 mptsas_return_to_pool(mpt, cmd);
1378 return (-1);
1382 * Fill in fw download message
1384 ASSERT(cmd->cmd_slot != 0);
1385 memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1386 bzero(memp, mpt->m_req_frame_size);
1388 if (mpt->m_MPI25)
1389 mptsas_uflash25((pMpi25FWDownloadRequest)memp,
1390 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1391 else
1392 mptsas_uflash2((pMpi2FWDownloadRequest)memp,
1393 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1396 * Start command
1398 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1399 DDI_DMA_SYNC_FORDEV);
1400 request_desc = (cmd->cmd_slot << 16) +
1401 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1402 cmd->cmd_rfm = 0;
1403 MPTSAS_START_CMD(mpt, request_desc);
1405 rvalue = 0;
1406 (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1407 drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1408 if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1409 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1410 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1411 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1413 rvalue = -1;
1415 mptsas_remove_cmd(mpt, cmd);
1416 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1418 return (rvalue);
1421 static int
1422 mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1423 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1424 va_list ap)
1426 #ifndef __lock_lint
1427 _NOTE(ARGUNUSED(ap))
1428 #endif
1429 pMpi2SasDevicePage0_t sasdevpage;
1430 int rval = DDI_SUCCESS, i;
1431 uint8_t *sas_addr = NULL;
1432 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1433 uint16_t *devhdl, *bay_num, *enclosure;
1434 uint64_t *sas_wwn;
1435 uint32_t *dev_info;
1436 uint8_t *physport, *phynum;
1437 uint16_t *pdevhdl, *io_flags;
1438 uint32_t page_address;
1440 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1441 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1442 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1443 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1444 iocstatus, iocloginfo);
1445 rval = DDI_FAILURE;
1446 return (rval);
1448 page_address = va_arg(ap, uint32_t);
1450 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1451 * are no more pages. If everything is OK up to this point but the
1452 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1453 * signal that device traversal is complete.
1455 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1456 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1457 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1458 mpt->m_done_traverse_dev = 1;
1460 rval = DDI_FAILURE;
1461 return (rval);
1463 devhdl = va_arg(ap, uint16_t *);
1464 sas_wwn = va_arg(ap, uint64_t *);
1465 dev_info = va_arg(ap, uint32_t *);
1466 physport = va_arg(ap, uint8_t *);
1467 phynum = va_arg(ap, uint8_t *);
1468 pdevhdl = va_arg(ap, uint16_t *);
1469 bay_num = va_arg(ap, uint16_t *);
1470 enclosure = va_arg(ap, uint16_t *);
1471 io_flags = va_arg(ap, uint16_t *);
1473 sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1475 *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1476 *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1477 sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1478 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1479 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1481 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1482 *sas_wwn = LE_64(*sas_wwn);
1483 *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1484 *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1485 *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1486 *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1487 *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1488 *io_flags = ddi_get16(accessp, &sasdevpage->Flags);
1490 if (*io_flags & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
1492 * Leave a messages about FP cabability in the log.
1494 mptsas_log(mpt, CE_CONT,
1495 "!w%016"PRIx64" FastPath Capable%s", *sas_wwn,
1496 (*io_flags &
1497 MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)?
1498 " and Enabled":" but Disabled");
1501 return (rval);
1505 * Request MPI configuration page SAS device page 0 to get DevHandle, device
1506 * info and SAS address.
1509 mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1510 uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1511 uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1512 uint16_t *bay_num, uint16_t *enclosure, uint16_t *io_flags)
1514 int rval = DDI_SUCCESS;
1516 ASSERT(mutex_owned(&mpt->m_mutex));
1519 * Get the header and config page. reply contains the reply frame,
1520 * which holds status info for the request.
1522 rval = mptsas_access_config_page(mpt,
1523 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1524 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1525 mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1526 dev_info, physport, phynum, pdev_handle,
1527 bay_num, enclosure, io_flags);
1529 return (rval);
1532 static int
1533 mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1534 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1535 va_list ap)
1537 #ifndef __lock_lint
1538 _NOTE(ARGUNUSED(ap))
1539 #endif
1540 pMpi2ExpanderPage0_t expddevpage;
1541 int rval = DDI_SUCCESS, i;
1542 uint8_t *sas_addr = NULL;
1543 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1544 uint16_t *devhdl;
1545 uint64_t *sas_wwn;
1546 uint8_t physport;
1547 mptsas_phymask_t *phymask;
1548 uint16_t *pdevhdl;
1549 uint32_t page_address;
1551 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1552 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1553 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
1554 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1555 iocstatus, iocloginfo);
1556 rval = DDI_FAILURE;
1557 return (rval);
1559 page_address = va_arg(ap, uint32_t);
1561 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1562 * are no more pages. If everything is OK up to this point but the
1563 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1564 * signal that device traversal is complete.
1566 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1567 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
1568 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
1569 mpt->m_done_traverse_smp = 1;
1571 rval = DDI_FAILURE;
1572 return (rval);
1574 devhdl = va_arg(ap, uint16_t *);
1575 sas_wwn = va_arg(ap, uint64_t *);
1576 phymask = va_arg(ap, mptsas_phymask_t *);
1577 pdevhdl = va_arg(ap, uint16_t *);
1579 expddevpage = (pMpi2ExpanderPage0_t)page_memp;
1581 *devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
1582 physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
1583 *phymask = mptsas_physport_to_phymask(mpt, physport);
1584 *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
1585 sas_addr = (uint8_t *)(&expddevpage->SASAddress);
1586 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1587 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1589 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1590 *sas_wwn = LE_64(*sas_wwn);
1592 return (rval);
1596 * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1597 * and SAS address.
1600 mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
1601 mptsas_smp_t *info)
1603 int rval = DDI_SUCCESS;
1605 ASSERT(mutex_owned(&mpt->m_mutex));
1608 * Get the header and config page. reply contains the reply frame,
1609 * which holds status info for the request.
1611 rval = mptsas_access_config_page(mpt,
1612 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1613 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
1614 mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
1615 &info->m_addr.mta_wwn, &info->m_addr.mta_phymask, &info->m_pdevhdl);
1617 return (rval);
1620 static int
1621 mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1622 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1623 va_list ap)
1625 #ifndef __lock_lint
1626 _NOTE(ARGUNUSED(ap))
1627 #endif
1628 int rval = DDI_SUCCESS, i;
1629 uint8_t *sas_addr = NULL;
1630 uint64_t *sas_wwn;
1631 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1632 uint8_t *portwidth;
1633 pMpi2SasPortPage0_t sasportpage;
1635 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1636 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
1637 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1638 iocstatus, iocloginfo);
1639 rval = DDI_FAILURE;
1640 return (rval);
1642 sas_wwn = va_arg(ap, uint64_t *);
1643 portwidth = va_arg(ap, uint8_t *);
1645 sasportpage = (pMpi2SasPortPage0_t)page_memp;
1646 sas_addr = (uint8_t *)(&sasportpage->SASAddress);
1647 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1648 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1650 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1651 *sas_wwn = LE_64(*sas_wwn);
1652 *portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
1653 return (rval);
1657 * Request MPI configuration page SAS port page 0 to get initiator SAS address
1658 * and port width.
1661 mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
1662 uint64_t *sas_wwn, uint8_t *portwidth)
1664 int rval = DDI_SUCCESS;
1666 ASSERT(mutex_owned(&mpt->m_mutex));
1669 * Get the header and config page. reply contains the reply frame,
1670 * which holds status info for the request.
1672 rval = mptsas_access_config_page(mpt,
1673 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1674 MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
1675 mptsas_sasportpage_0_cb, sas_wwn, portwidth);
1677 return (rval);
1680 static int
1681 mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
1682 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1683 va_list ap)
1685 #ifndef __lock_lint
1686 _NOTE(ARGUNUSED(ap))
1687 #endif
1688 int rval = DDI_SUCCESS;
1689 pMpi2SasIOUnitPage0_t sasioupage0;
1690 int i, num_phys;
1691 uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1692 uint8_t port_flags;
1694 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1695 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1696 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1697 iocstatus, iocloginfo);
1698 rval = DDI_FAILURE;
1699 return (rval);
1701 readpage1 = va_arg(ap, uint32_t *);
1702 retrypage0 = va_arg(ap, uint32_t *);
1704 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1706 num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1708 * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1709 * was initially set. This should never change throughout the life of
1710 * the driver.
1712 ASSERT(num_phys == mpt->m_num_phys);
1713 for (i = 0; i < num_phys; i++) {
1714 cpdi[i] = ddi_get32(accessp,
1715 &sasioupage0->PhyData[i].
1716 ControllerPhyDeviceInfo);
1717 port_flags = ddi_get8(accessp,
1718 &sasioupage0->PhyData[i].PortFlags);
1719 mpt->m_phy_info[i].port_num =
1720 ddi_get8(accessp,
1721 &sasioupage0->PhyData[i].Port);
1722 mpt->m_phy_info[i].ctrl_devhdl =
1723 ddi_get16(accessp, &sasioupage0->
1724 PhyData[i].ControllerDevHandle);
1725 mpt->m_phy_info[i].attached_devhdl =
1726 ddi_get16(accessp, &sasioupage0->
1727 PhyData[i].AttachedDevHandle);
1728 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1729 mpt->m_phy_info[i].port_flags = port_flags;
1731 if (port_flags & DISCOVERY_IN_PROGRESS) {
1732 *retrypage0 = *retrypage0 + 1;
1733 break;
1734 } else {
1735 *retrypage0 = 0;
1737 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
1739 * some PHY configuration described in
1740 * SAS IO Unit Page1
1742 *readpage1 = 1;
1746 return (rval);
1749 static int
1750 mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
1751 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1752 va_list ap)
1754 #ifndef __lock_lint
1755 _NOTE(ARGUNUSED(ap))
1756 #endif
1757 int rval = DDI_SUCCESS;
1758 pMpi2SasIOUnitPage1_t sasioupage1;
1759 int i, num_phys;
1760 uint32_t cpdi[MPTSAS_MAX_PHYS];
1761 uint8_t port_flags;
1763 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1764 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1765 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1766 iocstatus, iocloginfo);
1767 rval = DDI_FAILURE;
1768 return (rval);
1771 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1772 num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1774 * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
1775 * was initially set. This should never change throughout the life of
1776 * the driver.
1778 ASSERT(num_phys == mpt->m_num_phys);
1779 for (i = 0; i < num_phys; i++) {
1780 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1781 ControllerPhyDeviceInfo);
1782 port_flags = ddi_get8(accessp,
1783 &sasioupage1->PhyData[i].PortFlags);
1784 mpt->m_phy_info[i].port_num =
1785 ddi_get8(accessp,
1786 &sasioupage1->PhyData[i].Port);
1787 mpt->m_phy_info[i].port_flags = port_flags;
1788 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1790 return (rval);
1794 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1795 * page1 to update the PHY information. This is the message passing method of
1796 * this function which should be called except during initialization.
1799 mptsas_get_sas_io_unit_page(mptsas_t *mpt)
1801 int rval = DDI_SUCCESS, state;
1802 uint32_t readpage1 = 0, retrypage0 = 0;
1804 ASSERT(mutex_owned(&mpt->m_mutex));
1807 * Now we cycle through the state machine. Here's what happens:
1808 * 1. Read IO unit page 0 and set phy information
1809 * 2. See if Read IO unit page1 is needed because of port configuration
1810 * 3. Read IO unit page 1 and update phy information.
1812 state = IOUC_READ_PAGE0;
1813 while (state != IOUC_DONE) {
1814 if (state == IOUC_READ_PAGE0) {
1815 rval = mptsas_access_config_page(mpt,
1816 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1817 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
1818 mptsas_sasiou_page_0_cb, &readpage1,
1819 &retrypage0);
1820 } else if (state == IOUC_READ_PAGE1) {
1821 rval = mptsas_access_config_page(mpt,
1822 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1823 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
1824 mptsas_sasiou_page_1_cb);
1827 if (rval == DDI_SUCCESS) {
1828 switch (state) {
1829 case IOUC_READ_PAGE0:
1831 * retry 30 times if discovery is in process
1833 if (retrypage0 && (retrypage0 < 30)) {
1834 drv_usecwait(1000 * 100);
1835 state = IOUC_READ_PAGE0;
1836 break;
1837 } else if (retrypage0 == 30) {
1838 mptsas_log(mpt, CE_WARN,
1839 "!Discovery in progress, can't "
1840 "verify IO unit config, then "
1841 "after 30 times retry, give "
1842 "up!");
1843 state = IOUC_DONE;
1844 rval = DDI_FAILURE;
1845 break;
1848 if (readpage1 == 0) {
1849 state = IOUC_DONE;
1850 rval = DDI_SUCCESS;
1851 break;
1854 state = IOUC_READ_PAGE1;
1855 break;
1857 case IOUC_READ_PAGE1:
1858 state = IOUC_DONE;
1859 rval = DDI_SUCCESS;
1860 break;
1862 } else {
1863 return (rval);
1867 return (rval);
1870 static int
1871 mptsas_biospage_3_cb(mptsas_t *mpt, caddr_t page_memp,
1872 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1873 va_list ap)
1875 #ifndef __lock_lint
1876 _NOTE(ARGUNUSED(ap))
1877 #endif
1878 pMpi2BiosPage3_t sasbiospage;
1879 int rval = DDI_SUCCESS;
1880 uint32_t *bios_version;
1882 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1883 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1884 mptsas_log(mpt, CE_WARN, "mptsas_get_bios_page3 header: "
1885 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, iocloginfo);
1886 rval = DDI_FAILURE;
1887 return (rval);
1889 bios_version = va_arg(ap, uint32_t *);
1890 sasbiospage = (pMpi2BiosPage3_t)page_memp;
1891 *bios_version = ddi_get32(accessp, &sasbiospage->BiosVersion);
1893 return (rval);
1897 * Request MPI configuration page BIOS page 3 to get BIOS version. Since all
1898 * other information in this page is not needed, just ignore it.
1901 mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version)
1903 int rval = DDI_SUCCESS;
1905 ASSERT(mutex_owned(&mpt->m_mutex));
1908 * Get the header and config page. reply contains the reply frame,
1909 * which holds status info for the request.
1911 rval = mptsas_access_config_page(mpt,
1912 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, MPI2_CONFIG_PAGETYPE_BIOS, 3,
1913 0, mptsas_biospage_3_cb, bios_version);
1915 return (rval);
1919 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1920 * page1 to update the PHY information. This is the handshaking version of
1921 * this function, which should be called during initialization only.
1924 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1926 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
1927 ddi_dma_cookie_t page_cookie;
1928 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
1929 ddi_acc_handle_t recv_accessp, page_accessp;
1930 pMpi2ConfigReply_t configreply;
1931 pMpi2SasIOUnitPage0_t sasioupage0;
1932 pMpi2SasIOUnitPage1_t sasioupage1;
1933 int recv_numbytes;
1934 caddr_t recv_memp, page_memp;
1935 int i, num_phys, start_phy = 0;
1936 int page0_size =
1937 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1938 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1939 int page1_size =
1940 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1941 (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1942 uint32_t flags_length;
1943 uint32_t cpdi[MPTSAS_MAX_PHYS];
1944 uint32_t readpage1 = 0, retrypage0 = 0;
1945 uint16_t iocstatus;
1946 uint8_t port_flags, page_number, action;
1947 uint32_t reply_size;
1948 uint_t state;
1949 int rval = DDI_FAILURE;
1950 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
1953 * We want to find a reply_size that's large enough for the page0 and
1954 * page1 sizes and resistant to increase in the number of phys.
1956 reply_size = MAX(page0_size, page1_size);
1957 if (P2ROUNDUP(reply_size, 256) <= reply_size) {
1958 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page_hndsk: "
1959 "cannot size reply size");
1960 goto cleanup;
1964 * Initialize our "state machine". This is a bit convoluted,
1965 * but it keeps us from having to do the ddi allocations numerous
1966 * times.
1969 NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1970 ASSERT(mutex_owned(&mpt->m_mutex));
1971 state = IOUC_READ_PAGE0;
1974 * dynamically create a customized dma attribute structure
1975 * that describes mpt's config reply page request structure.
1977 recv_dma_attrs = mpt->m_msg_dma_attr;
1978 recv_dma_attrs.dma_attr_sgllen = 1;
1979 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
1981 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
1982 &recv_dma_handle, &recv_accessp, &recv_memp,
1983 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
1984 mptsas_log(mpt, CE_WARN,
1985 "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1986 goto cleanup;
1988 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
1989 free_recv = B_TRUE;
1991 page_dma_attrs = mpt->m_msg_dma_attr;
1992 page_dma_attrs.dma_attr_sgllen = 1;
1993 page_dma_attrs.dma_attr_granular = reply_size;
1995 if (mptsas_dma_addr_create(mpt, page_dma_attrs,
1996 &page_dma_handle, &page_accessp, &page_memp,
1997 reply_size, &page_cookie) == FALSE) {
1998 mptsas_log(mpt, CE_WARN,
1999 "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
2000 goto cleanup;
2002 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2003 free_page = B_TRUE;
2006 * Now we cycle through the state machine. Here's what happens:
2007 * 1. Read IO unit page 0 and set phy information
2008 * 2. See if Read IO unit page1 is needed because of port configuration
2009 * 3. Read IO unit page 1 and update phy information.
2012 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
2013 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
2015 while (state != IOUC_DONE) {
2016 switch (state) {
2017 case IOUC_READ_PAGE0:
2018 page_number = 0;
2019 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2020 flags_length = (uint32_t)page0_size;
2021 flags_length |= ((uint32_t)(
2022 MPI2_SGE_FLAGS_LAST_ELEMENT |
2023 MPI2_SGE_FLAGS_END_OF_BUFFER |
2024 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2025 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2026 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2027 MPI2_SGE_FLAGS_IOC_TO_HOST |
2028 MPI2_SGE_FLAGS_END_OF_LIST) <<
2029 MPI2_SGE_FLAGS_SHIFT);
2031 break;
2033 case IOUC_READ_PAGE1:
2034 page_number = 1;
2035 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2036 flags_length = (uint32_t)page1_size;
2037 flags_length |= ((uint32_t)(
2038 MPI2_SGE_FLAGS_LAST_ELEMENT |
2039 MPI2_SGE_FLAGS_END_OF_BUFFER |
2040 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2041 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2042 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2043 MPI2_SGE_FLAGS_IOC_TO_HOST |
2044 MPI2_SGE_FLAGS_END_OF_LIST) <<
2045 MPI2_SGE_FLAGS_SHIFT);
2047 break;
2048 default:
2049 break;
2052 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2053 configreply = (pMpi2ConfigReply_t)recv_memp;
2054 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2056 if (mptsas_send_extended_config_request_msg(mpt,
2057 MPI2_CONFIG_ACTION_PAGE_HEADER,
2058 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
2059 0, page_number, 0, 0, 0, 0)) {
2060 goto cleanup;
2063 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2064 recv_accessp)) {
2065 goto cleanup;
2068 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2069 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2071 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2072 mptsas_log(mpt, CE_WARN,
2073 "mptsas_get_sas_io_unit_page_hndshk: read page "
2074 "header iocstatus = 0x%x", iocstatus);
2075 goto cleanup;
2078 if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
2079 bzero(page_memp, reply_size);
2082 if (mptsas_send_extended_config_request_msg(mpt, action,
2083 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
2084 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2085 ddi_get16(recv_accessp, &configreply->ExtPageLength),
2086 flags_length, page_cookie.dmac_laddress)) {
2087 goto cleanup;
2090 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2091 recv_accessp)) {
2092 goto cleanup;
2095 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2096 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2098 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2099 mptsas_log(mpt, CE_WARN,
2100 "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2101 "config failed for action %d, iocstatus = 0x%x",
2102 action, iocstatus);
2103 goto cleanup;
2106 switch (state) {
2107 case IOUC_READ_PAGE0:
2108 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2109 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2110 goto cleanup;
2113 num_phys = ddi_get8(page_accessp,
2114 &sasioupage0->NumPhys);
2115 ASSERT(num_phys == mpt->m_num_phys);
2116 if (num_phys > MPTSAS_MAX_PHYS) {
2117 mptsas_log(mpt, CE_WARN, "Number of phys "
2118 "supported by HBA (%d) is more than max "
2119 "supported by driver (%d). Driver will "
2120 "not attach.", num_phys,
2121 MPTSAS_MAX_PHYS);
2122 rval = DDI_FAILURE;
2123 goto cleanup;
2125 for (i = start_phy; i < num_phys; i++, start_phy = i) {
2126 cpdi[i] = ddi_get32(page_accessp,
2127 &sasioupage0->PhyData[i].
2128 ControllerPhyDeviceInfo);
2129 port_flags = ddi_get8(page_accessp,
2130 &sasioupage0->PhyData[i].PortFlags);
2132 mpt->m_phy_info[i].port_num =
2133 ddi_get8(page_accessp,
2134 &sasioupage0->PhyData[i].Port);
2135 mpt->m_phy_info[i].ctrl_devhdl =
2136 ddi_get16(page_accessp, &sasioupage0->
2137 PhyData[i].ControllerDevHandle);
2138 mpt->m_phy_info[i].attached_devhdl =
2139 ddi_get16(page_accessp, &sasioupage0->
2140 PhyData[i].AttachedDevHandle);
2141 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2142 mpt->m_phy_info[i].port_flags = port_flags;
2144 if (port_flags & DISCOVERY_IN_PROGRESS) {
2145 retrypage0++;
2146 NDBG20(("Discovery in progress, can't "
2147 "verify IO unit config, then NO.%d"
2148 " times retry", retrypage0));
2149 break;
2150 } else {
2151 retrypage0 = 0;
2153 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
2155 * some PHY configuration described in
2156 * SAS IO Unit Page1
2158 readpage1 = 1;
2163 * retry 30 times if discovery is in process
2165 if (retrypage0 && (retrypage0 < 30)) {
2166 drv_usecwait(1000 * 100);
2167 state = IOUC_READ_PAGE0;
2168 break;
2169 } else if (retrypage0 == 30) {
2170 mptsas_log(mpt, CE_WARN,
2171 "!Discovery in progress, can't "
2172 "verify IO unit config, then after"
2173 " 30 times retry, give up!");
2174 state = IOUC_DONE;
2175 rval = DDI_FAILURE;
2176 break;
2179 if (readpage1 == 0) {
2180 state = IOUC_DONE;
2181 rval = DDI_SUCCESS;
2182 break;
2185 state = IOUC_READ_PAGE1;
2186 break;
2188 case IOUC_READ_PAGE1:
2189 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2190 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2191 goto cleanup;
2194 num_phys = ddi_get8(page_accessp,
2195 &sasioupage1->NumPhys);
2196 ASSERT(num_phys == mpt->m_num_phys);
2197 if (num_phys > MPTSAS_MAX_PHYS) {
2198 mptsas_log(mpt, CE_WARN, "Number of phys "
2199 "supported by HBA (%d) is more than max "
2200 "supported by driver (%d). Driver will "
2201 "not attach.", num_phys,
2202 MPTSAS_MAX_PHYS);
2203 rval = DDI_FAILURE;
2204 goto cleanup;
2206 for (i = 0; i < num_phys; i++) {
2207 cpdi[i] = ddi_get32(page_accessp,
2208 &sasioupage1->PhyData[i].
2209 ControllerPhyDeviceInfo);
2210 port_flags = ddi_get8(page_accessp,
2211 &sasioupage1->PhyData[i].PortFlags);
2212 mpt->m_phy_info[i].port_num =
2213 ddi_get8(page_accessp,
2214 &sasioupage1->PhyData[i].Port);
2215 mpt->m_phy_info[i].port_flags = port_flags;
2216 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2220 state = IOUC_DONE;
2221 rval = DDI_SUCCESS;
2222 break;
2225 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2226 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2227 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2228 rval = DDI_FAILURE;
2229 goto cleanup;
2231 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2232 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2233 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2234 rval = DDI_FAILURE;
2235 goto cleanup;
2238 cleanup:
2239 if (free_recv)
2240 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2241 if (free_page)
2242 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2243 if (rval != DDI_SUCCESS) {
2244 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2245 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2247 return (rval);
2251 * mptsas_get_manufacture_page5
2253 * This function will retrieve the base WWID from the adapter. Since this
2254 * function is only called during the initialization process, use handshaking.
2257 mptsas_get_manufacture_page5(mptsas_t *mpt)
2259 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2260 ddi_dma_cookie_t page_cookie;
2261 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2262 ddi_acc_handle_t recv_accessp, page_accessp;
2263 pMpi2ConfigReply_t configreply;
2264 caddr_t recv_memp, page_memp;
2265 int recv_numbytes;
2266 pMpi2ManufacturingPage5_t m5;
2267 uint32_t flagslength;
2268 int rval = DDI_SUCCESS;
2269 uint_t iocstatus;
2270 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2272 MPTSAS_DISABLE_INTR(mpt);
2274 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2275 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2276 rval = DDI_FAILURE;
2277 goto done;
2281 * dynamically create a customized dma attribute structure
2282 * that describes the MPT's config reply page request structure.
2284 recv_dma_attrs = mpt->m_msg_dma_attr;
2285 recv_dma_attrs.dma_attr_sgllen = 1;
2286 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2288 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2289 &recv_dma_handle, &recv_accessp, &recv_memp,
2290 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2291 rval = DDI_FAILURE;
2292 goto done;
2294 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2295 free_recv = B_TRUE;
2297 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2298 configreply = (pMpi2ConfigReply_t)recv_memp;
2299 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2302 * get config reply message
2304 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2305 recv_accessp)) {
2306 rval = DDI_FAILURE;
2307 goto done;
2310 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2311 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2312 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2313 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2314 goto done;
2318 * dynamically create a customized dma attribute structure
2319 * that describes the MPT's config page structure.
2321 page_dma_attrs = mpt->m_msg_dma_attr;
2322 page_dma_attrs.dma_attr_sgllen = 1;
2323 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2325 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2326 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2327 &page_cookie) == FALSE) {
2328 rval = DDI_FAILURE;
2329 goto done;
2331 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2332 free_page = B_TRUE;
2334 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2335 m5 = (pMpi2ManufacturingPage5_t)page_memp;
2336 NDBG20(("mptsas_get_manufacture_page5: paddr 0x%p",
2337 (void *)(uintptr_t)page_cookie.dmac_laddress));
2340 * Give reply address to IOC to store config page in and send
2341 * config request out.
2344 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2345 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2346 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2347 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2348 MPI2_SGE_FLAGS_IOC_TO_HOST |
2349 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2351 if (mptsas_send_config_request_msg(mpt,
2352 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2353 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2354 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2355 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2356 flagslength, page_cookie.dmac_laddress)) {
2357 rval = DDI_FAILURE;
2358 goto done;
2362 * get reply view handshake
2364 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2365 recv_accessp)) {
2366 rval = DDI_FAILURE;
2367 goto done;
2370 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2371 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2372 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2373 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2374 goto done;
2377 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2380 * Fusion-MPT stores fields in little-endian format. This is
2381 * why the low-order 32 bits are stored first.
2383 mpt->un.sasaddr.m_base_wwid_lo =
2384 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2385 mpt->un.sasaddr.m_base_wwid_hi =
2386 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2388 if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2389 "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2390 NDBG2(("%s%d: failed to create base-wwid property",
2391 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2395 * Set the number of PHYs present.
2397 mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2399 if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2400 "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2401 NDBG2(("%s%d: failed to create num-phys property",
2402 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2405 mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2406 mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2407 (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2409 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2410 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2411 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2412 rval = DDI_FAILURE;
2413 goto done;
2415 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2416 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2417 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2418 rval = DDI_FAILURE;
2420 done:
2422 * free up memory
2424 if (free_recv)
2425 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2426 if (free_page)
2427 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2428 MPTSAS_ENABLE_INTR(mpt);
2430 return (rval);
2433 static int
2434 mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2435 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2436 va_list ap)
2438 #ifndef __lock_lint
2439 _NOTE(ARGUNUSED(ap))
2440 #endif
2441 pMpi2SasPhyPage0_t sasphypage;
2442 int rval = DDI_SUCCESS;
2443 uint16_t *owner_devhdl, *attached_devhdl;
2444 uint8_t *attached_phy_identify;
2445 uint32_t *attached_phy_info;
2446 uint8_t *programmed_link_rate;
2447 uint8_t *hw_link_rate;
2448 uint8_t *change_count;
2449 uint32_t *phy_info;
2450 uint8_t *negotiated_link_rate;
2451 uint32_t page_address;
2453 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2454 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2455 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
2456 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2457 iocstatus, iocloginfo);
2458 rval = DDI_FAILURE;
2459 return (rval);
2461 page_address = va_arg(ap, uint32_t);
2463 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2464 * are no more pages. If everything is OK up to this point but the
2465 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2466 * signal that device traversal is complete.
2468 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2469 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2470 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2471 mpt->m_done_traverse_smp = 1;
2473 rval = DDI_FAILURE;
2474 return (rval);
2476 owner_devhdl = va_arg(ap, uint16_t *);
2477 attached_devhdl = va_arg(ap, uint16_t *);
2478 attached_phy_identify = va_arg(ap, uint8_t *);
2479 attached_phy_info = va_arg(ap, uint32_t *);
2480 programmed_link_rate = va_arg(ap, uint8_t *);
2481 hw_link_rate = va_arg(ap, uint8_t *);
2482 change_count = va_arg(ap, uint8_t *);
2483 phy_info = va_arg(ap, uint32_t *);
2484 negotiated_link_rate = va_arg(ap, uint8_t *);
2486 sasphypage = (pMpi2SasPhyPage0_t)page_memp;
2488 *owner_devhdl =
2489 ddi_get16(accessp, &sasphypage->OwnerDevHandle);
2490 *attached_devhdl =
2491 ddi_get16(accessp, &sasphypage->AttachedDevHandle);
2492 *attached_phy_identify =
2493 ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
2494 *attached_phy_info =
2495 ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
2496 *programmed_link_rate =
2497 ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
2498 *hw_link_rate =
2499 ddi_get8(accessp, &sasphypage->HwLinkRate);
2500 *change_count =
2501 ddi_get8(accessp, &sasphypage->ChangeCount);
2502 *phy_info =
2503 ddi_get32(accessp, &sasphypage->PhyInfo);
2504 *negotiated_link_rate =
2505 ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
2507 return (rval);
2511 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2512 * and SAS address.
2515 mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
2516 smhba_info_t *info)
2518 int rval = DDI_SUCCESS;
2520 ASSERT(mutex_owned(&mpt->m_mutex));
2523 * Get the header and config page. reply contains the reply frame,
2524 * which holds status info for the request.
2526 rval = mptsas_access_config_page(mpt,
2527 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2528 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
2529 mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
2530 &info->attached_devhdl, &info->attached_phy_identify,
2531 &info->attached_phy_info, &info->programmed_link_rate,
2532 &info->hw_link_rate, &info->change_count,
2533 &info->phy_info, &info->negotiated_link_rate);
2535 return (rval);
2538 static int
2539 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2540 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2541 va_list ap)
2543 #ifndef __lock_lint
2544 _NOTE(ARGUNUSED(ap))
2545 #endif
2546 pMpi2SasPhyPage1_t sasphypage;
2547 int rval = DDI_SUCCESS;
2549 uint32_t *invalid_dword_count;
2550 uint32_t *running_disparity_error_count;
2551 uint32_t *loss_of_dword_sync_count;
2552 uint32_t *phy_reset_problem_count;
2553 uint32_t page_address;
2555 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2556 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2557 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
2558 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2559 iocstatus, iocloginfo);
2560 rval = DDI_FAILURE;
2561 return (rval);
2563 page_address = va_arg(ap, uint32_t);
2565 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2566 * are no more pages. If everything is OK up to this point but the
2567 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2568 * signal that device traversal is complete.
2570 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2571 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2572 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2573 mpt->m_done_traverse_smp = 1;
2575 rval = DDI_FAILURE;
2576 return (rval);
2579 invalid_dword_count = va_arg(ap, uint32_t *);
2580 running_disparity_error_count = va_arg(ap, uint32_t *);
2581 loss_of_dword_sync_count = va_arg(ap, uint32_t *);
2582 phy_reset_problem_count = va_arg(ap, uint32_t *);
2584 sasphypage = (pMpi2SasPhyPage1_t)page_memp;
2586 *invalid_dword_count =
2587 ddi_get32(accessp, &sasphypage->InvalidDwordCount);
2588 *running_disparity_error_count =
2589 ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
2590 *loss_of_dword_sync_count =
2591 ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
2592 *phy_reset_problem_count =
2593 ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
2595 return (rval);
2599 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2600 * and SAS address.
2603 mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
2604 smhba_info_t *info)
2606 int rval = DDI_SUCCESS;
2608 ASSERT(mutex_owned(&mpt->m_mutex));
2611 * Get the header and config page. reply contains the reply frame,
2612 * which holds status info for the request.
2614 rval = mptsas_access_config_page(mpt,
2615 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2616 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
2617 mptsas_sasphypage_1_cb, page_address,
2618 &info->invalid_dword_count,
2619 &info->running_disparity_error_count,
2620 &info->loss_of_dword_sync_count,
2621 &info->phy_reset_problem_count);
2623 return (rval);
2626 * mptsas_get_manufacture_page0
2628 * This function will retrieve the base
2629 * Chip name, Board Name,Board Trace number from the adapter.
2630 * Since this function is only called during the
2631 * initialization process, use handshaking.
2634 mptsas_get_manufacture_page0(mptsas_t *mpt)
2636 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2637 ddi_dma_cookie_t page_cookie;
2638 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2639 ddi_acc_handle_t recv_accessp, page_accessp;
2640 pMpi2ConfigReply_t configreply;
2641 caddr_t recv_memp, page_memp;
2642 int recv_numbytes;
2643 pMpi2ManufacturingPage0_t m0;
2644 uint32_t flagslength;
2645 int rval = DDI_SUCCESS;
2646 uint_t iocstatus;
2647 uint8_t i = 0;
2648 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2650 MPTSAS_DISABLE_INTR(mpt);
2652 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2653 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2654 rval = DDI_FAILURE;
2655 goto done;
2659 * dynamically create a customized dma attribute structure
2660 * that describes the MPT's config reply page request structure.
2662 recv_dma_attrs = mpt->m_msg_dma_attr;
2663 recv_dma_attrs.dma_attr_sgllen = 1;
2664 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2666 if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2667 &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2668 NULL) == FALSE) {
2669 rval = DDI_FAILURE;
2670 goto done;
2672 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2673 free_recv = B_TRUE;
2675 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2676 configreply = (pMpi2ConfigReply_t)recv_memp;
2677 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2680 * get config reply message
2682 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2683 recv_accessp)) {
2684 rval = DDI_FAILURE;
2685 goto done;
2688 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2689 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2690 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2691 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2692 goto done;
2696 * dynamically create a customized dma attribute structure
2697 * that describes the MPT's config page structure.
2699 page_dma_attrs = mpt->m_msg_dma_attr;
2700 page_dma_attrs.dma_attr_sgllen = 1;
2701 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2703 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2704 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2705 &page_cookie) == FALSE) {
2706 rval = DDI_FAILURE;
2707 goto done;
2709 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2710 free_page = B_TRUE;
2712 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2713 m0 = (pMpi2ManufacturingPage0_t)page_memp;
2716 * Give reply address to IOC to store config page in and send
2717 * config request out.
2720 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2721 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2722 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2723 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2724 MPI2_SGE_FLAGS_IOC_TO_HOST |
2725 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2727 if (mptsas_send_config_request_msg(mpt,
2728 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2729 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2730 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2731 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2732 flagslength, page_cookie.dmac_laddress)) {
2733 rval = DDI_FAILURE;
2734 goto done;
2738 * get reply view handshake
2740 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2741 recv_accessp)) {
2742 rval = DDI_FAILURE;
2743 goto done;
2746 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2747 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2748 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2749 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2750 goto done;
2753 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2756 * Fusion-MPT stores fields in little-endian format. This is
2757 * why the low-order 32 bits are stored first.
2760 for (i = 0; i < 16; i++) {
2761 mpt->m_MANU_page0.ChipName[i] =
2762 ddi_get8(page_accessp,
2763 (uint8_t *)(void *)&m0->ChipName[i]);
2766 for (i = 0; i < 8; i++) {
2767 mpt->m_MANU_page0.ChipRevision[i] =
2768 ddi_get8(page_accessp,
2769 (uint8_t *)(void *)&m0->ChipRevision[i]);
2772 for (i = 0; i < 16; i++) {
2773 mpt->m_MANU_page0.BoardName[i] =
2774 ddi_get8(page_accessp,
2775 (uint8_t *)(void *)&m0->BoardName[i]);
2778 for (i = 0; i < 16; i++) {
2779 mpt->m_MANU_page0.BoardAssembly[i] =
2780 ddi_get8(page_accessp,
2781 (uint8_t *)(void *)&m0->BoardAssembly[i]);
2784 for (i = 0; i < 16; i++) {
2785 mpt->m_MANU_page0.BoardTracerNumber[i] =
2786 ddi_get8(page_accessp,
2787 (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2790 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2791 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2792 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2793 rval = DDI_FAILURE;
2794 goto done;
2796 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2797 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2798 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2799 rval = DDI_FAILURE;
2801 done:
2803 * free up memory
2805 if (free_recv)
2806 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2807 if (free_page)
2808 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2809 MPTSAS_ENABLE_INTR(mpt);
2811 return (rval);
2814 static int
2815 mptsas_enclosurepage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2816 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2817 va_list ap)
2819 uint32_t page_address;
2820 pMpi2SasEnclosurePage0_t encpage, encout;
2822 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2823 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2824 mptsas_log(mpt, CE_WARN, "mptsas_get_enclsourepage0 "
2825 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
2826 iocstatus, iocloginfo);
2827 return (DDI_FAILURE);
2830 page_address = va_arg(ap, uint32_t);
2831 encout = va_arg(ap, pMpi2SasEnclosurePage0_t);
2832 encpage = (pMpi2SasEnclosurePage0_t)page_memp;
2835 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2836 * are no more pages. If everything is OK up to this point but the
2837 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2838 * signal that enclosure traversal is complete.
2840 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2841 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
2842 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
2843 mpt->m_done_traverse_enc = 1;
2845 return (DDI_FAILURE);
2848 encout->Header.PageVersion = ddi_get8(accessp,
2849 &encpage->Header.PageVersion);
2850 encout->Header.PageNumber = ddi_get8(accessp,
2851 &encpage->Header.PageNumber);
2852 encout->Header.PageType = ddi_get8(accessp, &encpage->Header.PageType);
2853 encout->Header.ExtPageLength = ddi_get16(accessp,
2854 &encpage->Header.ExtPageLength);
2855 encout->Header.ExtPageType = ddi_get8(accessp,
2856 &encpage->Header.ExtPageType);
2858 encout->EnclosureLogicalID.Low = ddi_get32(accessp,
2859 &encpage->EnclosureLogicalID.Low);
2860 encout->EnclosureLogicalID.High = ddi_get32(accessp,
2861 &encpage->EnclosureLogicalID.High);
2862 encout->Flags = ddi_get16(accessp, &encpage->Flags);
2863 encout->EnclosureHandle = ddi_get16(accessp, &encpage->EnclosureHandle);
2864 encout->NumSlots = ddi_get16(accessp, &encpage->NumSlots);
2865 encout->StartSlot = ddi_get16(accessp, &encpage->StartSlot);
2866 encout->EnclosureLevel = ddi_get8(accessp, &encpage->EnclosureLevel);
2867 encout->SEPDevHandle = ddi_get16(accessp, &encpage->SEPDevHandle);
2869 return (DDI_SUCCESS);
2873 * Request information about the SES enclosures.
2876 mptsas_get_enclosure_page0(mptsas_t *mpt, uint32_t page_address,
2877 mptsas_enclosure_t *mep)
2879 int rval = DDI_SUCCESS;
2880 Mpi2SasEnclosurePage0_t encpage;
2882 ASSERT(MUTEX_HELD(&mpt->m_mutex));
2884 bzero(&encpage, sizeof (encpage));
2885 rval = mptsas_access_config_page(mpt,
2886 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2887 MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE, 0, page_address,
2888 mptsas_enclosurepage_0_cb, page_address, &encpage);
2890 if (rval == DDI_SUCCESS) {
2891 mep->me_enchdl = encpage.EnclosureHandle;
2892 mep->me_flags = encpage.Flags;
2895 return (rval);