blob: b701211cca84e15db5ff892c6ff08eb4b97afcf2 [file] [log] [blame]
/*******************************************************************************
Copyright (C) Marvell International Ltd. and its affiliates
This software file (the "File") is owned and distributed by Marvell
International Ltd. and/or its affiliates ("Marvell") under the following
alternative licensing terms. Once you have made an election to distribute the
File under one of the following license alternatives, please (i) delete this
introductory statement regarding license alternatives, (ii) delete the two
license alternatives that you have not elected to use and (iii) preserve the
Marvell copyright notice above.
********************************************************************************
Marvell GPL License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File in accordance with the terms and conditions of the General
Public License Version 2, June 1991 (the "GPL License"), a copy of which is
available along with the File in the license.txt file or by writing to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
DISCLAIMED. The GPL License provides additional details about this warranty
disclaimer.
*******************************************************************************/
/*******************************************************************************
* mvIALCommon.c
*
* DESCRIPTION:
* C implementation for IAL's common functions.
*
* DEPENDENCIES:
* mvIALCommon.h
*
*******************************************************************************/
/* includes */
#include "mvOs.h"
#include "mvScsiAtaLayer.h"
#include "mvIALCommon.h"
#include "mvIALCommonUtils.h"
#include "mvStorageDev.h"
/* defines */
#undef DISABLE_PM_SCC
/* typedefs */
/*Static functions*/
static MV_BOOLEAN mvGetDisksModes(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_SAL_ADAPTER_EXTENSION *pScsiAdapterExt,
MV_U8 channelIndex,
MV_BOOLEAN *TCQ,
MV_BOOLEAN *NCQ,
MV_U8 *numOfDrives);
static void mvFlushSCSICommandQueue(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex);
static void mvAddToSCSICommandQueue(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SATA_SCSI_CMD_BLOCK *Scb);
static MV_BOOLEAN mvAdapterStateMachine(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt);
static MV_BOOLEAN mvChannelStateMachine(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt);
static void mvSetChannelState(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_CHANNEL_STATE state);
static MV_BOOLEAN clearSErrorPorts(MV_SATA_ADAPTER *pSataAdapter, MV_U8 channelIndex,
MV_U8 PMnumberOfPorts);
/*PM related*/
static MV_BOOLEAN mvPMCommandCompletionCB(MV_SATA_ADAPTER *pSataAdapter,
MV_U8 channelIndex,
MV_COMPLETION_TYPE comp_type,
MV_VOID_PTR commandId,
MV_U16 responseFlags,
MV_U32 timeStamp,
MV_STORAGE_DEVICE_REGISTERS *registerStruct);
static MV_BOOLEAN mvQueuePMAccessRegisterCommand(
MV_IAL_COMMON_ADAPTER_EXTENSION* ialExt,
MV_U8 channelIndex,
MV_U8 PMPort,
MV_U8 PMReg,
MV_U32 Value,
MV_BOOLEAN isRead);
static MV_BOOLEAN mvPMEnableCommStatusChangeBits(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_BOOLEAN enable);
static MV_BOOLEAN mvPMEnableAsyncNotify(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex);
#if 0
static void mvCheckPMForError(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex);
#endif
/*End PM related*/
static MV_BOOLEAN mvStartChannelInit(MV_SATA_ADAPTER *pSataAdapter,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt,
MV_BOOLEAN *isChannelReady);
static MV_BOOLEAN mvChannelSRSTFinished(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_SATA_CHANNEL *pSataChannel,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt,
MV_BOOLEAN* bIsChannelReady,
MV_BOOLEAN* bFatalError);
static MV_BOOLEAN mvConfigChannelQueuingMode(
MV_IAL_COMMON_ADAPTER_EXTENSION* ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt);
static MV_BOOLEAN mvConfigChannelDMA(
MV_IAL_COMMON_ADAPTER_EXTENSION* ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt);
static void mvSetChannelTimer(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_U32 timeout);
static void mvDecrementChannelTimer(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex);
static MV_BOOLEAN mvIsChannelTimerExpired(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex);
/*Channel state machine*/
static MV_BOOLEAN mvChannelNotConnectedStateHandler(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt);
static MV_BOOLEAN mvChannelConnectedStateHandler(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt);
MV_BOOLEAN mvChannelInSrstStateHandler(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt);
static MV_BOOLEAN mvPMInitDevicesStateHandler(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt);
static MV_BOOLEAN mvChannelReadyStateHandler(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex);
static MV_BOOLEAN mvChannelPMHotPlugStateHandler(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt);
static void mvDrivesInfoSaveAll(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex);
static void mvDrivesInfoFlushAll(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex);
static void mvDrivesInfoFlushSingleDrive(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex, MV_U8 PMPort);
static void mvDrivesInfoSaveSingleDrive(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_U8 PMPort,
MV_BOOLEAN isDriveAdded,
MV_U16_PTR identifyBuffer);
static void mvSetDriveReady(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt,
MV_U8 channelIndex,
MV_U8 PMPort,
MV_BOOLEAN isReady,
MV_U16_PTR identifyBuffer);
static void mvDrivesInfoGetChannelRescanParams(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_U16 *drivesToRemove,
MV_U16 *drivesToAdd);
#ifdef DISABLE_PM_SCC
MV_BOOLEAN mvPMDisableSSC(MV_SATA_ADAPTER *pSataAdapter, MV_U8 channelIndex);
#endif
MV_BOOLEAN mvPMEnableLocking(MV_SATA_ADAPTER *pSataAdapter, MV_U8 channelIndex);
/*Public functions*/
/*******************************************************************************
* mvAdapterStartInitialization - start adapter initialization
*
* DESCRIPTION:
* Starts adapter initialization after driver load.
* State - machine related data structure is initialized for adapter
* and its channels. Begin staggered spin-up.
* Adapter state is changed to ADAPTER_READY.
* INPUT:
* pAdapter - pointer to the adapter data structure.
* scsiAdapterExt - SCSI to ATA layer adapter extension data structure
* OUTPUT:
* None.
*
* RETURN:
* MV_TRUE on success
* MV_FALSE on error
*
*******************************************************************************/
MV_BOOLEAN mvAdapterStartInitialization(MV_SATA_ADAPTER *pSataAdapter,
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
MV_U8 channelIndex;
ialExt->pSataAdapter = pSataAdapter;
ialExt->adapterState = ADAPTER_INITIALIZING;
for (channelIndex = 0; channelIndex < MV_SATA_CHANNELS_NUM; channelIndex++)
{
ialExt->channelState[channelIndex] = CHANNEL_NOT_CONNECTED;
ialExt->IALChannelExt[channelIndex].SRSTTimerThreshold = 0;
ialExt->IALChannelExt[channelIndex].SRSTTimerValue = 0;
ialExt->IALChannelExt[channelIndex].IALChannelPendingCmdQueue = NULL;
ialExt->IALChannelExt[channelIndex].completionError = MV_FALSE;
ialExt->IALChannelExt[channelIndex].pmRegAccessInProgress = MV_FALSE;
ialExt->IALChannelExt[channelIndex].pmRegPollCounter = 0;
ialExt->IALChannelExt[channelIndex].devInSRST =
MV_SATA_PM_CONTROL_PORT + 1;
ialExt->IALChannelExt[channelIndex].PMdevsToInit = 0;
ialExt->IALChannelExt[channelIndex].PMnumberOfPorts = 0;
ialExt->IALChannelExt[channelIndex].pmAccessType = 0;
ialExt->IALChannelExt[channelIndex].pmReg = 0;
ialExt->IALChannelExt[channelIndex].pmAsyncNotifyEnabled = MV_FALSE;
ialExt->IALChannelExt[channelIndex].bHotPlug = MV_FALSE;
memset(&ialExt->IALChannelExt[channelIndex].drivesInfo, 0, sizeof(MV_DRIVES_INFO));
}
return mvAdapterStateMachine(ialExt, scsiAdapterExt);
}
/*******************************************************************************
* mvRestartChannel - restart specific channel
*
* DESCRIPTION:
* The function is used in channel hot-plug to restart the channel
* initialization sequence. The channel stated is changed to
* CHANNEL_CONNECTED and any pending command in software queue are flushed
* INPUT:
* pAdapter - pointer to the adapter data structure.
* channelIndex - channel number
* scsiAdapterExt - SCSI to ATA layer adapter extension data structure
* bBusReset - MV_TRUE if the faunction is called because of bus reset,
* MV_FALSE otherwise
* OUTPUT:
* None.
*
* RETURN:
* MV_TRUE on success
* MV_FALSE on error
*
*******************************************************************************/
void mvRestartChannel(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt,
MV_BOOLEAN bBusReset)
{
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
MV_BOOLEAN bBusChangeNotify = MV_FALSE;
ialExt->IALChannelExt[channelIndex].bHotPlug = MV_TRUE;
mvSetDriveReady(ialExt,
scsiAdapterExt,
channelIndex, 0xFF, MV_FALSE, NULL);
if (pSataAdapter->sataChannel[channelIndex] != NULL)
{
if (mvStorageDevGetDeviceType(pSataAdapter,channelIndex)
== MV_SATA_DEVICE_TYPE_PM)
{
bBusChangeNotify = MV_TRUE;
}
mvSataDisableChannelDma(pSataAdapter, channelIndex);
mvSataFlushDmaQueue (pSataAdapter, channelIndex,
MV_FLUSH_TYPE_CALLBACK);
}
mvFlushSCSICommandQueue(ialExt, channelIndex);
ialExt->IALChannelExt[channelIndex].SRSTTimerThreshold = 0;
ialExt->IALChannelExt[channelIndex].SRSTTimerValue = 0;
ialExt->channelState[channelIndex] = CHANNEL_CONNECTED;
if (bBusReset == MV_TRUE)
{
if (bBusChangeNotify == MV_TRUE)
{
/*Notify about bus change*/
IALBusChangeNotify(pSataAdapter, channelIndex);
}
}
else
{
/*Notify about bus change*/
IALBusChangeNotify(pSataAdapter, channelIndex);
}
}
/*******************************************************************************
* mvPMHotPlugDetected - restart specific channel
*
* DESCRIPTION:
* The function is used in PM hot-plug to wait for empty EDMA command queue
* and then restart the channel initialization sequence.
* The channel stated is changed to CHANNEL_PM_HOT_PLUG if there are any
* pending command in EDMA queue
* INPUT:
* pAdapter - pointer to the adapter data structure.
* channelIndex - channel number
* OUTPUT:
* None.
*
* RETURN:
* None
*
*******************************************************************************/
void mvPMHotPlugDetected(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
if (ialExt->channelState[channelIndex] == CHANNEL_NOT_CONNECTED ||
ialExt->channelState[channelIndex] == CHANNEL_CONNECTED ||
ialExt->channelState[channelIndex] == CHANNEL_IN_SRST)
{
return;
}
mvSataDisableChannelDma(ialExt->pSataAdapter, channelIndex);
mvSataFlushDmaQueue (ialExt->pSataAdapter,
channelIndex, MV_FLUSH_TYPE_CALLBACK);
mvSataChannelHardReset(ialExt->pSataAdapter, channelIndex);
mvRestartChannel(ialExt, channelIndex, scsiAdapterExt, MV_FALSE);
}
/*******************************************************************************
* mvStopChannel - stop channel
*
* DESCRIPTION:
* The function is used when the channel is unplugged.
* The channel stated is changed to CHANNEL_NOT_CONNECTED
* until further connection.
* INPUT:
* pAdapter - pointer to the adapter data structure.
* channelIndex - channel number
* OUTPUT:
* None.
*
* RETURN:
* None
*******************************************************************************/
void mvStopChannel(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
MV_U16 drivesSnapshot =
ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotSaved;
mvDrivesInfoFlushAll(ialExt, channelIndex);
mvSetDriveReady(ialExt, scsiAdapterExt, channelIndex, 0xFF, MV_FALSE, NULL);
mvSetChannelState(ialExt, channelIndex, CHANNEL_NOT_CONNECTED);
if (pSataAdapter->sataChannel[channelIndex] != NULL)
{
mvSataDisableChannelDma(ialExt->pSataAdapter, channelIndex);
mvSataFlushDmaQueue (ialExt->pSataAdapter, channelIndex,
MV_FLUSH_TYPE_CALLBACK);
}
mvFlushSCSICommandQueue(ialExt, channelIndex);
if (pSataAdapter->sataChannel[channelIndex] != NULL)
{
mvSataRemoveChannel(pSataAdapter,channelIndex);
IALReleaseChannel(pSataAdapter, channelIndex);
}
pSataAdapter->sataChannel[channelIndex] = NULL;
/*Notify about bus change*/
IALBusChangeNotify(pSataAdapter, channelIndex);
if (drivesSnapshot != 0)
{
IALBusChangeNotifyEx(pSataAdapter, channelIndex, drivesSnapshot, 0);
}
}
/*******************************************************************************
* mvExecuteScsiCommand - execute SCSI command
*
* DESCRIPTION:
* IAL common layer wrapper of mvSataExecuteScsiCommand function.
* If either the adapter state is either other than ADAPTER_READY
* or the channel is connected but channel state is not CHANNEL_READY,
* the current SCSI command is queued in channel's SCSI commands
* software queue until channel initialization sequence completed.
* If channel is found in CHANNEL ready state the SCSI command is passed to
* SCSI ATA translation layer.
* INPUT:
* pScb - SCSI command block structure.
*
* OUTPUT:
* None.
*
* RETURN:
* Return MV_SCSI_COMMAND_STATUS_COMPLETED if the command has been added
* to channel software queue. Otherwise return the result of
* mvSataExecuteScsiCommand function call
*******************************************************************************/
MV_SCSI_COMMAND_STATUS_TYPE mvExecuteScsiCommand(MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_BOOLEAN canQueue)
{
MV_IAL_COMMON_ADAPTER_EXTENSION* ialExt = pScb->pIalAdapterExtension;
MV_U8 channelIndex = pScb->bus;
#if 0
if ((ialExt->adapterState == ADAPTER_READY) &&
(ialExt->channelState[channelIndex] == CHANNEL_READY))
{
mvCheckPMForError(ialExt, channelIndex);
}
#endif
if ((ialExt->adapterState == ADAPTER_READY) &&
((ialExt->channelState[channelIndex] == CHANNEL_READY) ||
(ialExt->channelState[channelIndex] == CHANNEL_NOT_CONNECTED)))
{
return mvSataExecuteScsiCommand(pScb);
}
if (canQueue == MV_FALSE)
{
pScb->ScsiStatus = MV_SCSI_STATUS_BUSY;
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_QUEUE_FULL;
if (pScb->completionCallBack)
{
pScb->completionCallBack(ialExt->pSataAdapter, pScb);
}
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
else
{
mvAddToSCSICommandQueue(ialExt, channelIndex, pScb);
return MV_SCSI_COMMAND_STATUS_QUEUED_BY_IAL;
}
}
/*******************************************************************************
* mvIALTimerCallback - IAL timer callback
*
* DESCRIPTION:
* The adapter/channel state machine is timer-driven.
* After being loaded, the IAL must call this callback every 0.5 seconds
* INPUT:
* pSataAdapter - pointer to the adapter data structure.
* scsiAdapterExt - SCSI to ATA layer adapter extension data structure
* OUTPUT:
* None.
*
* RETURN:
*
*******************************************************************************/
MV_BOOLEAN mvIALTimerCallback(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
return mvAdapterStateMachine(ialExt,
scsiAdapterExt);
}
/*******************************************************************************
* mvCommandCompletionErrorHandler - IAL common command completion error handler
*
* DESCRIPTION:
* Called by whether SAL completion of SMART completion function. Check whether
* command is failed because of PM hot plug
*
* INPUT:
* pSataAdapter - pointer to the adapter data structure.
* channelIndex - channelNumber
* OUTPUT:
* None.
*
* RETURN:
*
*******************************************************************************/
void mvCommandCompletionErrorHandler(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex)
{
MV_SATA_ADAPTER* pSataAdapter = ialExt->pSataAdapter;
if (pSataAdapter->sataChannel[channelIndex] == NULL)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: "
"Invalid channel data structure pointer.\n",
pSataAdapter->adapterId, channelIndex);
}
if ((ialExt->channelState[channelIndex] != CHANNEL_READY) ||
(mvStorageDevGetDeviceType(pSataAdapter,channelIndex) !=
MV_SATA_DEVICE_TYPE_PM) ||
(ialExt->IALChannelExt[channelIndex].pmAsyncNotifyEnabled == MV_TRUE))
{
return;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: "
"Set completion error to MV_TRUE.\n",
pSataAdapter->adapterId, channelIndex);
ialExt->IALChannelExt[channelIndex].completionError = MV_TRUE;
}
/*Static functions*/
static void printAtaDeviceRegisters(
MV_STORAGE_DEVICE_REGISTERS *mvStorageDevRegisters)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "ATA Drive Registers:\n");
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "%20s : %04x\n","Error",
mvStorageDevRegisters->errorRegister);
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "%20s : %04x\n","SectorCount",
mvStorageDevRegisters->sectorCountRegister);
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "%20s : %04x\n","LBA Low",
mvStorageDevRegisters->lbaLowRegister);
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "%20s : %04x\n","LBA Mid",
mvStorageDevRegisters->lbaMidRegister);
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "%20s : %04x\n","LBA High",
mvStorageDevRegisters->lbaHighRegister);
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "%20s : %04x\n","Device",
mvStorageDevRegisters->deviceRegister);
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "%20s : %04x\n","Status",
mvStorageDevRegisters->statusRegister);
}
static void mvDrivesInfoSaveAll(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex)
{
/*Save disk drives information for channel*/
ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotSaved =
ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotCurrent;
memcpy(ialExt->IALChannelExt[channelIndex].drivesInfo.driveSerialSaved,
ialExt->IALChannelExt[channelIndex].drivesInfo.driveSerialCurrent,
sizeof(ialExt->IALChannelExt[channelIndex].drivesInfo.driveSerialCurrent));
/*Reset current disk drives information*/
ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotCurrent = 0;
memset(ialExt->IALChannelExt[channelIndex].drivesInfo.driveSerialCurrent,
0,
sizeof(ialExt->IALChannelExt[channelIndex].drivesInfo.driveSerialCurrent));
}
static void mvDrivesInfoFlushAll(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex)
{
/*Flush drives info*/
memset(&ialExt->IALChannelExt[channelIndex].drivesInfo, 0,
sizeof(ialExt->IALChannelExt[channelIndex].drivesInfo));
}
static void mvDrivesInfoFlushSingleDrive(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex, MV_U8 PMPort)
{
/*Clear bit in disk drive drive snapshot*/
ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotCurrent &=
~(1 << PMPort);
ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotSaved &=
~(1 << PMPort);
/*Clear disk drive serial number string*/
ialExt->
IALChannelExt[channelIndex].drivesInfo.driveSerialSaved[PMPort].serial[0] = 0;
ialExt->
IALChannelExt[channelIndex].drivesInfo.driveSerialCurrent[PMPort].serial[0] = 0;
}
static void mvDrivesInfoSaveSingleDrive(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_U8 PMPort,
MV_BOOLEAN isDriveAdded,
MV_U16_PTR identifyBuffer)
{
if (MV_TRUE == isDriveAdded)
{
/*Set bit in disk drive snapshot for current disk drive*/
ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotCurrent |=
1 << PMPort;
/*Save serial number for current disk drive*/
memcpy(ialExt->IALChannelExt[channelIndex].drivesInfo.driveSerialCurrent[PMPort].serial,
&identifyBuffer[IDEN_SERIAL_NUM_OFFSET], IDEN_SERIAL_NUM_SIZE);
}
else
{
if (0xFF == PMPort)
{
ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotCurrent
= 0;
memset(ialExt->IALChannelExt[channelIndex].drivesInfo.driveSerialCurrent,
0,
sizeof(ialExt->IALChannelExt[channelIndex].drivesInfo.driveSerialCurrent));
}
else
{
ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotCurrent
&= ~(1 << PMPort);
ialExt->IALChannelExt[channelIndex].drivesInfo.driveSerialCurrent[PMPort].serial[0] = 0;
}
}
}
static void mvSetDriveReady(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt,
MV_U8 channelIndex,
MV_U8 PMPort,
MV_BOOLEAN isReady,
MV_U16_PTR identifyBuffer)
{
mvDrivesInfoSaveSingleDrive(ialExt,
channelIndex,
PMPort,
isReady,
identifyBuffer);
mvSataScsiSetDriveReady(scsiAdapterExt,
channelIndex, PMPort, isReady);
}
static void mvDrivesInfoGetChannelRescanParams(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_U16 *drivesToRemove,
MV_U16 *drivesToAdd)
{
MV_U8 PMPort;
*drivesToRemove = 0;
*drivesToAdd = 0;
for (PMPort = 0; PMPort < MV_SATA_PM_MAX_PORTS; PMPort++)
{
if (ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotCurrent
& (1 << PMPort))
{
if (ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotSaved
& (1 << PMPort))
{
if (memcmp(&ialExt->IALChannelExt[channelIndex].drivesInfo.driveSerialCurrent[PMPort].serial,
&ialExt->IALChannelExt[channelIndex].drivesInfo.driveSerialSaved[PMPort].serial,
IDEN_SERIAL_NUM_SIZE))
{
/*Disk drive connected to port is replaced*/
*drivesToAdd |= (1 << PMPort);
*drivesToRemove |= (1 << PMPort);
}
}
else
{
/*New drive connected to port*/
*drivesToAdd |= (1 << PMPort);
}
}
else
{
/*Drive removed from Port*/
if (ialExt->IALChannelExt[channelIndex].drivesInfo.drivesSnapshotSaved
& (1 << PMPort))
{
*drivesToRemove |= (1 << PMPort);
}
}
}
}
/*SCSI command queue functions*/
static void mvAddToSCSICommandQueue(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_SATA_SCSI_CMD_BLOCK *cmdBlock = (MV_SATA_SCSI_CMD_BLOCK *)
ialExt->IALChannelExt[channelIndex].IALChannelPendingCmdQueue;
pScb->pNext = NULL;
if (cmdBlock)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d] Adding next command to SW queue\n",
ialExt->pSataAdapter->adapterId, channelIndex);
while (cmdBlock->pNext)
{
cmdBlock = cmdBlock->pNext;
}
cmdBlock->pNext = pScb;
}
else
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d] Adding first command to SW queue\n",
ialExt->pSataAdapter->adapterId, channelIndex);
ialExt->IALChannelExt[channelIndex].IALChannelPendingCmdQueue =
(MV_VOID_PTR)pScb;
}
}
MV_BOOLEAN mvRemoveFromSCSICommandQueue(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_SATA_SCSI_CMD_BLOCK *cmdBlock = (MV_SATA_SCSI_CMD_BLOCK *)
ialExt->IALChannelExt[channelIndex].IALChannelPendingCmdQueue;
pScb->pNext = NULL;
if (cmdBlock)
{
if (cmdBlock == pScb)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d] Removing command"
" %p from head of SW queue\n",
ialExt->pSataAdapter->adapterId,channelIndex, pScb);
ialExt->IALChannelExt[channelIndex].IALChannelPendingCmdQueue =
(MV_VOID_PTR) cmdBlock->pNext;
return MV_TRUE;
}
else
{
while (cmdBlock->pNext)
{
if (cmdBlock->pNext == pScb)
{
break;
}
cmdBlock = cmdBlock->pNext;
}
if (cmdBlock->pNext == NULL)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d] Removing"
" command %p from SW queue failed. command not found\n",
ialExt->pSataAdapter->adapterId,channelIndex, pScb);
return MV_FALSE;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d] Removing command"
" %p from SW queue\n", ialExt->pSataAdapter->adapterId,
channelIndex, pScb);
cmdBlock->pNext = cmdBlock->pNext->pNext;
return MV_TRUE;
}
}
else
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d] Removing"
" command %p from SW queue failed. queue empty\n",
ialExt->pSataAdapter->adapterId,channelIndex, pScb);
return MV_FALSE;
}
return MV_FALSE;
}
static void mvFlushSCSICommandQueue(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex)
{
/*Abort all pending commands in SW queue*/
MV_SATA_SCSI_CMD_BLOCK *cmdBlock = (MV_SATA_SCSI_CMD_BLOCK *)
ialExt->IALChannelExt[channelIndex].IALChannelPendingCmdQueue;
while (cmdBlock)
{
MV_SATA_SCSI_CMD_BLOCK *nextBlock = cmdBlock->pNext;
if (cmdBlock->completionCallBack)
{
cmdBlock->ScsiStatus = MV_SCSI_STATUS_BUSY;
cmdBlock->dataTransfered = 0;
cmdBlock->ScsiCommandCompletion = MV_SCSI_COMPLETION_QUEUE_FULL;
cmdBlock->completionCallBack(ialExt->pSataAdapter, cmdBlock);
}
cmdBlock = nextBlock;
}
ialExt->IALChannelExt[channelIndex].IALChannelPendingCmdQueue = NULL;
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d]: Flush command queue is done\n",
ialExt->pSataAdapter->adapterId, channelIndex);
}
/*Port Multilier related functions*/
static MV_BOOLEAN mvPMCommandCompletionCB(MV_SATA_ADAPTER *pSataAdapter,
MV_U8 channelIndex,
MV_COMPLETION_TYPE comp_type,
MV_VOID_PTR commandId,
MV_U16 responseFlags,
MV_U32 timeStamp,
MV_STORAGE_DEVICE_REGISTERS *registerStruct)
{
MV_U32 value;
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt =
(MV_IAL_COMMON_ADAPTER_EXTENSION *)commandId;
ialExt->IALChannelExt[channelIndex].pmRegAccessInProgress = MV_FALSE;
switch (comp_type)
{
case MV_COMPLETION_TYPE_NORMAL:
if (ialExt->IALChannelExt[channelIndex].pmAccessType
== MV_ATA_COMMAND_PM_READ_REG)
{
value = registerStruct->sectorCountRegister;
value |= (registerStruct->lbaLowRegister << 8);
value |= (registerStruct->lbaMidRegister << 16);
value |= (registerStruct->lbaMidRegister << 24);
if (ialExt->IALChannelExt[channelIndex].pmReg
== MV_SATA_GSCR_ERROR_REG_NUM)
{
if (value != 0)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d]: PM GSCR[32] = 0x%X\n",
pSataAdapter->adapterId, channelIndex, value);
ialExt->IALChannelExt[channelIndex].PMdevsToInit =
(MV_U16)(value & 0x7FFF);
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d]: "
"PM Hot plug detected "
"Bitmask = 0x%X\n",
pSataAdapter->adapterId, channelIndex,
ialExt->IALChannelExt[channelIndex].PMdevsToInit);
mvSetChannelState(ialExt, channelIndex,
CHANNEL_PM_HOT_PLUG);
}
}
}
break;
case MV_COMPLETION_TYPE_ABORT:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: read PM register aborted!\n",
pSataAdapter->adapterId, channelIndex);
break;
case MV_COMPLETION_TYPE_ERROR:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: read PM register error!\n",
pSataAdapter->adapterId, channelIndex);
break;
default:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: Unknown completion type (%d)\n",
pSataAdapter->adapterId, channelIndex, comp_type);
return MV_FALSE;
}
return MV_TRUE;
}
static MV_BOOLEAN mvQueuePMAccessRegisterCommand(
MV_IAL_COMMON_ADAPTER_EXTENSION* ialExt,
MV_U8 channelIndex,
MV_U8 PMPort,
MV_U8 PMReg,
MV_U32 Value,
MV_BOOLEAN isRead)
{
MV_QUEUE_COMMAND_RESULT result;
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = &ialExt->IALChannelExt[channelIndex].commandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo, *pCommandInfo;
pCommandInfo = &commandInfo;
#endif
memset(pCommandInfo, 0, sizeof(MV_QUEUE_COMMAND_INFO));
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->commandParams.NoneUdmaCommand.protocolType =
MV_NON_UDMA_PROTOCOL_NON_DATA;
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_TRUE;
pCommandInfo->commandParams.NoneUdmaCommand.bufPtr = NULL;
pCommandInfo->PMPort = MV_SATA_PM_CONTROL_PORT;
pCommandInfo->commandParams.NoneUdmaCommand.count = 0;
pCommandInfo->commandParams.NoneUdmaCommand.features = PMReg;
pCommandInfo->commandParams.NoneUdmaCommand.device = (MV_U8)PMPort;
pCommandInfo->commandParams.NoneUdmaCommand.callBack =
mvPMCommandCompletionCB;
ialExt->IALChannelExt[channelIndex].pmReg = PMReg;
if (isRead == MV_TRUE)
{
ialExt->IALChannelExt[channelIndex].pmAccessType =
MV_ATA_COMMAND_PM_READ_REG;
pCommandInfo->commandParams.NoneUdmaCommand.command =
MV_ATA_COMMAND_PM_READ_REG;
pCommandInfo->commandParams.NoneUdmaCommand.commandId =
(MV_VOID_PTR)ialExt;
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh = 0;
}
else
{
ialExt->IALChannelExt[channelIndex].pmAccessType =
MV_ATA_COMMAND_PM_WRITE_REG;
pCommandInfo->commandParams.NoneUdmaCommand.command =
MV_ATA_COMMAND_PM_WRITE_REG;
pCommandInfo->commandParams.NoneUdmaCommand.commandId =
(MV_VOID_PTR)ialExt;
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount =
(MV_U16)((Value) & 0xff),
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow =
(MV_U16)(((Value) & 0xff00) >> 8);
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid =
(MV_U16)(((Value) & 0xff0000) >> 16);
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh =
(MV_U16)(((Value) & 0xff000000) >> 24);
}
ialExt->IALChannelExt[channelIndex].pmRegAccessInProgress = MV_TRUE;
result = mvSataQueueCommand(pSataAdapter,
channelIndex,
pCommandInfo);
if (result != MV_QUEUE_COMMAND_RESULT_OK)
{
switch (result)
{
case MV_QUEUE_COMMAND_RESULT_BAD_LBA_ADDRESS:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, ": Queue PM command failed. Bad LBA "
"\n");
break;
case MV_QUEUE_COMMAND_RESULT_QUEUED_MODE_DISABLED:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, ": Queue PM command failed. EDMA"
" disabled adapter %d channel %d\n",
pSataAdapter->adapterId, channelIndex);
break;
case MV_QUEUE_COMMAND_RESULT_FULL:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, ": Queue PM command failed. Queue is"
" Full adapter %d channel %d\n",
pSataAdapter->adapterId, channelIndex);
break;
case MV_QUEUE_COMMAND_RESULT_BAD_PARAMS:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, ": Queue PM command failed. (Bad "
"Params), pMvSataAdapter: %p, pSataChannel: %p.\n",
pSataAdapter, pSataAdapter->sataChannel[channelIndex]);
break;
default:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, ": Queue PM command bad result value (%d) "
"from queue command\n",
result);
}
ialExt->IALChannelExt[channelIndex].pmRegAccessInProgress = MV_FALSE;
return MV_FALSE;
}
return MV_TRUE;
}
static MV_BOOLEAN mvPMEnableCommStatusChangeBits(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_BOOLEAN enable)
{
MV_U32 regVal;
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
if (enable == MV_TRUE)
{
regVal = MV_BIT16;
}
else
{
regVal = 0;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d]: Set PM "
"GSCR[33] register to 0x%X\n",
pSataAdapter->adapterId, channelIndex, regVal);
/*Set N bit reflection in PM GSCR*/
if (mvPMDevWriteReg(pSataAdapter, channelIndex,
MV_SATA_PM_CONTROL_PORT,
MV_SATA_GSCR_ERROR_ENABLE_REG_NUM,
regVal, NULL) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: Failed to set "
"PortMultiplier Features Enable register\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
return MV_TRUE;
}
static MV_BOOLEAN mvPMEnableAsyncNotify(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex)
{
MV_U32 regVal1, regVal2;
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
/*Features register*/
if (mvPMDevReadReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
MV_SATA_GSCR_FEATURES_REG_NUM,
&regVal1, NULL) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: Failed to get Port Multiplier Features"
" supported register\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d]: Port Multiplier features supported: 0x%X\n",
pSataAdapter->adapterId, channelIndex, regVal1);
/*PM asynchronous notification supported*/
if (mvPMDevReadReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
MV_SATA_GSCR_FEATURES_ENABLE_REG_NUM,
&regVal2 ,NULL) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: Failed to get Port Multiplier Features"
" register\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d]: Port Multiplier features enabled "
"register: 0x%X\n",
pSataAdapter->adapterId, channelIndex, regVal2);
if (regVal1 & MV_BIT3)
{
regVal2 |= MV_BIT3;
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
MV_SATA_GSCR_FEATURES_ENABLE_REG_NUM,
regVal2 ,NULL) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: Failed to set "
"PortMultiplier Features Enable register\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
ialExt->IALChannelExt[channelIndex].pmAsyncNotifyEnabled = MV_TRUE;
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d]: PM asynchronous notification is "
"enabled.\n", pSataAdapter->adapterId, channelIndex);
}
else
{
regVal2 &= ~MV_BIT3;
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
MV_SATA_GSCR_FEATURES_ENABLE_REG_NUM,
regVal2 ,NULL) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: Failed to set "
"PortMultiplier Features Enable register\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
ialExt->IALChannelExt[channelIndex].pmAsyncNotifyEnabled = MV_FALSE;
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d]: PM asynchronous notification is "
"disabled.\n", pSataAdapter->adapterId, channelIndex);
}
return MV_TRUE;
}
static MV_BOOLEAN mvPMDisableAsyncNotify(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex)
{
MV_U32 regVal2;
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
/*PM asynchronous notification supported*/
if (mvPMDevReadReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
MV_SATA_GSCR_FEATURES_ENABLE_REG_NUM,
&regVal2 ,NULL) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: Failed to get Port Multiplier Features"
" register\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d]: Port Multiplier features enabled "
"register: 0x%X\n",
pSataAdapter->adapterId, channelIndex, regVal2);
regVal2 &= ~MV_BIT3;
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
MV_SATA_GSCR_FEATURES_ENABLE_REG_NUM,
regVal2 ,NULL) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: Failed to set "
"PortMultiplier Features Enable register\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
ialExt->IALChannelExt[channelIndex].pmAsyncNotifyEnabled = MV_FALSE;
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d]: PM asynchronous notification is "
"disabled.\n", pSataAdapter->adapterId, channelIndex);
return MV_TRUE;
}
static MV_BOOLEAN mvConfigurePMDevice(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex)
{
MV_SATA_PM_DEVICE_INFO PMInfo;
ialExt->IALChannelExt[channelIndex].pmAsyncNotifyEnabled = MV_FALSE;
if (mvGetPMDeviceInfo(ialExt->pSataAdapter, channelIndex, &PMInfo)
== MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: Failed to get PortMultiplier Info\n",
ialExt->pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d]: PM of %d ports found\n",
ialExt->pSataAdapter->adapterId, channelIndex,
PMInfo.numberOfPorts);
ialExt->IALChannelExt[channelIndex].PMnumberOfPorts = PMInfo.numberOfPorts;
#ifdef DISABLE_PM_SCC
if (PMInfo.vendorId == 0x11AB)
{
if (mvPMDisableSSC(ialExt->pSataAdapter, channelIndex) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: cannot disable SSC for PM.\n"
"unknown vendor.\n",
ialExt->pSataAdapter->adapterId, channelIndex);
}
}
else
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: cannot disable SSC for PM - "
"unknown vendor.\n",
ialExt->pSataAdapter->adapterId, channelIndex);
}
#endif
#if 1
if (clearSErrorPorts(ialExt->pSataAdapter, channelIndex,
ialExt->IALChannelExt[channelIndex].PMnumberOfPorts) !=
MV_TRUE)
{
return MV_FALSE;
}
#endif
if (mvPMEnableCommStatusChangeBits(ialExt,
channelIndex,
MV_FALSE) != MV_TRUE)
{
return MV_FALSE;
}
if (mvPMDisableAsyncNotify(ialExt, channelIndex) == MV_FALSE)
{
return MV_FALSE;
}
#if 0
if (mvPMDevEnableStaggeredSpinUpAll(ialExt->pSataAdapter,
channelIndex,
ialExt->IALChannelExt[channelIndex].PMnumberOfPorts,
&ialExt->IALChannelExt[channelIndex].PMdevsToInit) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: PM Enable Staggered Spin-\
Up Failed\n",
ialExt->pSataAdapter->adapterId, channelIndex);
ialExt->IALChannelExt[channelIndex].PMdevsToInit = 0;
return MV_FALSE;
}
#endif
return MV_TRUE;
}
static MV_BOOLEAN clearSErrorPorts(MV_SATA_ADAPTER *pSataAdapter, MV_U8 channelIndex,
MV_U8 PMnumberOfPorts)
{
MV_U8 PMPort;
for (PMPort = 0; PMPort < PMnumberOfPorts; PMPort++)
{
if (mvPMDevWriteReg(pSataAdapter, channelIndex, PMPort,
MV_SATA_PSCR_SERROR_REG_NUM, 0xFFFFFFFF, NULL) ==
MV_FALSE)
{
if (mvStorageDevATASoftResetDevice(pSataAdapter, channelIndex,
MV_SATA_PM_CONTROL_PORT, NULL) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: "
"failed to Soft Reset PM control port\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
}
}
return MV_TRUE;
}
MV_BOOLEAN mvPMEnableLocking(MV_SATA_ADAPTER *pSataAdapter, MV_U8 channelIndex)
{
MV_STORAGE_DEVICE_REGISTERS regs;
if (mvPMDevWriteReg(pSataAdapter, channelIndex,
MV_SATA_PM_CONTROL_PORT,
0x89,
0x8000003F,
&regs) == MV_TRUE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: NCQ lock is enabled for PM.\n",
pSataAdapter->adapterId, channelIndex);
return MV_TRUE;
}
else
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d]: cannot enable NCQ lock for PM.\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
return MV_TRUE;
}
#ifdef DISABLE_PM_SCC
MV_BOOLEAN mvPMDisableSSC(MV_SATA_ADAPTER *pSataAdapter, MV_U8 channelIndex)
{
MV_STORAGE_DEVICE_REGISTERS regs;
MV_U32 regVal = 0;
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: "
"Disable SSC for all PM ports.\n",
pSataAdapter->adapterId, channelIndex);
if (mvPMDevReadReg(pSataAdapter,channelIndex, MV_SATA_PM_CONTROL_PORT,
MV_SATA_GSCR_FEATURES_ENABLE_REG_NUM,
&regVal,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
/*Host SSC disable*/
regVal &= ~MV_BIT2;
if (mvPMDevWriteReg(pSataAdapter,channelIndex, MV_SATA_PM_CONTROL_PORT,
MV_SATA_GSCR_FEATURES_ENABLE_REG_NUM,
regVal,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
/* disable ssc for port 0*/
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
0x8C,
0,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
0x92,
0xb02a402a,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
/* disable ssc for port 1*/
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
0x8C,
1,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
0x92,
0xb02a402a,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
/* disable ssc for port 2*/
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
0x8C,
2,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
0x92,
0xb02a402a,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
/* disable ssc for port 3*/
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
0x8C,
3,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
0x92,
0xb02a402a,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
/* disable ssc for port 15*/
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
0x8C,
MV_SATA_PM_CONTROL_PORT,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
if (mvPMDevWriteReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
0x92,
0xb02a402a,
&regs) != MV_TRUE)
{
return MV_FALSE;
}
return MV_TRUE;
}
#endif
static MV_BOOLEAN mvConfigChannelQueuingMode(MV_IAL_COMMON_ADAPTER_EXTENSION* ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
MV_EDMA_MODE EDMAMode = MV_EDMA_MODE_NOT_QUEUED;
MV_SATA_SWITCHING_MODE switchingMode;
MV_BOOLEAN isTCQSupported = MV_FALSE;
MV_BOOLEAN isNCQSupported = MV_FALSE;
MV_U8 numOfDrives = 0;
MV_SATA_PM_DEVICE_INFO PMInfo;
MV_SATA_DEVICE_TYPE connectedDevice;
MV_BOOLEAN use128Entries = MV_FALSE;
if (mvGetDisksModes(ialExt,
scsiAdapterExt,
channelIndex,
&isTCQSupported,
&isNCQSupported,
&numOfDrives) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_FATAL_ERROR,
"[%d %d]:mvConfigChannelQueuingMode: failed to get disks modes.\n"
,pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
else
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: Supported queuing mode: TCQ = %s, "
"NCQ = %s. number of disks %d\n",
pSataAdapter->adapterId, channelIndex,
(isTCQSupported == MV_TRUE) ? "Yes" : "No",
(isNCQSupported == MV_TRUE) ? "Yes" : "No",
numOfDrives);
}
connectedDevice = mvStorageDevGetDeviceType(pSataAdapter,channelIndex);
if (connectedDevice == MV_SATA_DEVICE_TYPE_UNKNOWN)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_FATAL_ERROR,
"[%d %d] mvConfigChannelQueuingMode: failed to get device type.\n"
,pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
if (connectedDevice == MV_SATA_DEVICE_TYPE_PM)
{
if (mvGetPMDeviceInfo(ialExt->pSataAdapter, channelIndex, &PMInfo)
== MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_FATAL_ERROR,
"[%d %d] mvConfigChannelQueuingMode: Failed to get "
"PortMultiplier Info\n",
ialExt->pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
}
mvSelectConfiguration(pSataAdapter, channelIndex,
pSataAdapter->sataAdapterGeneration,
connectedDevice,&PMInfo,
isNCQSupported,
isTCQSupported,
numOfDrives,
&EDMAMode,
&switchingMode,
&use128Entries);
#ifndef MV_SATA_SUPPORT_GEN2E_128_QUEUE_LEN
use128Entries = MV_FALSE;
#endif
switch (switchingMode)
{
case MV_SATA_SWITCHING_MODE_FBS:
{
if (mvSataSetFBSMode(pSataAdapter, channelIndex, MV_TRUE,
use128Entries) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_FATAL_ERROR,
"[%d %d] mvConfigChannelQueuingMode: failed to enable FBS.\n"
,pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
}
break;
case MV_SATA_SWITCHING_MODE_QCBS:
if (mvPMEnableLocking(pSataAdapter,channelIndex) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_FATAL_ERROR,
"[%d %d] mvConfigChannelQueuingMode: failed to enable QCBS.\n"
,pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
break;
default:
break;
}
IALConfigQueuingMode(pSataAdapter,
channelIndex,
EDMAMode,
switchingMode,
use128Entries);
return MV_TRUE;
}
/*Channel related functions*/
static void mvSetChannelState(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_CHANNEL_STATE state)
{
if (ialExt->channelState[channelIndex] != state)
{
if ((state == CHANNEL_READY) || (state == CHANNEL_NOT_CONNECTED))
{
ialExt->IALChannelExt[channelIndex].SRSTTimerThreshold = 0;
ialExt->IALChannelExt[channelIndex].SRSTTimerValue = 0;
}
if (state == CHANNEL_READY)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: CHANNEL_READY\n",
ialExt->pSataAdapter->adapterId,
channelIndex);
ialExt->IALChannelExt[channelIndex].pmRegAccessInProgress
= MV_FALSE;
ialExt->IALChannelExt[channelIndex].completionError = MV_FALSE;
ialExt->channelState[channelIndex] = state;
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d] flush pending queue\n",
ialExt->pSataAdapter->adapterId, channelIndex);
/*Abort all pending commands in SW queue*/
mvFlushSCSICommandQueue(ialExt, channelIndex);
if (MV_TRUE == ialExt->IALChannelExt[channelIndex].bHotPlug)
{
MV_U16 drivesToRemove;
MV_U16 drivesToAdd;
ialExt->IALChannelExt[channelIndex].bHotPlug = MV_FALSE;
mvDrivesInfoGetChannelRescanParams(ialExt,
channelIndex,
&drivesToRemove,
&drivesToAdd);
if (drivesToRemove != 0 || drivesToAdd != 0)
{
IALBusChangeNotifyEx(ialExt->pSataAdapter,
channelIndex,
drivesToRemove,
drivesToAdd);
}
}
mvDrivesInfoSaveAll(ialExt, channelIndex);
}
else
{
ialExt->channelState[channelIndex] = state;
}
}
}
static MV_BOOLEAN mvStartChannelInit(MV_SATA_ADAPTER *pSataAdapter,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt,
MV_BOOLEAN* bIsChannelReady)
{
*bIsChannelReady = MV_FALSE;
if (mvSataConfigureChannel(pSataAdapter, channelIndex) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d]: configure channel failed\n",
pSataAdapter->adapterId,
channelIndex);
return MV_FALSE;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: start channel\n",
pSataAdapter->adapterId,
channelIndex);
/*Just check SStatus in case of SATA I adapter*/
if (pSataAdapter->sataAdapterGeneration == MV_SATA_GEN_I)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: starting SATA I channel.\n",
pSataAdapter->adapterId, channelIndex);
}
else
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: starting SATA II channel.\n",
pSataAdapter->adapterId, channelIndex);
}
return mvStorageDevATAStartSoftResetDevice(pSataAdapter,
channelIndex,
MV_SATA_PM_CONTROL_PORT);
}
static MV_BOOLEAN mvChannelSRSTFinished(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_SATA_CHANNEL *pSataChannel,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt,
MV_BOOLEAN* bIsChannelReady,
MV_BOOLEAN* bFatalError)
{
MV_SATA_DEVICE_TYPE deviceType;
MV_STORAGE_DEVICE_REGISTERS mvStorageDevRegisters;
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
MV_SATA_SCSI_DRIVE_DATA *pDriveData;
*bIsChannelReady = MV_FALSE;
*bFatalError = MV_FALSE;
if (pSataAdapter->sataAdapterGeneration > MV_SATA_GEN_I)
{
if (mvStorageIsDeviceBsyBitOff(pSataAdapter,
channelIndex,
&mvStorageDevRegisters)
== MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: soft Reset PM control port "
"in progress\n",
pSataAdapter->adapterId, channelIndex);
printAtaDeviceRegisters(&mvStorageDevRegisters);
return MV_FALSE;
}
deviceType = mvGetSataDeviceType(&mvStorageDevRegisters);
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: soft reset SATA II channel - "
"device ready.\n",
pSataAdapter->adapterId, channelIndex);
}
else
{
if (mvStorageIsDeviceBsyBitOff(pSataAdapter,
channelIndex,
&mvStorageDevRegisters)
== MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: soft reset of SATA I channel "
"in progress\n",
pSataAdapter->adapterId, channelIndex);
printAtaDeviceRegisters(&mvStorageDevRegisters);
return MV_FALSE;
}
deviceType = mvGetSataDeviceType(&mvStorageDevRegisters);
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: soft reset SATA I channel - "
"device ready.\n",
pSataAdapter->adapterId, channelIndex);
deviceType = mvGetSataDeviceType(&mvStorageDevRegisters);
if (deviceType != MV_SATA_DEVICE_TYPE_ATA_DISK)
{
deviceType = MV_SATA_DEVICE_TYPE_UNKNOWN;
}
}
switch (deviceType)
{
case MV_SATA_DEVICE_TYPE_ATA_DISK:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO,"[%d %d]: SATA disk found\n",
pSataAdapter->adapterId, channelIndex);
if (mvStorageDevSetDeviceType(pSataAdapter,channelIndex, deviceType) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d]: Failed to initialize disk\n",
pSataAdapter->adapterId, channelIndex);
*bFatalError = MV_TRUE;
return MV_FALSE;
}
pDriveData = &scsiAdapterExt->ataDriveData[channelIndex][0];
if (mvInitSataDisk(pSataAdapter,
channelIndex,
0,
&pDriveData->identifyInfo,
pDriveData->identifyBuffer) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d]: Failed to initialize disk\n",
pSataAdapter->adapterId, channelIndex);
*bFatalError = MV_TRUE;
mvDrivesInfoFlushSingleDrive(ialExt,
channelIndex,
0);
return MV_FALSE;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO,"[%d %d]: Disk ready\n",
pSataAdapter->adapterId, channelIndex);
mvSetDriveReady(ialExt,
scsiAdapterExt,
channelIndex,
0,
MV_TRUE,
pDriveData->identifyBuffer);
mvSataScsiNotifyUA(scsiAdapterExt, channelIndex, 0);
*bIsChannelReady = MV_TRUE;
return MV_TRUE;
break;
case MV_SATA_DEVICE_TYPE_PM:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO,"[%d %d]: PortMultiplier device found\n",
pSataAdapter->adapterId, channelIndex);
if (mvStorageDevSetDeviceType(pSataAdapter,channelIndex, deviceType) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d]: Failed to initialize PM\n",
pSataAdapter->adapterId, channelIndex);
*bFatalError = MV_TRUE;
return MV_FALSE;
}
break;
#ifdef MV_SUPPORT_ATAPI
case MV_SATA_DEVICE_TYPE_ATAPI_DEVICE:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO,"[%d %d]: ATAPI device found\n",
pSataAdapter->adapterId, channelIndex);
if (mvStorageDevSetDeviceType(pSataAdapter,channelIndex, deviceType) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d]: Failed to initialize ATAPI device\n",
pSataAdapter->adapterId, channelIndex);
*bFatalError = MV_TRUE;
return MV_FALSE;
}
pDriveData = &scsiAdapterExt->ataDriveData[channelIndex][0];
if (mvInitSataATAPI(pSataAdapter,
channelIndex,
0,
&pDriveData->identifyInfo,
pDriveData->identifyBuffer) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d]: Failed to initialize ATAPI device\n",
pSataAdapter->adapterId, channelIndex);
*bFatalError = MV_TRUE;
mvDrivesInfoFlushSingleDrive(ialExt,
channelIndex,
0);
return MV_FALSE;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO,"[%d %d]: ATAPI Device ready\n",
pSataAdapter->adapterId, channelIndex);
mvSetDriveReady(ialExt,
scsiAdapterExt,
channelIndex,
0,
MV_TRUE,
pDriveData->identifyBuffer);
mvSataScsiNotifyUA(scsiAdapterExt, channelIndex, 0);
*bIsChannelReady = MV_TRUE;
return MV_TRUE;
break;
#endif
default:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d]: ERROR: unknown device type\n",
pSataAdapter->adapterId, channelIndex);
*bFatalError = MV_TRUE;
return MV_FALSE;
}
return MV_TRUE;
}
static MV_BOOLEAN mvConfigChannelDMA(
MV_IAL_COMMON_ADAPTER_EXTENSION* ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d] config queueing mode\n",
pSataAdapter->adapterId, channelIndex);
if (mvConfigChannelQueuingMode(ialExt,
channelIndex,
scsiAdapterExt)
== MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d] Failed to config DMA queuing\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
/* Enable EDMA */
if (mvSataEnableChannelDma(pSataAdapter, channelIndex) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d] Failed to enable DMA, channel=%d\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d]: channel started successfully\n",
pSataAdapter->adapterId, channelIndex);
return MV_TRUE;
}
static void mvSetChannelTimer(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_U32 timeout)
{
ialExt->IALChannelExt[channelIndex].SRSTTimerThreshold = timeout;
ialExt->IALChannelExt[channelIndex].SRSTTimerValue = 1;
}
static void mvDecrementChannelTimer(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex)
{
if (ialExt->IALChannelExt[channelIndex].SRSTTimerThreshold > 0)
{
ialExt->IALChannelExt[channelIndex].SRSTTimerValue +=
MV_IAL_ASYNC_TIMER_PERIOD;
}
}
static MV_BOOLEAN mvIsChannelTimerExpired(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex)
{
if (ialExt->IALChannelExt[channelIndex].SRSTTimerValue >
ialExt->IALChannelExt[channelIndex].SRSTTimerThreshold)
{
return MV_TRUE;
}
else
{
return MV_FALSE;
}
}
/*******************************************************************************
*State Machine related functions:
* Return MV_TRUE to proceed to the next channel
* Return MV_FALSE to proceed to the next state on current channel
*******************************************************************************/
static MV_BOOLEAN mvChannelNotConnectedStateHandler(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
if (pSataAdapter->sataChannel[channelIndex] != NULL)
{
mvSataRemoveChannel(pSataAdapter,channelIndex);
pSataAdapter->sataChannel[channelIndex] = NULL;
mvSetDriveReady(ialExt,
scsiAdapterExt,
channelIndex,
0xFF, MV_FALSE, NULL);
mvFlushSCSICommandQueue(ialExt, channelIndex);
}
return MV_TRUE;
}
static MV_BOOLEAN mvChannelConnectedStateHandler(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
MV_BOOLEAN res = MV_FALSE;
MV_BOOLEAN isChannelReady;
MV_SATA_CHANNEL *pSataChannel;
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d] CHANNEL_CONNECTED\n",
ialExt->pSataAdapter->adapterId, channelIndex);
if (pSataAdapter->sataChannel[channelIndex] == NULL)
{
if (IALInitChannel(pSataAdapter, channelIndex) == MV_FALSE)
{
IALReleaseChannel(pSataAdapter, channelIndex);
mvDrivesInfoFlushAll(ialExt, channelIndex);
mvSetChannelState(ialExt, channelIndex, CHANNEL_NOT_CONNECTED);
return MV_TRUE;
}
}
pSataChannel = pSataAdapter->sataChannel[channelIndex];
res = mvStartChannelInit(pSataAdapter,
channelIndex,
scsiAdapterExt,
&isChannelReady);
if (res == MV_TRUE)
{
if (isChannelReady == MV_FALSE)
{
/*SRST channel, Set polling timer*/
mvSetChannelTimer(ialExt, channelIndex,
MV_IAL_SRST_TIMEOUT);
mvSetChannelState(ialExt,
channelIndex,
CHANNEL_IN_SRST);
}
else
{
if (mvConfigChannelDMA(ialExt,
channelIndex,
scsiAdapterExt) == MV_TRUE)
{
mvSetChannelState(ialExt,
channelIndex,
CHANNEL_READY);
}
else
{
mvStopChannel(ialExt,
channelIndex,
scsiAdapterExt);
}
}
}
else
{
mvStopChannel(ialExt,
channelIndex,
scsiAdapterExt);
}
return MV_TRUE;
}
MV_BOOLEAN mvChannelInSrstStateHandler(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
MV_BOOLEAN bFatalError;
MV_BOOLEAN res = MV_FALSE;
MV_BOOLEAN isChannelReady;
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
MV_SATA_CHANNEL *pSataChannel = pSataAdapter->sataChannel[channelIndex];
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d] CHANNEL_IN_SRST\n",
pSataAdapter->adapterId, channelIndex);
mvDecrementChannelTimer(ialExt, channelIndex);
res = mvChannelSRSTFinished(ialExt,
pSataChannel,
channelIndex,
scsiAdapterExt,
&isChannelReady,
&bFatalError);
if (res == MV_TRUE)
{
/*Finishing channel initialization*/
if (isChannelReady == MV_TRUE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO,"[%d %d]: Sata device ready\n",
pSataAdapter->adapterId,channelIndex);
if (mvConfigChannelDMA(ialExt,
channelIndex,
scsiAdapterExt) == MV_TRUE)
{
mvSetChannelState(ialExt,
channelIndex,
CHANNEL_READY);
}
else
{
mvStopChannel(ialExt,
channelIndex,
scsiAdapterExt);
}
}
else
{/*If channel not ready and function call succeed -> PM is found*/
if (mvConfigurePMDevice(ialExt, channelIndex) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d]: Failed to "
"initialize PM\n",
pSataAdapter->adapterId,channelIndex);
#if 0
mvStopChannel(ialExt,
channelIndex,
scsiAdapterExt);
#else
mvSataChannelHardReset(pSataAdapter, channelIndex);
mvRestartChannel(ialExt, channelIndex, scsiAdapterExt, MV_FALSE);
#endif
}
else
{
MV_IAL_COMMON_CHANNEL_EXTENSION* channelExt =
&ialExt->IALChannelExt[channelIndex];
channelExt->port_state = MV_PORT_NOT_INITIALIZED;
channelExt->devInSRST = 0;
mvSetChannelState(ialExt, channelIndex,
CHANNEL_PM_INIT_DEVICES);
return MV_FALSE;
}
}
}
else
{
if (bFatalError == MV_TRUE)
{
mvStopChannel(ialExt,
channelIndex,
scsiAdapterExt);
}
else
{
if (mvIsChannelTimerExpired(ialExt, channelIndex) == MV_TRUE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,
"[%d %d]: SW reset Failed, timer expired\n",
pSataAdapter->adapterId,channelIndex);
mvStopChannel(ialExt,
channelIndex,
scsiAdapterExt);
}
}
}
return MV_TRUE;
}
MV_BOOLEAN classifyAndInitDevice(MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt,
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex, MV_U8 PMPort)
{
MV_SATA_DEVICE_TYPE deviceType;
MV_SATA_ADAPTER *pSataAdapter = scsiAdapterExt->pSataAdapter;
MV_IAL_COMMON_CHANNEL_EXTENSION* channelExt = &ialExt->IALChannelExt[channelIndex];
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &scsiAdapterExt->ataDriveData[channelIndex][PMPort];
MV_STORAGE_DEVICE_REGISTERS *mvStorageDevRegisters = &channelExt->mvStorageDevRegisters;
deviceType = mvGetSataDeviceType(mvStorageDevRegisters);
if (deviceType == MV_SATA_DEVICE_TYPE_ATA_DISK)
{
if (mvInitSataDisk(pSataAdapter,
channelIndex ,
PMPort, &pDriveData->identifyInfo,
pDriveData->identifyBuffer) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d %d]: Failed to initialize disk\n",
pSataAdapter->adapterId, channelIndex, PMPort);
mvDrivesInfoFlushSingleDrive(ialExt, channelIndex, PMPort);
}
else
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO, "[%d %d %d]: Disk ready\n",
pSataAdapter->adapterId, channelIndex, PMPort);
mvSetDriveReady(ialExt,
scsiAdapterExt,
channelIndex, PMPort,
MV_TRUE,
pDriveData->identifyBuffer);
mvSataScsiNotifyUA(scsiAdapterExt, channelIndex, PMPort);
}
}
#ifdef MV_SUPPORT_ATAPI
else if (deviceType == MV_SATA_DEVICE_TYPE_ATAPI_DEVICE)
{
if (mvInitSataATAPI(pSataAdapter,
channelIndex ,
PMPort, &pDriveData->identifyInfo,
pDriveData->identifyBuffer) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d %d]: Failed to initialize ATAPI device\n",
pSataAdapter->adapterId, channelIndex, PMPort);
mvDrivesInfoFlushSingleDrive(ialExt, channelIndex, PMPort);
}
else
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO, "[%d %d %d]: ATAPI device ready\n",
pSataAdapter->adapterId, channelIndex, PMPort);
mvSetDriveReady(ialExt,
scsiAdapterExt,
channelIndex, PMPort,
MV_TRUE,
pDriveData->identifyBuffer);
mvSataScsiNotifyUA(scsiAdapterExt, channelIndex, PMPort);
}
}
#endif
else
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d %d]: bad type for the connected device, deviceType = %d\n",
pSataAdapter->adapterId, channelIndex, PMPort, deviceType - MV_SATA_DEVICE_TYPE_UNKNOWN);
mvDrivesInfoFlushSingleDrive(ialExt, channelIndex, PMPort);
}
return MV_TRUE;
}
static MV_BOOLEAN mvPMPortProbeLink(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_U8 PMPort,
MV_BOOLEAN force_speed_gen1,
MV_U32 *SStatus,
MV_BOOLEAN *H2DReceived)
{
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
mvPMDevEnableStaggeredSpinUpPort(pSataAdapter, channelIndex, PMPort,
force_speed_gen1);
/* clear N bit (16) and X bit (26)in serror */
/* some driver expect the host to respond with R_RDY immediatly */
if (mvPMDevWriteReg(pSataAdapter, channelIndex, PMPort,
MV_SATA_PSCR_SERROR_REG_NUM,
MV_BIT26 | MV_BIT18 |MV_BIT16, NULL) ==
MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,
"[%d %d %d]: PM Write SERROR Failed\n",
pSataAdapter->adapterId, channelIndex, PMPort);
}
mvMicroSecondsDelay(pSataAdapter, 50000);
*H2DReceived = mvSataIfD2HReceived(pSataAdapter, channelIndex, PMPort);
/* clear again*/
mvPMDevWriteReg(pSataAdapter, channelIndex, PMPort,
MV_SATA_PSCR_SERROR_REG_NUM,
MV_BIT26| MV_BIT18 |MV_BIT16, NULL);
if (mvPMDevReadReg(pSataAdapter, channelIndex, PMPort,
MV_SATA_PSCR_SSTATUS_REG_NUM, SStatus, NULL) ==
MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d %d]: mvPMDevReadReg Failed\n",
pSataAdapter->adapterId, channelIndex, PMPort);
return MV_FALSE;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO, "[%d %d %d]: S-Status: 0x%x\n",
pSataAdapter->adapterId,
channelIndex, PMPort, *SStatus);
/* clear X bit in serror */
if (mvPMDevWriteReg(pSataAdapter, channelIndex, PMPort,
MV_SATA_PSCR_SERROR_REG_NUM,
MV_BIT26 | MV_BIT18 | MV_BIT16, NULL) ==
MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,
"[%d %d %d]: PM Write SERROR Failed\n",
pSataAdapter->adapterId, channelIndex, PMPort);
}
return MV_TRUE;
}
static MV_BOOLEAN mvPMInitDevicesStateHandler(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
MV_IAL_COMMON_CHANNEL_EXTENSION* channelExt =
&ialExt->IALChannelExt[channelIndex];
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
MV_U8 PMPort = channelExt->devInSRST;
MV_U32 SStatus;
MV_STORAGE_DEVICE_REGISTERS *mvStorageDevRegisters = &channelExt->mvStorageDevRegisters;
MV_BOOLEAN H2DReceived = MV_FALSE;
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d] CHANNEL_PM_INIT_DEVICES port:%d status:%d\n",
ialExt->pSataAdapter->adapterId, channelIndex, PMPort,
channelExt->port_state);
if(channelExt->port_state == MV_PORT_NOT_INITIALIZED)
{
MV_BOOLEAN found_device = MV_FALSE;
MV_U32 retry_count = 0;
MV_BOOLEAN force_speed_gen1 = MV_FALSE;
do {
if(mvPMPortProbeLink(ialExt, channelIndex, PMPort, force_speed_gen1,
&SStatus, &H2DReceived) == MV_FALSE) {
if (mvStorageDevATASoftResetDevice(pSataAdapter, channelIndex,
MV_SATA_PM_CONTROL_PORT, NULL)
== MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,
"[%d %d]:failed to Soft Reset PM control port\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
PMPort++;
if(PMPort == channelExt->PMnumberOfPorts)
break;
else
continue;
}
if ((SStatus & 0xf) == 3) {
if(H2DReceived == MV_TRUE){
channelExt->port_state = MV_PORT_ISSUE_SRST;
}else{
mvSetChannelTimer(ialExt, channelIndex,
MV_IAL_WAIT_FOR_RDY_TIMEOUT);
channelExt->port_state = MV_PORT_WAIT_FOR_RDY;
}
channelExt->devInSRST = PMPort;
found_device = MV_TRUE;
return MV_FALSE;
}
if((SStatus & 0xf) == 1) {
if(retry_count++ < 5) {
/* probe link again
*/
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,
"[%d %d %d]: retry link (%d)\n",
pSataAdapter->adapterId, channelIndex, PMPort,
SStatus & 0xf, retry_count);
if((SStatus & 0xf0) == 0x10)
force_speed_gen1 = MV_TRUE;
continue;
}
}
/* next PORT*/
PMPort++;
if(PMPort == channelExt->PMnumberOfPorts)
{
channelExt->port_state = MV_PORT_DONE;
break;
}
}while(found_device == MV_FALSE);
}else if(channelExt->port_state == MV_PORT_WAIT_FOR_RDY){
mvDecrementChannelTimer(ialExt, channelIndex);
if(mvSataIfD2HReceived(pSataAdapter, channelIndex, PMPort) == MV_FALSE){
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,
"[%d %d %d] - disk not ready: wait a little more\n",
pSataAdapter->adapterId, channelIndex, PMPort);
printAtaDeviceRegisters(mvStorageDevRegisters);
if(mvIsChannelTimerExpired(ialExt, channelIndex) == MV_TRUE){
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,
"[%d %d %d]: PM port signature timed out\n",
pSataAdapter->adapterId, channelIndex, PMPort);
}else{
return MV_TRUE;
}
}else{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO, "[%d %d %d]: "
"device signature received.\n",
pSataAdapter->adapterId, channelIndex, PMPort);
}
channelExt->port_state = MV_PORT_ISSUE_SRST;
channelExt->devInSRST = PMPort;
return MV_FALSE; /* re-call this function without delay*/
}else if(channelExt->port_state == MV_PORT_ISSUE_SRST){
MV_U32 SError;
/* check if disk is connected*/
mvPMDevReadReg(pSataAdapter, channelIndex, PMPort,
MV_SATA_PSCR_SERROR_REG_NUM, &SError, NULL);
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d %d]:SError "
" 0x%08x\n",
pSataAdapter->adapterId, channelIndex, PMPort, SError);
/*check N bit*/
if(SError & MV_BIT16)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO, "[%d %d %d]: "
"link was changed\n",
pSataAdapter->adapterId, channelIndex, PMPort);
if(++channelExt->devInSRST == channelExt->PMnumberOfPorts)
{
channelExt->port_state = MV_PORT_DONE;
}else{
channelExt->port_state = MV_PORT_NOT_INITIALIZED;
}
return MV_TRUE;
}
if (mvStorageDevATAStartSoftResetDevice(pSataAdapter,
channelIndex,
PMPort) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d %d]: "
"failed to Soft Reset PM device port.\n",
pSataAdapter->adapterId, channelIndex, PMPort);
/* this port not functional, next port*/
channelExt->port_state = MV_PORT_NOT_INITIALIZED;
channelExt->devInSRST++;
}
else
{
mvSetChannelTimer(ialExt, channelIndex, MV_IAL_SRST_TIMEOUT);
channelExt->port_state = MV_PORT_IN_SRST;
channelExt->devInSRST = PMPort;
return MV_TRUE;
}
}else if(channelExt->port_state == MV_PORT_IN_SRST){
mvDecrementChannelTimer(ialExt, channelIndex);
if (mvStorageIsDeviceBsyBitOff(pSataAdapter,
channelIndex,
mvStorageDevRegisters) == MV_FALSE)
{
if (mvIsChannelTimerExpired(ialExt, channelIndex) !=
MV_TRUE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d %d] - disk not ready: wait a "
"little more\n",
pSataAdapter->adapterId,
channelIndex, PMPort);
printAtaDeviceRegisters(mvStorageDevRegisters);
return MV_TRUE;
}
/* SRST timeout*/
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d %d]: Soft Reset PM port time out\n",
pSataAdapter->adapterId, channelIndex, PMPort);
if (mvStorageDevATASoftResetDevice(pSataAdapter, channelIndex,
MV_SATA_PM_CONTROL_PORT, NULL) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR, "[%d %d]: "
"failed to Soft Reset PM control port\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
if(++channelExt->devInSRST == channelExt->PMnumberOfPorts)
{
channelExt->port_state = MV_PORT_DONE;
}else{
channelExt->port_state = MV_PORT_NOT_INITIALIZED;
return MV_TRUE;
}
}
/* SRST completed*/
channelExt->port_state = MV_PORT_INIT_DEVICE;
return MV_TRUE;
}else if(channelExt->port_state == MV_PORT_INIT_DEVICE){
MV_U32 SError;
/* check if disk is connected*/
mvPMDevReadReg(pSataAdapter, channelIndex, PMPort,
MV_SATA_PSCR_SERROR_REG_NUM, &SError, NULL);
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG, "[%d %d %d]:SError "
" 0x%08x\n",
pSataAdapter->adapterId, channelIndex, PMPort, SError);
/*check N bit*/
if(SError & MV_BIT16)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO, "[%d %d %d]: "
"link was changed\n",
pSataAdapter->adapterId, channelIndex, PMPort);
} else {
classifyAndInitDevice(scsiAdapterExt, ialExt,
channelIndex, PMPort);
}
/* next port*/
if(++channelExt->devInSRST == channelExt->PMnumberOfPorts)
{
channelExt->port_state = MV_PORT_DONE;
}else{
channelExt->port_state = MV_PORT_NOT_INITIALIZED;
return MV_TRUE;
}
}
if(channelExt->port_state == MV_PORT_DONE) {
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_INFO,"[%d %d]: PM devices initialized\n", pSataAdapter->adapterId,
channelIndex, PMPort, channelExt->port_state);
#if 0
if (clearSErrorPorts(ialExt->pSataAdapter, channelIndex,
ialExt->IALChannelExt[channelIndex].PMnumberOfPorts) !=
MV_TRUE)
{
return MV_FALSE;
}
#endif
#if 1
if (mvPMEnableCommStatusChangeBits(ialExt,
channelIndex,
MV_TRUE) != MV_TRUE)
{
return MV_FALSE;
}
if (mvPMEnableAsyncNotify(ialExt, channelIndex) == MV_FALSE)
{
return MV_FALSE;
}
#endif
if (mvConfigChannelDMA(ialExt,
channelIndex,
scsiAdapterExt) == MV_TRUE)
{
mvSetChannelState(ialExt, channelIndex, CHANNEL_READY);
}
else
{
mvStopChannel(ialExt, channelIndex, scsiAdapterExt);
}
}else if(channelExt->port_state == MV_PORT_FAILED){
mvStopChannel(ialExt, channelIndex, scsiAdapterExt);
}else {
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_FATAL_ERROR,"[%d %d %d] - unknown port"
" status: %d\n", pSataAdapter->adapterId,
channelIndex, PMPort, channelExt->port_state);
}
return MV_TRUE;
}
static MV_BOOLEAN mvChannelReadyStateHandler(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex)
{
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
if ((ialExt->IALChannelExt[channelIndex].pmRegAccessInProgress == MV_FALSE) &&
(mvStorageDevGetDeviceType (pSataAdapter, channelIndex) == MV_SATA_DEVICE_TYPE_PM) &&
(ialExt->IALChannelExt[channelIndex].pmAsyncNotifyEnabled == MV_FALSE))
{
/*poll pm GSCR error register one time of 4 steps (2 seconds)*/
if (ialExt->IALChannelExt[channelIndex].pmRegPollCounter++ & 0x3)
{
return MV_TRUE;
}
if (mvQueuePMAccessRegisterCommand(ialExt,
channelIndex,
MV_SATA_PM_CONTROL_PORT,
MV_SATA_GSCR_ERROR_REG_NUM,
0,
MV_TRUE) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d] error reading "
" PM GSCR_ERROR register.\n",
pSataAdapter->adapterId, channelIndex);
}
}
mvSata60X1B2CheckDevError(pSataAdapter, channelIndex);
return MV_TRUE;
}
static MV_BOOLEAN mvChannelPMHotPlugStateHandler(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d %d] CHANNEL_PM_HOT_PLUG\n",
ialExt->pSataAdapter->adapterId, channelIndex);
mvSataDisableChannelDma(ialExt->pSataAdapter, channelIndex);
mvSataFlushDmaQueue (ialExt->pSataAdapter,
channelIndex, MV_FLUSH_TYPE_CALLBACK);
mvSataChannelHardReset(ialExt->pSataAdapter, channelIndex);
mvRestartChannel(ialExt, channelIndex, scsiAdapterExt, MV_FALSE);
return MV_TRUE;
}
static MV_BOOLEAN mvChannelStateMachine(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_U8 channelIndex,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
MV_BOOLEAN res = MV_FALSE;
do
{
switch (ialExt->channelState[channelIndex])
{
case CHANNEL_NOT_CONNECTED:
res = mvChannelNotConnectedStateHandler(ialExt,
channelIndex,
scsiAdapterExt);
break;
case CHANNEL_CONNECTED:
res = mvChannelConnectedStateHandler(ialExt,
channelIndex,
scsiAdapterExt);
break;
case CHANNEL_IN_SRST:
res = mvChannelInSrstStateHandler(ialExt,
channelIndex,
scsiAdapterExt);
break;
case CHANNEL_PM_INIT_DEVICES:
res = mvPMInitDevicesStateHandler(ialExt,
channelIndex,
scsiAdapterExt);
break;
case CHANNEL_READY:
res = mvChannelReadyStateHandler(ialExt,
channelIndex);
break;
case CHANNEL_PM_HOT_PLUG:
res = mvChannelPMHotPlugStateHandler(ialExt,
channelIndex,
scsiAdapterExt);
break;
default:
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d]: Unknown channel state.\n",
ialExt->pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
} while (res == MV_FALSE);
return MV_TRUE;
}
static MV_BOOLEAN mvAdapterStateMachine(
MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_SAL_ADAPTER_EXTENSION *scsiAdapterExt)
{
MV_BOOLEAN res = MV_TRUE;
MV_U8 channelIndex;
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
switch (ialExt->adapterState)
{
case ADAPTER_INITIALIZING: {
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d] ADAPTER_INITIALIZING\n",
pSataAdapter->adapterId);
res = mvSataEnableStaggeredSpinUpAll(pSataAdapter);
if (res == MV_TRUE)
{
if (mvSataUnmaskAdapterInterrupt(pSataAdapter) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d]: "
"mvSataUnmaskAdapterInterrupt failed\n",
pSataAdapter->adapterId);
ialExt->adapterState = ADAPTER_FATAL_ERROR;
return MV_FALSE;
}
ialExt->adapterState = ADAPTER_READY;
}
}
break;
case ADAPTER_READY:
for (channelIndex = 0;
channelIndex < pSataAdapter->numberOfChannels; channelIndex++)
{
mvChannelStateMachine(ialExt,
channelIndex,
scsiAdapterExt);
}
return MV_TRUE;
break;
default:
break;
}
if (ialExt->adapterState != ADAPTER_READY)
{
return res;
}
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG,"[%d] ADAPTER_READY\n",
pSataAdapter->adapterId);
/*Start channel initialization for connected channels*/
for (channelIndex = 0;
channelIndex < pSataAdapter->numberOfChannels;
channelIndex++)
{
mvFlushSCSICommandQueue(ialExt, channelIndex);
if (mvSataIsStorageDeviceConnected(pSataAdapter, channelIndex, NULL) ==
MV_FALSE)
{
mvSetChannelState(ialExt,
channelIndex,
CHANNEL_NOT_CONNECTED);
continue;
}
mvSetChannelState(ialExt,
channelIndex,
CHANNEL_CONNECTED);
if (mvChannelStateMachine(ialExt,
channelIndex,
scsiAdapterExt) == MV_FALSE)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_ERROR,"[%d %d]: Failed to "
"start channel.\n", pSataAdapter->adapterId, channelIndex);
mvSetChannelState(ialExt,
channelIndex,
CHANNEL_NOT_CONNECTED);
mvFlushSCSICommandQueue(ialExt, channelIndex);
mvSataRemoveChannel(pSataAdapter,channelIndex);
IALReleaseChannel(pSataAdapter, channelIndex);
pSataAdapter->sataChannel[channelIndex] = NULL;
mvDrivesInfoFlushAll(ialExt, channelIndex);
mvSetDriveReady(ialExt,
scsiAdapterExt,
channelIndex,
0xFF, MV_FALSE, NULL);
continue;
}
}
return res;
}
static MV_BOOLEAN mvGetDisksModes(MV_IAL_COMMON_ADAPTER_EXTENSION *ialExt,
MV_SAL_ADAPTER_EXTENSION *pScsiAdapterExt,
MV_U8 channelIndex,
MV_BOOLEAN *TCQ,
MV_BOOLEAN *NCQ,
MV_U8 *numOfDrives)
{
MV_SATA_ADAPTER *pSataAdapter = ialExt->pSataAdapter;
MV_BOOLEAN allNCQ = MV_TRUE;
MV_BOOLEAN allTCQ = MV_TRUE;
MV_U8 i;
if ((pSataAdapter == NULL) || (pScsiAdapterExt == NULL))
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_FATAL_ERROR,"[%d %d]"
" mvGetDisksModes failed, bad pointer\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
if ((ialExt->adapterState != ADAPTER_READY) ||
(ialExt->channelState[channelIndex] == CHANNEL_NOT_CONNECTED))
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_FATAL_ERROR,"[%d %d] "
"mvGetDisksModes failed,Bad Adapter or Channel State\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
if (pSataAdapter->sataChannel[channelIndex] == NULL)
{
mvLogMsg(MV_IAL_COMMON_LOG_ID, MV_DEBUG_FATAL_ERROR,"[%d %d] "
"mvGetDisksModes failed, channel not configured\n",
pSataAdapter->adapterId, channelIndex);
return MV_FALSE;
}
*numOfDrives = 0;
for (i = 0; i < MV_SATA_PM_MAX_PORTS; i++)
{
if ((pScsiAdapterExt->
ataDriveData[channelIndex][i].driveReady == MV_TRUE) &&
(pScsiAdapterExt->ataDriveData[channelIndex][i].identifyInfo.deviceType == MV_SATA_DEVICE_TYPE_ATA_DISK))
{
(*numOfDrives)++;
if (pScsiAdapterExt->ataDriveData[channelIndex][i].
identifyInfo.DMAQueuedModeSupported == MV_FALSE)
{
allTCQ = MV_FALSE;
}
if (pScsiAdapterExt->
ataDriveData[channelIndex][i].identifyInfo.
SATACapabilities.NCQSupported == MV_FALSE)
{
allNCQ = MV_FALSE;
}
}
}
if (TCQ)
{
if ((*numOfDrives > 0) && (allTCQ == MV_TRUE))
{
*TCQ = MV_TRUE;
}
else
{
*TCQ = MV_FALSE;
}
}
if (NCQ)
{
if ((*numOfDrives > 0) && (allNCQ == MV_TRUE))
{
*NCQ = MV_TRUE;
}
else
{
*NCQ = MV_FALSE;
}
}
return MV_TRUE;
}