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.
30 * Copyright (c) 2000 to 2010, LSI Corporation.
31 * All rights reserved.
33 * Redistribution and use in source and binary forms of all code within
34 * this file that is exclusively owned by LSI, with or without
35 * modification, is permitted provided that, in addition to the CDDL 1.0
36 * License requirements, the following conditions are met:
38 * Neither the name of the author nor the names of its contributors may be
39 * used to endorse or promote products derived from this software without
40 * specific prior written permission.
42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
45 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
46 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
48 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
49 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
50 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
51 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
52 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
57 * mptsas_impl - This file contains all the basic functions for communicating
58 * to MPT based hardware.
61 #if defined(lint) || defined(DEBUG)
66 * standard header files
69 #include <sys/scsi/scsi.h>
73 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
74 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
75 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
76 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
77 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
78 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
79 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
83 * private header files.
85 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
86 #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
91 #include <sys/fm/io/ddi.h>
93 #if defined(MPTSAS_DEBUG)
94 extern uint32_t mptsas_debug_flags
;
100 static void mptsas_ioc_event_cmdq_add(mptsas_t
*mpt
, m_event_struct_t
*cmd
);
101 static void mptsas_ioc_event_cmdq_delete(mptsas_t
*mpt
, m_event_struct_t
*cmd
);
102 static m_event_struct_t
*mptsas_ioc_event_find_by_cmd(mptsas_t
*mpt
,
103 struct mptsas_cmd
*cmd
);
106 * add ioc evnet cmd into the queue
109 mptsas_ioc_event_cmdq_add(mptsas_t
*mpt
, m_event_struct_t
*cmd
)
111 if ((cmd
->m_event_linkp
= mpt
->m_ioc_event_cmdq
) == NULL
) {
112 mpt
->m_ioc_event_cmdtail
= &cmd
->m_event_linkp
;
113 mpt
->m_ioc_event_cmdq
= cmd
;
115 cmd
->m_event_linkp
= NULL
;
116 *(mpt
->m_ioc_event_cmdtail
) = cmd
;
117 mpt
->m_ioc_event_cmdtail
= &cmd
->m_event_linkp
;
122 * remove specified cmd from the ioc event queue
125 mptsas_ioc_event_cmdq_delete(mptsas_t
*mpt
, m_event_struct_t
*cmd
)
127 m_event_struct_t
*prev
= mpt
->m_ioc_event_cmdq
;
129 if ((mpt
->m_ioc_event_cmdq
= cmd
->m_event_linkp
) == NULL
) {
130 mpt
->m_ioc_event_cmdtail
= &mpt
->m_ioc_event_cmdq
;
132 cmd
->m_event_linkp
= NULL
;
135 while (prev
!= NULL
) {
136 if (prev
->m_event_linkp
== cmd
) {
137 prev
->m_event_linkp
= cmd
->m_event_linkp
;
138 if (cmd
->m_event_linkp
== NULL
) {
139 mpt
->m_ioc_event_cmdtail
= &prev
->m_event_linkp
;
142 cmd
->m_event_linkp
= NULL
;
145 prev
= prev
->m_event_linkp
;
149 static m_event_struct_t
*
150 mptsas_ioc_event_find_by_cmd(mptsas_t
*mpt
, struct mptsas_cmd
*cmd
)
152 m_event_struct_t
*ioc_cmd
= NULL
;
154 ioc_cmd
= mpt
->m_ioc_event_cmdq
;
155 while (ioc_cmd
!= NULL
) {
156 if (&(ioc_cmd
->m_event_cmd
) == cmd
) {
159 ioc_cmd
= ioc_cmd
->m_event_linkp
;
166 mptsas_destroy_ioc_event_cmd(mptsas_t
*mpt
)
168 m_event_struct_t
*ioc_cmd
= NULL
;
169 m_event_struct_t
*ioc_cmd_tmp
= NULL
;
170 ioc_cmd
= mpt
->m_ioc_event_cmdq
;
173 * because the IOC event queue is resource of per instance for driver,
174 * it's not only ACK event commands used it, but also some others used
175 * it. We need destroy all ACK event commands when IOC reset, but can't
176 * disturb others.So we use filter to clear the ACK event cmd in ioc
177 * event queue, and other requests should be reserved, and they would
178 * be free by its owner.
180 while (ioc_cmd
!= NULL
) {
181 if (ioc_cmd
->m_event_cmd
.cmd_flags
& CFLAG_CMDACK
) {
182 NDBG20(("destroy!! remove Ack Flag ioc_cmd\n"));
183 if ((mpt
->m_ioc_event_cmdq
=
184 ioc_cmd
->m_event_linkp
) == NULL
)
185 mpt
->m_ioc_event_cmdtail
=
186 &mpt
->m_ioc_event_cmdq
;
187 ioc_cmd_tmp
= ioc_cmd
;
188 ioc_cmd
= ioc_cmd
->m_event_linkp
;
189 kmem_free(ioc_cmd_tmp
, M_EVENT_STRUCT_SIZE
);
192 * it's not ack cmd, so continue to check next one
195 NDBG20(("destroy!! it's not Ack Flag, continue\n"));
196 ioc_cmd
= ioc_cmd
->m_event_linkp
;
203 mptsas_start_config_page_access(mptsas_t
*mpt
, mptsas_cmd_t
*cmd
)
205 pMpi2ConfigRequest_t request
;
206 pMpi2SGESimple64_t sge
;
207 struct scsi_pkt
*pkt
= cmd
->cmd_pkt
;
208 mptsas_config_request_t
*config
= pkt
->pkt_ha_private
;
210 uint32_t length
, flagslength
, request_desc_low
;
212 ASSERT(mutex_owned(&mpt
->m_mutex
));
215 * Point to the correct message and clear it as well as the global
216 * config page memory.
218 request
= (pMpi2ConfigRequest_t
)(mpt
->m_req_frame
+
219 (mpt
->m_req_frame_size
* cmd
->cmd_slot
));
220 bzero(request
, mpt
->m_req_frame_size
);
223 * Form the request message.
225 ddi_put8(mpt
->m_acc_req_frame_hdl
, &request
->Function
,
226 MPI2_FUNCTION_CONFIG
);
227 ddi_put8(mpt
->m_acc_req_frame_hdl
, &request
->Action
, config
->action
);
228 direction
= MPI2_SGE_FLAGS_IOC_TO_HOST
;
230 sge
= (pMpi2SGESimple64_t
)&request
->PageBufferSGE
;
231 if (config
->action
== MPI2_CONFIG_ACTION_PAGE_HEADER
) {
232 if (config
->page_type
> MPI2_CONFIG_PAGETYPE_MASK
) {
233 ddi_put8(mpt
->m_acc_req_frame_hdl
,
234 &request
->Header
.PageType
,
235 MPI2_CONFIG_PAGETYPE_EXTENDED
);
236 ddi_put8(mpt
->m_acc_req_frame_hdl
,
237 &request
->ExtPageType
, config
->page_type
);
239 ddi_put8(mpt
->m_acc_req_frame_hdl
,
240 &request
->Header
.PageType
, config
->page_type
);
243 ddi_put8(mpt
->m_acc_req_frame_hdl
, &request
->ExtPageType
,
244 config
->ext_page_type
);
245 ddi_put16(mpt
->m_acc_req_frame_hdl
, &request
->ExtPageLength
,
246 config
->ext_page_length
);
247 ddi_put8(mpt
->m_acc_req_frame_hdl
, &request
->Header
.PageType
,
249 ddi_put8(mpt
->m_acc_req_frame_hdl
, &request
->Header
.PageLength
,
250 config
->page_length
);
251 ddi_put8(mpt
->m_acc_req_frame_hdl
,
252 &request
->Header
.PageVersion
, config
->page_version
);
253 if ((config
->page_type
& MPI2_CONFIG_PAGETYPE_MASK
) ==
254 MPI2_CONFIG_PAGETYPE_EXTENDED
) {
255 length
= config
->ext_page_length
* 4;
257 length
= config
->page_length
* 4;
260 if (config
->action
== MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM
) {
261 direction
= MPI2_SGE_FLAGS_HOST_TO_IOC
;
263 ddi_put32(mpt
->m_acc_req_frame_hdl
, &sge
->Address
.Low
,
264 (uint32_t)cmd
->cmd_dma_addr
);
265 ddi_put32(mpt
->m_acc_req_frame_hdl
, &sge
->Address
.High
,
266 (uint32_t)(cmd
->cmd_dma_addr
>> 32));
268 ddi_put8(mpt
->m_acc_req_frame_hdl
, &request
->Header
.PageNumber
,
269 config
->page_number
);
270 ddi_put32(mpt
->m_acc_req_frame_hdl
, &request
->PageAddress
,
271 config
->page_address
);
272 flagslength
= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT
|
273 MPI2_SGE_FLAGS_END_OF_BUFFER
|
274 MPI2_SGE_FLAGS_SIMPLE_ELEMENT
|
275 MPI2_SGE_FLAGS_SYSTEM_ADDRESS
|
276 MPI2_SGE_FLAGS_64_BIT_ADDRESSING
|
278 MPI2_SGE_FLAGS_END_OF_LIST
) << MPI2_SGE_FLAGS_SHIFT
);
279 flagslength
|= length
;
280 ddi_put32(mpt
->m_acc_req_frame_hdl
, &sge
->FlagsLength
, flagslength
);
282 (void) ddi_dma_sync(mpt
->m_dma_req_frame_hdl
, 0, 0,
283 DDI_DMA_SYNC_FORDEV
);
284 request_desc_low
= (cmd
->cmd_slot
<< 16) +
285 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE
;
287 MPTSAS_START_CMD(mpt
, request_desc_low
, 0);
288 if ((mptsas_check_dma_handle(mpt
->m_dma_req_frame_hdl
) !=
290 (mptsas_check_acc_handle(mpt
->m_acc_req_frame_hdl
) !=
292 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_UNAFFECTED
);
297 mptsas_access_config_page(mptsas_t
*mpt
, uint8_t action
, uint8_t page_type
,
298 uint8_t page_number
, uint32_t page_address
, int (*callback
) (mptsas_t
*,
299 caddr_t
, ddi_acc_handle_t
, uint16_t, uint32_t, va_list), ...)
302 ddi_dma_attr_t attrs
;
303 ddi_dma_cookie_t cookie
;
304 ddi_acc_handle_t accessp
;
306 mptsas_config_request_t config
;
307 int rval
= DDI_SUCCESS
, config_flags
= 0;
309 struct scsi_pkt
*pkt
;
310 pMpi2ConfigReply_t reply
;
311 uint16_t iocstatus
= 0;
314 boolean_t free_dma
= B_FALSE
;
316 va_start(ap
, callback
);
317 ASSERT(mutex_owned(&mpt
->m_mutex
));
320 * Get a command from the pool.
322 if ((rval
= (mptsas_request_from_pool(mpt
, &cmd
, &pkt
))) == -1) {
323 mptsas_log(mpt
, CE_NOTE
, "command pool is full for config "
328 config_flags
|= MPTSAS_REQUEST_POOL_CMD
;
330 bzero((caddr_t
)cmd
, sizeof (*cmd
));
331 bzero((caddr_t
)pkt
, scsi_pkt_size());
332 bzero((caddr_t
)&config
, sizeof (config
));
335 * Save the data for this request to be used in the call to start the
336 * config header request.
338 config
.action
= MPI2_CONFIG_ACTION_PAGE_HEADER
;
339 config
.page_type
= page_type
;
340 config
.page_number
= page_number
;
341 config
.page_address
= page_address
;
344 * Form a blank cmd/pkt to store the acknowledgement message
346 pkt
->pkt_ha_private
= (opaque_t
)&config
;
347 pkt
->pkt_flags
= FLAG_HEAD
;
350 cmd
->cmd_flags
= CFLAG_CMDIOC
| CFLAG_CONFIG
;
353 * Save the config header request message in a slot.
355 if (mptsas_save_cmd(mpt
, cmd
) == TRUE
) {
356 cmd
->cmd_flags
|= CFLAG_PREPARED
;
357 mptsas_start_config_page_access(mpt
, cmd
);
359 mptsas_waitq_add(mpt
, cmd
);
363 * If this is a request for a RAID info page, or any page called during
364 * the RAID info page request, poll because these config page requests
365 * are nested. Poll to avoid data corruption due to one page's data
366 * overwriting the outer page request's data. This can happen when
367 * the mutex is released in cv_wait.
369 if ((page_type
== MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG
) ||
370 (page_type
== MPI2_CONFIG_PAGETYPE_RAID_VOLUME
) ||
371 (page_type
== MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK
)) {
372 (void) mptsas_poll(mpt
, cmd
, pkt
->pkt_time
* 1000);
374 while ((cmd
->cmd_flags
& CFLAG_FINISHED
) == 0) {
375 cv_wait(&mpt
->m_config_cv
, &mpt
->m_mutex
);
380 * Check if the header request completed without timing out
382 if (cmd
->cmd_flags
& CFLAG_TIMEOUT
) {
383 mptsas_log(mpt
, CE_WARN
, "config header request timeout");
389 * cmd_rfm points to the reply message if a reply was given. Check the
390 * IOCStatus to make sure everything went OK with the header request.
393 config_flags
|= MPTSAS_ADDRESS_REPLY
;
394 (void) ddi_dma_sync(mpt
->m_dma_reply_frame_hdl
, 0, 0,
395 DDI_DMA_SYNC_FORCPU
);
396 reply
= (pMpi2ConfigReply_t
)(mpt
->m_reply_frame
+ (cmd
->cmd_rfm
397 - mpt
->m_reply_frame_dma_addr
));
398 config
.page_type
= ddi_get8(mpt
->m_acc_reply_frame_hdl
,
399 &reply
->Header
.PageType
);
400 config
.page_number
= ddi_get8(mpt
->m_acc_reply_frame_hdl
,
401 &reply
->Header
.PageNumber
);
402 config
.page_length
= ddi_get8(mpt
->m_acc_reply_frame_hdl
,
403 &reply
->Header
.PageLength
);
404 config
.page_version
= ddi_get8(mpt
->m_acc_reply_frame_hdl
,
405 &reply
->Header
.PageVersion
);
406 config
.ext_page_type
= ddi_get8(mpt
->m_acc_reply_frame_hdl
,
407 &reply
->ExtPageType
);
408 config
.ext_page_length
= ddi_get16(mpt
->m_acc_reply_frame_hdl
,
409 &reply
->ExtPageLength
);
411 iocstatus
= ddi_get16(mpt
->m_acc_reply_frame_hdl
,
413 iocloginfo
= ddi_get32(mpt
->m_acc_reply_frame_hdl
,
417 NDBG13(("mptsas_access_config_page header: "
418 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus
,
424 if ((config
.page_type
& MPI2_CONFIG_PAGETYPE_MASK
) ==
425 MPI2_CONFIG_PAGETYPE_EXTENDED
)
426 len
= (config
.ext_page_length
* 4);
428 len
= (config
.page_length
* 4);
432 if (pkt
->pkt_reason
== CMD_RESET
) {
433 mptsas_log(mpt
, CE_WARN
, "ioc reset abort config header "
440 * Put the reply frame back on the free queue, increment the free
441 * index, and write the new index to the free index register. But only
442 * if this reply is an ADDRESS reply.
444 if (config_flags
& MPTSAS_ADDRESS_REPLY
) {
445 ddi_put32(mpt
->m_acc_free_queue_hdl
,
446 &((uint32_t *)(void *)mpt
->m_free_queue
)[mpt
->m_free_index
],
448 (void) ddi_dma_sync(mpt
->m_dma_free_queue_hdl
, 0, 0,
449 DDI_DMA_SYNC_FORDEV
);
450 if (++mpt
->m_free_index
== mpt
->m_free_queue_depth
) {
451 mpt
->m_free_index
= 0;
453 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->ReplyFreeHostIndex
,
455 config_flags
&= (~MPTSAS_ADDRESS_REPLY
);
459 * Allocate DMA buffer here. Store the info regarding this buffer in
460 * the cmd struct so that it can be used for this specific command and
461 * de-allocated after the command completes. The size of the reply
462 * will not be larger than the reply frame size.
464 attrs
= mpt
->m_msg_dma_attr
;
465 attrs
.dma_attr_sgllen
= 1;
466 attrs
.dma_attr_granular
= (uint32_t)len
;
468 if (mptsas_dma_addr_create(mpt
, attrs
,
469 &cmd
->cmd_dmahandle
, &accessp
, &page_memp
,
470 len
, &cookie
) == FALSE
) {
472 mptsas_log(mpt
, CE_WARN
,
473 "mptsas_dma_addr_create(len=0x%x) failed", (int)len
);
476 /* NOW we can safely call mptsas_dma_addr_destroy(). */
479 cmd
->cmd_dma_addr
= cookie
.dmac_laddress
;
480 bzero(page_memp
, len
);
483 * Save the data for this request to be used in the call to start the
486 config
.action
= action
;
487 config
.page_address
= page_address
;
490 * Re-use the cmd that was used to get the header. Reset some of the
493 bzero((caddr_t
)pkt
, scsi_pkt_size());
494 pkt
->pkt_ha_private
= (opaque_t
)&config
;
495 pkt
->pkt_flags
= FLAG_HEAD
;
497 cmd
->cmd_flags
= CFLAG_PREPARED
| CFLAG_CMDIOC
| CFLAG_CONFIG
;
500 * Send the config page request. cmd is re-used from header request.
502 mptsas_start_config_page_access(mpt
, cmd
);
505 * If this is a request for a RAID info page, or any page called during
506 * the RAID info page request, poll because these config page requests
507 * are nested. Poll to avoid data corruption due to one page's data
508 * overwriting the outer page request's data. This can happen when
509 * the mutex is released in cv_wait.
511 if ((page_type
== MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG
) ||
512 (page_type
== MPI2_CONFIG_PAGETYPE_RAID_VOLUME
) ||
513 (page_type
== MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK
)) {
514 (void) mptsas_poll(mpt
, cmd
, pkt
->pkt_time
* 1000);
516 while ((cmd
->cmd_flags
& CFLAG_FINISHED
) == 0) {
517 cv_wait(&mpt
->m_config_cv
, &mpt
->m_mutex
);
522 * Check if the request completed without timing out
524 if (cmd
->cmd_flags
& CFLAG_TIMEOUT
) {
525 mptsas_log(mpt
, CE_WARN
, "config page request timeout");
531 * cmd_rfm points to the reply message if a reply was given. The reply
532 * frame and the config page are returned from this function in the
536 config_flags
|= MPTSAS_ADDRESS_REPLY
;
537 (void) ddi_dma_sync(mpt
->m_dma_reply_frame_hdl
, 0, 0,
538 DDI_DMA_SYNC_FORCPU
);
539 (void) ddi_dma_sync(cmd
->cmd_dmahandle
, 0, 0,
540 DDI_DMA_SYNC_FORCPU
);
541 reply
= (pMpi2ConfigReply_t
)(mpt
->m_reply_frame
+ (cmd
->cmd_rfm
542 - mpt
->m_reply_frame_dma_addr
));
543 iocstatus
= ddi_get16(mpt
->m_acc_reply_frame_hdl
,
545 iocstatus
= MPTSAS_IOCSTATUS(iocstatus
);
546 iocloginfo
= ddi_get32(mpt
->m_acc_reply_frame_hdl
,
550 if (callback(mpt
, page_memp
, accessp
, iocstatus
, iocloginfo
, ap
)) {
555 mptsas_fma_check(mpt
, cmd
);
557 * Check the DMA/ACC handles and then free the DMA buffer.
559 if ((mptsas_check_dma_handle(cmd
->cmd_dmahandle
) != DDI_SUCCESS
) ||
560 (mptsas_check_acc_handle(accessp
) != DDI_SUCCESS
)) {
561 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_UNAFFECTED
);
565 if (pkt
->pkt_reason
== CMD_TRAN_ERR
) {
566 mptsas_log(mpt
, CE_WARN
, "config fma error");
570 if (pkt
->pkt_reason
== CMD_RESET
) {
571 mptsas_log(mpt
, CE_WARN
, "ioc reset abort config request");
579 * Put the reply frame back on the free queue, increment the free
580 * index, and write the new index to the free index register. But only
581 * if this reply is an ADDRESS reply.
583 if (config_flags
& MPTSAS_ADDRESS_REPLY
) {
584 ddi_put32(mpt
->m_acc_free_queue_hdl
,
585 &((uint32_t *)(void *)mpt
->m_free_queue
)[mpt
->m_free_index
],
587 (void) ddi_dma_sync(mpt
->m_dma_free_queue_hdl
, 0, 0,
588 DDI_DMA_SYNC_FORDEV
);
589 if (++mpt
->m_free_index
== mpt
->m_free_queue_depth
) {
590 mpt
->m_free_index
= 0;
592 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->ReplyFreeHostIndex
,
597 mptsas_dma_addr_destroy(&cmd
->cmd_dmahandle
, &accessp
);
599 if (cmd
&& (cmd
->cmd_flags
& CFLAG_PREPARED
)) {
600 mptsas_remove_cmd(mpt
, cmd
);
601 config_flags
&= (~MPTSAS_REQUEST_POOL_CMD
);
603 if (config_flags
& MPTSAS_REQUEST_POOL_CMD
)
604 mptsas_return_to_pool(mpt
, cmd
);
606 if (config_flags
& MPTSAS_CMD_TIMEOUT
) {
607 mpt
->m_softstate
&= ~MPTSAS_SS_MSG_UNIT_RESET
;
608 if ((mptsas_restart_ioc(mpt
)) == DDI_FAILURE
) {
609 mptsas_log(mpt
, CE_WARN
, "mptsas_restart_ioc failed");
617 mptsas_send_config_request_msg(mptsas_t
*mpt
, uint8_t action
, uint8_t pagetype
,
618 uint32_t pageaddress
, uint8_t pagenumber
, uint8_t pageversion
,
619 uint8_t pagelength
, uint32_t SGEflagslength
, uint32_t SGEaddress32
)
621 pMpi2ConfigRequest_t config
;
624 bzero(mpt
->m_hshk_memp
, sizeof (MPI2_CONFIG_REQUEST
));
625 config
= (pMpi2ConfigRequest_t
)mpt
->m_hshk_memp
;
626 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->Function
, MPI2_FUNCTION_CONFIG
);
627 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->Action
, action
);
628 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->Header
.PageNumber
, pagenumber
);
629 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->Header
.PageType
, pagetype
);
630 ddi_put32(mpt
->m_hshk_acc_hdl
, &config
->PageAddress
, pageaddress
);
631 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->Header
.PageVersion
, pageversion
);
632 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->Header
.PageLength
, pagelength
);
633 ddi_put32(mpt
->m_hshk_acc_hdl
,
634 &config
->PageBufferSGE
.MpiSimple
.FlagsLength
, SGEflagslength
);
635 ddi_put32(mpt
->m_hshk_acc_hdl
,
636 &config
->PageBufferSGE
.MpiSimple
.u
.Address32
, SGEaddress32
);
637 send_numbytes
= sizeof (MPI2_CONFIG_REQUEST
);
640 * Post message via handshake
642 if (mptsas_send_handshake_msg(mpt
, (caddr_t
)config
, send_numbytes
,
643 mpt
->m_hshk_acc_hdl
)) {
650 mptsas_send_extended_config_request_msg(mptsas_t
*mpt
, uint8_t action
,
651 uint8_t extpagetype
, uint32_t pageaddress
, uint8_t pagenumber
,
652 uint8_t pageversion
, uint16_t extpagelength
,
653 uint32_t SGEflagslength
, uint32_t SGEaddress32
)
655 pMpi2ConfigRequest_t config
;
658 bzero(mpt
->m_hshk_memp
, sizeof (MPI2_CONFIG_REQUEST
));
659 config
= (pMpi2ConfigRequest_t
)mpt
->m_hshk_memp
;
660 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->Function
, MPI2_FUNCTION_CONFIG
);
661 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->Action
, action
);
662 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->Header
.PageNumber
, pagenumber
);
663 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->Header
.PageType
,
664 MPI2_CONFIG_PAGETYPE_EXTENDED
);
665 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->ExtPageType
, extpagetype
);
666 ddi_put32(mpt
->m_hshk_acc_hdl
, &config
->PageAddress
, pageaddress
);
667 ddi_put8(mpt
->m_hshk_acc_hdl
, &config
->Header
.PageVersion
, pageversion
);
668 ddi_put16(mpt
->m_hshk_acc_hdl
, &config
->ExtPageLength
, extpagelength
);
669 ddi_put32(mpt
->m_hshk_acc_hdl
,
670 &config
->PageBufferSGE
.MpiSimple
.FlagsLength
, SGEflagslength
);
671 ddi_put32(mpt
->m_hshk_acc_hdl
,
672 &config
->PageBufferSGE
.MpiSimple
.u
.Address32
, SGEaddress32
);
673 send_numbytes
= sizeof (MPI2_CONFIG_REQUEST
);
676 * Post message via handshake
678 if (mptsas_send_handshake_msg(mpt
, (caddr_t
)config
, send_numbytes
,
679 mpt
->m_hshk_acc_hdl
)) {
686 mptsas_ioc_wait_for_response(mptsas_t
*mpt
)
690 while ((ddi_get32(mpt
->m_datap
,
691 &mpt
->m_reg
->HostInterruptStatus
) & MPI2_HIS_IOP_DOORBELL_STATUS
)) {
693 if (polls
++ > 60000) {
701 mptsas_ioc_wait_for_doorbell(mptsas_t
*mpt
)
705 while ((ddi_get32(mpt
->m_datap
,
706 &mpt
->m_reg
->HostInterruptStatus
) & MPI2_HIM_DIM
) == 0) {
708 if (polls
++ > 300000) {
716 mptsas_send_handshake_msg(mptsas_t
*mpt
, caddr_t memp
, int numbytes
,
717 ddi_acc_handle_t accessp
)
722 * clean pending doorbells
724 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->HostInterruptStatus
, 0);
725 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->Doorbell
,
726 ((MPI2_FUNCTION_HANDSHAKE
<< MPI2_DOORBELL_FUNCTION_SHIFT
) |
727 ((numbytes
/ 4) << MPI2_DOORBELL_ADD_DWORDS_SHIFT
)));
729 if (mptsas_ioc_wait_for_doorbell(mpt
)) {
730 NDBG19(("mptsas_send_handshake failed. Doorbell not ready\n"));
735 * clean pending doorbells again
737 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->HostInterruptStatus
, 0);
739 if (mptsas_ioc_wait_for_response(mpt
)) {
740 NDBG19(("mptsas_send_handshake failed. Doorbell not "
746 * post handshake message
748 for (i
= 0; (i
< numbytes
/ 4); i
++, memp
+= 4) {
749 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->Doorbell
,
750 ddi_get32(accessp
, (uint32_t *)((void *)(memp
))));
751 if (mptsas_ioc_wait_for_response(mpt
)) {
752 NDBG19(("mptsas_send_handshake failed posting "
758 if (mptsas_check_acc_handle(mpt
->m_datap
) != DDI_SUCCESS
) {
759 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_UNAFFECTED
);
760 ddi_fm_acc_err_clear(mpt
->m_datap
, DDI_FME_VER0
);
768 mptsas_get_handshake_msg(mptsas_t
*mpt
, caddr_t memp
, int numbytes
,
769 ddi_acc_handle_t accessp
)
771 int i
, totalbytes
, bytesleft
;
777 if (mptsas_ioc_wait_for_doorbell(mpt
)) {
778 NDBG19(("mptsas_get_handshake failed. Doorbell not ready\n"));
783 * get first 2 bytes of handshake message to determine how much
784 * data we will be getting
786 for (i
= 0; i
< 2; i
++, memp
+= 2) {
787 val
= (ddi_get32(mpt
->m_datap
,
788 &mpt
->m_reg
->Doorbell
) & MPI2_DOORBELL_DATA_MASK
);
789 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->HostInterruptStatus
, 0);
790 if (mptsas_ioc_wait_for_doorbell(mpt
)) {
791 NDBG19(("mptsas_get_handshake failure getting initial"
795 ddi_put16(accessp
, (uint16_t *)((void *)(memp
)), val
);
797 totalbytes
= (val
& 0xFF) * 2;
802 * If we are expecting less bytes than the message wants to send
803 * we simply save as much as we expected and then throw out the rest
806 if (totalbytes
> (numbytes
/ 2)) {
807 bytesleft
= ((numbytes
/ 2) - 2);
809 bytesleft
= (totalbytes
- 2);
813 * Get the rest of the data
815 for (i
= 0; i
< bytesleft
; i
++, memp
+= 2) {
816 val
= (ddi_get32(mpt
->m_datap
,
817 &mpt
->m_reg
->Doorbell
) & MPI2_DOORBELL_DATA_MASK
);
818 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->HostInterruptStatus
, 0);
819 if (mptsas_ioc_wait_for_doorbell(mpt
)) {
820 NDBG19(("mptsas_get_handshake failure getting"
824 ddi_put16(accessp
, (uint16_t *)((void *)(memp
)), val
);
828 * Sometimes the device will send more data than is expected
829 * This data is not used by us but needs to be cleared from
830 * ioc doorbell. So we just read the values and throw
833 if (totalbytes
> (numbytes
/ 2)) {
834 for (i
= (numbytes
/ 2); i
< totalbytes
; i
++) {
835 val
= (ddi_get32(mpt
->m_datap
,
836 &mpt
->m_reg
->Doorbell
) &
837 MPI2_DOORBELL_DATA_MASK
);
838 ddi_put32(mpt
->m_datap
,
839 &mpt
->m_reg
->HostInterruptStatus
, 0);
840 if (mptsas_ioc_wait_for_doorbell(mpt
)) {
841 NDBG19(("mptsas_get_handshake failure getting "
842 "extra garbage data\n"));
848 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->HostInterruptStatus
, 0);
850 if (mptsas_check_acc_handle(mpt
->m_datap
) != DDI_SUCCESS
) {
851 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_UNAFFECTED
);
852 ddi_fm_acc_err_clear(mpt
->m_datap
, DDI_FME_VER0
);
860 mptsas_kick_start(mptsas_t
*mpt
)
863 uint32_t diag_reg
, ioc_state
, saved_HCB_size
;
866 * Start a hard reset. Write magic number and wait 500 mSeconds.
868 MPTSAS_ENABLE_DRWE(mpt
);
869 drv_usecwait(500000);
872 * Read the current Diag Reg and save the Host Controlled Boot size.
874 diag_reg
= ddi_get32(mpt
->m_datap
, &mpt
->m_reg
->HostDiagnostic
);
875 saved_HCB_size
= ddi_get32(mpt
->m_datap
, &mpt
->m_reg
->HCBSize
);
878 * Set Reset Adapter bit and wait 50 mSeconds.
880 diag_reg
|= MPI2_DIAG_RESET_ADAPTER
;
881 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->HostDiagnostic
, diag_reg
);
885 * Poll, waiting for Reset Adapter bit to clear. 300 Seconds max
886 * (600000 * 500 = 300,000,000 uSeconds, 300 seconds).
887 * If no more adapter (all FF's), just return failure.
889 for (polls
= 0; polls
< 600000; polls
++) {
890 diag_reg
= ddi_get32(mpt
->m_datap
,
891 &mpt
->m_reg
->HostDiagnostic
);
892 if (diag_reg
== 0xFFFFFFFF) {
893 mptsas_fm_ereport(mpt
, DDI_FM_DEVICE_NO_RESPONSE
);
894 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_LOST
);
895 return (DDI_FAILURE
);
897 if (!(diag_reg
& MPI2_DIAG_RESET_ADAPTER
)) {
902 if (polls
== 600000) {
903 mptsas_fm_ereport(mpt
, DDI_FM_DEVICE_NO_RESPONSE
);
904 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_LOST
);
905 return (DDI_FAILURE
);
909 * Check if adapter is in Host Boot Mode. If so, restart adapter
910 * assuming the HCB points to good FW.
911 * Set BootDeviceSel to HCDW (Host Code and Data Window).
913 if (diag_reg
& MPI2_DIAG_HCB_MODE
) {
914 diag_reg
&= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK
;
915 diag_reg
|= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW
;
916 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->HostDiagnostic
, diag_reg
);
919 * Re-enable the HCDW.
921 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->HCBSize
,
922 (saved_HCB_size
| MPI2_HCB_SIZE_HCB_ENABLE
));
926 * Restart the adapter.
928 diag_reg
&= ~MPI2_DIAG_HOLD_IOC_RESET
;
929 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->HostDiagnostic
, diag_reg
);
932 * Disable writes to the Host Diag register.
934 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->WriteSequence
,
935 MPI2_WRSEQ_FLUSH_KEY_VALUE
);
938 * Wait 60 seconds max for FW to come to ready state.
940 for (polls
= 0; polls
< 60000; polls
++) {
941 ioc_state
= ddi_get32(mpt
->m_datap
, &mpt
->m_reg
->Doorbell
);
942 if (ioc_state
== 0xFFFFFFFF) {
943 mptsas_fm_ereport(mpt
, DDI_FM_DEVICE_NO_RESPONSE
);
944 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_LOST
);
945 return (DDI_FAILURE
);
947 if ((ioc_state
& MPI2_IOC_STATE_MASK
) ==
948 MPI2_IOC_STATE_READY
) {
953 if (polls
== 60000) {
954 mptsas_fm_ereport(mpt
, DDI_FM_DEVICE_NO_RESPONSE
);
955 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_LOST
);
956 return (DDI_FAILURE
);
960 * Clear the ioc ack events queue.
962 mptsas_destroy_ioc_event_cmd(mpt
);
964 return (DDI_SUCCESS
);
968 mptsas_ioc_reset(mptsas_t
*mpt
, int first_time
)
974 ioc_state
= ddi_get32(mpt
->m_datap
, &mpt
->m_reg
->Doorbell
);
976 * If chip is already in ready state then there is nothing to do.
978 if (ioc_state
== MPI2_IOC_STATE_READY
) {
979 return (MPTSAS_NO_RESET
);
982 * If the chip is already operational, we just need to send
983 * it a message unit reset to put it back in the ready state
985 if (ioc_state
& MPI2_IOC_STATE_OPERATIONAL
) {
987 * If the first time, try MUR anyway, because we haven't even
988 * queried the card for m_event_replay and other capabilities.
989 * Other platforms do it this way, we can still do a hard
990 * reset if we need to, MUR takes less time than a full
991 * adapter reset, and there are reports that some HW
992 * combinations will lock up when receiving a hard reset.
994 if ((first_time
|| mpt
->m_event_replay
) &&
995 (mpt
->m_softstate
& MPTSAS_SS_MSG_UNIT_RESET
)) {
996 mpt
->m_softstate
&= ~MPTSAS_SS_MSG_UNIT_RESET
;
997 reset_msg
= MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET
;
998 ddi_put32(mpt
->m_datap
, &mpt
->m_reg
->Doorbell
,
999 (reset_msg
<< MPI2_DOORBELL_FUNCTION_SHIFT
));
1000 if (mptsas_ioc_wait_for_response(mpt
)) {
1001 NDBG19(("mptsas_ioc_reset failure sending "
1002 "message_unit_reset\n"));
1007 * Wait no more than 60 seconds for chip to become
1010 while ((ddi_get32(mpt
->m_datap
, &mpt
->m_reg
->Doorbell
) &
1011 MPI2_IOC_STATE_READY
) == 0x0) {
1013 if (polls
++ > 60000) {
1019 * Save the last reset mode done on IOC which will be
1020 * helpful while resuming from suspension.
1022 mpt
->m_softstate
|= MPTSAS_DID_MSG_UNIT_RESET
;
1025 * the message unit reset would do reset operations
1026 * clear reply and request queue, so we should clear
1029 mptsas_destroy_ioc_event_cmd(mpt
);
1030 return (MPTSAS_SUCCESS_MUR
);
1034 mpt
->m_softstate
&= ~MPTSAS_DID_MSG_UNIT_RESET
;
1035 if (mptsas_kick_start(mpt
) == DDI_FAILURE
) {
1036 mptsas_fm_ereport(mpt
, DDI_FM_DEVICE_NO_RESPONSE
);
1037 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_LOST
);
1038 return (MPTSAS_RESET_FAIL
);
1040 return (MPTSAS_SUCCESS_HARDRESET
);
1045 mptsas_request_from_pool(mptsas_t
*mpt
, mptsas_cmd_t
**cmd
,
1046 struct scsi_pkt
**pkt
)
1048 m_event_struct_t
*ioc_cmd
= NULL
;
1050 ioc_cmd
= kmem_zalloc(M_EVENT_STRUCT_SIZE
, KM_SLEEP
);
1051 if (ioc_cmd
== NULL
) {
1052 return (DDI_FAILURE
);
1054 ioc_cmd
->m_event_linkp
= NULL
;
1055 mptsas_ioc_event_cmdq_add(mpt
, ioc_cmd
);
1056 *cmd
= &(ioc_cmd
->m_event_cmd
);
1057 *pkt
= &(ioc_cmd
->m_event_pkt
);
1059 return (DDI_SUCCESS
);
1063 mptsas_return_to_pool(mptsas_t
*mpt
, mptsas_cmd_t
*cmd
)
1065 m_event_struct_t
*ioc_cmd
= NULL
;
1067 ioc_cmd
= mptsas_ioc_event_find_by_cmd(mpt
, cmd
);
1068 if (ioc_cmd
== NULL
) {
1072 mptsas_ioc_event_cmdq_delete(mpt
, ioc_cmd
);
1073 kmem_free(ioc_cmd
, M_EVENT_STRUCT_SIZE
);
1078 * NOTE: We should be able to queue TM requests in the controller to make this
1079 * a lot faster. If resetting all targets, for example, we can load the hi
1080 * priority queue with its limit and the controller will reply as they are
1081 * completed. This way, we don't have to poll for one reply at a time.
1082 * Think about enhancing this later.
1085 mptsas_ioc_task_management(mptsas_t
*mpt
, int task_type
, uint16_t dev_handle
,
1086 int lun
, uint8_t *reply
, uint32_t reply_size
, int mode
)
1089 * In order to avoid allocating variables on the stack,
1090 * we make use of the pre-existing mptsas_cmd_t and
1091 * scsi_pkt which are included in the mptsas_t which
1092 * is passed to this routine.
1095 pMpi2SCSITaskManagementRequest_t task
;
1098 struct scsi_pkt
*pkt
;
1099 mptsas_slots_t
*slots
= mpt
->m_active
;
1100 uint32_t request_desc_low
, i
;
1101 pMPI2DefaultReply_t reply_msg
;
1104 * Can't start another task management routine.
1106 if (slots
->m_slot
[MPTSAS_TM_SLOT(mpt
)] != NULL
) {
1107 mptsas_log(mpt
, CE_WARN
, "Can only start 1 task management"
1108 " command at a time\n");
1112 cmd
= &(mpt
->m_event_task_mgmt
.m_event_cmd
);
1113 pkt
= &(mpt
->m_event_task_mgmt
.m_event_pkt
);
1115 bzero((caddr_t
)cmd
, sizeof (*cmd
));
1116 bzero((caddr_t
)pkt
, scsi_pkt_size());
1118 pkt
->pkt_cdbp
= (opaque_t
)&cmd
->cmd_cdb
[0];
1119 pkt
->pkt_scbp
= (opaque_t
)&cmd
->cmd_scb
;
1120 pkt
->pkt_ha_private
= (opaque_t
)cmd
;
1121 pkt
->pkt_flags
= (FLAG_NOINTR
| FLAG_HEAD
);
1123 pkt
->pkt_address
.a_target
= dev_handle
;
1124 pkt
->pkt_address
.a_lun
= (uchar_t
)lun
;
1126 cmd
->cmd_scblen
= 1;
1127 cmd
->cmd_flags
= CFLAG_TM_CMD
;
1128 cmd
->cmd_slot
= MPTSAS_TM_SLOT(mpt
);
1130 slots
->m_slot
[MPTSAS_TM_SLOT(mpt
)] = cmd
;
1133 * Store the TM message in memory location corresponding to the TM slot
1136 task
= (pMpi2SCSITaskManagementRequest_t
)(mpt
->m_req_frame
+
1137 (mpt
->m_req_frame_size
* cmd
->cmd_slot
));
1138 bzero(task
, mpt
->m_req_frame_size
);
1141 * form message for requested task
1143 mptsas_init_std_hdr(mpt
->m_acc_req_frame_hdl
, task
, dev_handle
, lun
, 0,
1144 MPI2_FUNCTION_SCSI_TASK_MGMT
);
1149 ddi_put8(mpt
->m_acc_req_frame_hdl
, &task
->TaskType
, task_type
);
1152 * Send TM request using High Priority Queue.
1154 (void) ddi_dma_sync(mpt
->m_dma_req_frame_hdl
, 0, 0,
1155 DDI_DMA_SYNC_FORDEV
);
1156 request_desc_low
= (cmd
->cmd_slot
<< 16) +
1157 MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY
;
1158 MPTSAS_START_CMD(mpt
, request_desc_low
, 0);
1159 rval
= mptsas_poll(mpt
, cmd
, MPTSAS_POLL_TIME
);
1161 if (pkt
->pkt_reason
== CMD_INCOMPLETE
)
1165 * If a reply frame was used and there is a reply buffer to copy the
1166 * reply data into, copy it. If this fails, log a message, but don't
1167 * fail the TM request.
1169 if (cmd
->cmd_rfm
&& reply
) {
1170 (void) ddi_dma_sync(mpt
->m_dma_reply_frame_hdl
, 0, 0,
1171 DDI_DMA_SYNC_FORCPU
);
1172 reply_msg
= (pMPI2DefaultReply_t
)
1173 (mpt
->m_reply_frame
+ (cmd
->cmd_rfm
-
1174 mpt
->m_reply_frame_dma_addr
));
1175 if (reply_size
> sizeof (MPI2_SCSI_TASK_MANAGE_REPLY
)) {
1176 reply_size
= sizeof (MPI2_SCSI_TASK_MANAGE_REPLY
);
1178 mutex_exit(&mpt
->m_mutex
);
1179 for (i
= 0; i
< reply_size
; i
++) {
1180 if (ddi_copyout((uint8_t *)reply_msg
+ i
, reply
+ i
, 1,
1182 mptsas_log(mpt
, CE_WARN
, "failed to copy out "
1183 "reply data for TM request");
1187 mutex_enter(&mpt
->m_mutex
);
1191 * clear the TM slot before returning
1193 slots
->m_slot
[MPTSAS_TM_SLOT(mpt
)] = NULL
;
1196 * If we lost our task management command
1197 * we need to reset the ioc
1199 if (rval
== FALSE
) {
1200 mptsas_log(mpt
, CE_WARN
, "mptsas_ioc_task_management failed "
1201 "try to reset ioc to recovery!");
1202 mpt
->m_softstate
&= ~MPTSAS_SS_MSG_UNIT_RESET
;
1203 if (mptsas_restart_ioc(mpt
)) {
1204 mptsas_log(mpt
, CE_WARN
, "mptsas_restart_ioc failed");
1213 * Complete firmware download frame for v2.0 cards.
1216 mptsas_uflash2(pMpi2FWDownloadRequest fwdownload
,
1217 ddi_acc_handle_t acc_hdl
, uint32_t size
, uint8_t type
,
1218 ddi_dma_cookie_t flsh_cookie
)
1220 pMpi2FWDownloadTCSGE_t tcsge
;
1221 pMpi2SGESimple64_t sge
;
1222 uint32_t flagslength
;
1224 ddi_put8(acc_hdl
, &fwdownload
->Function
,
1225 MPI2_FUNCTION_FW_DOWNLOAD
);
1226 ddi_put8(acc_hdl
, &fwdownload
->ImageType
, type
);
1227 ddi_put8(acc_hdl
, &fwdownload
->MsgFlags
,
1228 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT
);
1229 ddi_put32(acc_hdl
, &fwdownload
->TotalImageSize
, size
);
1231 tcsge
= (pMpi2FWDownloadTCSGE_t
)&fwdownload
->SGL
;
1232 ddi_put8(acc_hdl
, &tcsge
->ContextSize
, 0);
1233 ddi_put8(acc_hdl
, &tcsge
->DetailsLength
, 12);
1234 ddi_put8(acc_hdl
, &tcsge
->Flags
, 0);
1235 ddi_put32(acc_hdl
, &tcsge
->ImageOffset
, 0);
1236 ddi_put32(acc_hdl
, &tcsge
->ImageSize
, size
);
1238 sge
= (pMpi2SGESimple64_t
)(tcsge
+ 1);
1240 flagslength
|= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT
|
1241 MPI2_SGE_FLAGS_END_OF_BUFFER
|
1242 MPI2_SGE_FLAGS_SIMPLE_ELEMENT
|
1243 MPI2_SGE_FLAGS_SYSTEM_ADDRESS
|
1244 MPI2_SGE_FLAGS_64_BIT_ADDRESSING
|
1245 MPI2_SGE_FLAGS_HOST_TO_IOC
|
1246 MPI2_SGE_FLAGS_END_OF_LIST
) << MPI2_SGE_FLAGS_SHIFT
);
1247 ddi_put32(acc_hdl
, &sge
->FlagsLength
, flagslength
);
1248 ddi_put32(acc_hdl
, &sge
->Address
.Low
,
1249 flsh_cookie
.dmac_address
);
1250 ddi_put32(acc_hdl
, &sge
->Address
.High
,
1251 (uint32_t)(flsh_cookie
.dmac_laddress
>> 32));
1255 * Complete firmware download frame for v2.5 cards.
1258 mptsas_uflash25(pMpi25FWDownloadRequest fwdownload
,
1259 ddi_acc_handle_t acc_hdl
, uint32_t size
, uint8_t type
,
1260 ddi_dma_cookie_t flsh_cookie
)
1262 pMpi2IeeeSgeSimple64_t sge
;
1265 ddi_put8(acc_hdl
, &fwdownload
->Function
,
1266 MPI2_FUNCTION_FW_DOWNLOAD
);
1267 ddi_put8(acc_hdl
, &fwdownload
->ImageType
, type
);
1268 ddi_put8(acc_hdl
, &fwdownload
->MsgFlags
,
1269 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT
);
1270 ddi_put32(acc_hdl
, &fwdownload
->TotalImageSize
, size
);
1272 ddi_put32(acc_hdl
, &fwdownload
->ImageOffset
, 0);
1273 ddi_put32(acc_hdl
, &fwdownload
->ImageSize
, size
);
1275 sge
= (pMpi2IeeeSgeSimple64_t
)&fwdownload
->SGL
;
1276 flags
= MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT
|
1277 MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR
|
1278 MPI25_IEEE_SGE_FLAGS_END_OF_LIST
;
1279 ddi_put8(acc_hdl
, &sge
->Flags
, flags
);
1280 ddi_put32(acc_hdl
, &sge
->Length
, size
);
1281 ddi_put32(acc_hdl
, &sge
->Address
.Low
,
1282 flsh_cookie
.dmac_address
);
1283 ddi_put32(acc_hdl
, &sge
->Address
.High
,
1284 (uint32_t)(flsh_cookie
.dmac_laddress
>> 32));
1287 static int mptsas_enable_mpi25_flashupdate
= 0;
1290 mptsas_update_flash(mptsas_t
*mpt
, caddr_t ptrbuffer
, uint32_t size
,
1291 uint8_t type
, int mode
)
1295 * In order to avoid allocating variables on the stack,
1296 * we make use of the pre-existing mptsas_cmd_t and
1297 * scsi_pkt which are included in the mptsas_t which
1298 * is passed to this routine.
1301 ddi_dma_attr_t flsh_dma_attrs
;
1302 ddi_dma_cookie_t flsh_cookie
;
1303 ddi_dma_handle_t flsh_dma_handle
;
1304 ddi_acc_handle_t flsh_accessp
;
1305 caddr_t memp
, flsh_memp
;
1307 struct scsi_pkt
*pkt
;
1310 uint32_t request_desc_low
;
1312 if (mpt
->m_MPI25
&& !mptsas_enable_mpi25_flashupdate
) {
1314 * The code is there but not tested yet.
1315 * User has to know there are risks here.
1317 mptsas_log(mpt
, CE_WARN
, "mptsas_update_flash(): "
1318 "Updating firmware through MPI 2.5 has not been "
1320 "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
1322 } /* Otherwise, you pay your money and you take your chances. */
1324 if ((rvalue
= (mptsas_request_from_pool(mpt
, &cmd
, &pkt
))) == -1) {
1325 mptsas_log(mpt
, CE_WARN
, "mptsas_update_flash(): allocation "
1326 "failed. event ack command pool is full\n");
1330 bzero((caddr_t
)cmd
, sizeof (*cmd
));
1331 bzero((caddr_t
)pkt
, scsi_pkt_size());
1332 cmd
->ioc_cmd_slot
= (uint32_t)rvalue
;
1335 * dynamically create a customized dma attribute structure
1336 * that describes the flash file.
1338 flsh_dma_attrs
= mpt
->m_msg_dma_attr
;
1339 flsh_dma_attrs
.dma_attr_sgllen
= 1;
1341 if (mptsas_dma_addr_create(mpt
, flsh_dma_attrs
, &flsh_dma_handle
,
1342 &flsh_accessp
, &flsh_memp
, size
, &flsh_cookie
) == FALSE
) {
1343 mptsas_log(mpt
, CE_WARN
,
1344 "(unable to allocate dma resource.");
1345 mptsas_return_to_pool(mpt
, cmd
);
1349 bzero(flsh_memp
, size
);
1351 for (i
= 0; i
< size
; i
++) {
1352 (void) ddi_copyin(ptrbuffer
+ i
, flsh_memp
+ i
, 1, mode
);
1354 (void) ddi_dma_sync(flsh_dma_handle
, 0, 0, DDI_DMA_SYNC_FORDEV
);
1357 * form a cmd/pkt to store the fw download message
1359 pkt
->pkt_cdbp
= (opaque_t
)&cmd
->cmd_cdb
[0];
1360 pkt
->pkt_scbp
= (opaque_t
)&cmd
->cmd_scb
;
1361 pkt
->pkt_ha_private
= (opaque_t
)cmd
;
1362 pkt
->pkt_flags
= FLAG_HEAD
;
1365 cmd
->cmd_scblen
= 1;
1366 cmd
->cmd_flags
= CFLAG_CMDIOC
| CFLAG_FW_CMD
;
1369 * Save the command in a slot
1371 if (mptsas_save_cmd(mpt
, cmd
) == FALSE
) {
1372 mptsas_dma_addr_destroy(&flsh_dma_handle
, &flsh_accessp
);
1373 mptsas_return_to_pool(mpt
, cmd
);
1378 * Fill in fw download message
1380 ASSERT(cmd
->cmd_slot
!= 0);
1381 memp
= mpt
->m_req_frame
+ (mpt
->m_req_frame_size
* cmd
->cmd_slot
);
1382 bzero(memp
, mpt
->m_req_frame_size
);
1385 mptsas_uflash25((pMpi25FWDownloadRequest
)memp
,
1386 mpt
->m_acc_req_frame_hdl
, size
, type
, flsh_cookie
);
1388 mptsas_uflash2((pMpi2FWDownloadRequest
)memp
,
1389 mpt
->m_acc_req_frame_hdl
, size
, type
, flsh_cookie
);
1394 (void) ddi_dma_sync(mpt
->m_dma_req_frame_hdl
, 0, 0,
1395 DDI_DMA_SYNC_FORDEV
);
1396 request_desc_low
= (cmd
->cmd_slot
<< 16) +
1397 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE
;
1398 cmd
->cmd_rfm
= NULL
;
1399 MPTSAS_START_CMD(mpt
, request_desc_low
, 0);
1402 (void) cv_reltimedwait(&mpt
->m_fw_cv
, &mpt
->m_mutex
,
1403 drv_usectohz(60 * MICROSEC
), TR_CLOCK_TICK
);
1404 if (!(cmd
->cmd_flags
& CFLAG_FINISHED
)) {
1405 mpt
->m_softstate
&= ~MPTSAS_SS_MSG_UNIT_RESET
;
1406 if ((mptsas_restart_ioc(mpt
)) == DDI_FAILURE
) {
1407 mptsas_log(mpt
, CE_WARN
, "mptsas_restart_ioc failed");
1411 mptsas_remove_cmd(mpt
, cmd
);
1412 mptsas_dma_addr_destroy(&flsh_dma_handle
, &flsh_accessp
);
1418 mptsas_sasdevpage_0_cb(mptsas_t
*mpt
, caddr_t page_memp
,
1419 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
1423 _NOTE(ARGUNUSED(ap
))
1425 pMpi2SasDevicePage0_t sasdevpage
;
1426 int rval
= DDI_SUCCESS
, i
;
1427 uint8_t *sas_addr
= NULL
;
1428 uint8_t tmp_sas_wwn
[SAS_WWN_BYTE_SIZE
];
1429 uint16_t *devhdl
, *bay_num
, *enclosure
;
1432 uint8_t *physport
, *phynum
;
1433 uint16_t *pdevhdl
, *io_flags
;
1434 uint32_t page_address
;
1436 if ((iocstatus
!= MPI2_IOCSTATUS_SUCCESS
) &&
1437 (iocstatus
!= MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
)) {
1438 mptsas_log(mpt
, CE_WARN
, "mptsas_get_sas_device_page0 "
1439 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1440 iocstatus
, iocloginfo
);
1444 page_address
= va_arg(ap
, uint32_t);
1446 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1447 * are no more pages. If everything is OK up to this point but the
1448 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1449 * signal that device traversal is complete.
1451 if (iocstatus
== MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
) {
1452 if ((page_address
& MPI2_SAS_DEVICE_PGAD_FORM_MASK
) ==
1453 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE
) {
1454 mpt
->m_done_traverse_dev
= 1;
1459 devhdl
= va_arg(ap
, uint16_t *);
1460 sas_wwn
= va_arg(ap
, uint64_t *);
1461 dev_info
= va_arg(ap
, uint32_t *);
1462 physport
= va_arg(ap
, uint8_t *);
1463 phynum
= va_arg(ap
, uint8_t *);
1464 pdevhdl
= va_arg(ap
, uint16_t *);
1465 bay_num
= va_arg(ap
, uint16_t *);
1466 enclosure
= va_arg(ap
, uint16_t *);
1467 io_flags
= va_arg(ap
, uint16_t *);
1469 sasdevpage
= (pMpi2SasDevicePage0_t
)page_memp
;
1471 *dev_info
= ddi_get32(accessp
, &sasdevpage
->DeviceInfo
);
1472 *devhdl
= ddi_get16(accessp
, &sasdevpage
->DevHandle
);
1473 sas_addr
= (uint8_t *)(&sasdevpage
->SASAddress
);
1474 for (i
= 0; i
< SAS_WWN_BYTE_SIZE
; i
++) {
1475 tmp_sas_wwn
[i
] = ddi_get8(accessp
, sas_addr
+ i
);
1477 bcopy(tmp_sas_wwn
, sas_wwn
, SAS_WWN_BYTE_SIZE
);
1478 *sas_wwn
= LE_64(*sas_wwn
);
1479 *physport
= ddi_get8(accessp
, &sasdevpage
->PhysicalPort
);
1480 *phynum
= ddi_get8(accessp
, &sasdevpage
->PhyNum
);
1481 *pdevhdl
= ddi_get16(accessp
, &sasdevpage
->ParentDevHandle
);
1482 *bay_num
= ddi_get16(accessp
, &sasdevpage
->Slot
);
1483 *enclosure
= ddi_get16(accessp
, &sasdevpage
->EnclosureHandle
);
1484 *io_flags
= ddi_get16(accessp
, &sasdevpage
->Flags
);
1486 if (*io_flags
& MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE
) {
1488 * Leave a messages about FP cabability in the log.
1490 mptsas_log(mpt
, CE_CONT
,
1491 "!w%016"PRIx64
" FastPath Capable%s", *sas_wwn
,
1493 MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH
)?
1494 " and Enabled":" but Disabled");
1501 * Request MPI configuration page SAS device page 0 to get DevHandle, device
1502 * info and SAS address.
1505 mptsas_get_sas_device_page0(mptsas_t
*mpt
, uint32_t page_address
,
1506 uint16_t *dev_handle
, uint64_t *sas_wwn
, uint32_t *dev_info
,
1507 uint8_t *physport
, uint8_t *phynum
, uint16_t *pdev_handle
,
1508 uint16_t *bay_num
, uint16_t *enclosure
, uint16_t *io_flags
)
1510 int rval
= DDI_SUCCESS
;
1512 ASSERT(mutex_owned(&mpt
->m_mutex
));
1515 * Get the header and config page. reply contains the reply frame,
1516 * which holds status info for the request.
1518 rval
= mptsas_access_config_page(mpt
,
1519 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
,
1520 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE
, 0, page_address
,
1521 mptsas_sasdevpage_0_cb
, page_address
, dev_handle
, sas_wwn
,
1522 dev_info
, physport
, phynum
, pdev_handle
,
1523 bay_num
, enclosure
, io_flags
);
1529 mptsas_sasexpdpage_0_cb(mptsas_t
*mpt
, caddr_t page_memp
,
1530 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
1534 _NOTE(ARGUNUSED(ap
))
1536 pMpi2ExpanderPage0_t expddevpage
;
1537 int rval
= DDI_SUCCESS
, i
;
1538 uint8_t *sas_addr
= NULL
;
1539 uint8_t tmp_sas_wwn
[SAS_WWN_BYTE_SIZE
];
1543 mptsas_phymask_t
*phymask
;
1545 uint32_t page_address
;
1547 if ((iocstatus
!= MPI2_IOCSTATUS_SUCCESS
) &&
1548 (iocstatus
!= MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
)) {
1549 mptsas_log(mpt
, CE_WARN
, "mptsas_get_sas_expander_page0 "
1550 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1551 iocstatus
, iocloginfo
);
1555 page_address
= va_arg(ap
, uint32_t);
1557 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1558 * are no more pages. If everything is OK up to this point but the
1559 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1560 * signal that device traversal is complete.
1562 if (iocstatus
== MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
) {
1563 if ((page_address
& MPI2_SAS_EXPAND_PGAD_FORM_MASK
) ==
1564 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL
) {
1565 mpt
->m_done_traverse_smp
= 1;
1570 devhdl
= va_arg(ap
, uint16_t *);
1571 sas_wwn
= va_arg(ap
, uint64_t *);
1572 phymask
= va_arg(ap
, mptsas_phymask_t
*);
1573 pdevhdl
= va_arg(ap
, uint16_t *);
1575 expddevpage
= (pMpi2ExpanderPage0_t
)page_memp
;
1577 *devhdl
= ddi_get16(accessp
, &expddevpage
->DevHandle
);
1578 physport
= ddi_get8(accessp
, &expddevpage
->PhysicalPort
);
1579 *phymask
= mptsas_physport_to_phymask(mpt
, physport
);
1580 *pdevhdl
= ddi_get16(accessp
, &expddevpage
->ParentDevHandle
);
1581 sas_addr
= (uint8_t *)(&expddevpage
->SASAddress
);
1582 for (i
= 0; i
< SAS_WWN_BYTE_SIZE
; i
++) {
1583 tmp_sas_wwn
[i
] = ddi_get8(accessp
, sas_addr
+ i
);
1585 bcopy(tmp_sas_wwn
, sas_wwn
, SAS_WWN_BYTE_SIZE
);
1586 *sas_wwn
= LE_64(*sas_wwn
);
1592 * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1596 mptsas_get_sas_expander_page0(mptsas_t
*mpt
, uint32_t page_address
,
1599 int rval
= DDI_SUCCESS
;
1601 ASSERT(mutex_owned(&mpt
->m_mutex
));
1604 * Get the header and config page. reply contains the reply frame,
1605 * which holds status info for the request.
1607 rval
= mptsas_access_config_page(mpt
,
1608 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
,
1609 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER
, 0, page_address
,
1610 mptsas_sasexpdpage_0_cb
, page_address
, &info
->m_devhdl
,
1611 &info
->m_addr
.mta_wwn
, &info
->m_addr
.mta_phymask
, &info
->m_pdevhdl
);
1617 mptsas_sasportpage_0_cb(mptsas_t
*mpt
, caddr_t page_memp
,
1618 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
1622 _NOTE(ARGUNUSED(ap
))
1624 int rval
= DDI_SUCCESS
, i
;
1625 uint8_t *sas_addr
= NULL
;
1627 uint8_t tmp_sas_wwn
[SAS_WWN_BYTE_SIZE
];
1629 pMpi2SasPortPage0_t sasportpage
;
1631 if (iocstatus
!= MPI2_IOCSTATUS_SUCCESS
) {
1632 mptsas_log(mpt
, CE_WARN
, "mptsas_get_sas_port_page0 "
1633 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1634 iocstatus
, iocloginfo
);
1638 sas_wwn
= va_arg(ap
, uint64_t *);
1639 portwidth
= va_arg(ap
, uint8_t *);
1641 sasportpage
= (pMpi2SasPortPage0_t
)page_memp
;
1642 sas_addr
= (uint8_t *)(&sasportpage
->SASAddress
);
1643 for (i
= 0; i
< SAS_WWN_BYTE_SIZE
; i
++) {
1644 tmp_sas_wwn
[i
] = ddi_get8(accessp
, sas_addr
+ i
);
1646 bcopy(tmp_sas_wwn
, sas_wwn
, SAS_WWN_BYTE_SIZE
);
1647 *sas_wwn
= LE_64(*sas_wwn
);
1648 *portwidth
= ddi_get8(accessp
, &sasportpage
->PortWidth
);
1653 * Request MPI configuration page SAS port page 0 to get initiator SAS address
1657 mptsas_get_sas_port_page0(mptsas_t
*mpt
, uint32_t page_address
,
1658 uint64_t *sas_wwn
, uint8_t *portwidth
)
1660 int rval
= DDI_SUCCESS
;
1662 ASSERT(mutex_owned(&mpt
->m_mutex
));
1665 * Get the header and config page. reply contains the reply frame,
1666 * which holds status info for the request.
1668 rval
= mptsas_access_config_page(mpt
,
1669 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
,
1670 MPI2_CONFIG_EXTPAGETYPE_SAS_PORT
, 0, page_address
,
1671 mptsas_sasportpage_0_cb
, sas_wwn
, portwidth
);
1677 mptsas_sasiou_page_0_cb(mptsas_t
*mpt
, caddr_t page_memp
,
1678 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
1682 _NOTE(ARGUNUSED(ap
))
1684 int rval
= DDI_SUCCESS
;
1685 pMpi2SasIOUnitPage0_t sasioupage0
;
1687 uint32_t cpdi
[MPTSAS_MAX_PHYS
], *retrypage0
, *readpage1
;
1690 if (iocstatus
!= MPI2_IOCSTATUS_SUCCESS
) {
1691 mptsas_log(mpt
, CE_WARN
, "mptsas_get_sas_io_unit_page0 "
1692 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1693 iocstatus
, iocloginfo
);
1697 readpage1
= va_arg(ap
, uint32_t *);
1698 retrypage0
= va_arg(ap
, uint32_t *);
1700 sasioupage0
= (pMpi2SasIOUnitPage0_t
)page_memp
;
1702 num_phys
= ddi_get8(accessp
, &sasioupage0
->NumPhys
);
1704 * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1705 * was initially set. This should never change throughout the life of
1708 ASSERT(num_phys
== mpt
->m_num_phys
);
1709 for (i
= 0; i
< num_phys
; i
++) {
1710 cpdi
[i
] = ddi_get32(accessp
,
1711 &sasioupage0
->PhyData
[i
].
1712 ControllerPhyDeviceInfo
);
1713 port_flags
= ddi_get8(accessp
,
1714 &sasioupage0
->PhyData
[i
].PortFlags
);
1715 mpt
->m_phy_info
[i
].port_num
=
1717 &sasioupage0
->PhyData
[i
].Port
);
1718 mpt
->m_phy_info
[i
].ctrl_devhdl
=
1719 ddi_get16(accessp
, &sasioupage0
->
1720 PhyData
[i
].ControllerDevHandle
);
1721 mpt
->m_phy_info
[i
].attached_devhdl
=
1722 ddi_get16(accessp
, &sasioupage0
->
1723 PhyData
[i
].AttachedDevHandle
);
1724 mpt
->m_phy_info
[i
].phy_device_type
= cpdi
[i
];
1725 mpt
->m_phy_info
[i
].port_flags
= port_flags
;
1727 if (port_flags
& DISCOVERY_IN_PROGRESS
) {
1728 *retrypage0
= *retrypage0
+ 1;
1733 if (!(port_flags
& AUTO_PORT_CONFIGURATION
)) {
1735 * some PHY configuration described in
1746 mptsas_sasiou_page_1_cb(mptsas_t
*mpt
, caddr_t page_memp
,
1747 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
1751 _NOTE(ARGUNUSED(ap
))
1753 int rval
= DDI_SUCCESS
;
1754 pMpi2SasIOUnitPage1_t sasioupage1
;
1756 uint32_t cpdi
[MPTSAS_MAX_PHYS
];
1759 if (iocstatus
!= MPI2_IOCSTATUS_SUCCESS
) {
1760 mptsas_log(mpt
, CE_WARN
, "mptsas_get_sas_io_unit_page1 "
1761 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1762 iocstatus
, iocloginfo
);
1767 sasioupage1
= (pMpi2SasIOUnitPage1_t
)page_memp
;
1768 num_phys
= ddi_get8(accessp
, &sasioupage1
->NumPhys
);
1770 * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
1771 * was initially set. This should never change throughout the life of
1774 ASSERT(num_phys
== mpt
->m_num_phys
);
1775 for (i
= 0; i
< num_phys
; i
++) {
1776 cpdi
[i
] = ddi_get32(accessp
, &sasioupage1
->PhyData
[i
].
1777 ControllerPhyDeviceInfo
);
1778 port_flags
= ddi_get8(accessp
,
1779 &sasioupage1
->PhyData
[i
].PortFlags
);
1780 mpt
->m_phy_info
[i
].port_num
=
1782 &sasioupage1
->PhyData
[i
].Port
);
1783 mpt
->m_phy_info
[i
].port_flags
= port_flags
;
1784 mpt
->m_phy_info
[i
].phy_device_type
= cpdi
[i
];
1790 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1791 * page1 to update the PHY information. This is the message passing method of
1792 * this function which should be called except during initialization.
1795 mptsas_get_sas_io_unit_page(mptsas_t
*mpt
)
1797 int rval
= DDI_SUCCESS
, state
;
1798 uint32_t readpage1
= 0, retrypage0
= 0;
1800 ASSERT(mutex_owned(&mpt
->m_mutex
));
1803 * Now we cycle through the state machine. Here's what happens:
1804 * 1. Read IO unit page 0 and set phy information
1805 * 2. See if Read IO unit page1 is needed because of port configuration
1806 * 3. Read IO unit page 1 and update phy information.
1808 state
= IOUC_READ_PAGE0
;
1809 while (state
!= IOUC_DONE
) {
1810 if (state
== IOUC_READ_PAGE0
) {
1811 rval
= mptsas_access_config_page(mpt
,
1812 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
,
1813 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
, 0, 0,
1814 mptsas_sasiou_page_0_cb
, &readpage1
,
1816 } else if (state
== IOUC_READ_PAGE1
) {
1817 rval
= mptsas_access_config_page(mpt
,
1818 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
,
1819 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
, 1, 0,
1820 mptsas_sasiou_page_1_cb
);
1823 if (rval
== DDI_SUCCESS
) {
1825 case IOUC_READ_PAGE0
:
1827 * retry 30 times if discovery is in process
1829 if (retrypage0
&& (retrypage0
< 30)) {
1830 drv_usecwait(1000 * 100);
1831 state
= IOUC_READ_PAGE0
;
1833 } else if (retrypage0
== 30) {
1834 mptsas_log(mpt
, CE_WARN
,
1835 "!Discovery in progress, can't "
1836 "verify IO unit config, then "
1837 "after 30 times retry, give "
1844 if (readpage1
== 0) {
1850 state
= IOUC_READ_PAGE1
;
1853 case IOUC_READ_PAGE1
:
1867 mptsas_biospage_3_cb(mptsas_t
*mpt
, caddr_t page_memp
,
1868 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
1872 _NOTE(ARGUNUSED(ap
))
1874 pMpi2BiosPage3_t sasbiospage
;
1875 int rval
= DDI_SUCCESS
;
1876 uint32_t *bios_version
;
1878 if ((iocstatus
!= MPI2_IOCSTATUS_SUCCESS
) &&
1879 (iocstatus
!= MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
)) {
1880 mptsas_log(mpt
, CE_WARN
, "mptsas_get_bios_page3 header: "
1881 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus
, iocloginfo
);
1885 bios_version
= va_arg(ap
, uint32_t *);
1886 sasbiospage
= (pMpi2BiosPage3_t
)page_memp
;
1887 *bios_version
= ddi_get32(accessp
, &sasbiospage
->BiosVersion
);
1893 * Request MPI configuration page BIOS page 3 to get BIOS version. Since all
1894 * other information in this page is not needed, just ignore it.
1897 mptsas_get_bios_page3(mptsas_t
*mpt
, uint32_t *bios_version
)
1899 int rval
= DDI_SUCCESS
;
1901 ASSERT(mutex_owned(&mpt
->m_mutex
));
1904 * Get the header and config page. reply contains the reply frame,
1905 * which holds status info for the request.
1907 rval
= mptsas_access_config_page(mpt
,
1908 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
, MPI2_CONFIG_PAGETYPE_BIOS
, 3,
1909 0, mptsas_biospage_3_cb
, bios_version
);
1915 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1916 * page1 to update the PHY information. This is the handshaking version of
1917 * this function, which should be called during initialization only.
1920 mptsas_get_sas_io_unit_page_hndshk(mptsas_t
*mpt
)
1922 ddi_dma_attr_t recv_dma_attrs
, page_dma_attrs
;
1923 ddi_dma_cookie_t page_cookie
;
1924 ddi_dma_handle_t recv_dma_handle
, page_dma_handle
;
1925 ddi_acc_handle_t recv_accessp
, page_accessp
;
1926 pMpi2ConfigReply_t configreply
;
1927 pMpi2SasIOUnitPage0_t sasioupage0
;
1928 pMpi2SasIOUnitPage1_t sasioupage1
;
1930 caddr_t recv_memp
, page_memp
;
1931 int i
, num_phys
, start_phy
= 0;
1933 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0
) +
1934 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA
) * (MPTSAS_MAX_PHYS
- 1));
1936 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1
) +
1937 (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA
) * (MPTSAS_MAX_PHYS
- 1));
1938 uint32_t flags_length
;
1939 uint32_t cpdi
[MPTSAS_MAX_PHYS
];
1940 uint32_t readpage1
= 0, retrypage0
= 0;
1942 uint8_t port_flags
, page_number
, action
;
1943 uint32_t reply_size
= 256; /* Big enough for any page */
1945 int rval
= DDI_FAILURE
;
1946 boolean_t free_recv
= B_FALSE
, free_page
= B_FALSE
;
1949 * Initialize our "state machine". This is a bit convoluted,
1950 * but it keeps us from having to do the ddi allocations numerous
1954 NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1955 ASSERT(mutex_owned(&mpt
->m_mutex
));
1956 state
= IOUC_READ_PAGE0
;
1959 * dynamically create a customized dma attribute structure
1960 * that describes mpt's config reply page request structure.
1962 recv_dma_attrs
= mpt
->m_msg_dma_attr
;
1963 recv_dma_attrs
.dma_attr_sgllen
= 1;
1964 recv_dma_attrs
.dma_attr_granular
= (sizeof (MPI2_CONFIG_REPLY
));
1966 if (mptsas_dma_addr_create(mpt
, recv_dma_attrs
,
1967 &recv_dma_handle
, &recv_accessp
, &recv_memp
,
1968 (sizeof (MPI2_CONFIG_REPLY
)), NULL
) == FALSE
) {
1969 mptsas_log(mpt
, CE_WARN
,
1970 "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1973 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
1976 page_dma_attrs
= mpt
->m_msg_dma_attr
;
1977 page_dma_attrs
.dma_attr_sgllen
= 1;
1978 page_dma_attrs
.dma_attr_granular
= reply_size
;
1980 if (mptsas_dma_addr_create(mpt
, page_dma_attrs
,
1981 &page_dma_handle
, &page_accessp
, &page_memp
,
1982 reply_size
, &page_cookie
) == FALSE
) {
1983 mptsas_log(mpt
, CE_WARN
,
1984 "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
1987 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
1991 * Now we cycle through the state machine. Here's what happens:
1992 * 1. Read IO unit page 0 and set phy information
1993 * 2. See if Read IO unit page1 is needed because of port configuration
1994 * 3. Read IO unit page 1 and update phy information.
1997 sasioupage0
= (pMpi2SasIOUnitPage0_t
)page_memp
;
1998 sasioupage1
= (pMpi2SasIOUnitPage1_t
)page_memp
;
2000 while (state
!= IOUC_DONE
) {
2002 case IOUC_READ_PAGE0
:
2004 action
= MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
;
2005 flags_length
= (uint32_t)page0_size
;
2006 flags_length
|= ((uint32_t)(
2007 MPI2_SGE_FLAGS_LAST_ELEMENT
|
2008 MPI2_SGE_FLAGS_END_OF_BUFFER
|
2009 MPI2_SGE_FLAGS_SIMPLE_ELEMENT
|
2010 MPI2_SGE_FLAGS_SYSTEM_ADDRESS
|
2011 MPI2_SGE_FLAGS_32_BIT_ADDRESSING
|
2012 MPI2_SGE_FLAGS_IOC_TO_HOST
|
2013 MPI2_SGE_FLAGS_END_OF_LIST
) <<
2014 MPI2_SGE_FLAGS_SHIFT
);
2018 case IOUC_READ_PAGE1
:
2020 action
= MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
;
2021 flags_length
= (uint32_t)page1_size
;
2022 flags_length
|= ((uint32_t)(
2023 MPI2_SGE_FLAGS_LAST_ELEMENT
|
2024 MPI2_SGE_FLAGS_END_OF_BUFFER
|
2025 MPI2_SGE_FLAGS_SIMPLE_ELEMENT
|
2026 MPI2_SGE_FLAGS_SYSTEM_ADDRESS
|
2027 MPI2_SGE_FLAGS_32_BIT_ADDRESSING
|
2028 MPI2_SGE_FLAGS_IOC_TO_HOST
|
2029 MPI2_SGE_FLAGS_END_OF_LIST
) <<
2030 MPI2_SGE_FLAGS_SHIFT
);
2037 bzero(recv_memp
, sizeof (MPI2_CONFIG_REPLY
));
2038 configreply
= (pMpi2ConfigReply_t
)recv_memp
;
2039 recv_numbytes
= sizeof (MPI2_CONFIG_REPLY
);
2041 if (mptsas_send_extended_config_request_msg(mpt
,
2042 MPI2_CONFIG_ACTION_PAGE_HEADER
,
2043 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
2044 0, page_number
, 0, 0, 0, 0)) {
2048 if (mptsas_get_handshake_msg(mpt
, recv_memp
, recv_numbytes
,
2053 iocstatus
= ddi_get16(recv_accessp
, &configreply
->IOCStatus
);
2054 iocstatus
= MPTSAS_IOCSTATUS(iocstatus
);
2056 if (iocstatus
!= MPI2_IOCSTATUS_SUCCESS
) {
2057 mptsas_log(mpt
, CE_WARN
,
2058 "mptsas_get_sas_io_unit_page_hndshk: read page "
2059 "header iocstatus = 0x%x", iocstatus
);
2063 if (action
!= MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM
) {
2064 bzero(page_memp
, reply_size
);
2067 if (mptsas_send_extended_config_request_msg(mpt
, action
,
2068 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
, 0, page_number
,
2069 ddi_get8(recv_accessp
, &configreply
->Header
.PageVersion
),
2070 ddi_get16(recv_accessp
, &configreply
->ExtPageLength
),
2071 flags_length
, page_cookie
.dmac_address
)) {
2075 if (mptsas_get_handshake_msg(mpt
, recv_memp
, recv_numbytes
,
2080 iocstatus
= ddi_get16(recv_accessp
, &configreply
->IOCStatus
);
2081 iocstatus
= MPTSAS_IOCSTATUS(iocstatus
);
2083 if (iocstatus
!= MPI2_IOCSTATUS_SUCCESS
) {
2084 mptsas_log(mpt
, CE_WARN
,
2085 "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2086 "config failed for action %d, iocstatus = 0x%x",
2092 case IOUC_READ_PAGE0
:
2093 if ((ddi_dma_sync(page_dma_handle
, 0, 0,
2094 DDI_DMA_SYNC_FORCPU
)) != DDI_SUCCESS
) {
2098 num_phys
= ddi_get8(page_accessp
,
2099 &sasioupage0
->NumPhys
);
2100 ASSERT(num_phys
== mpt
->m_num_phys
);
2101 if (num_phys
> MPTSAS_MAX_PHYS
) {
2102 mptsas_log(mpt
, CE_WARN
, "Number of phys "
2103 "supported by HBA (%d) is more than max "
2104 "supported by driver (%d). Driver will "
2105 "not attach.", num_phys
,
2110 for (i
= start_phy
; i
< num_phys
; i
++, start_phy
= i
) {
2111 cpdi
[i
] = ddi_get32(page_accessp
,
2112 &sasioupage0
->PhyData
[i
].
2113 ControllerPhyDeviceInfo
);
2114 port_flags
= ddi_get8(page_accessp
,
2115 &sasioupage0
->PhyData
[i
].PortFlags
);
2117 mpt
->m_phy_info
[i
].port_num
=
2118 ddi_get8(page_accessp
,
2119 &sasioupage0
->PhyData
[i
].Port
);
2120 mpt
->m_phy_info
[i
].ctrl_devhdl
=
2121 ddi_get16(page_accessp
, &sasioupage0
->
2122 PhyData
[i
].ControllerDevHandle
);
2123 mpt
->m_phy_info
[i
].attached_devhdl
=
2124 ddi_get16(page_accessp
, &sasioupage0
->
2125 PhyData
[i
].AttachedDevHandle
);
2126 mpt
->m_phy_info
[i
].phy_device_type
= cpdi
[i
];
2127 mpt
->m_phy_info
[i
].port_flags
= port_flags
;
2129 if (port_flags
& DISCOVERY_IN_PROGRESS
) {
2131 NDBG20(("Discovery in progress, can't "
2132 "verify IO unit config, then NO.%d"
2133 " times retry", retrypage0
));
2138 if (!(port_flags
& AUTO_PORT_CONFIGURATION
)) {
2140 * some PHY configuration described in
2148 * retry 30 times if discovery is in process
2150 if (retrypage0
&& (retrypage0
< 30)) {
2151 drv_usecwait(1000 * 100);
2152 state
= IOUC_READ_PAGE0
;
2154 } else if (retrypage0
== 30) {
2155 mptsas_log(mpt
, CE_WARN
,
2156 "!Discovery in progress, can't "
2157 "verify IO unit config, then after"
2158 " 30 times retry, give up!");
2164 if (readpage1
== 0) {
2170 state
= IOUC_READ_PAGE1
;
2173 case IOUC_READ_PAGE1
:
2174 if ((ddi_dma_sync(page_dma_handle
, 0, 0,
2175 DDI_DMA_SYNC_FORCPU
)) != DDI_SUCCESS
) {
2179 num_phys
= ddi_get8(page_accessp
,
2180 &sasioupage1
->NumPhys
);
2181 ASSERT(num_phys
== mpt
->m_num_phys
);
2182 if (num_phys
> MPTSAS_MAX_PHYS
) {
2183 mptsas_log(mpt
, CE_WARN
, "Number of phys "
2184 "supported by HBA (%d) is more than max "
2185 "supported by driver (%d). Driver will "
2186 "not attach.", num_phys
,
2191 for (i
= 0; i
< num_phys
; i
++) {
2192 cpdi
[i
] = ddi_get32(page_accessp
,
2193 &sasioupage1
->PhyData
[i
].
2194 ControllerPhyDeviceInfo
);
2195 port_flags
= ddi_get8(page_accessp
,
2196 &sasioupage1
->PhyData
[i
].PortFlags
);
2197 mpt
->m_phy_info
[i
].port_num
=
2198 ddi_get8(page_accessp
,
2199 &sasioupage1
->PhyData
[i
].Port
);
2200 mpt
->m_phy_info
[i
].port_flags
= port_flags
;
2201 mpt
->m_phy_info
[i
].phy_device_type
= cpdi
[i
];
2210 if ((mptsas_check_dma_handle(recv_dma_handle
) != DDI_SUCCESS
) ||
2211 (mptsas_check_dma_handle(page_dma_handle
) != DDI_SUCCESS
)) {
2212 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_UNAFFECTED
);
2216 if ((mptsas_check_acc_handle(recv_accessp
) != DDI_SUCCESS
) ||
2217 (mptsas_check_acc_handle(page_accessp
) != DDI_SUCCESS
)) {
2218 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_UNAFFECTED
);
2225 mptsas_dma_addr_destroy(&recv_dma_handle
, &recv_accessp
);
2227 mptsas_dma_addr_destroy(&page_dma_handle
, &page_accessp
);
2228 if (rval
!= DDI_SUCCESS
) {
2229 mptsas_fm_ereport(mpt
, DDI_FM_DEVICE_NO_RESPONSE
);
2230 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_LOST
);
2236 * mptsas_get_manufacture_page5
2238 * This function will retrieve the base WWID from the adapter. Since this
2239 * function is only called during the initialization process, use handshaking.
2242 mptsas_get_manufacture_page5(mptsas_t
*mpt
)
2244 ddi_dma_attr_t recv_dma_attrs
, page_dma_attrs
;
2245 ddi_dma_cookie_t page_cookie
;
2246 ddi_dma_handle_t recv_dma_handle
, page_dma_handle
;
2247 ddi_acc_handle_t recv_accessp
, page_accessp
;
2248 pMpi2ConfigReply_t configreply
;
2249 caddr_t recv_memp
, page_memp
;
2251 pMpi2ManufacturingPage5_t m5
;
2252 uint32_t flagslength
;
2253 int rval
= DDI_SUCCESS
;
2255 boolean_t free_recv
= B_FALSE
, free_page
= B_FALSE
;
2257 MPTSAS_DISABLE_INTR(mpt
);
2259 if (mptsas_send_config_request_msg(mpt
, MPI2_CONFIG_ACTION_PAGE_HEADER
,
2260 MPI2_CONFIG_PAGETYPE_MANUFACTURING
, 0, 5, 0, 0, 0, 0)) {
2266 * dynamically create a customized dma attribute structure
2267 * that describes the MPT's config reply page request structure.
2269 recv_dma_attrs
= mpt
->m_msg_dma_attr
;
2270 recv_dma_attrs
.dma_attr_sgllen
= 1;
2271 recv_dma_attrs
.dma_attr_granular
= (sizeof (MPI2_CONFIG_REPLY
));
2273 if (mptsas_dma_addr_create(mpt
, recv_dma_attrs
,
2274 &recv_dma_handle
, &recv_accessp
, &recv_memp
,
2275 (sizeof (MPI2_CONFIG_REPLY
)), NULL
) == FALSE
) {
2279 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2282 bzero(recv_memp
, sizeof (MPI2_CONFIG_REPLY
));
2283 configreply
= (pMpi2ConfigReply_t
)recv_memp
;
2284 recv_numbytes
= sizeof (MPI2_CONFIG_REPLY
);
2287 * get config reply message
2289 if (mptsas_get_handshake_msg(mpt
, recv_memp
, recv_numbytes
,
2295 if (iocstatus
= ddi_get16(recv_accessp
, &configreply
->IOCStatus
)) {
2296 mptsas_log(mpt
, CE_WARN
, "mptsas_get_manufacture_page5 update: "
2297 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus
,
2298 ddi_get32(recv_accessp
, &configreply
->IOCLogInfo
));
2303 * dynamically create a customized dma attribute structure
2304 * that describes the MPT's config page structure.
2306 page_dma_attrs
= mpt
->m_msg_dma_attr
;
2307 page_dma_attrs
.dma_attr_sgllen
= 1;
2308 page_dma_attrs
.dma_attr_granular
= (sizeof (MPI2_CONFIG_PAGE_MAN_5
));
2310 if (mptsas_dma_addr_create(mpt
, page_dma_attrs
, &page_dma_handle
,
2311 &page_accessp
, &page_memp
, (sizeof (MPI2_CONFIG_PAGE_MAN_5
)),
2312 &page_cookie
) == FALSE
) {
2316 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2319 bzero(page_memp
, sizeof (MPI2_CONFIG_PAGE_MAN_5
));
2320 m5
= (pMpi2ManufacturingPage5_t
)page_memp
;
2323 * Give reply address to IOC to store config page in and send
2324 * config request out.
2327 flagslength
= sizeof (MPI2_CONFIG_PAGE_MAN_5
);
2328 flagslength
|= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT
|
2329 MPI2_SGE_FLAGS_END_OF_BUFFER
| MPI2_SGE_FLAGS_SIMPLE_ELEMENT
|
2330 MPI2_SGE_FLAGS_SYSTEM_ADDRESS
| MPI2_SGE_FLAGS_32_BIT_ADDRESSING
|
2331 MPI2_SGE_FLAGS_IOC_TO_HOST
|
2332 MPI2_SGE_FLAGS_END_OF_LIST
) << MPI2_SGE_FLAGS_SHIFT
);
2334 if (mptsas_send_config_request_msg(mpt
,
2335 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
,
2336 MPI2_CONFIG_PAGETYPE_MANUFACTURING
, 0, 5,
2337 ddi_get8(recv_accessp
, &configreply
->Header
.PageVersion
),
2338 ddi_get8(recv_accessp
, &configreply
->Header
.PageLength
),
2339 flagslength
, page_cookie
.dmac_address
)) {
2345 * get reply view handshake
2347 if (mptsas_get_handshake_msg(mpt
, recv_memp
, recv_numbytes
,
2353 if (iocstatus
= ddi_get16(recv_accessp
, &configreply
->IOCStatus
)) {
2354 mptsas_log(mpt
, CE_WARN
, "mptsas_get_manufacture_page5 config: "
2355 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus
,
2356 ddi_get32(recv_accessp
, &configreply
->IOCLogInfo
));
2360 (void) ddi_dma_sync(page_dma_handle
, 0, 0, DDI_DMA_SYNC_FORCPU
);
2363 * Fusion-MPT stores fields in little-endian format. This is
2364 * why the low-order 32 bits are stored first.
2366 mpt
->un
.sasaddr
.m_base_wwid_lo
=
2367 ddi_get32(page_accessp
, (uint32_t *)(void *)&m5
->Phy
[0].WWID
);
2368 mpt
->un
.sasaddr
.m_base_wwid_hi
=
2369 ddi_get32(page_accessp
, (uint32_t *)(void *)&m5
->Phy
[0].WWID
+ 1);
2371 if (ddi_prop_update_int64(DDI_DEV_T_NONE
, mpt
->m_dip
,
2372 "base-wwid", mpt
->un
.m_base_wwid
) != DDI_PROP_SUCCESS
) {
2373 NDBG2(("%s%d: failed to create base-wwid property",
2374 ddi_driver_name(mpt
->m_dip
), ddi_get_instance(mpt
->m_dip
)));
2378 * Set the number of PHYs present.
2380 mpt
->m_num_phys
= ddi_get8(page_accessp
, (uint8_t *)&m5
->NumPhys
);
2382 if (ddi_prop_update_int(DDI_DEV_T_NONE
, mpt
->m_dip
,
2383 "num-phys", mpt
->m_num_phys
) != DDI_PROP_SUCCESS
) {
2384 NDBG2(("%s%d: failed to create num-phys property",
2385 ddi_driver_name(mpt
->m_dip
), ddi_get_instance(mpt
->m_dip
)));
2388 mptsas_log(mpt
, CE_NOTE
, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2389 mpt
->m_instance
, (unsigned long long)mpt
->un
.m_base_wwid
,
2390 (unsigned long long)mpt
->un
.m_base_wwid
+ mpt
->m_num_phys
- 1);
2392 if ((mptsas_check_dma_handle(recv_dma_handle
) != DDI_SUCCESS
) ||
2393 (mptsas_check_dma_handle(page_dma_handle
) != DDI_SUCCESS
)) {
2394 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_UNAFFECTED
);
2398 if ((mptsas_check_acc_handle(recv_accessp
) != DDI_SUCCESS
) ||
2399 (mptsas_check_acc_handle(page_accessp
) != DDI_SUCCESS
)) {
2400 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_UNAFFECTED
);
2408 mptsas_dma_addr_destroy(&recv_dma_handle
, &recv_accessp
);
2410 mptsas_dma_addr_destroy(&page_dma_handle
, &page_accessp
);
2411 MPTSAS_ENABLE_INTR(mpt
);
2417 mptsas_sasphypage_0_cb(mptsas_t
*mpt
, caddr_t page_memp
,
2418 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
2422 _NOTE(ARGUNUSED(ap
))
2424 pMpi2SasPhyPage0_t sasphypage
;
2425 int rval
= DDI_SUCCESS
;
2426 uint16_t *owner_devhdl
, *attached_devhdl
;
2427 uint8_t *attached_phy_identify
;
2428 uint32_t *attached_phy_info
;
2429 uint8_t *programmed_link_rate
;
2430 uint8_t *hw_link_rate
;
2431 uint8_t *change_count
;
2433 uint8_t *negotiated_link_rate
;
2434 uint32_t page_address
;
2436 if ((iocstatus
!= MPI2_IOCSTATUS_SUCCESS
) &&
2437 (iocstatus
!= MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
)) {
2438 mptsas_log(mpt
, CE_WARN
, "mptsas_get_sas_expander_page0 "
2439 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2440 iocstatus
, iocloginfo
);
2444 page_address
= va_arg(ap
, uint32_t);
2446 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2447 * are no more pages. If everything is OK up to this point but the
2448 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2449 * signal that device traversal is complete.
2451 if (iocstatus
== MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
) {
2452 if ((page_address
& MPI2_SAS_EXPAND_PGAD_FORM_MASK
) ==
2453 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL
) {
2454 mpt
->m_done_traverse_smp
= 1;
2459 owner_devhdl
= va_arg(ap
, uint16_t *);
2460 attached_devhdl
= va_arg(ap
, uint16_t *);
2461 attached_phy_identify
= va_arg(ap
, uint8_t *);
2462 attached_phy_info
= va_arg(ap
, uint32_t *);
2463 programmed_link_rate
= va_arg(ap
, uint8_t *);
2464 hw_link_rate
= va_arg(ap
, uint8_t *);
2465 change_count
= va_arg(ap
, uint8_t *);
2466 phy_info
= va_arg(ap
, uint32_t *);
2467 negotiated_link_rate
= va_arg(ap
, uint8_t *);
2469 sasphypage
= (pMpi2SasPhyPage0_t
)page_memp
;
2472 ddi_get16(accessp
, &sasphypage
->OwnerDevHandle
);
2474 ddi_get16(accessp
, &sasphypage
->AttachedDevHandle
);
2475 *attached_phy_identify
=
2476 ddi_get8(accessp
, &sasphypage
->AttachedPhyIdentifier
);
2477 *attached_phy_info
=
2478 ddi_get32(accessp
, &sasphypage
->AttachedPhyInfo
);
2479 *programmed_link_rate
=
2480 ddi_get8(accessp
, &sasphypage
->ProgrammedLinkRate
);
2482 ddi_get8(accessp
, &sasphypage
->HwLinkRate
);
2484 ddi_get8(accessp
, &sasphypage
->ChangeCount
);
2486 ddi_get32(accessp
, &sasphypage
->PhyInfo
);
2487 *negotiated_link_rate
=
2488 ddi_get8(accessp
, &sasphypage
->NegotiatedLinkRate
);
2494 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2498 mptsas_get_sas_phy_page0(mptsas_t
*mpt
, uint32_t page_address
,
2501 int rval
= DDI_SUCCESS
;
2503 ASSERT(mutex_owned(&mpt
->m_mutex
));
2506 * Get the header and config page. reply contains the reply frame,
2507 * which holds status info for the request.
2509 rval
= mptsas_access_config_page(mpt
,
2510 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
,
2511 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY
, 0, page_address
,
2512 mptsas_sasphypage_0_cb
, page_address
, &info
->owner_devhdl
,
2513 &info
->attached_devhdl
, &info
->attached_phy_identify
,
2514 &info
->attached_phy_info
, &info
->programmed_link_rate
,
2515 &info
->hw_link_rate
, &info
->change_count
,
2516 &info
->phy_info
, &info
->negotiated_link_rate
);
2522 mptsas_sasphypage_1_cb(mptsas_t
*mpt
, caddr_t page_memp
,
2523 ddi_acc_handle_t accessp
, uint16_t iocstatus
, uint32_t iocloginfo
,
2527 _NOTE(ARGUNUSED(ap
))
2529 pMpi2SasPhyPage1_t sasphypage
;
2530 int rval
= DDI_SUCCESS
;
2532 uint32_t *invalid_dword_count
;
2533 uint32_t *running_disparity_error_count
;
2534 uint32_t *loss_of_dword_sync_count
;
2535 uint32_t *phy_reset_problem_count
;
2536 uint32_t page_address
;
2538 if ((iocstatus
!= MPI2_IOCSTATUS_SUCCESS
) &&
2539 (iocstatus
!= MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
)) {
2540 mptsas_log(mpt
, CE_WARN
, "mptsas_get_sas_expander_page1 "
2541 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2542 iocstatus
, iocloginfo
);
2546 page_address
= va_arg(ap
, uint32_t);
2548 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2549 * are no more pages. If everything is OK up to this point but the
2550 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2551 * signal that device traversal is complete.
2553 if (iocstatus
== MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
) {
2554 if ((page_address
& MPI2_SAS_EXPAND_PGAD_FORM_MASK
) ==
2555 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL
) {
2556 mpt
->m_done_traverse_smp
= 1;
2562 invalid_dword_count
= va_arg(ap
, uint32_t *);
2563 running_disparity_error_count
= va_arg(ap
, uint32_t *);
2564 loss_of_dword_sync_count
= va_arg(ap
, uint32_t *);
2565 phy_reset_problem_count
= va_arg(ap
, uint32_t *);
2567 sasphypage
= (pMpi2SasPhyPage1_t
)page_memp
;
2569 *invalid_dword_count
=
2570 ddi_get32(accessp
, &sasphypage
->InvalidDwordCount
);
2571 *running_disparity_error_count
=
2572 ddi_get32(accessp
, &sasphypage
->RunningDisparityErrorCount
);
2573 *loss_of_dword_sync_count
=
2574 ddi_get32(accessp
, &sasphypage
->LossDwordSynchCount
);
2575 *phy_reset_problem_count
=
2576 ddi_get32(accessp
, &sasphypage
->PhyResetProblemCount
);
2582 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2586 mptsas_get_sas_phy_page1(mptsas_t
*mpt
, uint32_t page_address
,
2589 int rval
= DDI_SUCCESS
;
2591 ASSERT(mutex_owned(&mpt
->m_mutex
));
2594 * Get the header and config page. reply contains the reply frame,
2595 * which holds status info for the request.
2597 rval
= mptsas_access_config_page(mpt
,
2598 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
,
2599 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY
, 1, page_address
,
2600 mptsas_sasphypage_1_cb
, page_address
,
2601 &info
->invalid_dword_count
,
2602 &info
->running_disparity_error_count
,
2603 &info
->loss_of_dword_sync_count
,
2604 &info
->phy_reset_problem_count
);
2609 * mptsas_get_manufacture_page0
2611 * This function will retrieve the base
2612 * Chip name, Board Name,Board Trace number from the adapter.
2613 * Since this function is only called during the
2614 * initialization process, use handshaking.
2617 mptsas_get_manufacture_page0(mptsas_t
*mpt
)
2619 ddi_dma_attr_t recv_dma_attrs
, page_dma_attrs
;
2620 ddi_dma_cookie_t page_cookie
;
2621 ddi_dma_handle_t recv_dma_handle
, page_dma_handle
;
2622 ddi_acc_handle_t recv_accessp
, page_accessp
;
2623 pMpi2ConfigReply_t configreply
;
2624 caddr_t recv_memp
, page_memp
;
2626 pMpi2ManufacturingPage0_t m0
;
2627 uint32_t flagslength
;
2628 int rval
= DDI_SUCCESS
;
2631 boolean_t free_recv
= B_FALSE
, free_page
= B_FALSE
;
2633 MPTSAS_DISABLE_INTR(mpt
);
2635 if (mptsas_send_config_request_msg(mpt
, MPI2_CONFIG_ACTION_PAGE_HEADER
,
2636 MPI2_CONFIG_PAGETYPE_MANUFACTURING
, 0, 0, 0, 0, 0, 0)) {
2642 * dynamically create a customized dma attribute structure
2643 * that describes the MPT's config reply page request structure.
2645 recv_dma_attrs
= mpt
->m_msg_dma_attr
;
2646 recv_dma_attrs
.dma_attr_sgllen
= 1;
2647 recv_dma_attrs
.dma_attr_granular
= (sizeof (MPI2_CONFIG_REPLY
));
2649 if (mptsas_dma_addr_create(mpt
, recv_dma_attrs
, &recv_dma_handle
,
2650 &recv_accessp
, &recv_memp
, (sizeof (MPI2_CONFIG_REPLY
)),
2655 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2658 bzero(recv_memp
, sizeof (MPI2_CONFIG_REPLY
));
2659 configreply
= (pMpi2ConfigReply_t
)recv_memp
;
2660 recv_numbytes
= sizeof (MPI2_CONFIG_REPLY
);
2663 * get config reply message
2665 if (mptsas_get_handshake_msg(mpt
, recv_memp
, recv_numbytes
,
2671 if (iocstatus
= ddi_get16(recv_accessp
, &configreply
->IOCStatus
)) {
2672 mptsas_log(mpt
, CE_WARN
, "mptsas_get_manufacture_page5 update: "
2673 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus
,
2674 ddi_get32(recv_accessp
, &configreply
->IOCLogInfo
));
2679 * dynamically create a customized dma attribute structure
2680 * that describes the MPT's config page structure.
2682 page_dma_attrs
= mpt
->m_msg_dma_attr
;
2683 page_dma_attrs
.dma_attr_sgllen
= 1;
2684 page_dma_attrs
.dma_attr_granular
= (sizeof (MPI2_CONFIG_PAGE_MAN_0
));
2686 if (mptsas_dma_addr_create(mpt
, page_dma_attrs
, &page_dma_handle
,
2687 &page_accessp
, &page_memp
, (sizeof (MPI2_CONFIG_PAGE_MAN_0
)),
2688 &page_cookie
) == FALSE
) {
2692 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2695 bzero(page_memp
, sizeof (MPI2_CONFIG_PAGE_MAN_0
));
2696 m0
= (pMpi2ManufacturingPage0_t
)page_memp
;
2699 * Give reply address to IOC to store config page in and send
2700 * config request out.
2703 flagslength
= sizeof (MPI2_CONFIG_PAGE_MAN_0
);
2704 flagslength
|= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT
|
2705 MPI2_SGE_FLAGS_END_OF_BUFFER
| MPI2_SGE_FLAGS_SIMPLE_ELEMENT
|
2706 MPI2_SGE_FLAGS_SYSTEM_ADDRESS
| MPI2_SGE_FLAGS_32_BIT_ADDRESSING
|
2707 MPI2_SGE_FLAGS_IOC_TO_HOST
|
2708 MPI2_SGE_FLAGS_END_OF_LIST
) << MPI2_SGE_FLAGS_SHIFT
);
2710 if (mptsas_send_config_request_msg(mpt
,
2711 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
,
2712 MPI2_CONFIG_PAGETYPE_MANUFACTURING
, 0, 0,
2713 ddi_get8(recv_accessp
, &configreply
->Header
.PageVersion
),
2714 ddi_get8(recv_accessp
, &configreply
->Header
.PageLength
),
2715 flagslength
, page_cookie
.dmac_address
)) {
2721 * get reply view handshake
2723 if (mptsas_get_handshake_msg(mpt
, recv_memp
, recv_numbytes
,
2729 if (iocstatus
= ddi_get16(recv_accessp
, &configreply
->IOCStatus
)) {
2730 mptsas_log(mpt
, CE_WARN
, "mptsas_get_manufacture_page0 config: "
2731 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus
,
2732 ddi_get32(recv_accessp
, &configreply
->IOCLogInfo
));
2736 (void) ddi_dma_sync(page_dma_handle
, 0, 0, DDI_DMA_SYNC_FORCPU
);
2739 * Fusion-MPT stores fields in little-endian format. This is
2740 * why the low-order 32 bits are stored first.
2743 for (i
= 0; i
< 16; i
++) {
2744 mpt
->m_MANU_page0
.ChipName
[i
] =
2745 ddi_get8(page_accessp
,
2746 (uint8_t *)(void *)&m0
->ChipName
[i
]);
2749 for (i
= 0; i
< 8; i
++) {
2750 mpt
->m_MANU_page0
.ChipRevision
[i
] =
2751 ddi_get8(page_accessp
,
2752 (uint8_t *)(void *)&m0
->ChipRevision
[i
]);
2755 for (i
= 0; i
< 16; i
++) {
2756 mpt
->m_MANU_page0
.BoardName
[i
] =
2757 ddi_get8(page_accessp
,
2758 (uint8_t *)(void *)&m0
->BoardName
[i
]);
2761 for (i
= 0; i
< 16; i
++) {
2762 mpt
->m_MANU_page0
.BoardAssembly
[i
] =
2763 ddi_get8(page_accessp
,
2764 (uint8_t *)(void *)&m0
->BoardAssembly
[i
]);
2767 for (i
= 0; i
< 16; i
++) {
2768 mpt
->m_MANU_page0
.BoardTracerNumber
[i
] =
2769 ddi_get8(page_accessp
,
2770 (uint8_t *)(void *)&m0
->BoardTracerNumber
[i
]);
2773 if ((mptsas_check_dma_handle(recv_dma_handle
) != DDI_SUCCESS
) ||
2774 (mptsas_check_dma_handle(page_dma_handle
) != DDI_SUCCESS
)) {
2775 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_UNAFFECTED
);
2779 if ((mptsas_check_acc_handle(recv_accessp
) != DDI_SUCCESS
) ||
2780 (mptsas_check_acc_handle(page_accessp
) != DDI_SUCCESS
)) {
2781 ddi_fm_service_impact(mpt
->m_dip
, DDI_SERVICE_UNAFFECTED
);
2789 mptsas_dma_addr_destroy(&recv_dma_handle
, &recv_accessp
);
2791 mptsas_dma_addr_destroy(&page_dma_handle
, &page_accessp
);
2792 MPTSAS_ENABLE_INTR(mpt
);