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]
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
58 * mptsas_impl - This file contains all the basic functions for communicating
59 * to MPT based hardware.
67 * standard header files
70 #include <sys/scsi/scsi.h>
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>
84 * private header files.
86 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
87 #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
92 #include <sys/fm/io/ddi.h>
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
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
;
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
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
;
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
;
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
;
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
) {
156 ioc_cmd
= ioc_cmd
->m_event_linkp
;
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
);
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
;
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
;
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
;
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
);
237 ddi_put8(mpt
->m_acc_req_frame_hdl
,
238 &request
->Header
.PageType
, config
->page_type
);
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
,
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;
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
|
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
;
285 MPTSAS_START_CMD(mpt
, request_desc
);
286 if ((mptsas_check_dma_handle(mpt
->m_dma_req_frame_hdl
) !=
288 (mptsas_check_acc_handle(mpt
->m_acc_req_frame_hdl
) !=
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), ...)
300 ddi_dma_attr_t attrs
;
301 ddi_dma_cookie_t cookie
;
302 ddi_acc_handle_t accessp
;
304 mptsas_config_request_t config
;
305 int rval
= DDI_SUCCESS
, config_flags
= 0;
307 struct scsi_pkt
*pkt
;
308 pMpi2ConfigReply_t reply
;
309 uint16_t iocstatus
= 0;
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 "
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
;
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
);
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);
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");
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.
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
,
411 iocloginfo
= ddi_get32(mpt
->m_acc_reply_frame_hdl
,
415 NDBG13(("mptsas_access_config_page header: "
416 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus
,
422 if ((config
.page_type
& MPI2_CONFIG_PAGETYPE_MASK
) ==
423 MPI2_CONFIG_PAGETYPE_EXTENDED
)
424 len
= (config
.ext_page_length
* 4);
426 len
= (config
.page_length
* 4);
430 if (pkt
->pkt_reason
== CMD_RESET
) {
431 mptsas_log(mpt
, CE_WARN
, "ioc reset abort config header "
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
],
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
,
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
) {
470 mptsas_log(mpt
, CE_WARN
,
471 "mptsas_dma_addr_create(len=0x%x) failed", (int)len
);
474 /* NOW we can safely call mptsas_dma_addr_destroy(). */
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
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
491 bzero((caddr_t
)pkt
, scsi_pkt_size());
492 pkt
->pkt_ha_private
= (opaque_t
)&config
;
493 pkt
->pkt_flags
= FLAG_HEAD
;
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);
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");
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
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
,
543 iocstatus
= MPTSAS_IOCSTATUS(iocstatus
);
544 iocloginfo
= ddi_get32(mpt
->m_acc_reply_frame_hdl
,
548 if (callback(mpt
, page_memp
, accessp
, iocstatus
, iocloginfo
, ap
)) {
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
);
563 if (pkt
->pkt_reason
== CMD_TRAN_ERR
) {
564 mptsas_log(mpt
, CE_WARN
, "config fma error");
568 if (pkt
->pkt_reason
== CMD_RESET
) {
569 mptsas_log(mpt
, CE_WARN
, "ioc reset abort config request");
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
],
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
,
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");
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
;
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
,
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
)) {
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
;
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
,
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
)) {
690 mptsas_ioc_wait_for_response(mptsas_t
*mpt
)
694 while ((ddi_get32(mpt
->m_datap
,
695 &mpt
->m_reg
->HostInterruptStatus
) & MPI2_HIS_IOP_DOORBELL_STATUS
)) {
697 if (polls
++ > 60000) {
705 mptsas_ioc_wait_for_doorbell(mptsas_t
*mpt
)
709 while ((ddi_get32(mpt
->m_datap
,
710 &mpt
->m_reg
->HostInterruptStatus
) & MPI2_HIM_DIM
) == 0) {
712 if (polls
++ > 300000) {
720 mptsas_send_handshake_msg(mptsas_t
*mpt
, caddr_t memp
, int numbytes
,
721 ddi_acc_handle_t accessp
)
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"));
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 "
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 "
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
);
772 mptsas_get_handshake_msg(mptsas_t
*mpt
, caddr_t memp
, int numbytes
,
773 ddi_acc_handle_t accessp
)
775 int i
, totalbytes
, bytesleft
;
781 if (mptsas_ioc_wait_for_doorbell(mpt
)) {
782 NDBG19(("mptsas_get_handshake failed. Doorbell not ready\n"));
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"
799 ddi_put16(accessp
, (uint16_t *)((void *)(memp
)), val
);
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
810 if (totalbytes
> (numbytes
/ 2)) {
811 bytesleft
= ((numbytes
/ 2) - 2);
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"
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
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"));
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
);
864 mptsas_kick_start(mptsas_t
*mpt
)
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
);
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
)) {
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
) {
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
)
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"));
1011 * Wait no more than 60 seconds for chip to become
1014 while ((ddi_get32(mpt
->m_datap
, &mpt
->m_reg
->Doorbell
) &
1015 MPI2_IOC_STATE_READY
) == 0x0) {
1017 if (polls
++ > 60000) {
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
1033 mptsas_destroy_ioc_event_cmd(mpt
);
1034 return (MPTSAS_SUCCESS_MUR
);
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
);
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
) {
1076 mptsas_ioc_event_cmdq_delete(mpt
, ioc_cmd
);
1077 kmem_free(ioc_cmd
, M_EVENT_STRUCT_SIZE
);
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
;
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");
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
);
1127 pkt
->pkt_address
.a_target
= dev_handle
;
1128 pkt
->pkt_address
.a_lun
= (uchar_t
)lun
;
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
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
);
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
)
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,
1186 mptsas_log(mpt
, CE_WARN
, "failed to copy out "
1187 "reply data for TM request");
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");
1217 * Complete firmware download frame for v2.0 cards.
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);
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.
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
;
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
;
1311 struct scsi_pkt
*pkt
;
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 "
1324 "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
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");
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
);
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
;
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
);
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
);
1389 mptsas_uflash25((pMpi25FWDownloadRequest
)memp
,
1390 mpt
->m_acc_req_frame_hdl
, size
, type
, flsh_cookie
);
1392 mptsas_uflash2((pMpi2FWDownloadRequest
)memp
,
1393 mpt
->m_acc_req_frame_hdl
, size
, type
, flsh_cookie
);
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
;
1403 MPTSAS_START_CMD(mpt
, request_desc
);
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");
1415 mptsas_remove_cmd(mpt
, cmd
);
1416 mptsas_dma_addr_destroy(&flsh_dma_handle
, &flsh_accessp
);
1422 mptsas_sasdevpage_0_cb(mptsas_t
*mpt
, caddr_t page_memp
,
1423 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
1427 _NOTE(ARGUNUSED(ap
))
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
;
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
);
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;
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
,
1497 MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH
)?
1498 " and Enabled":" but Disabled");
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
);
1533 mptsas_sasexpdpage_0_cb(mptsas_t
*mpt
, caddr_t page_memp
,
1534 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
1538 _NOTE(ARGUNUSED(ap
))
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
];
1547 mptsas_phymask_t
*phymask
;
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
);
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;
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
);
1596 * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1600 mptsas_get_sas_expander_page0(mptsas_t
*mpt
, uint32_t page_address
,
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
);
1621 mptsas_sasportpage_0_cb(mptsas_t
*mpt
, caddr_t page_memp
,
1622 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
1626 _NOTE(ARGUNUSED(ap
))
1628 int rval
= DDI_SUCCESS
, i
;
1629 uint8_t *sas_addr
= NULL
;
1631 uint8_t tmp_sas_wwn
[SAS_WWN_BYTE_SIZE
];
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
);
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
);
1657 * Request MPI configuration page SAS port page 0 to get initiator SAS address
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
);
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
,
1686 _NOTE(ARGUNUSED(ap
))
1688 int rval
= DDI_SUCCESS
;
1689 pMpi2SasIOUnitPage0_t sasioupage0
;
1691 uint32_t cpdi
[MPTSAS_MAX_PHYS
], *retrypage0
, *readpage1
;
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
);
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
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
=
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;
1737 if (!(port_flags
& AUTO_PORT_CONFIGURATION
)) {
1739 * some PHY configuration described in
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
,
1755 _NOTE(ARGUNUSED(ap
))
1757 int rval
= DDI_SUCCESS
;
1758 pMpi2SasIOUnitPage1_t sasioupage1
;
1760 uint32_t cpdi
[MPTSAS_MAX_PHYS
];
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
);
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
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
=
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
];
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
,
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
) {
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
;
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 "
1848 if (readpage1
== 0) {
1854 state
= IOUC_READ_PAGE1
;
1857 case IOUC_READ_PAGE1
:
1871 mptsas_biospage_3_cb(mptsas_t
*mpt
, caddr_t page_memp
,
1872 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
1876 _NOTE(ARGUNUSED(ap
))
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
);
1889 bios_version
= va_arg(ap
, uint32_t *);
1890 sasbiospage
= (pMpi2BiosPage3_t
)page_memp
;
1891 *bios_version
= ddi_get32(accessp
, &sasbiospage
->BiosVersion
);
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
);
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
;
1934 caddr_t recv_memp
, page_memp
;
1935 int i
, num_phys
, start_phy
= 0;
1937 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0
) +
1938 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA
) * (MPTSAS_MAX_PHYS
- 1));
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;
1946 uint8_t port_flags
, page_number
, action
;
1947 uint32_t reply_size
;
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");
1964 * Initialize our "state machine". This is a bit convoluted,
1965 * but it keeps us from having to do the ddi allocations numerous
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");
1988 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
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");
2002 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
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
) {
2017 case IOUC_READ_PAGE0
:
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
);
2033 case IOUC_READ_PAGE1
:
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
);
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)) {
2063 if (mptsas_get_handshake_msg(mpt
, recv_memp
, recv_numbytes
,
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
);
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
)) {
2090 if (mptsas_get_handshake_msg(mpt
, recv_memp
, recv_numbytes
,
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",
2107 case IOUC_READ_PAGE0
:
2108 if ((ddi_dma_sync(page_dma_handle
, 0, 0,
2109 DDI_DMA_SYNC_FORCPU
)) != DDI_SUCCESS
) {
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
,
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
) {
2146 NDBG20(("Discovery in progress, can't "
2147 "verify IO unit config, then NO.%d"
2148 " times retry", retrypage0
));
2153 if (!(port_flags
& AUTO_PORT_CONFIGURATION
)) {
2155 * some PHY configuration described in
2163 * retry 30 times if discovery is in process
2165 if (retrypage0
&& (retrypage0
< 30)) {
2166 drv_usecwait(1000 * 100);
2167 state
= IOUC_READ_PAGE0
;
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!");
2179 if (readpage1
== 0) {
2185 state
= IOUC_READ_PAGE1
;
2188 case IOUC_READ_PAGE1
:
2189 if ((ddi_dma_sync(page_dma_handle
, 0, 0,
2190 DDI_DMA_SYNC_FORCPU
)) != DDI_SUCCESS
) {
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
,
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
];
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
);
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
);
2240 mptsas_dma_addr_destroy(&recv_dma_handle
, &recv_accessp
);
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
);
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
;
2266 pMpi2ManufacturingPage5_t m5
;
2267 uint32_t flagslength
;
2268 int rval
= DDI_SUCCESS
;
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)) {
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
) {
2294 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
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
,
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
));
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
) {
2331 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
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
)) {
2362 * get reply view handshake
2364 if (mptsas_get_handshake_msg(mpt
, recv_memp
, recv_numbytes
,
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
));
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
);
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
);
2425 mptsas_dma_addr_destroy(&recv_dma_handle
, &recv_accessp
);
2427 mptsas_dma_addr_destroy(&page_dma_handle
, &page_accessp
);
2428 MPTSAS_ENABLE_INTR(mpt
);
2434 mptsas_sasphypage_0_cb(mptsas_t
*mpt
, caddr_t page_memp
,
2435 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
2439 _NOTE(ARGUNUSED(ap
))
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
;
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
);
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;
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
;
2489 ddi_get16(accessp
, &sasphypage
->OwnerDevHandle
);
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
);
2499 ddi_get8(accessp
, &sasphypage
->HwLinkRate
);
2501 ddi_get8(accessp
, &sasphypage
->ChangeCount
);
2503 ddi_get32(accessp
, &sasphypage
->PhyInfo
);
2504 *negotiated_link_rate
=
2505 ddi_get8(accessp
, &sasphypage
->NegotiatedLinkRate
);
2511 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2515 mptsas_get_sas_phy_page0(mptsas_t
*mpt
, uint32_t page_address
,
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
);
2539 mptsas_sasphypage_1_cb(mptsas_t
*mpt
, caddr_t page_memp
,
2540 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
2544 _NOTE(ARGUNUSED(ap
))
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
);
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;
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
);
2599 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2603 mptsas_get_sas_phy_page1(mptsas_t
*mpt
, uint32_t page_address
,
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
);
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
;
2643 pMpi2ManufacturingPage0_t m0
;
2644 uint32_t flagslength
;
2645 int rval
= DDI_SUCCESS
;
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)) {
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
)),
2672 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
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
,
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
));
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
) {
2709 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
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
)) {
2738 * get reply view handshake
2740 if (mptsas_get_handshake_msg(mpt
, recv_memp
, recv_numbytes
,
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
));
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
);
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
);
2806 mptsas_dma_addr_destroy(&recv_dma_handle
, &recv_accessp
);
2808 mptsas_dma_addr_destroy(&page_dma_handle
, &page_accessp
);
2809 MPTSAS_ENABLE_INTR(mpt
);
2815 mptsas_enclosurepage_0_cb(mptsas_t
*mpt
, caddr_t page_memp
,
2816 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
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
;