mptsas_impl.c revision 9814ff7f66c508579713f72e69cbb6271713c068
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* Copyright (c) 2000 to 2010, LSI Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms of all code within
* this file that is exclusively owned by LSI, with or without
* modification, is permitted provided that, in addition to the CDDL 1.0
* License requirements, the following conditions are met:
*
* Neither the name of the author nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/*
* mptsas_impl - This file contains all the basic functions for communicating
* to MPT based hardware.
*/
#define MPTSAS_DEBUG
#endif
/*
* standard header files
*/
#pragma pack(1)
#pragma pack()
/*
* private header files.
*/
/*
* FMA header files.
*/
#if defined(MPTSAS_DEBUG)
extern uint32_t mptsas_debug_flags;
#endif
/*
* prototypes
*/
struct mptsas_cmd *cmd);
/*
* add ioc evnet cmd into the queue
*/
static void
{
} else {
}
}
/*
* remove specified cmd from the ioc event queue
*/
static void
{
}
return;
}
}
return;
}
}
}
static m_event_struct_t *
{
return (ioc_cmd);
}
}
return (ioc_cmd);
}
void
{
/*
* because the IOC event queue is resource of per instance for driver,
* it's not only ACK event commands used it, but also some others used
* it. We need destroy all ACK event commands when IOC reset, but can't
* disturb others.So we use filter to clear the ACK event cmd in ioc
* event queue, and other requests should be reserved, and they would
* be free by its owner.
*/
NDBG20(("destroy!! remove Ack Flag ioc_cmd\n"));
if ((mpt->m_ioc_event_cmdq =
} else {
/*
* it's not ack cmd, so continue to check next one
*/
NDBG20(("destroy!! it's not Ack Flag, continue\n"));
}
}
}
void
{
/*
* Point to the correct message and clear it as well as the global
* config page memory.
*/
/*
* Form the request message.
*/
length = 0;
} else {
}
} else {
} else {
}
}
}
flagslength |= length;
DDI_SUCCESS) ||
DDI_SUCCESS)) {
}
}
int
{
/*
* Get a command from the pool.
*/
"page request");
rval = DDI_FAILURE;
goto page_done;
}
/*
* Save the data for this request to be used in the call to start the
* config header request.
*/
/*
*/
/*
* Save the config header request message in a slot.
*/
} else {
}
/*
* If this is a request for a RAID info page, or any page called during
* the RAID info page request, poll because these config page requests
* are nested. Poll to avoid data corruption due to one page's data
* overwriting the outer page request's data. This can happen when
* the mutex is released in cv_wait.
*/
if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
} else {
}
}
/*
* Check if the header request completed without timing out
*/
rval = DDI_FAILURE;
goto page_done;
}
/*
* cmd_rfm points to the reply message if a reply was given. Check the
* IOCStatus to make sure everything went OK with the header request.
*/
- mpt->m_reply_frame_dma_addr));
&reply->ExtPageType);
&reply->ExtPageLength);
&reply->IOCLogInfo);
if (iocstatus) {
NDBG13(("mptsas_access_config_page header: "
"IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
iocloginfo));
rval = DDI_FAILURE;
goto page_done;
}
else
}
"request");
rval = DDI_FAILURE;
goto page_done;
}
/*
* Put the reply frame back on the free queue, increment the free
* index, and write the new index to the free index register. But only
* if this reply is an ADDRESS reply.
*/
if (config_flags & MPTSAS_ADDRESS_REPLY) {
mpt->m_free_index = 0;
}
mpt->m_free_index);
config_flags &= (~MPTSAS_ADDRESS_REPLY);
}
/*
* Allocate DMA buffer here. Store the info regarding this buffer in
* the cmd struct so that it can be used for this specific command and
* de-allocated after the command completes. The size of the reply
* will not be larger than the reply frame size.
*/
"config page.");
rval = DDI_FAILURE;
goto page_done;
}
"structure.");
rval = DDI_FAILURE;
goto page_done;
}
(void) ddi_dma_mem_free(&accessp);
"config page.");
rval = DDI_FAILURE;
goto page_done;
}
/*
* Save the data for this request to be used in the call to start the
* config page read
*/
/*
* Re-use the cmd that was used to get the header. Reset some of the
* values.
*/
/*
* Send the config page request. cmd is re-used from header request.
*/
/*
* If this is a request for a RAID info page, or any page called during
* the RAID info page request, poll because these config page requests
* are nested. Poll to avoid data corruption due to one page's data
* overwriting the outer page request's data. This can happen when
* the mutex is released in cv_wait.
*/
if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
} else {
}
}
/*
* Check if the request completed without timing out
*/
rval = DDI_FAILURE;
goto page_done;
}
/*
* cmd_rfm points to the reply message if a reply was given. The reply
* frame and the config page are returned from this function in the
* param list.
*/
- mpt->m_reply_frame_dma_addr));
&reply->IOCLogInfo);
}
rval = DDI_FAILURE;
goto page_done;
}
/*
*/
rval = DDI_FAILURE;
}
rval = DDI_FAILURE;
goto page_done;
}
rval = DDI_FAILURE;
goto page_done;
}
/*
* Put the reply frame back on the free queue, increment the free
* index, and write the new index to the free index register. But only
* if this reply is an ADDRESS reply.
*/
if (config_flags & MPTSAS_ADDRESS_REPLY) {
mpt->m_free_index = 0;
}
mpt->m_free_index);
}
(void) ddi_dma_mem_free(&accessp);
}
}
if (config_flags & MPTSAS_CMD_TIMEOUT) {
}
}
return (rval);
}
int
{
int send_numbytes;
send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
/*
* Post message via handshake
*/
mpt->m_hshk_acc_hdl)) {
return (-1);
}
return (0);
}
int
{
int send_numbytes;
send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
/*
* Post message via handshake
*/
mpt->m_hshk_acc_hdl)) {
return (-1);
}
return (0);
}
int
{
int polls = 0;
drv_usecwait(1000);
if (polls++ > 60000) {
return (-1);
}
}
return (0);
}
int
{
int polls = 0;
drv_usecwait(1000);
if (polls++ > 300000) {
return (-1);
}
}
return (0);
}
int
{
int i;
/*
* clean pending doorbells
*/
if (mptsas_ioc_wait_for_doorbell(mpt)) {
NDBG19(("mptsas_send_handshake failed. Doorbell not ready\n"));
return (-1);
}
/*
* clean pending doorbells again
*/
if (mptsas_ioc_wait_for_response(mpt)) {
NDBG19(("mptsas_send_handshake failed. Doorbell not "
"cleared\n"));
return (-1);
}
/*
* post handshake message
*/
if (mptsas_ioc_wait_for_response(mpt)) {
NDBG19(("mptsas_send_handshake failed posting "
"message\n"));
return (-1);
}
}
return (-1);
}
return (0);
}
int
{
int i, totalbytes, bytesleft;
/*
* wait for doorbell
*/
if (mptsas_ioc_wait_for_doorbell(mpt)) {
NDBG19(("mptsas_get_handshake failed. Doorbell not ready\n"));
return (-1);
}
/*
* get first 2 bytes of handshake message to determine how much
* data we will be getting
*/
if (mptsas_ioc_wait_for_doorbell(mpt)) {
NDBG19(("mptsas_get_handshake failure getting initial"
" data\n"));
return (-1);
}
if (i == 1) {
}
}
/*
* If we are expecting less bytes than the message wants to send
* we simply save as much as we expected and then throw out the rest
* later
*/
} else {
}
/*
* Get the rest of the data
*/
if (mptsas_ioc_wait_for_doorbell(mpt)) {
NDBG19(("mptsas_get_handshake failure getting"
" main data\n"));
return (-1);
}
}
/*
* Sometimes the device will send more data than is expected
* This data is not used by us but needs to be cleared from
* ioc doorbell. So we just read the values and throw
* them out.
*/
if (mptsas_ioc_wait_for_doorbell(mpt)) {
NDBG19(("mptsas_get_handshake failure getting "
"extra garbage data\n"));
return (-1);
}
}
}
return (-1);
}
return (0);
}
int
{
int polls = 0;
/*
* Start a hard reset. Write magic number and wait 900 uSeconds.
*/
drv_usecwait(900);
/*
* Read the current Diag Reg and save the Host Controlled Boot size.
*/
/*
* Set Reset Adapter bit and wait 50 mSeconds.
*/
drv_usecwait(50000);
/*
* Poll, waiting for Reset Adapter bit to clear. 300 Seconds max
* (600000 * 500 = 300,000,000 uSeconds, 300 seconds).
* If no more adapter (all FF's), just return failure.
*/
if (diag_reg == 0xFFFFFFFF) {
return (DDI_FAILURE);
}
if (!(diag_reg & MPI2_DIAG_RESET_ADAPTER)) {
break;
}
drv_usecwait(500);
}
if (polls == 600000) {
return (DDI_FAILURE);
}
/*
* Check if adapter is in Host Boot Mode. If so, restart adapter
* assuming the HCB points to good FW.
* Set BootDeviceSel to HCDW (Host Code and Data Window).
*/
if (diag_reg & MPI2_DIAG_HCB_MODE) {
/*
* Re-enable the HCDW.
*/
}
/*
* Restart the adapter.
*/
/*
* Disable writes to the Host Diag register.
*/
/*
* Wait 60 seconds max for FW to come to ready state.
*/
if (ioc_state == 0xFFFFFFFF) {
return (DDI_FAILURE);
}
if ((ioc_state & MPI2_IOC_STATE_MASK) ==
break;
}
drv_usecwait(1000);
}
if (polls == 60000) {
return (DDI_FAILURE);
}
/*
* Clear the ioc ack events queue.
*/
return (DDI_SUCCESS);
}
int
{
#ifdef SLM
int polls = 0;
#endif
/*
* If chip is already in ready state then there is nothing to do.
*/
if (ioc_state == MPI2_IOC_STATE_READY) {
return (MPTSAS_NO_RESET);
}
/*
* SLM-test; skip MUR for now
*/
#ifdef SLM
/*
* If the chip is already operational, we just need to send
* it a message unit reset to put it back in the ready state
*/
if (ioc_state & MPI2_IOC_STATE_OPERATIONAL) {
if (mptsas_ioc_wait_for_response(mpt)) {
NDBG19(("mptsas_ioc_reset failure sending "
"message_unit_reset\n"));
goto hard_reset;
}
/*
* Wait no more than 60 seconds for chip to become ready.
*/
MPI2_IOC_STATE_READY) == 0x0) {
drv_usecwait(1000);
if (polls++ > 60000) {
goto hard_reset;
}
}
/*
* the message unit reset would do reset operations
* clear reply and request queue, so we should clear
* ACK event cmd.
*/
return (MPTSAS_NO_RESET);
}
#endif
return (MPTSAS_RESET_FAIL);
}
return (MPTSAS_SUCCESS_HARDRESET);
}
int
{
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
void
{
return;
}
}
/*
* NOTE: We should be able to queue TM requests in the controller to make this
* a lot faster. If resetting all targets, for example, we can load the hi
* priority queue with its limit and the controller will reply as they are
* completed. This way, we don't have to poll for one reply at a time.
* Think about enhancing this later.
*/
int
{
/*
* In order to avoid allocating variables on the stack,
* we make use of the pre-existing mptsas_cmd_t and
* scsi_pkt which are included in the mptsas_t which
* is passed to this routine.
*/
/*
* Can't start another task management routine.
*/
" command at a time\n");
return (FALSE);
}
/*
* Store the TM message in memory location corresponding to the TM slot
* number.
*/
/*
* form message for requested task
*/
/*
* Set the task type
*/
/*
* Send TM request using High Priority Queue.
*/
/*
* If a reply frame was used and there is a reply buffer to copy the
* reply data into, copy it. If this fails, log a message, but don't
* fail the TM request.
*/
if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
}
for (i = 0; i < reply_size; i++) {
mode)) {
"reply data for TM request");
break;
}
}
}
/*
* clear the TM slot before returning
*/
/*
* If we lost our task management command
* we need to reset the ioc
*/
"try to reset ioc to recovery!");
if (mptsas_restart_ioc(mpt)) {
}
}
return (rval);
}
int
{
/*
* In order to avoid allocating variables on the stack,
* we make use of the pre-existing mptsas_cmd_t and
* scsi_pkt which are included in the mptsas_t which
* is passed to this routine.
*/
int i;
int rvalue = 0;
"failed. event ack command pool is full\n");
return (rvalue);
}
/*
* dynamically create a customized dma attribute structure
* that describes the flash file.
*/
"(unable to allocate dma handle.");
return (-1);
}
"unable to allocate flash structure.");
return (-1);
}
(void) ddi_dma_mem_free(&flsh_accessp);
return (-1);
}
for (i = 0; i < size; i++) {
}
/*
*/
/*
* Save the command in a slot
*/
(void) ddi_dma_unbind_handle(flsh_dma_handle);
(void) ddi_dma_mem_free(&flsh_accessp);
return (-1);
}
/*
* Fill in fw download message
*/
fwdownload = (void *)memp;
flagslength = size;
/*
* Start command
*/
rvalue = 0;
}
rvalue = -1;
}
(void) ddi_dma_unbind_handle(flsh_dma_handle);
(void) ddi_dma_mem_free(&flsh_accessp);
return (rvalue);
}
static int
{
#ifndef __lock_lint
#endif
int rval = DDI_SUCCESS, i;
if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
"header: IOCStatus=0x%x, IOCLogInfo=0x%x",
rval = DDI_FAILURE;
return (rval);
}
/*
* The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
* are no more pages. If everything is OK up to this point but the
* status is INVALID_PAGE, change rval to FAILURE and quit. Also,
* signal that device traversal is complete.
*/
if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
}
rval = DDI_FAILURE;
return (rval);
}
for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
}
return (rval);
}
/*
* Request MPI configuration page SAS device page 0 to get DevHandle, device
* info and SAS address.
*/
int
{
int rval = DDI_SUCCESS;
/*
* Get the header and config page. reply contains the reply frame,
* which holds status info for the request.
*/
return (rval);
}
static int
{
#ifndef __lock_lint
#endif
int rval = DDI_SUCCESS, i;
if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
"config: IOCStatus=0x%x, IOCLogInfo=0x%x",
rval = DDI_FAILURE;
return (rval);
}
/*
* The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
* are no more pages. If everything is OK up to this point but the
* status is INVALID_PAGE, change rval to FAILURE and quit. Also,
* signal that device traversal is complete.
*/
if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
}
rval = DDI_FAILURE;
return (rval);
}
for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
}
return (rval);
}
/*
* Request MPI configuration page SAS device page 0 to get DevHandle, phymask
* and SAS address.
*/
int
{
int rval = DDI_SUCCESS;
/*
* Get the header and config page. reply contains the reply frame,
* which holds status info for the request.
*/
return (rval);
}
static int
{
#ifndef __lock_lint
#endif
int rval = DDI_SUCCESS, i;
if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
"config: IOCStatus=0x%x, IOCLogInfo=0x%x",
rval = DDI_FAILURE;
return (rval);
}
for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
}
return (rval);
}
/*
* Request MPI configuration page SAS port page 0 to get initiator SAS address
* and port width.
*/
int
{
int rval = DDI_SUCCESS;
/*
* Get the header and config page. reply contains the reply frame,
* which holds status info for the request.
*/
return (rval);
}
static int
{
#ifndef __lock_lint
#endif
int rval = DDI_SUCCESS;
int i, num_phys;
if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
"config: IOCStatus=0x%x, IOCLogInfo=0x%x",
rval = DDI_FAILURE;
return (rval);
}
/*
* ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
* was initially set. This should never change throughout the life of
* the driver.
*/
for (i = 0; i < num_phys; i++) {
&sasioupage0->PhyData[i].
PhyData[i].AttachedDevHandle);
if (port_flags & DISCOVERY_IN_PROGRESS) {
break;
} else {
*retrypage0 = 0;
}
if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
/*
* some PHY configuration described in
* SAS IO Unit Page1
*/
*readpage1 = 1;
}
}
return (rval);
}
static int
{
#ifndef __lock_lint
#endif
int rval = DDI_SUCCESS;
int i, num_phys;
if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
"config: IOCStatus=0x%x, IOCLogInfo=0x%x",
rval = DDI_FAILURE;
return (rval);
}
/*
* ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
* was initially set. This should never change throughout the life of
* the driver.
*/
for (i = 0; i < num_phys; i++) {
}
return (rval);
}
/*
* Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
* page1 to update the PHY information. This is the message passing method of
* this function which should be called except during initialization.
*/
int
{
/*
* Now we cycle through the state machine. Here's what happens:
* 1. Read IO unit page 0 and set phy information
* 2. See if Read IO unit page1 is needed because of port configuration
* 3. Read IO unit page 1 and update phy information.
*/
if (state == IOUC_READ_PAGE0) {
&retrypage0);
} else if (state == IOUC_READ_PAGE1) {
}
if (rval == DDI_SUCCESS) {
switch (state) {
case IOUC_READ_PAGE0:
/*
* retry 30 times if discovery is in process
*/
break;
} else if (retrypage0 == 30) {
"!Discovery in progress, can't "
"verify IO unit config, then "
"after 30 times retry, give "
"up!");
rval = DDI_FAILURE;
break;
}
if (readpage1 == 0) {
rval = DDI_SUCCESS;
break;
}
break;
case IOUC_READ_PAGE1:
rval = DDI_SUCCESS;
break;
}
} else {
return (rval);
}
}
return (rval);
}
static int
{
#ifndef __lock_lint
#endif
int rval = DDI_SUCCESS;
if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
rval = DDI_FAILURE;
return (rval);
}
return (rval);
}
/*
* Request MPI configuration page BIOS page 3 to get BIOS version. Since all
* other information in this page is not needed, just ignore it.
*/
int
{
int rval = DDI_SUCCESS;
/*
* Get the header and config page. reply contains the reply frame,
* which holds status info for the request.
*/
return (rval);
}
/*
* Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
* page1 to update the PHY information. This is the handshaking version of
* this function, which should be called during initialization only.
*/
int
{
int recv_numbytes;
int recv_dmastate = 0;
int page_dmastate = 0;
int page0_size =
sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
int page1_size =
sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
int rval = DDI_FAILURE;
/*
* Initialize our "state machine". This is a bit convoluted,
* but it keeps us from having to do the ddi allocations numerous
* times.
*/
NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
/*
* dynamically create a customized dma attribute structure
* that describes mpt's config reply page request structure.
*/
goto cleanup;
}
(sizeof (MPI2_CONFIG_REPLY)),
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
/*
* Page 0 size is larger, so just use that for both.
*/
goto cleanup;
}
goto cleanup;
}
/*
* Now we cycle through the state machine. Here's what happens:
* 1. Read IO unit page 0 and set phy information
* 2. See if Read IO unit page1 is needed because of port configuration
* 3. Read IO unit page 1 and update phy information.
*/
switch (state) {
case IOUC_READ_PAGE0:
page_number = 0;
flags_length |= ((uint32_t)(
break;
case IOUC_READ_PAGE1:
page_number = 1;
flags_length |= ((uint32_t)(
break;
default:
break;
}
recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
0, page_number, 0, 0, 0, 0)) {
goto cleanup;
}
recv_accessp)) {
goto cleanup;
}
if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
"mptsas_get_sas_io_unit_page_hndshk: read page "
"header iocstatus = 0x%x", iocstatus);
goto cleanup;
}
if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
}
goto cleanup;
}
recv_accessp)) {
goto cleanup;
}
if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
"mptsas_get_sas_io_unit_page_hndshk: IO unit "
"config failed for action %d, iocstatus = 0x%x",
goto cleanup;
}
switch (state) {
case IOUC_READ_PAGE0:
if ((ddi_dma_sync(page_dma_handle, 0, 0,
DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
goto cleanup;
}
&sasioupage0->NumPhys);
if (num_phys > MPTSAS_MAX_PHYS) {
"supported by HBA (%d) is more than max "
"supported by driver (%d). Driver will "
"not attach.", num_phys,
rval = DDI_FAILURE;
goto cleanup;
}
&sasioupage0->PhyData[i].
PhyData[i].AttachedDevHandle);
if (port_flags & DISCOVERY_IN_PROGRESS) {
retrypage0++;
NDBG20(("Discovery in progress, can't "
"verify IO unit config, then NO.%d"
" times retry", retrypage0));
break;
} else {
retrypage0 = 0;
}
if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
/*
* some PHY configuration described in
* SAS IO Unit Page1
*/
readpage1 = 1;
}
}
/*
* retry 30 times if discovery is in process
*/
break;
} else if (retrypage0 == 30) {
"!Discovery in progress, can't "
"verify IO unit config, then after"
" 30 times retry, give up!");
rval = DDI_FAILURE;
break;
}
if (readpage1 == 0) {
rval = DDI_SUCCESS;
break;
}
break;
case IOUC_READ_PAGE1:
if ((ddi_dma_sync(page_dma_handle, 0, 0,
DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
goto cleanup;
}
&sasioupage1->NumPhys);
if (num_phys > MPTSAS_MAX_PHYS) {
"supported by HBA (%d) is more than max "
"supported by driver (%d). Driver will "
"not attach.", num_phys,
rval = DDI_FAILURE;
goto cleanup;
}
for (i = 0; i < num_phys; i++) {
&sasioupage1->PhyData[i].
}
rval = DDI_SUCCESS;
break;
}
}
rval = DDI_FAILURE;
goto cleanup;
}
rval = DDI_FAILURE;
goto cleanup;
}
(void) ddi_dma_unbind_handle(recv_dma_handle);
(void) ddi_dma_unbind_handle(page_dma_handle);
(void) ddi_dma_mem_free(&recv_accessp);
(void) ddi_dma_mem_free(&page_accessp);
if (rval != DDI_SUCCESS) {
}
return (rval);
}
/*
* mptsas_get_manufacture_page5
*
* This function will retrieve the base WWID from the adapter. Since this
* function is only called during the initialization process, use handshaking.
*/
int
{
int recv_numbytes;
int recv_dmastate = 0;
int page_dmastate = 0;
int rval = DDI_SUCCESS;
MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
rval = DDI_FAILURE;
goto done;
}
/*
* dynamically create a customized dma attribute structure
* that describes the MPT's config reply page request structure.
*/
"(unable to allocate dma handle.");
rval = DDI_FAILURE;
goto done;
}
(sizeof (MPI2_CONFIG_REPLY)),
"unable to allocate config_reply structure.");
rval = DDI_FAILURE;
goto done;
}
rval = DDI_FAILURE;
goto done;
}
recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
/*
* get config reply message
*/
recv_accessp)) {
rval = DDI_FAILURE;
goto done;
}
"IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
goto done;
}
/*
* dynamically create a customized dma attribute structure
* that describes the MPT's config page structure.
*/
"(unable to allocate dma handle.");
rval = DDI_FAILURE;
goto done;
}
(sizeof (MPI2_CONFIG_PAGE_MAN_5)),
"unable to allocate manufacturing page structure.");
rval = DDI_FAILURE;
goto done;
}
rval = DDI_FAILURE;
goto done;
}
/*
* Give reply address to IOC to store config page in and send
* config request out.
*/
flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
rval = DDI_FAILURE;
goto done;
}
/*
* get reply view handshake
*/
recv_accessp)) {
rval = DDI_FAILURE;
goto done;
}
"IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
goto done;
}
/*
* Fusion-MPT stores fields in little-endian format. This is
* why the low-order 32 bits are stored first.
*/
NDBG2(("%s%d: failed to create base-wwid property",
}
/*
* Set the number of PHYs present.
*/
NDBG2(("%s%d: failed to create num-phys property",
}
rval = DDI_FAILURE;
goto done;
}
rval = DDI_FAILURE;
}
done:
/*
* free up memory
*/
(void) ddi_dma_unbind_handle(recv_dma_handle);
(void) ddi_dma_unbind_handle(page_dma_handle);
(void) ddi_dma_mem_free(&recv_accessp);
(void) ddi_dma_mem_free(&page_accessp);
return (rval);
}