blob: a1782478ff91ab9e19df1703301d60cd99a85d3c [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.
*******************************************************************************/
/*******************************************************************************
* mvScsiAtaLayer.c
*
* DESCRIPTION:
* C implementation for SCSI to ATA translation layer.
*
* DEPENDENCIES:
* mvIALCommon.h
* mvScsiAtaLayer.h
*
*******************************************************************************/
/* includes */
#include "mvScsiAtaLayer.h"
#include "mvIALCommon.h"
#ifdef MV_LOGGER
#define SAL_SPRINTF sprintf
#endif
/* ATA defines */
/* Bits for HD_ERROR */
#define NM_ERR 0x02 /* media present */
#define ABRT_ERR 0x04 /* Command aborted */
#define MCR_ERR 0x08 /* media change request */
#define IDNF_ERR 0x10 /* ID field not found */
#define MC_ERR 0x20 /* media changed */
#define UNC_ERR 0x40 /* Uncorrect data */
#define WP_ERR 0x40 /* write protect */
#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */
#ifdef MV_LOGGER
static MV_VOID reportScbCompletion(MV_SATA_ADAPTER* pSataAdapter,
MV_SATA_SCSI_CMD_BLOCK *pScb);
#endif
/* Locals */
static MV_VOID mvAta2HostString(IN MV_U16 *source,
OUT MV_U16 *target,
IN MV_U32 wordsCount);
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaGetInquiryData(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaTestUnitReady(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaSendDataCommand(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaGetReadCapacityData(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaReportLuns(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaSendVerifyCommand(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaReassignBlocks(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaSendSyncCacheCommand(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaGetRequestSenseData(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaGetModeSenseData(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_BOOLEAN mvScsiAtaGetModeSenseDataPhase2(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaModeSelect(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_U8 modeSelect(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_SCSI_COMMAND_STATUS_TYPE *pCommandStatus);
static MV_U8 mvParseModeCachingPage(MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_U8 *buffer,
MV_SCSI_COMMAND_STATUS_TYPE *pCommandStatus);
static MV_U32 mvModeSenseCachingPage(MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_U8 *buffer, MV_U8 pageControl);
static MV_U32 mvModeSenseControlPage(MV_SATA_ADAPTER *pSataAdapter,
MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_U8 *buffer, MV_U8 pageControl);
static MV_BOOLEAN SALCommandCompletionCB(MV_SATA_ADAPTER *pSataAdapter,
MV_U8 channelNum,
MV_COMPLETION_TYPE comp_type,
MV_VOID_PTR commandId,
MV_U16 responseFlags,
MV_U32 timeStamp,
MV_STORAGE_DEVICE_REGISTERS *registerStruct);
MV_VOID setSenseData(IN MV_SATA_SCSI_CMD_BLOCK *pScb, IN MV_U8 SenseKey,
IN MV_U8 AdditionalSenseCode, IN MV_U8 ASCQ);
MV_VOID _fillSenseInformation(IN MV_SATA_SCSI_CMD_BLOCK *pScb, MV_SCSI_SENSE_DATA *SenseData,
MV_STORAGE_DEVICE_REGISTERS *registerStruct);
MV_VOID handleNoneUdmaError(MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_STORAGE_DEVICE_REGISTERS *registerStruct);
static MV_VOID handleUdmaError(MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_U32 responseFlags,
MV_STORAGE_DEVICE_REGISTERS *registerStruct);
/*static*/ MV_VOID checkQueueCommandResult(MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_QUEUE_COMMAND_RESULT result);
static MV_VOID mvScsiAtaSendSplittedVerifyCommand(IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_VOID mvScsiAtaSendReadLookAhead(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb);
static MV_VOID mvAta2HostString(IN MV_U16 *source,
OUT MV_U16 *target,
IN MV_U32 wordsCount
)
{
MV_U32 i;
for (i=0 ; i < wordsCount; i++)
{
target[i] = (source[i] >> 8) | ((source[i] & 0xff) << 8);
target[i] = MV_LE16_TO_CPU(target[i]);
}
}
MV_VOID setSenseData(IN MV_SATA_SCSI_CMD_BLOCK *pScb, IN MV_U8 SenseKey,
IN MV_U8 AdditionalSenseCode, IN MV_U8 ASCQ)
{
MV_SCSI_SENSE_DATA SenseData;
if (pScb->senseBufferLength == 0)
{
pScb->senseDataLength = 0;
return;
}
memset(&SenseData, 0, sizeof(MV_SCSI_SENSE_DATA));
// SenseData.Valid = 0;
SenseData.ResponseCode = MV_SCSI_RESPONSE_CODE;
SenseData.SenseKey = SenseKey;
SenseData.AdditionalSenseCode = AdditionalSenseCode;
SenseData.AdditionalSenseCodeQualifier = ASCQ;
SenseData.AdditionalSenseLength = sizeof(MV_SCSI_SENSE_DATA) - 8;
pScb->senseDataLength = sizeof(MV_SCSI_SENSE_DATA);
if (pScb->senseBufferLength < pScb->senseDataLength)
{
pScb->senseDataLength = pScb->senseBufferLength;
}
memcpy(pScb->pSenseBuffer, &SenseData, pScb->senseDataLength);
}
MV_VOID _fillSenseInformation(IN MV_SATA_SCSI_CMD_BLOCK *pScb, MV_SCSI_SENSE_DATA *SenseData,
MV_STORAGE_DEVICE_REGISTERS *registerStruct)
{
if (pScb->isExtended == MV_TRUE)
{
/* LBA 48 error handling */
SenseData->InformationDesc.information[2] = (MV_U8)((registerStruct->lbaHighRegister >> 8) & 0xff);
SenseData->InformationDesc.information[3] = (MV_U8)((registerStruct->lbaMidRegister >> 8) & 0xff);
SenseData->InformationDesc.information[4] = (MV_U8)((registerStruct->lbaLowRegister >> 8) & 0xff);
}
else
{
/* LBA 28 error handling */
SenseData->InformationDesc.information[4] = (MV_U8)((registerStruct->deviceRegister) & 0x0f);
}
SenseData->InformationDesc.information[5] = (MV_U8)(registerStruct->lbaHighRegister & 0xff);
SenseData->InformationDesc.information[6] = (MV_U8)(registerStruct->lbaMidRegister & 0xff);
SenseData->InformationDesc.information[7] = (MV_U8)(registerStruct->lbaLowRegister & 0xff);
}
/*
* setPassThruSense - Set SCSI PassThru sense block.
*
* This function is specific to the ATA passthru command.
* Regardless of whether the command issue or not, fill the sense
* buffer with the ATA descriptor return.
*/
static MV_VOID setPassThruSense(MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_STORAGE_DEVICE_REGISTERS *registerStruct)
{
MV_SCSI_SENSE_DATA *sb = (MV_SCSI_SENSE_DATA *) pScb->pSenseBuffer;
MV_U8 *desc;
/* Some sanity checks */
if (unlikely(!pScb->pSenseBuffer ||
(pScb->senseBufferLength < sizeof(MV_SCSI_SENSE_DATA))))
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR,
"Can't set ATA pass through sense: invalid buffer\n");
return;
}
memset(sb, 0, sizeof(MV_SCSI_SENSE_DATA));
desc = (MV_U8 *) &sb->InformationDesc;
sb->ResponseCode = MV_SCSI_RESPONSE_CODE;
/* CK_COND bit it on, need to return indication to application */
if (pScb->ScsiCdb[2] & MV_BIT5)
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
/*
* TODO: Check registerStruct->errorRegister and fill the sense
* buffer accordingly.
*/
pScb->senseDataLength = 22;
/* Set length of additional sense data */
sb->AdditionalSenseLength = 14;
/*
* Copy registers into the additional sense buffer.
* This buffer should map the ATA descriptor return.
*/
desc[0] = 0x09;
desc[1] = 12; /* Additional length */
desc[2] = 0x00;
desc[3] = registerStruct->errorRegister;
desc[5] = (MV_U8)(registerStruct->sectorCountRegister);
desc[7] = (MV_U8)(registerStruct->lbaLowRegister);
desc[9] = (MV_U8)(registerStruct->lbaMidRegister);
desc[11] = (MV_U8)(registerStruct->lbaHighRegister);
desc[12] = registerStruct->deviceRegister;
desc[13] = registerStruct->statusRegister;
/* LBA 48 error handling */
if (pScb->isExtended == MV_TRUE)
{
desc[2] |= 0x01; /* Extended ATA descriptor return bit */
desc[4] = (MV_U8)(registerStruct->sectorCountRegister >> 8);
desc[6] = (MV_U8)(registerStruct->lbaLowRegister >> 8);
desc[8] = (MV_U8)(registerStruct->lbaMidRegister >> 8);
desc[10] = (MV_U8)(registerStruct->lbaHighRegister >> 8);
}
}
static MV_BOOLEAN checkLBAOutOfRange(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb,
IN MV_U64 ATADiskSize, IN MV_U64 LBA,
IN MV_U32 sectors)
{
if ((ATADiskSize <= LBA) || ((ATADiskSize - LBA) < sectors) || sectors > 0xFFFF)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Error LBA out of range. DiskSize %x sectors %x LBA %x\n"
, ATADiskSize, sectors, LBA);
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_ADSENSE_ILLEGAL_BLOCK, 0);
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCSI_COMMAND;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_TRUE;
}
return MV_FALSE;
}
/*******************************************************************************
* mvScsiAtaGetInquiryData - Get the SCSI-3 standard inquiry(12h) data
*
* DESCRIPTION: This function fills the data buffer with Scsi standard inquiry
* data according to the ATA Identify data
*
* INPUT:
* pSataAdapter - pointer to the SATA adapter data structure.
* pScb->bus - the index of the specific SATA channel.
* pScb - pointer to the Scsi command block.
*
* RETURN:
* MV_TRUE on success, MV_FALSE on failure.
*
* COMMENTS:
* No sanity check is done for the parameters.
*
*******************************************************************************/
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaGetInquiryData(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_U8 buff[42];
MV_U32 inquiryLen;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
memset(buff, 0, 42);
if ((pScb->ScsiCdb[1] & (MV_BIT0 | MV_BIT1)) ||
(pScb->ScsiCdb[2]))
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%d %d: Inquiry completed with error: cmd[1] %x cmd[2] %x\n",
pSataAdapter->adapterId, pScb->bus, pScb->ScsiCdb[1],
pScb->ScsiCdb[2]);
if (pDriveData->UAConditionPending == MV_TRUE)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Unit Attention condition is pending.\n");
if (pDriveData->UAEvents & MV_BIT0)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Report Bus Reset.\n");
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_UA_RESET;
setSenseData(pScb, SCSI_SENSE_UNIT_ATTENTION, SCSI_ADSENSE_BUS_RESET
, 2);
pDriveData->UAEvents &= ~MV_BIT0;
}
else if (pDriveData->UAEvents & MV_BIT1)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Report Mode Parameters Changed.\n");
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_UA_PARAMS_CHANGED;
setSenseData(pScb, SCSI_SENSE_UNIT_ATTENTION,
SCSI_ADSENSE_PARAMETERS_CHANGED, 1);
pDriveData->UAEvents &= ~MV_BIT1;
}
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
if (pDriveData->UAEvents == 0)
{
pDriveData->UAConditionPending = MV_FALSE;
}
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_INVALID_CDB,
0);
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCSI_COMMAND;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
if (pScb->lun)
{
buff[0] = 0x7f;
inquiryLen = 5;
}
else
{
MV_U8 Vendor[9],Product[17], temp[24];
buff[0] = MV_SCSI_DIRECT_ACCESS_DEVICE;
buff[1] = 0; /* Not Removable disk */
buff[2] = 5; /*claim conformance to SCSI-3*/
buff[3] = 2; /* set RESPONSE DATA FORMAT to 2*/
buff[4] = 41 - 4; /* n - 4, n start from 0 */
#if 0
buff[6] = 0x80; /* basic queuing*/
buff[7] = 0;
#else
buff[6] = 0x0; /* tagged queuing*/
buff[7] = 2;
#endif
memcpy(temp, pDriveData->identifyInfo.model, 24);
mvAta2HostString((MV_U16 *)temp, (MV_U16 *)(temp), 12);
{
MV_U32 i;
for (i = 0; i < 9; i++)
{
if (temp[i] == ' ')
{
break;
}
}
if (i == 9)
{
if (((temp[0] == 'I') && (temp[1] == 'C')) ||
((temp[0] == 'H') && (temp[1] == 'T')) ||
((temp[0] == 'H') && (temp[1] == 'D')) ||
((temp[0] == 'D') && (temp[1] == 'K')))
{ /*Hitachi*/
Vendor[0] = 'H';
Vendor[1] = 'i';
Vendor[2] = 't';
Vendor[3] = 'a';
Vendor[4] = 'c';
Vendor[5] = 'h';
Vendor[6] = 'i';
Vendor[7] = ' ';
Vendor[8] = '\0';
}
else if ((temp[0] == 'S') && (temp[1] == 'T'))
{
/*Seagate*/
Vendor[0] = 'S';
Vendor[1] = 'e';
Vendor[2] = 'a';
Vendor[3] = 'g';
Vendor[4] = 'a';
Vendor[5] = 't';
Vendor[6] = 'e';
Vendor[7] = ' ';
Vendor[8] = '\0';
}
else
{
/*Unkown*/
Vendor[0] = 'A';
Vendor[1] = 'T';
Vendor[2] = 'A';
Vendor[3] = ' ';
Vendor[4] = ' ';
Vendor[5] = ' ';
Vendor[6] = ' ';
Vendor[7] = ' ';
Vendor[8] = '\0';
}
memcpy(Product, temp, 16);
Product[16] = '\0';
}
else
{
MV_U32 j = i;
memcpy(Vendor, temp, j);
for (; j < 9; j++)
{
Vendor[j] = ' ';
}
Vendor[8] = '\0';
for (; i < 24; i++)
{
if (temp[i] != ' ')
{
break;
}
}
memcpy(Product, &temp[i], 24 - i);
Product[16] = '\0';
}
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Vendor %s Product %s\n", Vendor, Product);
memcpy(&buff[8], Vendor, 8);
memcpy(&buff[16], Product, 16);
memcpy(&buff[32], pDriveData->identifyInfo.firmware, 4);
mvAta2HostString((MV_U16 *)(&buff[32]), (MV_U16 *)(&buff[32]), 2);
}
memcpy(&buff[36], "MVSATA", 6);
/*buff[32] = '3';*/
inquiryLen = 42;
}
if (pScb->dataBufferLength > inquiryLen)
{
memcpy(pScb->pDataBuffer, buff, inquiryLen);
pScb->dataTransfered = inquiryLen;
}
else
{
memcpy(pScb->pDataBuffer, buff, pScb->dataBufferLength);
pScb->dataTransfered = pScb->dataBufferLength;
}
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
pScb->senseDataLength = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaTestUnitReady(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
pScb->senseDataLength = 0;
pScb->dataTransfered = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaSendDataCommand(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_U8 *cmd = pScb->ScsiCdb;
MV_QUEUE_COMMAND_RESULT result;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
MV_SAL_ADAPTER_EXTENSION *pAdapterExt = pScb->pSalAdapterExtension;
MV_U32 sectors;
MV_U64 LBA;
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
MV_UDMA_COMMAND_PARAMS *pUdmaParams = &pCommandInfo->commandParams.udmaCommand;
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_UDMA;
pCommandInfo->PMPort = pScb->target;
pUdmaParams->readWrite = MV_UDMA_TYPE_WRITE;
pUdmaParams->isEXT = MV_FALSE;
pUdmaParams->FUA = MV_FALSE;
pUdmaParams->highLBAAddress = 0;
pUdmaParams->callBack = SALCommandCompletionCB;
pUdmaParams->commandId = (MV_VOID_PTR )pScb;
#ifdef MV_SATA_SUPPORT_EDMA_SINGLE_DATA_REGION
pUdmaParams->singleDataRegion = pScb->singleDataRegion;
pUdmaParams->byteCount = pScb->byteCount;
#endif
#else
MV_QUEUE_COMMAND_INFO commandInfo =
{
MV_QUEUED_COMMAND_TYPE_UDMA,
pScb->target,
{
{
MV_UDMA_TYPE_WRITE, MV_FALSE, MV_FALSE, 0, 0, 0, 0, 0,
#ifdef MV_SATA_SUPPORT_EDMA_SINGLE_DATA_REGION
pScb->singleDataRegion,
pScb->byteCount,
#endif
SALCommandCompletionCB, (MV_VOID_PTR )pScb
}
}
};
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
MV_UDMA_COMMAND_PARAMS *pUdmaParams = &pCommandInfo->commandParams.udmaCommand;
#endif
if ((cmd[0] == SCSI_OPCODE_READ6) || (cmd[0] == SCSI_OPCODE_WRITE6))
{
pUdmaParams->lowLBAAddress =
( (MV_U32) cmd[3]) |
(((MV_U32) cmd[2]) << 8) |
((((MV_U32) cmd[1]) & 0x1f) << 16);
sectors = (MV_U16) cmd[4];
}
else if ((cmd[0] == SCSI_OPCODE_READ10) || (cmd[0] == SCSI_OPCODE_WRITE10))
{
pUdmaParams->lowLBAAddress =
(((MV_U32) cmd[5]) << 0) |
(((MV_U32) cmd[4]) << 8) |
(((MV_U32) cmd[3]) << 16) |
(((MV_U32) cmd[2]) << 24);
sectors = ((MV_U16) cmd[8]) |
(((MV_U16) cmd[7]) << 8);
if (cmd[1] & MV_BIT3)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%d %d: READ10/WRITE10 command "
"received with FUA\n",
pSataAdapter->adapterId, pScb->bus);
pUdmaParams->FUA = MV_TRUE;
}
}
else
{
pUdmaParams->lowLBAAddress =
(((MV_U32) cmd[9]) << 0) |
(((MV_U32) cmd[8]) << 8) |
(((MV_U32) cmd[7]) << 16) |
(((MV_U32) cmd[6]) << 24);
pUdmaParams->highLBAAddress =
(((MV_U32) cmd[5]) << 0) |
(((MV_U32) cmd[4]) << 8) |
(((MV_U32) cmd[3]) << 16) |
(((MV_U32) cmd[2]) << 24);
sectors = (cmd[13]) |
(cmd[12] << 8) |
(cmd[11] << 16) |
(cmd[10] << 24);
if (cmd[1] & MV_BIT3)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%d %d: READ16/WRITE16 command "
"received with FUA\n",
pSataAdapter->adapterId, pScb->bus);
pUdmaParams->FUA = MV_TRUE;
}
}
LBA = ((MV_U64)pUdmaParams->highLBAAddress << 32) | (MV_U64)pUdmaParams->lowLBAAddress;
pScb->isExtended = pUdmaParams->isEXT = pDriveData->identifyInfo.LBA48Supported;
/* If READ10 / WRITE10 with 0 sectors (no data transfer), then complete */
/* the command with OK. */
/* If READ6 / WRITE6 with 0 sectors, seemse the Windows have problem with */
/* this and doesn't allocate and buffers for this ; so complete this */
/* command with ILLEGAL REQUEST sense and INVLAID CDB in addition sense */
/* code. */
if (sectors == 0)
{
if ((cmd[0] == SCSI_OPCODE_READ10) || (cmd[0] == SCSI_OPCODE_WRITE10) ||
(cmd[0] == SCSI_OPCODE_READ16) || (cmd[0] == SCSI_OPCODE_WRITE16))
{
if (checkLBAOutOfRange(pSataAdapter, pScb,
pDriveData->identifyInfo.ATADiskSize,
LBA, 0) == MV_TRUE)
{
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
else
{
/* READ6 / WRITE6 with sector count 0, which means 256 sectors */
sectors = 256;
}
}
if (checkLBAOutOfRange(pSataAdapter, pScb,
pDriveData->identifyInfo.ATADiskSize,
LBA, sectors) == MV_TRUE)
{
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/* If trying to send more than 256 sectors or DataTransferLength field is
* not equal to number of sectors request in CDB then return invalid
* request.
*/
if (((sectors > 256) && (pUdmaParams->isEXT == MV_FALSE)) ||
((sectors * ATA_SECTOR_SIZE) != pScb->dataBufferLength))
{
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCB;
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
if ((cmd[0] == SCSI_OPCODE_READ6) || (cmd[0] == SCSI_OPCODE_READ10) ||
(cmd[0] == SCSI_OPCODE_READ16))
{
pUdmaParams->readWrite = MV_UDMA_TYPE_READ;
}
pScb->dataTransfered = sectors * ATA_SECTOR_SIZE;
pScb->udmaType = pUdmaParams->readWrite;
pScb->commandType = MV_QUEUED_COMMAND_TYPE_UDMA;
pScb->LowLbaAddress = pUdmaParams->lowLBAAddress;
pUdmaParams->numOfSectors = sectors;
if ((sectors == 256) &&
((pDriveData->identifyInfo.LBA48Supported == MV_FALSE)))
{
pUdmaParams->numOfSectors = 0;
}
pUdmaParams->prdLowAddr = pScb->PRDTableLowPhyAddress;
pUdmaParams->prdHighAddr = pScb->PRDTableHighPhyAddress;
result = mvSataQueueCommand(pSataAdapter, pScb->bus, pCommandInfo);
if (result != MV_QUEUE_COMMAND_RESULT_OK)
{
checkQueueCommandResult(pScb, result);
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/*update statistics*/
pAdapterExt->totalAccumulatedOutstanding[pScb->bus] +=
mvSataNumOfDmaCommands(pSataAdapter,pScb->bus);
pDriveData->stats.totalIOs++;
pDriveData->stats.totalSectorsTransferred += pUdmaParams->numOfSectors;
return MV_SCSI_COMMAND_STATUS_QUEUED;
}
/*******************************************************************************
* mvScsiAtaStartStopCommand - Translate SCSI START_STOP UNIT command
*
* DESCRIPTION:Enqueue an ATA command to issue STANDBY (to stop) or READ VERIFY
* (to start). Perhaps these commands should be preceded by
* CHECK POWER MODE to see what power mode the device is already in.
* [See SAT revision 5 at www.t10.org]
*
* INPUT:
* pSataAdapter - pointer to the SATA adapter data structure.
* pScb - SCSI command block structure.
*
* RETURNS:
* MV_SCSI_COMMAND_STATUS_COMPLETED or MV_SCSI_COMMAND_STATUS_QUEUED.
*******************************************************************************/
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaStartStopCommand(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo;
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
#endif
MV_QUEUE_COMMAND_RESULT result;
MV_U8 *cdb = pScb->ScsiCdb;
MV_U32 sectors = 0;
MV_U8 command;
if (pScb->ScsiCdbLength < 5)
{
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCB;
goto error;
}
/* FIXME : Don't know how to handle Immed flag. */
if (cdb[1] & 0x1) {
;
}
if (cdb[4] & 0x2) /* LOEJ bit set not supported */
{
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCB;
goto error;
}
if (((cdb[4] >> 6) & 0xf) != 0)
{
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCB;
goto error;
}
if (cdb[4] & 0x1) /* START UNIT command */
{
sectors = 1;
command = MV_ATA_COMMAND_READ_VERIFY_SECTORS;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG,
"Sending VERIFY command (emulate SCSI START UNIT): channel %d, Srb %p\n", pScb->bus, pScb);
}
else /* STOP UNIT command */
{
command = MV_ATA_COMMAND_STANDBY_IMMEDIATE;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG,
"Sending STANDBY_IMMEDIATE command (emulate SCSI STOP UNIT): channel %d, Srb %p\n", pScb->bus, pScb);
}
memset(pCommandInfo, 0, sizeof(MV_QUEUE_COMMAND_INFO));
pScb->commandType = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->PMPort = pScb->target;
pCommandInfo->commandParams.NoneUdmaCommand.protocolType = MV_NON_UDMA_PROTOCOL_NON_DATA;
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_FALSE;
pCommandInfo->commandParams.NoneUdmaCommand.bufPtr = NULL;
pCommandInfo->commandParams.NoneUdmaCommand.count = 0;
pCommandInfo->commandParams.NoneUdmaCommand.features = 0;
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = sectors;
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh = 0;
pCommandInfo->commandParams.NoneUdmaCommand.device = (MV_U8)(MV_BIT6);
pCommandInfo->commandParams.NoneUdmaCommand.command = command;
pCommandInfo->commandParams.NoneUdmaCommand.callBack = SALCommandCompletionCB;
pCommandInfo->commandParams.NoneUdmaCommand.commandId = (MV_VOID_PTR) pScb;
result = mvSataQueueCommand(pSataAdapter, pScb->bus, pCommandInfo);
if (result == MV_QUEUE_COMMAND_RESULT_OK)
return MV_SCSI_COMMAND_STATUS_QUEUED;
else
checkQueueCommandResult(pScb, result);
error:
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
static inline MV_NON_UDMA_PROTOCOL mvScsiAtaPassThru_MapProto(MV_U8 byte)
{
switch((byte & 0x1e) >> 1)
{
case 3: /* Non-data */
return MV_NON_UDMA_PROTOCOL_NON_DATA;
case 4: /* PIO Data-in */
case 10: /* UDMA Data-in */
return MV_NON_UDMA_PROTOCOL_PIO_DATA_IN;
case 5: /* PIO Data-out */
case 11: /* UDMA Data-Out */
return MV_NON_UDMA_PROTOCOL_PIO_DATA_OUT;
case 0: /* Hard Reset */
case 1: /* SRST */
case 6: /* DMA */
case 8: /* Device Diagnostic */
case 9: /* Device Reset */
case 7: /* DMA Queued */
case 12: /* FPDMA */
case 15: /* Return Response Info */
default: /* Reserved */
break;
}
return MV_NON_UDMA_PROTOCOL_UNKNOWN;
}
/*
* mvScsiAtaPassThru - Enqueue an ATA pass-thru command
*
* INPUT:
* pSataAdapter - pointer to the SATA adapter data structure.
* pScb - SCSI command block structure.
*
* RETURNS:
* MV_SCSI_COMMAND_STATUS_COMPLETED or MV_SCSI_COMMAND_STATUS_QUEUED.
*/
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaPassThru(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo;
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
#endif
MV_QUEUE_COMMAND_RESULT result;
MV_NON_UDMA_PROTOCOL protocolType;
MV_U8 *cdb = pScb->ScsiCdb;
memset(pCommandInfo, 0, sizeof(MV_QUEUE_COMMAND_INFO));
protocolType = mvScsiAtaPassThru_MapProto(cdb[1]);
if (protocolType == MV_NON_UDMA_PROTOCOL_UNKNOWN)
{
pScb->dataTransfered = 0;
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCB;
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_ADSENSE_INVALID_CDB, 0);
goto error;
}
/* PIO command can process a "multi_count" number of sectors. */
if (cdb[1] & 0xe0)
{
/*
* FIXME : How to check the passed "multi_count" value ?
* Please remove the unused attribute when unneeded.
*/
unsigned int multi_count __attribute__((unused)) = 1 << (cdb[1] >> 5);
}
if (cdb[0] == SCSI_OPCODE_ATA16)
{
/* 16-byte CDB can contain extend commands. */
if (cdb[1] & 0x01)
{
pCommandInfo->commandParams.NoneUdmaCommand.features = MV_LE16_TO_CPU(*((MV_U16 *) &cdb[3]));
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = MV_LE16_TO_CPU(*((MV_U16 *) &cdb[5]));
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow = MV_LE16_TO_CPU(*((MV_U16 *) &cdb[7]));
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid = MV_LE16_TO_CPU(*((MV_U16 *) &cdb[9]));
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh = MV_LE16_TO_CPU(*((MV_U16 *) &cdb[11]));
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_TRUE;
}
else
{
pCommandInfo->commandParams.NoneUdmaCommand.features = cdb[4];
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = cdb[6];
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow = cdb[8];
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid = cdb[10];
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh = cdb[12];
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_FALSE;
}
pCommandInfo->commandParams.NoneUdmaCommand.device = cdb[13];
pCommandInfo->commandParams.NoneUdmaCommand.command = cdb[14];
}
else
{
pCommandInfo->commandParams.NoneUdmaCommand.features = cdb[3];
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = cdb[4];
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow = cdb[5];
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid = cdb[6];
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh = cdb[7];
pCommandInfo->commandParams.NoneUdmaCommand.device = cdb[8];
pCommandInfo->commandParams.NoneUdmaCommand.command = cdb[9];
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_FALSE;
}
pScb->commandType = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->PMPort = pScb->target;
pCommandInfo->commandParams.NoneUdmaCommand.protocolType = protocolType;
pCommandInfo->commandParams.NoneUdmaCommand.bufPtr = (MV_U16_PTR)pScb->pDataBuffer;
/* count is in words (double byte), so we devide by 2 */
pCommandInfo->commandParams.NoneUdmaCommand.count = pScb->dataBufferLength >> 1;
pCommandInfo->commandParams.NoneUdmaCommand.callBack = SALCommandCompletionCB;
pCommandInfo->commandParams.NoneUdmaCommand.commandId = (MV_VOID_PTR) pScb;
result = mvSataQueueCommand(pSataAdapter, pScb->bus, pCommandInfo);
if (result == MV_QUEUE_COMMAND_RESULT_OK)
return MV_SCSI_COMMAND_STATUS_QUEUED;
else
checkQueueCommandResult(pScb, result);
error:
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/*******************************************************************************
* mvScsiAtaGetReadCapacityData - Get the SCSI-3 Read Capacity (10h/16h) data
*
* DESCRIPTION: This function fills the data buffer with Scsi Read Capacity 10 or
* Read Capacity 16 data according to the disk size as it is reported in
* the ATA Identify data.
*
* INPUT:
* pSataAdapter - pointer to the SATA adapter data structure.
* pScb->bus - the index of the specific SATA channel.
*
* OUTPUT:
* RETURN:
* MV_TRUE on success, MV_FALSE on failure.
*
* COMMENTS:
* No sanity check is done for the parameters.
*
*******************************************************************************/
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaGetReadCapacityData(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_U32 lastAddressableLBA;
MV_U8 *buff;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
if ((pScb->ScsiCdb[8] & MV_BIT1) == 0)
{
if (pScb->ScsiCdb[2] || pScb->ScsiCdb[3] ||pScb->ScsiCdb[4] ||
pScb->ScsiCdb[5])
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Inquiry completed with error: PMI = 0, LBA != 0\n",
pSataAdapter->adapterId, pScb->bus);
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_ADSENSE_INVALID_CDB, 0);
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCSI_COMMAND;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
}
if((pDriveData->identifyInfo.ATADiskSize >> 32) & 0xFFFFFFFF)
{
lastAddressableLBA = 0xFFFFFFFF;
}
else
{
lastAddressableLBA = pDriveData->identifyInfo.ATADiskSize - 1;
}
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "MVSATA: last Addressable sector = 0x%x "
" (sec size=%d bytes)\n", lastAddressableLBA, ATA_SECTOR_SIZE);
/* The disk size as indicated by the ATA spec is the total addressable
* secotrs on the drive ; while the SCSI translation of the command
* should be the last addressable sector.
*/
buff = pScb->pDataBuffer;
memset(buff, 0, pScb->dataBufferLength);
buff[0] = (MV_U8)(lastAddressableLBA >> 24);
buff[1] = (MV_U8)((lastAddressableLBA >> 16) & 0xff);
buff[2] = (MV_U8)((lastAddressableLBA >> 8) & 0xff);
buff[3] = (MV_U8)(lastAddressableLBA & 0xff);
buff[4] = 0;
buff[5] = 0;
buff[6] = (MV_U8)((ATA_SECTOR_SIZE >> 8) & 0xff); /* 512 byte sectors */
buff[7] = (MV_U8)(ATA_SECTOR_SIZE & 0xff);
pScb->dataTransfered = 8;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
pScb->senseDataLength = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/*******************************************************************************
* mvScsiAtaGetReadCapacity16Data - Get the SCSI-3 Read Capacity (16h) data
*
* DESCRIPTION: This function fills the data buffer with Scsi Read Capacity 16
* data according to the disk size as it is reported in
* the ATA Identify data.
*
* INPUT:
* pSataAdapter - pointer to the SATA adapter data structure.
* pScb->bus - the index of the specific SATA channel.
*
* OUTPUT:
* RETURN:
* MV_TRUE on success, MV_FALSE on failure.
*
* COMMENTS:
* No sanity check is done for the parameters.
*
*******************************************************************************/
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaGetReadCapacity16Data(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_U64 lastAddressableLBA;
MV_U8 *buff;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
if ((pScb->ScsiCdb[14] & MV_BIT1) == 0)
{
if (pScb->ScsiCdb[2] || pScb->ScsiCdb[3] ||pScb->ScsiCdb[4] ||
pScb->ScsiCdb[5] || pScb->ScsiCdb[6] ||pScb->ScsiCdb[7] ||
pScb->ScsiCdb[8] || pScb->ScsiCdb[9])
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Read Capacity completed with error: PMI = 0, LBA != 0\n",
pSataAdapter->adapterId, pScb->bus);
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_ADSENSE_INVALID_CDB, 0);
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCSI_COMMAND;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
}
lastAddressableLBA = pDriveData->identifyInfo.ATADiskSize - 1;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "MVSATA: last Addressable sector = 0x%x "
" (sec size=%d bytes)\n", lastAddressableLBA, ATA_SECTOR_SIZE);
/* The disk size as indicated by the ATA spec is the total addressable
* secotrs on the drive ; while the SCSI translation of the command
* should be the last addressable sector.
*/
buff = pScb->pDataBuffer;
memset(buff, 0, pScb->dataBufferLength);
buff[0] = (MV_U8)((lastAddressableLBA >> 56) & 0xff);
buff[1] = (MV_U8)((lastAddressableLBA >> 48) & 0xff);
buff[2] = (MV_U8)((lastAddressableLBA >> 40) & 0xff);
buff[3] = (MV_U8)((lastAddressableLBA >> 32) & 0xff);
buff[4] = (MV_U8)((lastAddressableLBA >> 24) & 0xff);
buff[5] = (MV_U8)((lastAddressableLBA >> 16) & 0xff);
buff[6] = (MV_U8)((lastAddressableLBA >> 8) & 0xff);
buff[7] = (MV_U8)(lastAddressableLBA & 0xff);
buff[8] = 0;
buff[9] = 0;
buff[10] = (MV_U8)((ATA_SECTOR_SIZE >> 8) & 0xff); /* 512 byte sectors */
buff[11] = (MV_U8)(ATA_SECTOR_SIZE & 0xff);
pScb->dataTransfered = 8;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
pScb->senseDataLength = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/*******************************************************************************
* mvScsiAtaReportLuns - handle the SCSI-3 Report LUNS
*
* DESCRIPTION: Report 1 LUN
*
* INPUT:
* pSataAdapter - pointer to the SATA adapter data structure.
* pScb->bus - the index of the specific SATA channel.
*
* OUTPUT:
* RETURN:
* MV_TRUE on success, MV_FALSE on failure.
*
* COMMENTS:
* No sanity check is done for the parameters.
*
*******************************************************************************/
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaReportLuns(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_U8 *buff;
buff = pScb->pDataBuffer;
memset(buff, 0, pScb->dataBufferLength);
buff[3] = 8; /* 1 lun*/
pScb->dataTransfered = 16;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
pScb->senseDataLength = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaSendVerifyCommand(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo;
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
#endif
MV_QUEUE_COMMAND_RESULT result;
MV_U8 *cmd = pScb->ScsiCdb;
MV_U64 LbaAddress;
MV_U32 sectors;
MV_U16 commands;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
MV_SAL_ADAPTER_EXTENSION *pAdapterExt = pScb->pSalAdapterExtension;
if (cmd[0] == SCSI_OPCODE_VERIFY6)
{
LbaAddress =
( (unsigned) cmd[3]) |
(((unsigned) cmd[2]) << 8) |
((((unsigned) cmd[1]) & 0x1f) << 16);
sectors = (unsigned) cmd[4];
}
else if (cmd[0] == SCSI_OPCODE_VERIFY10)
{
LbaAddress =
(((unsigned) cmd[5]) << 0) |
(((unsigned) cmd[4]) << 8) |
(((unsigned) cmd[3]) << 16) |
(((unsigned) cmd[2]) << 24);
sectors = ((unsigned) cmd[8]) |
(((unsigned) cmd[7]) << 8);
}
else
{
LbaAddress =
(((MV_U64) cmd[9]) << 0) |
(((MV_U64) cmd[8]) << 8) |
(((MV_U64) cmd[7]) << 16) |
(((MV_U64) cmd[6]) << 24) |
(((MV_U64) cmd[5]) << 32) |
(((MV_U64) cmd[4]) << 40) |
(((MV_U64) cmd[3]) << 48) |
(((MV_U64) cmd[2]) << 56);
sectors =
((unsigned) cmd[13]) |
(((unsigned) cmd[12]) << 8) |
(((unsigned) cmd[11]) << 16) |
(((unsigned) cmd[10]) << 24);
}
if (sectors == 0)
{
if ((cmd[0] == SCSI_OPCODE_VERIFY10) || (cmd[0] == SCSI_OPCODE_VERIFY16))
{
if (checkLBAOutOfRange(pSataAdapter, pScb,
pDriveData->identifyInfo.ATADiskSize,
LbaAddress, 0) == MV_TRUE)
{
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->senseDataLength = 0;
pScb->dataTransfered = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
else
{
/* If VERIFY6 to 48bit device, then 256 sectors is OK ; otherwise
the CORE driver must get sector count of 0 in order to understand that
256 sectors must be transferred
*/
if (pDriveData->identifyInfo.LBA48Supported == MV_TRUE)
{
sectors = 256;
}
else
{
sectors = 0;
}
}
if (checkLBAOutOfRange(pSataAdapter, pScb,
pDriveData->identifyInfo.ATADiskSize,
LbaAddress, 256) == MV_TRUE)
{
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
}
else
{
if (checkLBAOutOfRange(pSataAdapter, pScb,
pDriveData->identifyInfo.ATADiskSize,
LbaAddress, sectors) == MV_TRUE)
{
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
}
pScb->commandType = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pScb->LowLbaAddress = (MV_U32)(LbaAddress & 0xFFFFFFFF);
// pScb->highLbaAddress = (MV_U32)(LbaAddress >> 32);
if (pDriveData->identifyInfo.LBA48Supported == MV_TRUE)
{
pScb->splitCount = 1;
pScb->isExtended = MV_TRUE;
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->PMPort = pScb->target;
pCommandInfo->commandParams.NoneUdmaCommand.bufPtr = NULL;
pCommandInfo->commandParams.NoneUdmaCommand.callBack = SALCommandCompletionCB;
pCommandInfo->commandParams.NoneUdmaCommand.command = MV_ATA_COMMAND_READ_VERIFY_SECTORS_EXT;
pCommandInfo->commandParams.NoneUdmaCommand.commandId = (MV_VOID_PTR) pScb;
pCommandInfo->commandParams.NoneUdmaCommand.count = 0;
pCommandInfo->commandParams.NoneUdmaCommand.features = 0;
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_TRUE;
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh =
(MV_U16)(((LbaAddress & 0xff0000000000ULL) >> 40) | ((LbaAddress & 0xff0000) >> 16));
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid =
(MV_U16)(((LbaAddress & 0xff00000000ULL) >> 32) | ((LbaAddress & 0xff00) >> 8));
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow =
(MV_U16)(((LbaAddress & 0xff000000) >> 24) | (LbaAddress & 0xff));
pCommandInfo->commandParams.NoneUdmaCommand.protocolType = MV_NON_UDMA_PROTOCOL_NON_DATA;
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = sectors;
pCommandInfo->commandParams.NoneUdmaCommand.device = (MV_U8)(MV_BIT6);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Sending EXT Verify command: channel %d, code %x lba %x(%x.%x.%x), sectors %d[%d] Srb %p\n",
pScb->bus, cmd[0], LbaAddress,
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh,
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid,
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow,
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount,
mvSataNumOfDmaCommands(pSataAdapter,pScb->bus), pScb);
result = mvSataQueueCommand(pSataAdapter, pScb->bus, pCommandInfo);
if (result != MV_QUEUE_COMMAND_RESULT_OK)
{
checkQueueCommandResult(pScb, result);
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/* update stats*/
pAdapterExt->totalAccumulatedOutstanding[pScb->bus] +=
mvSataNumOfDmaCommands(pSataAdapter,pScb->bus);
pDriveData->stats.totalIOs++;
pDriveData->stats.totalSectorsTransferred += sectors;
}
else
{
/* The following only in case command is VERIFY 6 with 0 sector count */
if (sectors == 0)
{
commands = 1;
}
else
{
commands = (MV_U16)((((MV_U32)sectors + 0xff) & 0x1ff00) >> 8);
}
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "split Verify to %d commands: channel %d, lba %x, sectors %d\n",
commands,pScb->bus, LbaAddress, sectors);
pScb->splitCount = commands;
pScb->sequenceNumber = 0;
pScb->isExtended = MV_FALSE;
mvScsiAtaSendSplittedVerifyCommand(pScb);
}
return MV_SCSI_COMMAND_STATUS_QUEUED;
}
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaSeek(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_U32 lbaAddress;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
lbaAddress = (((MV_U32) pScb->ScsiCdb[5]) << 0) |
(((MV_U32) pScb->ScsiCdb[4]) << 8) |
(((MV_U32) pScb->ScsiCdb[3]) << 16) |
(((MV_U32) pScb->ScsiCdb[2]) << 24);
if (checkLBAOutOfRange(pSataAdapter, pScb,
pDriveData->identifyInfo.ATADiskSize,
lbaAddress, 0) == MV_TRUE)
{
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaReassignBlocks(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
setSenseData(pScb, SCSI_SENSE_HARDWARE_ERROR, 0x32, 0);
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_ATA_FAILED;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_TRUE;
}
#ifdef MV_SATA_SUPPORT_READ_WRITE_LONG
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaWriteLong(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo;
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
#endif
MV_QUEUE_COMMAND_RESULT result;
MV_U32 LBA;
MV_U16 eccBytes;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
MV_SAL_ADAPTER_EXTENSION *pAdapterExt = pScb->pSalAdapterExtension;
memset(pCommandInfo, 0, sizeof(MV_QUEUE_COMMAND_INFO));
LBA = (((MV_U32) pScb->ScsiCdb[5]) << 0) |
(((MV_U32) pScb->ScsiCdb[4]) << 8) |
(((MV_U32) pScb->ScsiCdb[3]) << 16) |
(((MV_U32) pScb->ScsiCdb[2]) << 24);
eccBytes = (MV_U16)pScb->ScsiCdb[8];
if ((pScb->ScsiCdb[7] != 2) || ((eccBytes != 4) && (eccBytes != 8)))
{
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCB;
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
if (checkLBAOutOfRange(pSataAdapter, pScb,
pDriveData->identifyInfo.ATADiskSize,
LBA, 1) == MV_TRUE)
{
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/*if (checkLBAOutOfRange(pSataAdapter, pScb, MV_BIT28 - 2,
LBA, 1) == MV_TRUE)
{
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}*/
if (LBA & (MV_BIT31|MV_BIT30|MV_BIT29|MV_BIT28))
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Error LBA (0x%x) out of range.\n", LBA);
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_ADSENSE_ILLEGAL_BLOCK, 0);
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCSI_COMMAND;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_TRUE;
}
pScb->commandType = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->PMPort = pScb->target;
pCommandInfo->commandParams.NoneUdmaCommand.bufPtr = (MV_U16_PTR)pScb->pDataBuffer;
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_FALSE;
pCommandInfo->commandParams.NoneUdmaCommand.callBack = SALCommandCompletionCB;
pCommandInfo->commandParams.NoneUdmaCommand.commandId = (MV_VOID_PTR) pScb;
pCommandInfo->commandParams.NoneUdmaCommand.count = 256+4;
pCommandInfo->commandParams.NoneUdmaCommand.features = eccBytes;
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh = (MV_U16)((LBA & 0xff0000) >> 16);
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid = (MV_U16)((LBA & 0xff00) >> 8) ;
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow = (MV_U16)LBA & 0xff;
pCommandInfo->commandParams.NoneUdmaCommand.protocolType = MV_NON_UDMA_PROTOCOL_PIO_DATA_OUT;
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = 1;
pCommandInfo->commandParams.NoneUdmaCommand.device = MV_BIT6 | (MV_U16)((LBA & 0xf000000) >> 24) ;
pScb->isExtended = MV_FALSE;
pCommandInfo->commandParams.NoneUdmaCommand.command = 0x32;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Sending WRITE LONG command : channel %d, code %x pScb %p\n",
pScb->bus, pScb->ScsiCdb[0], pScb);
result = mvSataQueueCommand(pSataAdapter, pScb->bus, pCommandInfo);
if (result != MV_QUEUE_COMMAND_RESULT_OK)
{
checkQueueCommandResult(pScb, result);
/* shoudl complete the Scsi request here*/
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/* update stats*/
pAdapterExt->totalAccumulatedOutstanding[pScb->bus] += mvSataNumOfDmaCommands(pSataAdapter,pScb->bus);
pDriveData->stats.totalIOs++;
return MV_SCSI_COMMAND_STATUS_QUEUED;
}
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaReadLong(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo;
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
#endif
MV_QUEUE_COMMAND_RESULT result;
MV_U32 LBA;
MV_U16 eccBytes;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
MV_SAL_ADAPTER_EXTENSION *pAdapterExt = pScb->pSalAdapterExtension;
memset(pCommandInfo, 0, sizeof(MV_QUEUE_COMMAND_INFO));
LBA = (((MV_U32) pScb->ScsiCdb[5]) << 0) |
(((MV_U32) pScb->ScsiCdb[4]) << 8) |
(((MV_U32) pScb->ScsiCdb[3]) << 16) |
(((MV_U32) pScb->ScsiCdb[2]) << 24);
eccBytes = (MV_U16)pScb->ScsiCdb[8];
if ((pScb->ScsiCdb[7] != 2) || ((eccBytes != 4) && (eccBytes != 8)))
{
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCB;
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
if (checkLBAOutOfRange(pSataAdapter, pScb,
pDriveData->identifyInfo.ATADiskSize,
LBA, 1) == MV_TRUE)
{
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/*if (checkLBAOutOfRange(pSataAdapter, pScb, MV_BIT28 - 2,
LBA, 1) == MV_TRUE)
{
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}*/
if (LBA & (MV_BIT31|MV_BIT30|MV_BIT29|MV_BIT28))
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Error LBA (0x%x) out of range.\n", LBA);
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_ADSENSE_ILLEGAL_BLOCK, 0);
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCSI_COMMAND;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_TRUE;
}
pScb->commandType = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->PMPort = pScb->target;
pCommandInfo->commandParams.NoneUdmaCommand.bufPtr = (MV_U16_PTR)pScb->pDataBuffer;
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_FALSE;
pCommandInfo->commandParams.NoneUdmaCommand.callBack = SALCommandCompletionCB;
pCommandInfo->commandParams.NoneUdmaCommand.commandId = (MV_VOID_PTR) pScb;
pCommandInfo->commandParams.NoneUdmaCommand.count = 256+4;
pCommandInfo->commandParams.NoneUdmaCommand.features = eccBytes;
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh = (MV_U16)((LBA & 0xff0000) >> 16);
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid = (MV_U16)((LBA & 0xff00) >> 8) ;
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow = (MV_U16)LBA & 0xff;
pCommandInfo->commandParams.NoneUdmaCommand.protocolType = MV_NON_UDMA_PROTOCOL_PIO_DATA_IN;
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = 1;
pCommandInfo->commandParams.NoneUdmaCommand.device = MV_BIT6 | (MV_U16)((LBA & 0xf000000) >> 24) ;
pScb->isExtended = MV_FALSE;
pCommandInfo->commandParams.NoneUdmaCommand.command = 0x22;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Sending READ LONG command : channel %d, code %x pScb %p\n",
pScb->bus, pScb->ScsiCdb[0], pScb);
result = mvSataQueueCommand(pSataAdapter, pScb->bus, pCommandInfo);
if (result != MV_QUEUE_COMMAND_RESULT_OK)
{
checkQueueCommandResult(pScb, result);
/* shoudl complete the Scsi request here*/
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/* update stats*/
pAdapterExt->totalAccumulatedOutstanding[pScb->bus] += mvSataNumOfDmaCommands(pSataAdapter,pScb->bus);
pDriveData->stats.totalIOs++;
return MV_SCSI_COMMAND_STATUS_QUEUED;
}
#endif
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaSendSyncCacheCommand(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo;
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
#endif
MV_QUEUE_COMMAND_RESULT result;
MV_U64 LBA;
MV_U32 sectors;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
MV_SAL_ADAPTER_EXTENSION *pAdapterExt = pScb->pSalAdapterExtension;
/* Check if IMMED bit is set, if so then return ILLEGAL REQUEST */
if (pScb->ScsiCdb[1] & MV_BIT1)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Synchronise cache completed with error:"
" IMMED is set\n", pSataAdapter->adapterId,
pScb->bus);
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_INVALID_CDB,
0);
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCSI_COMMAND;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
memset(pCommandInfo, 0, sizeof(MV_QUEUE_COMMAND_INFO));
if(pScb->ScsiCdb[0] == SCSI_OPCODE_SYNCHRONIZE_CACHE10)
{
LBA = (((MV_U64) pScb->ScsiCdb[5]) << 0) |
(((MV_U64) pScb->ScsiCdb[4]) << 8) |
(((MV_U64) pScb->ScsiCdb[3]) << 16) |
(((MV_U64) pScb->ScsiCdb[2]) << 24);
sectors = ((MV_U32) pScb->ScsiCdb[8]) |
(((MV_U32) pScb->ScsiCdb[7]) << 8);
}
else
{
LBA = (((MV_U64) pScb->ScsiCdb[9]) << 0) |
(((MV_U64) pScb->ScsiCdb[8]) << 8) |
(((MV_U64) pScb->ScsiCdb[7]) << 16) |
(((MV_U64) pScb->ScsiCdb[6]) << 24) |
(((MV_U64) pScb->ScsiCdb[5]) << 32) |
(((MV_U64) pScb->ScsiCdb[4]) << 40) |
(((MV_U64) pScb->ScsiCdb[3]) << 48) |
(((MV_U64) pScb->ScsiCdb[2]) << 56);
sectors = ((MV_U32) pScb->ScsiCdb[13]) |
(((MV_U32) pScb->ScsiCdb[12]) << 8) |
(((MV_U32) pScb->ScsiCdb[11]) << 16) |
(((MV_U32) pScb->ScsiCdb[10]) << 24);
}
if (checkLBAOutOfRange(pSataAdapter, pScb,
pDriveData->identifyInfo.ATADiskSize,LBA, sectors)
== MV_TRUE)
{
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
pScb->commandType = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->PMPort = pScb->target;
pCommandInfo->commandParams.NoneUdmaCommand.bufPtr = NULL;
pCommandInfo->commandParams.NoneUdmaCommand.callBack = SALCommandCompletionCB;
pCommandInfo->commandParams.NoneUdmaCommand.commandId = (MV_VOID_PTR) pScb;
pCommandInfo->commandParams.NoneUdmaCommand.count = 0;
pCommandInfo->commandParams.NoneUdmaCommand.features = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow = 0;
pCommandInfo->commandParams.NoneUdmaCommand.protocolType =
MV_NON_UDMA_PROTOCOL_NON_DATA;
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = 0;
pCommandInfo->commandParams.NoneUdmaCommand.device = (MV_U8)(MV_BIT6);
if (pDriveData->identifyInfo.LBA48Supported == MV_TRUE)
{
pScb->isExtended = MV_TRUE;
pCommandInfo->commandParams.NoneUdmaCommand.command = MV_ATA_COMMAND_FLUSH_CACHE_EXT;
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_TRUE;
}
else
{
pScb->isExtended = MV_FALSE;
pCommandInfo->commandParams.NoneUdmaCommand.command = MV_ATA_COMMAND_FLUSH_CACHE;
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_FALSE;
}
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Sending Flush Cache command : channel %d, code %x (extended -->"
" %s) pScb %p\n", pScb->bus, pScb->ScsiCdb[0],
(pScb->isExtended == MV_TRUE) ? "Yes":"No", pScb);
result = mvSataQueueCommand(pSataAdapter, pScb->bus, pCommandInfo);
if (result != MV_QUEUE_COMMAND_RESULT_OK)
{
checkQueueCommandResult(pScb, result);
/* shoudl complete the Scsi request here*/
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/* update stats*/
pAdapterExt->totalAccumulatedOutstanding[pScb->bus] += mvSataNumOfDmaCommands(pSataAdapter,pScb->bus);
pDriveData->stats.totalIOs++;
return MV_SCSI_COMMAND_STATUS_QUEUED;
}
/*******************************************************************************
* mvScsiAtaGetRequestSenseData - Get the SCSI-3 Request Sense(03h) data
*
* DESCRIPTION: This function fills the sense buffer with a sense key of NO SENSE
* and an additional sense code of NO ADDITIONAL SENSE INFORMATION.
*
* INPUT:
* pSataAdapter - pointer to the SATA adapter data structure.
* pScb->bus - the index of the specific SATA channel.
* Cdb - specifies the SCSI-3 command descriptor block.
*
* OUTPUT:
* pScsiStatus - pointer to the Scsi status to be returned.
* pSenseBuffer - pointer to the Scsi sense buffer.
* senseBufferLength - the size in bytes of the sense buffer.
* pDataTransfered - the size in bytes of the data transfered into the data
* buffer(alwasy zero for this command).
*
* RETURN:
* MV_TRUE on success, MV_FALSE on failure.
*
* COMMENTS:
* No sanity check is done for the parameters.
*
*******************************************************************************/
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaGetRequestSenseData(IN MV_SATA_ADAPTER* pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_SCSI_SENSE_DATA SenseData;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
memset(pScb->pDataBuffer, 0, pScb->dataBufferLength);
memset(&SenseData, 0, sizeof(MV_SCSI_SENSE_DATA));
// SenseData.Valid = 0;
SenseData.ResponseCode = MV_SCSI_RESPONSE_CODE;
SenseData.SenseKey = SCSI_SENSE_NO_SENSE;
SenseData.AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE;
SenseData.AdditionalSenseLength = sizeof(MV_SCSI_SENSE_DATA) - 8;
pScb->senseDataLength = 0;
if (pDriveData->UAConditionPending == MV_TRUE)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Unit Attention condition is pending.\n");
SenseData.SenseKey = SCSI_SENSE_UNIT_ATTENTION;
if (pDriveData->UAEvents & MV_BIT0)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Report Bus Reset.\n");
SenseData.AdditionalSenseCode = SCSI_ADSENSE_BUS_RESET;
SenseData.AdditionalSenseCodeQualifier = 2;
pDriveData->UAEvents &= ~MV_BIT0;
}
else if (pDriveData->UAEvents & MV_BIT1)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Report Mode Parameters Changed.\n");
SenseData.AdditionalSenseCode = SCSI_ADSENSE_PARAMETERS_CHANGED;
SenseData.AdditionalSenseCodeQualifier = 1;
pDriveData->UAEvents &= ~MV_BIT1;
}
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
if (pDriveData->UAEvents == 0)
{
pDriveData->UAConditionPending = MV_FALSE;
}
}
else
{
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
}
if (pScb->dataBufferLength >= sizeof(MV_SCSI_SENSE_DATA))
{
pScb->dataTransfered = sizeof(MV_SCSI_SENSE_DATA);
memcpy(pScb->pDataBuffer, &SenseData, pScb->dataTransfered);
/*pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;*/
/*pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;*/
}
else
{
pScb->dataTransfered = pScb->dataBufferLength;
memcpy(pScb->pDataBuffer, &SenseData, pScb->dataTransfered);
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;/*TBD*/
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
}
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
/*******************************************************************************
* mvScsiAtaGetModeSenseData - Get the SCSI-3 Mode Sense data
*
* DESCRIPTION: This function issues ATA Identify command, in the command
* completion, the Mode Sense data will be filled according to the returned
* Identify Data.
*
* INPUT:
* pSataAdapter - pointer to the SATA adapter data structure.
* pScb->bus - the index of the specific SATA channel.
* Cdb - specifies the SCSI-3 command descriptor block.
*
* RETURN:
* MV_TRUE on success, MV_FALSE on failure.
*
* COMMENTS:
* No sanity check is done for the parameters.
*
*******************************************************************************/
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaGetModeSenseData(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo;
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
#endif
MV_QUEUE_COMMAND_RESULT result;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
memset(pCommandInfo, 0, sizeof(MV_QUEUE_COMMAND_INFO));
pScb->commandType = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->PMPort = pScb->target;
pCommandInfo->commandParams.NoneUdmaCommand.bufPtr = pDriveData->identifyBuffer;
pCommandInfo->commandParams.NoneUdmaCommand.count = 256; /* 512 bytes */
pCommandInfo->commandParams.NoneUdmaCommand.callBack = SALCommandCompletionCB;
pCommandInfo->commandParams.NoneUdmaCommand.command = MV_ATA_COMMAND_IDENTIFY;
pCommandInfo->commandParams.NoneUdmaCommand.commandId = (MV_VOID_PTR) pScb;
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_FALSE;
pCommandInfo->commandParams.NoneUdmaCommand.protocolType = MV_NON_UDMA_PROTOCOL_PIO_DATA_IN;
pCommandInfo->commandParams.NoneUdmaCommand.device = (MV_U8)(MV_BIT6);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Sending Identify command: channel %d, Srb %p\n",
pScb->bus, pScb);
result = mvSataQueueCommand(pSataAdapter, pScb->bus, pCommandInfo);
if (result != MV_QUEUE_COMMAND_RESULT_OK)
{
checkQueueCommandResult(pScb, result);
/* shoudl complete the Scsi request here*/
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
return MV_SCSI_COMMAND_STATUS_QUEUED;
}
static MV_BOOLEAN mvScsiAtaGetModeSenseDataPhase2(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_U8 AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE;
MV_U8 *cmd = pScb->ScsiCdb;
MV_U8 pageCode= cmd[2] & 0x3f;
MV_U8 pageControl = (MV_U8)((cmd[2] & 0xc0) >> 6);
MV_U8 modeSenseResult[MV_MAX_MODE_SENSE_RESULT_LENGTH];
MV_U32 offset;
MV_U32 pageLength;
MV_BOOLEAN commandFailed = MV_FALSE;
memset(pScb->pDataBuffer, 0, pScb->dataBufferLength);
memset(modeSenseResult, 0, MV_MAX_MODE_SENSE_RESULT_LENGTH);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Sense: cmd[2] 0x%xcode 0x%x control 0x%x "
"allocation length %d \n", pSataAdapter->adapterId, pScb->bus,
cmd[2], pageCode, pageControl, (MV_U32)cmd[4]);
if (pageControl == 0x3)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Sense: save control not supported\n.",
pSataAdapter->adapterId, pScb->bus);
AdditionalSenseCode = 0x39; /*SAVING PARAMETERS NOT SUPPORTED */
commandFailed = MV_TRUE;
}
if (commandFailed != MV_TRUE)
{
memset(modeSenseResult, 0, MV_MAX_MODE_SENSE_RESULT_LENGTH);
/*1. Mode parameter header*/
/* Mode data length will be set later */
/* Medium Type 0: Default medium type */
/* Device-specific parameter 0: write enabled, target */
/* supports the DPO and FUA bits only in NCQ mode*/
if (pSataAdapter->sataChannel[pScb->bus]->queuedDMA == MV_EDMA_MODE_NATIVE_QUEUING)
{
modeSenseResult[2] = MV_BIT4;
}
/* Block descriptor length 0: no block descriptors*/
/*2. Block descriptor(s): Empty list*/
/*3. Page(s)*/
offset = 4;
switch (pageCode)
{
case 0x3f:
case 0x8: /*Caching page */
pageLength = mvModeSenseCachingPage(pScb,
modeSenseResult + offset,
pageControl);
offset += pageLength;
if (pageCode == 0x8)
{
break;
}
case 0xa:
pageLength = mvModeSenseControlPage(pSataAdapter,pScb,
modeSenseResult + offset,
pageControl);
offset += pageLength;
break;
default:
AdditionalSenseCode = SCSI_ADSENSE_INVALID_CDB;
commandFailed = MV_TRUE;
}
/* set the DATA LENGTH of the Mode parameter list not including the number*/
/* of bytes of the DATA LENGTH itself ( 1 byte for Mode Selet(6)) */
modeSenseResult[0] = (MV_U8)(offset - 1);
if (pScb->dataBufferLength < offset)
{
memcpy(pScb->pDataBuffer, modeSenseResult, pScb->dataBufferLength);
pScb->dataTransfered = pScb->dataBufferLength;
}
else
{
memcpy(pScb->pDataBuffer, modeSenseResult, offset);
pScb->dataTransfered = offset;
}
}
if (commandFailed == MV_TRUE)
{
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST, AdditionalSenseCode, 0);
pScb->dataTransfered = 0;
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCSI_COMMAND;
}
else
{
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
}
return MV_TRUE;
}
static MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaModeSelect(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_U8 result;
MV_SCSI_COMMAND_STATUS_TYPE commandStatus= MV_SCSI_COMMAND_STATUS_FAILED;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " MODE SELECT RECEIVED: cmd:");
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %02x, %02x, %02x, %02x, %02x, %02x\n", pScb->ScsiCdb[0], pScb->ScsiCdb[1],
pScb->ScsiCdb[2], pScb->ScsiCdb[3], pScb->ScsiCdb[4], pScb->ScsiCdb[5]);
}
result = modeSelect(pSataAdapter, pScb, &commandStatus);
if (result != 0x0)
{
if (result == 0x1)/*PARAMETER LIST LENGTH ERROR*/
{
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST, 0x1a, 0);
}
else if (result == 0x2)
{
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_ADSENSE_INVALID_CDB, 0);
}
else if (result == 0x3)
{
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_ADSENSE_INVALID_FIELD_IN_PARAMETER_LIST, 0);
}
else
{
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_ADSENSE_NO_SENSE, 0);
}
pScb->dataTransfered = 0;
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCSI_COMMAND;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
return commandStatus;
}
static MV_U8
modeSelect(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_SCSI_COMMAND_STATUS_TYPE *pCommandStatus)
{
MV_U8 *cmd = pScb->ScsiCdb;
MV_VOID_PTR pBuffer = pScb->pDataBuffer;
MV_U32 length = pScb->dataBufferLength;
MV_U8 PF = (cmd[1] & MV_BIT4) >> 4;
MV_U8 SP = (cmd[1] & MV_BIT0);
MV_U8 *list = (MV_U8 *)pBuffer;
MV_U32 offset;
MV_U32 cachePageOffset = 0;
{
MV_U32 i;
for (i =0 ; i < length; i++)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %02x", list[i]);
}
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "\n");
}
if (PF == 0)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%d %d: Mode Select Error: PF not supported\n.",
pSataAdapter->adapterId, pScb->bus);
return 0x2; /* Invalid field in CDB */
}
if (SP == 1)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%d %d: Mode Select Error: SP not supported\n.",
pSataAdapter->adapterId, pScb->bus);
return 0x2; /* PARAMETER LIST LENGTH ERROR */
}
if (length == 0)
{
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
*pCommandStatus = MV_SCSI_COMMAND_STATUS_COMPLETED;
return 0;
}
if (length < 4)
{
return 0x1; /* PARAMETER LIST LENGTH ERROR */
}
if (list[0] || (list[1] != MV_SCSI_DIRECT_ACCESS_DEVICE) || list[2])
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: invalid field in parameter "
"list\n", pSataAdapter->adapterId, pScb->bus);
return 0x3; /* Invalid field in parameter list */
}
if (list[3])
{
if (list[3] != 8)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: wrong size for mode parameter"
" block descriptor, BLOCK DESCRIPTOR LENGTH %d\n.",
pSataAdapter->adapterId, pScb->bus, list[3]);
return 0x3; /* Invalid field in parameter list */
}
if (length < 12)
{
return 0x1; /* PARAMETER LIST LENGTH ERROR */
}
if (list[4] || list[5] || list[6] || list[7] || list[8] || list[9] ||
(list[10] != 0x2) || list[11])
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: invalid field in parameter "
"block descriptor list\n", pSataAdapter->adapterId,
pScb->bus);
return 0x3; /* Invalid field in parameter list */
}
}
offset = 4 + list[3];/* skip the mode parameter block descriptor */
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select: PF 0x%x SP 0x%x parameter length %x "
"length %d(0x%x)\n offset %d", pSataAdapter->adapterId, pScb->bus,
PF, SP, (MV_U32)cmd[4], length, length,
offset);
if (length == offset)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select : no mode pages available\n",
pSataAdapter->adapterId, pScb->bus);
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
*pCommandStatus = MV_SCSI_COMMAND_STATUS_COMPLETED;
return 0;
}
while ((offset + 2) < length)
{
switch (list[offset] & 0x3f)
{
case 0x8:
if (list[offset + 1] != 0x12)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: bad length in caching mode "
"page %d\n.",
pSataAdapter->adapterId, pScb->bus, list[offset + 1]);
return 0x3; /* Invalid field in parameter list */
}
cachePageOffset = offset;
offset += list[offset + 1] + 2;
break;
case 0xa:
if ((list[offset] != 0xa) || (list[offset+1] != 0xa))
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: invalid field in"
" mode control page, list[%x] %x, list[%x] %x\n",
pSataAdapter->adapterId, pScb->bus, offset,
list[offset], offset + 1, list[offset+1]);
return 0x3;
}
if (list[offset + 3] != MV_BIT4)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: invalid field in"
" mode control page, list[%x] %x\n",
pSataAdapter->adapterId, pScb->bus, offset + 3,
list[offset + 3]);
return 0x3;
}
if (list[offset + 2] || list[offset + 4] || list[offset + 5] ||
list[offset + 6] || list[offset + 7]||list[offset + 8] ||
list[offset + 9]|| list[offset + 10] || list[offset + 11])
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: invalid field in"
" mode control page, line %d\n",
pSataAdapter->adapterId, pScb->bus, __LINE__);
return 0x3;
}
offset += list[offset + 1] + 2;
break;
default:
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: invalid field in parameter "
"list, mode page %d not supported, offset %d\n",
pSataAdapter->adapterId, pScb->bus, list[offset],
offset);
return 0x3; /* Invalid field in parameter list */
}
}
if (length != offset)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: bad length %d\n.",
pSataAdapter->adapterId, pScb->bus, length);
return 0x1; /* PARAMETER LIST LENGTH ERROR */
}
if (cachePageOffset)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Mode Select: caching Page found, offset %d\n", cachePageOffset);
return mvParseModeCachingPage(pSataAdapter, pScb,list + cachePageOffset, pCommandStatus);
}
else
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Mode Select: No caching Page found\n");
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
*pCommandStatus = MV_SCSI_COMMAND_STATUS_COMPLETED;
return 0;
}
}
static MV_U8
mvParseModeCachingPage(MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_U8 *buffer,
MV_SCSI_COMMAND_STATUS_TYPE *pCommandStatus)
{
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo;
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
#endif
MV_QUEUE_COMMAND_RESULT result;
MV_U8 index = 0;
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
if ((buffer[index++] & 0xc0) || (buffer[index++] != 0x12) ||
((buffer[index++] | MV_BIT2)!= MV_BIT2) || (buffer[index++]) ||
(buffer[index++] != 0xff) || (buffer[index++] != 0xff) ||
buffer[index++] || buffer[index++] || buffer[index++] ||
(buffer[index++] != 0x10) || buffer[index++] ||
(buffer[index++] != 0x10) || ((buffer[index++] | MV_BIT5) != MV_BIT5) ||
(buffer[index++] != 0x1) || (buffer[index++] != 0xff) ||
(buffer[index++] != 0xff) || buffer[index++] || buffer[index++]
|| buffer[index++] || buffer[index++])
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: invalid field in caching mode"
" page, index %d\n", pSataAdapter->adapterId, pScb->bus,
index);
return 0x3; /* Invalid field in parameter list */
}
pScb->splitCount = 2;
pScb->sequenceNumber = 1;
if (buffer[12] & MV_BIT5) /* Disable Look Ahead*/
{
if (pDriveData->identifyInfo.readAheadSupported == MV_FALSE)
{
pScb->splitCount--;
}
pScb->LowLbaAddress = 0;
}
else
{
if (pDriveData->identifyInfo.readAheadSupported == MV_FALSE)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: invalid field in caching mode"
" page, enable read ahead (feature not supported)\n",
pSataAdapter->adapterId, pScb->bus);
return 0x3; /* Invalid field in parameter list */
}
pScb->LowLbaAddress = 1;
}
if (buffer[2] & MV_BIT2) /* enable write cache*/
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Parse Caching Page: enable Write Cache\n");
if (pDriveData->identifyInfo.writeCacheSupported == MV_FALSE)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d: Mode Select Error: invalid field in caching mode"
" page, enable write cache (feature not supported)\n",
pSataAdapter->adapterId, pScb->bus);
return 0x3; /* Invalid field in parameter list */
}
pCommandInfo->commandParams.NoneUdmaCommand.features = MV_ATA_SET_FEATURES_ENABLE_WCACHE;
}
else
{
if (pDriveData->identifyInfo.writeCacheSupported == MV_FALSE)
{
pScb->splitCount--;
if (pScb->splitCount == 1)
{
mvScsiAtaSendReadLookAhead(pSataAdapter, pScb);
*pCommandStatus = MV_SCSI_COMMAND_STATUS_QUEUED;
return 0;
}
}
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Parse Caching Page: disable Write Cache\n");
pCommandInfo->commandParams.NoneUdmaCommand.features = MV_ATA_SET_FEATURES_DISABLE_WCACHE;
}
if (pScb->splitCount == 0)
{
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
*pCommandStatus = MV_SCSI_COMMAND_STATUS_COMPLETED;
return 0;
}
pScb->commandType = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->PMPort = pScb->target;
pCommandInfo->commandParams.NoneUdmaCommand.bufPtr = NULL;
pCommandInfo->commandParams.NoneUdmaCommand.callBack = SALCommandCompletionCB;
pCommandInfo->commandParams.NoneUdmaCommand.command = MV_ATA_COMMAND_SET_FEATURES;
pCommandInfo->commandParams.NoneUdmaCommand.commandId = (MV_VOID_PTR) pScb;
pCommandInfo->commandParams.NoneUdmaCommand.count = 0;
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_FALSE;
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow = 0;
pCommandInfo->commandParams.NoneUdmaCommand.protocolType = MV_NON_UDMA_PROTOCOL_NON_DATA;
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = 0;
pCommandInfo->commandParams.NoneUdmaCommand.device = (MV_U8)(MV_BIT6);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Sending SET FEATURES command: features %d\n",
pCommandInfo->commandParams.NoneUdmaCommand.features);
result = mvSataQueueCommand(pSataAdapter, pScb->bus, pCommandInfo);
if (result != MV_QUEUE_COMMAND_RESULT_OK)
{
checkQueueCommandResult(pScb, result);
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
*pCommandStatus = MV_SCSI_COMMAND_STATUS_COMPLETED;
return 0;
}
*pCommandStatus = MV_SCSI_COMMAND_STATUS_QUEUED;
return 0;
}
static MV_U32
mvModeSenseCachingPage(MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_U8 *buffer,MV_U8 pageControl)
{
MV_SATA_SCSI_DRIVE_DATA *pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
buffer[0] = 0x8; /* caching page*/
buffer[1] = 0x12; /* length = 2 + 0x12*/
buffer[2] = 0;
if (pageControl == 2) /*default values*/
{
if (pDriveData->identifyInfo.writeCacheSupported == MV_TRUE)
{
buffer[2] = MV_BIT2;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Cache Page: writeCacheEnabledByDefault\n");
}
}
else if (pageControl == 0) /* current values*/
{
if ((pDriveData->identifyInfo.writeCacheSupported == MV_TRUE) &&
(pDriveData->identifyBuffer[85] & MV_BIT5))
{
buffer[2] = MV_BIT2;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Cache Page: writeCacheEnabled\n");
}
}
else if (pageControl == 1) /* changeable values*/
{
if (pDriveData->identifyInfo.writeCacheSupported == MV_TRUE)
{
buffer[2] = MV_BIT2;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Cache Page: writeCacheSupported\n");
}
}
buffer[3] = 0;
if (pageControl != 1)
{
buffer[4] = 0xff;
buffer[5] = 0xff;
buffer[9] = 0x10;
buffer[11] = 0x10;
}
if (pageControl == 2) /*default values*/
{
if (pDriveData->identifyInfo.readAheadSupported == MV_FALSE)
{
buffer[12] = MV_BIT5;
}
}
else if (pageControl == 0) /* current values*/
{
if ((pDriveData->identifyInfo.readAheadSupported == MV_TRUE) &&
(pDriveData->identifyBuffer[85] & MV_BIT6))
{
buffer[12] = 0;
}
else
{
buffer[12] = MV_BIT5;
}
}
else if (pageControl == 1) /* changeable values*/
{
if (pDriveData->identifyInfo.readAheadSupported == MV_TRUE)
{
buffer[12] = MV_BIT5;
}
}
if (pageControl != 1)
{
buffer[13] = 0x01;
buffer[14] = 0xff;
buffer[15] = 0xff;
}
{
MV_U32 i;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Cache Page: \n");
for (i = 0; i < 0x14; i++)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "[%d] %x\n",i, buffer[i]);
}
}
return 0x14;
}
static MV_U32
mvModeSenseControlPage(MV_SATA_ADAPTER *pSataAdapter,
MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_U8 *buffer, MV_U8 pageControl)
{
buffer[0] = 0xA; /* control page */
buffer[1] = 0xA; /* length 2 + 0xa*/
if (pageControl != 1)
{
buffer[3] = MV_BIT4/*Unrestricted reordering allowed*/;
}
{
MV_U32 i;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Control Page: \n");
for (i = 0; i < 0xc; i++)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "[%d] %x\n",i , buffer[i]);
}
}
return 0xc;
}
static MV_BOOLEAN
SALCommandCompletionCB(MV_SATA_ADAPTER *pSataAdapter,
MV_U8 channelNum,
MV_COMPLETION_TYPE comp_type,
MV_VOID_PTR commandId,
MV_U16 responseFlags,
MV_U32 timeStamp,
MV_STORAGE_DEVICE_REGISTERS *registerStruct)
{
MV_SATA_SCSI_CMD_BLOCK *pScb;
if (commandId == NULL)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_FATAL_ERROR, " commandId is NULL, can't hanlde this !!!,adapterId=%d,"
" channel=%d \n", pSataAdapter->adapterId, channelNum);
return MV_FALSE;
}
pScb = commandId;
switch (comp_type)
{
case MV_COMPLETION_TYPE_NORMAL:
/* finish */
#ifdef MV_SUPPORT_ATAPI
if(pScb->commandType == MV_QUEUED_COMMAND_TYPE_PACKET)
{
if ((registerStruct->statusRegister & MV_ATA_ERROR_STATUS) ||
(registerStruct->statusRegister & MV_ATA_DEVICE_FAULT_STATUS))
{
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "packet command completed ",
"with check condition\n", pScb);
}
else
{
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
}
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
pScb->dataTransfered = timeStamp;
break;
}
#endif
/* If splited VERIFY command, then SRB completion will be on the last fragment */
if ((((pScb->ScsiCdb[0] == SCSI_OPCODE_VERIFY6) ||
(pScb->ScsiCdb[0] == SCSI_OPCODE_VERIFY10) ||
(pScb->ScsiCdb[0] == SCSI_OPCODE_VERIFY16) ||
(pScb->ScsiCdb[0] == SCSI_OPCODE_MODE_SELECT6)))
&& (pScb->splitCount > pScb->sequenceNumber))
{
/* add the command to the list for post interrupt service*/
pScb->pNext = pScb->pSalAdapterExtension->pHead;
pScb->pSalAdapterExtension->pHead = pScb;
return MV_TRUE;
}
if (pScb->ScsiCdb[0] == SCSI_OPCODE_MODE_SENSE6)
{
mvScsiAtaGetModeSenseDataPhase2(pSataAdapter, pScb);
}
else
{
pScb->ScsiStatus = MV_SCSI_STATUS_GOOD;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_SUCCESS;
}
/*
* ATA passthru command have to return some consistent sense
* data when the caller ask for it.
*/
if (((pScb->ScsiCdb[0] == SCSI_OPCODE_ATA12) ||
(pScb->ScsiCdb[0] == SCSI_OPCODE_ATA16)) &&
(pScb->ScsiCdb[2] & 0x20))
{
setPassThruSense(pScb, registerStruct);
}
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "command completed. pScb %p\n", pScb);
break;
case MV_COMPLETION_TYPE_ABORT:
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "Error: command Aborted. Cdb: %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x\n", pScb->ScsiCdb[0],
pScb->ScsiCdb[1], pScb->ScsiCdb[2], pScb->ScsiCdb[3],
pScb->ScsiCdb[4], pScb->ScsiCdb[5], pScb->ScsiCdb[6],
pScb->ScsiCdb[7], pScb->ScsiCdb[8], pScb->ScsiCdb[9]);
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_ABORTED;
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
mvCommandCompletionErrorHandler(pScb->pIalAdapterExtension, channelNum);
break;
case MV_COMPLETION_TYPE_ERROR:
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_ATA_FAILED;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "COMPLETION ERROR , adapter =%d, channel=%d, flags=%x\n",
pSataAdapter->adapterId, channelNum, responseFlags);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " Failed command Cdb: %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x\n", pScb->ScsiCdb[0],
pScb->ScsiCdb[1], pScb->ScsiCdb[2], pScb->ScsiCdb[3],
pScb->ScsiCdb[4], pScb->ScsiCdb[5], pScb->ScsiCdb[6],
pScb->ScsiCdb[7], pScb->ScsiCdb[8], pScb->ScsiCdb[9]);
/* here the eDMA will be stopped, so we have to flush */
/* the pending commands */
if (pScb->commandType == MV_QUEUED_COMMAND_TYPE_UDMA)
{
handleUdmaError(pScb, responseFlags, registerStruct);
#ifdef MV_LOGGER
memcpy(&pScb->ATAregStruct, registerStruct,
sizeof(pScb->ATAregStruct));
#endif
}
else
{
handleNoneUdmaError(pScb, registerStruct);
#ifdef MV_LOGGER
memcpy(&pScb->ATAregStruct, registerStruct,
sizeof(pScb->ATAregStruct));
#endif
}
mvCommandCompletionErrorHandler(pScb->pIalAdapterExtension, channelNum);
break;
default:
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_FATAL_ERROR, " Unknown completion type (%d)\n", comp_type);
return MV_FALSE;
}
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
if (!virt_addr_valid(pScb->completionCallBack))
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "IAL ERROR: invalid completionCallBack=0x%X\n",
pScb->completionCallBack);
return MV_FALSE;
}
pScb->completionCallBack(pSataAdapter, pScb);
return MV_TRUE;
}
MV_VOID
handleNoneUdmaError(MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_STORAGE_DEVICE_REGISTERS *registerStruct)
{
MV_U8 errorReg = registerStruct->errorRegister;
MV_SCSI_SENSE_DATA SenseData;
memset(&SenseData, 0, sizeof(MV_SCSI_SENSE_DATA));
pScb->dataBufferLength = 0;
/*if (pSrb->SenseInfoBufferLength < 13)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "IAL ERROR: invalid Sense Info buffer len (%d)\n",
Srb->SenseInfoBufferLength);
Srb->SrbStatus = SRB_STATUS_ERROR;
return;
}*/
memset(pScb->pSenseBuffer, 0, pScb->senseBufferLength);
/*pScb->ScsiCommandCompletion = ;*/
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
SenseData.ResponseCode = MV_SCSI_RESPONSE_CODE;
// SenseData.Valid = 0;
SenseData.AdditionalSenseLength = 12;
SenseData.InformationDesc.type = 0;
SenseData.InformationDesc.AdditionalLength = 0xA;
SenseData.InformationDesc.valid = 1 << 7;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " ATA Drive Registers:\n");
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","Error", registerStruct->errorRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","SectorCount", registerStruct->sectorCountRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","LBA Low", registerStruct->lbaLowRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","LBA Mid", registerStruct->lbaMidRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","LBA High", registerStruct->lbaHighRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","Device", registerStruct->deviceRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","Status", registerStruct->statusRegister);
/* If the command is synchronize cache */
if ((pScb->ScsiCdb[0] == SCSI_OPCODE_SYNCHRONIZE_CACHE10) ||
(pScb->ScsiCdb[0] == SCSI_OPCODE_SYNCHRONIZE_CACHE16))
{
if (!(registerStruct->errorRegister & ABRT_ERR))
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " received error completion on flush cache command"
" but ABORT bit in error register is not set\n");
}
SenseData.SenseKey = SCSI_SENSE_MEDIUM_ERROR;
_fillSenseInformation(pScb, &SenseData, registerStruct);
}
else if ((pScb->ScsiCdb[0] == SCSI_OPCODE_VERIFY10) ||
(pScb->ScsiCdb[0] == SCSI_OPCODE_VERIFY6) ||
(pScb->ScsiCdb[0] == SCSI_OPCODE_VERIFY16))
{
if (errorReg & (NM_ERR | MC_ERR | MCR_ERR))
{
SenseData.SenseKey = SCSI_SENSE_UNIT_ATTENTION;
}
else if (errorReg & UNC_ERR)
{
#if 0
MV_U32 LowLbaAddress = pScb->LowLbaAddress;
#endif
SenseData.SenseKey = SCSI_SENSE_MEDIUM_ERROR;
#if 0
/* Since high 8 bit address are taken immediatly from LowLbaAddress and
not from the completion info ; the following code is relevant for both
48bit and 28bit LBA addressing*/
SenseData.Information[0] = (MV_U8)((LowLbaAddress & 0xff000000) >> 24);
SenseData.Information[1] = (MV_U8)(registerStruct->lbaHighRegister & 0xff);
SenseData.Information[2] = (MV_U8)(registerStruct->lbaMidRegister & 0xff);
SenseData.Information[3] = (MV_U8)(registerStruct->lbaLowRegister & 0xff);
#endif
_fillSenseInformation(pScb, &SenseData, registerStruct);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " Read Verify failed on UNC at sector %02x %02x %02x %02x %02x %02x\n",
SenseData.InformationDesc.information[2],
SenseData.InformationDesc.information[3],
SenseData.InformationDesc.information[4],
SenseData.InformationDesc.information[5],
SenseData.InformationDesc.information[6],
SenseData.InformationDesc.information[7]
);
}
/*else if (errorReg & IDNF_ERR)
{
SenseData.SenseKey = SCSI_SENSE_VOL_OVERFLOW;
}*/
else if ((errorReg & ABRT_ERR) || (errorReg & IDNF_ERR))
{
SenseData.SenseKey = SCSI_SENSE_ABORTED_COMMAND;
SenseData.AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE;
}
else
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " in mapping ATA error to SCSI error\n");
SenseData.SenseKey = SCSI_SENSE_NO_SENSE;
}
}
else if (pScb->ScsiCdb[0] == SCSI_OPCODE_MODE_SELECT6)
{
/* MODE SELECT is only when enabling / disabling write cache */
if (errorReg & ABRT_ERR)
{
SenseData.SenseKey = SCSI_SENSE_ABORTED_COMMAND;
SenseData.AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE;
}
else
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " in mapping ATA error to SCSI error\n");
SenseData.SenseKey = SCSI_SENSE_NO_SENSE;
}
}
pScb->senseDataLength = 20;
memcpy(pScb->pSenseBuffer, &SenseData,
(pScb->senseBufferLength > pScb->senseDataLength) ?
pScb->senseDataLength : pScb->senseBufferLength);
}
static MV_VOID
handleUdmaError(MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_U32 responseFlags,
MV_STORAGE_DEVICE_REGISTERS *registerStruct)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "UDMA %s command failed\n", (pScb->udmaType == MV_UDMA_TYPE_READ) ?
"READ" : "WRITE");
if (responseFlags & (MV_BIT3))
{
/* prevent the error_handler from re-send any commands */
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_DISCONNECT;
}
else if (responseFlags & MV_BIT2) /* ATA error*/
{
MV_SCSI_SENSE_DATA SenseData;
memset(&SenseData, 0, sizeof(MV_SCSI_SENSE_DATA));
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
pScb->senseDataLength = 13;
// SenseData.Valid = 1;
SenseData.ResponseCode = MV_SCSI_RESPONSE_CODE;
SenseData.AdditionalSenseLength = 12;
SenseData.InformationDesc.type = 0;
SenseData.InformationDesc.AdditionalLength = 0xA;
SenseData.InformationDesc.valid = 1 << 7;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " ATA Drive Registers:\n");
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","Error", registerStruct->errorRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","SectorCount", registerStruct->sectorCountRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","LBA Low", registerStruct->lbaLowRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","LBA Mid", registerStruct->lbaMidRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","LBA High", registerStruct->lbaHighRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","Device", registerStruct->deviceRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "%20s : %04x\n","Status", registerStruct->statusRegister);
if ((registerStruct->errorRegister & ICRC_ERR)||
(registerStruct->errorRegister == 0xC))/*error code injected by 88i8030*/
{
SenseData.SenseKey = SCSI_SENSE_ABORTED_COMMAND;
SenseData.AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE;
}
else if (registerStruct->errorRegister &
(NM_ERR | MC_ERR | MCR_ERR))
{
SenseData.SenseKey = SCSI_SENSE_UNIT_ATTENTION;
SenseData.AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
}
else if ((registerStruct->errorRegister & UNC_ERR) ||
(registerStruct->errorRegister == 1))
{
#if 0
MV_U32 LowLbaAddress = pScb->LowLbaAddress;
SenseData.Valid = 1;
SenseData.Information[0] = (MV_U8)((LowLbaAddress & 0xff000000) >> 24);
SenseData.Information[1] = (MV_U8)(registerStruct->lbaHighRegister & 0xff);
SenseData.Information[2] = (MV_U8)(registerStruct->lbaMidRegister & 0xff);
SenseData.Information[3] = (MV_U8)(registerStruct->lbaLowRegister & 0xff);
#endif
_fillSenseInformation(pScb, &SenseData, registerStruct);
if (pScb->udmaType == MV_UDMA_TYPE_READ)
{
SenseData.SenseKey = SCSI_SENSE_MEDIUM_ERROR;
SenseData.AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " DMA Read failed on UNC at sector %02x %02x %02x %02x %02x %02x\n",
SenseData.InformationDesc.information[2],
SenseData.InformationDesc.information[3],
SenseData.InformationDesc.information[4],
SenseData.InformationDesc.information[5],
SenseData.InformationDesc.information[6],
SenseData.InformationDesc.information[7]
);
}
else
{
SenseData.SenseKey = SCSI_SENSE_DATA_PROTECT;
SenseData.AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE;
}
}
else if ((registerStruct->errorRegister & IDNF_ERR) &&
(!(registerStruct->errorRegister & ABRT_ERR)))
{
/* In case IDNF is set and ABRT reset OR IDNF reset and ABRT is set */
SenseData.SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
SenseData.AdditionalSenseCode = SCSI_ADSENSE_ILLEGAL_BLOCK;
}
else if (registerStruct->errorRegister & ABRT_ERR)
{
SenseData.SenseKey = SCSI_SENSE_ABORTED_COMMAND;
SenseData.AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE;
}
else
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " in mapping ATA error to SCSI error\n");
SenseData.SenseKey = SCSI_SENSE_ABORTED_COMMAND;
SenseData.AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE;
}
pScb->senseDataLength = 20;
memcpy(pScb->pSenseBuffer, &SenseData,
(pScb->senseBufferLength > pScb->senseDataLength) ?
pScb->senseDataLength : pScb->senseBufferLength);
}
else if (responseFlags & (MV_BIT0 | MV_BIT1))
{
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_PARITY_ERROR;
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->senseDataLength = 0;
pScb->dataTransfered = 0;
}
else if (responseFlags & (MV_BIT6|MV_BIT5))
{
if (responseFlags & MV_BIT6)
{
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_UNDERRUN;
}
else
{
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_OVERRUN;
}
pScb->dataTransfered = 0;
}
}
/*******************************************************************************
* checkQueueCommandResult -
*
* DESCRIPTION: set the scsi request completion status and the Scsi Status
* according to the result returned form the mvSataQueueCommand function
*
* INPUT:
*
* OUTPUT:
*
* RETURN:
*
* COMMENTS:
*
*
*******************************************************************************/
/*static*/ MV_VOID checkQueueCommandResult(MV_SATA_SCSI_CMD_BLOCK *pScb,
MV_QUEUE_COMMAND_RESULT result)
{
switch (result)
{
case MV_QUEUE_COMMAND_RESULT_BAD_LBA_ADDRESS:
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " Edma Queue command failed. Bad LBA \n");
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCB;
break;
case MV_QUEUE_COMMAND_RESULT_QUEUED_MODE_DISABLED:
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " Edma Queue command failed. EDMA disabled\n");
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_NOT_READY;
break;
case MV_QUEUE_COMMAND_RESULT_FULL:
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " Edma Queue command failed. Queue is Full\n");
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_QUEUE_FULL;
pScb->ScsiStatus = MV_SCSI_STATUS_QUEUE_FULL;
break;
case MV_QUEUE_COMMAND_RESULT_BAD_PARAMS:
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " Edma Queue command failed. (Bad Params)\n");
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCB;
break;
default:
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " Bad result value (%d) from queue"
" command\n", result);
}
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " mvSataQueueUDmaCommand Failed\n");
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
}
#ifdef MV_LOGGER
static MV_VOID reportScbCompletion(MV_SATA_ADAPTER* pSataAdapter,
MV_SATA_SCSI_CMD_BLOCK *pScb)
{
if (pScb->ScsiCommandCompletion != MV_SCSI_COMPLETION_SUCCESS)
{
MV_U8 buffer[100];
MV_U32 index = 0;
MV_BOOLEAN printInfo = MV_TRUE;
switch (pScb->ScsiCommandCompletion)
{
case MV_SCSI_COMPLETION_BAD_SCSI_COMMAND:
SAL_SPRINTF(buffer, "%s", "MV_SCSI_COMPLETION_BAD_SCSI_COMMAND");
break;
case MV_SCSI_COMPLETION_ATA_FAILED:
SAL_SPRINTF(buffer, "%s", "MV_SCSI_COMPLETION_ATA_FAILED");
break;
case MV_SCSI_COMPLETION_PARITY_ERROR:
SAL_SPRINTF(buffer, "%s", "MV_SCSI_COMPLETION_PARITY");
break;
default:
printInfo = MV_FALSE;
}
if (printInfo == MV_TRUE)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " %d %d %d :Scsi command completed. pScb %p, ScsiStatus %d "
"completionStatus %s\n", pSataAdapter->adapterId,
pScb->bus, pScb->target, pScb, pScb->ScsiStatus, buffer);
}
else
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Scsi command completed. pScb %p, ScsiStatus %d "
"completionStatus %d\n", pScb, pScb->ScsiStatus,
pScb->ScsiCommandCompletion);
}
index = SAL_SPRINTF(buffer, "%s", "CDB:");
{
MV_U32 i;
for (i =0 ; i < pScb->ScsiCdbLength; i++)
{
index += SAL_SPRINTF(&buffer[index], "%x ",
pScb->ScsiCdb[i]);
}
buffer[index] = '\n';
buffer[index+1] = 0;
mvLogMsg(MV_SAL_LOG_ID,(printInfo == MV_TRUE) ?
MV_DEBUG_ERROR : MV_DEBUG, buffer);
if (pScb->ScsiStatus == MV_SCSI_STATUS_CHECK_CONDITION)
{
if ((pScb->pSenseBuffer != NULL) && (pScb->senseBufferLength > 0))
{
MV_U32 len = pScb->senseDataLength > pScb->senseBufferLength ?
pScb->senseBufferLength:pScb->senseDataLength;
index = SAL_SPRINTF(buffer, "%s", "Sense Data:");
for (i = 0; i < len; i++)
{
index += SAL_SPRINTF(buffer + index, "%x ",
pScb->pSenseBuffer[i]);
}
buffer[index] = '\n';
buffer[index+1] = 0;
mvLogMsg(MV_SAL_LOG_ID, (printInfo == MV_TRUE) ?
MV_DEBUG_ERROR : MV_DEBUG, buffer);
}
}
}
if (pScb->ScsiCommandCompletion == MV_SCSI_COMPLETION_ATA_FAILED)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " ATA Drive Registers:\n");
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "%20s : %04x\n","Error", pScb->ATAregStruct.errorRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "%20s : %04x\n","SectorCount", pScb->ATAregStruct.sectorCountRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "%20s : %04x\n","LBA Low", pScb->ATAregStruct.lbaLowRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "%20s : %04x\n","LBA Mid", pScb->ATAregStruct.lbaMidRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "%20s : %04x\n","LBA High", pScb->ATAregStruct.lbaHighRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "%20s : %04x\n","Device", pScb->ATAregStruct.deviceRegister);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "%20s : %04x\n","Status", pScb->ATAregStruct.statusRegister);
}
}
else
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Scsi command completed. pScb %p, ScsiStatus %d "
"completionStatus %d dataTransfered %d \n", pScb, pScb->ScsiStatus,
pScb->ScsiCommandCompletion, pScb->dataTransfered);
}
}
#endif
static MV_VOID mvScsiAtaSendSplittedVerifyCommand(IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo;
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
#endif
MV_QUEUE_COMMAND_RESULT result;
MV_U8 sectors = 0;/*256 sectors*/
pScb->sequenceNumber++;
if (pScb->sequenceNumber == 1)/*for the first command*/
{
if (pScb->ScsiCdb[0] == SCSI_OPCODE_VERIFY6)
{
sectors = pScb->ScsiCdb[4];
}
else if (pScb->ScsiCdb[0] == SCSI_OPCODE_VERIFY10)
{
sectors = pScb->ScsiCdb[8];
}
else
{
sectors = pScb->ScsiCdb[13];
}
}
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->PMPort = pScb->target;
pCommandInfo->commandParams.NoneUdmaCommand.bufPtr = NULL;
pCommandInfo->commandParams.NoneUdmaCommand.callBack = SALCommandCompletionCB;
pCommandInfo->commandParams.NoneUdmaCommand.command = MV_ATA_COMMAND_READ_VERIFY_SECTORS;
pCommandInfo->commandParams.NoneUdmaCommand.commandId = (MV_VOID_PTR) pScb;
pCommandInfo->commandParams.NoneUdmaCommand.count = 0;
pCommandInfo->commandParams.NoneUdmaCommand.features = 0;
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_FALSE;
pCommandInfo->commandParams.NoneUdmaCommand.protocolType = MV_NON_UDMA_PROTOCOL_NON_DATA;
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh = (MV_U16)((pScb->LowLbaAddress & 0xff0000) >> 16);
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid = (MV_U16)((pScb->LowLbaAddress & 0xff00) >> 8);
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow = (MV_U16)(pScb->LowLbaAddress & 0xff);
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = sectors;
pCommandInfo->commandParams.NoneUdmaCommand.device = (MV_U8)(MV_BIT6 |
((pScb->LowLbaAddress & 0xf000000) >> 24));
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d %d: Sending Splitted Verify command:seq# %d code %x lba"
" %x(%x.%x.%x), sectors %d[%d] Srb %p\n",
pScb->pSalAdapterExtension->pSataAdapter->adapterId, pScb->bus,
pScb->target,
pScb->sequenceNumber,pScb->ScsiCdb[0],
pScb->LowLbaAddress,
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh,
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid,
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow,
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount,
mvSataNumOfDmaCommands(pScb->pSalAdapterExtension->pSataAdapter,
pScb->bus), pScb);
if (sectors)
{
pScb->LowLbaAddress += sectors;
}
else
{
pScb->LowLbaAddress += 0x100;
}
result = mvSataQueueCommand(pScb->pSalAdapterExtension->pSataAdapter,
pScb->bus, pCommandInfo);
if (result != MV_QUEUE_COMMAND_RESULT_OK)
{
checkQueueCommandResult(pScb, result);
#ifdef MV_LOGGER
reportScbCompletion(pScb->pSalAdapterExtension->pSataAdapter, pScb);
#endif
return;
}
/* update stats*/
pScb->pSalAdapterExtension->totalAccumulatedOutstanding[pScb->bus] +=
mvSataNumOfDmaCommands(pScb->pSalAdapterExtension->pSataAdapter,pScb->bus);
pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target].stats.totalIOs++;
pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target].stats.totalSectorsTransferred += sectors;
}
static MV_VOID mvScsiAtaSendReadLookAhead(IN MV_SATA_ADAPTER *pSataAdapter,
IN MV_SATA_SCSI_CMD_BLOCK *pScb)
{
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo;
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
#endif
MV_QUEUE_COMMAND_RESULT result;
if (pScb->LowLbaAddress == 0) /* Disable Look Ahead*/
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Parse Caching Page: Disable Read Look Ahead\n");
pCommandInfo->commandParams.NoneUdmaCommand.features = MV_ATA_SET_FEATURES_DISABLE_RLA;
}
else
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Parse Caching Page: Enable Look Ahead\n");
pCommandInfo->commandParams.NoneUdmaCommand.features = MV_ATA_SET_FEATURES_ENABLE_RLA;
}
pScb->commandType = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA;
pCommandInfo->PMPort = pScb->target;
pCommandInfo->commandParams.NoneUdmaCommand.bufPtr = NULL;
pCommandInfo->commandParams.NoneUdmaCommand.callBack = SALCommandCompletionCB;
pCommandInfo->commandParams.NoneUdmaCommand.command = MV_ATA_COMMAND_SET_FEATURES;
pCommandInfo->commandParams.NoneUdmaCommand.commandId = (MV_VOID_PTR) pScb;
pCommandInfo->commandParams.NoneUdmaCommand.count = 0;
pCommandInfo->commandParams.NoneUdmaCommand.isEXT = MV_FALSE;
pCommandInfo->commandParams.NoneUdmaCommand.lbaHigh = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaMid = 0;
pCommandInfo->commandParams.NoneUdmaCommand.lbaLow = 0;
pCommandInfo->commandParams.NoneUdmaCommand.protocolType = MV_NON_UDMA_PROTOCOL_NON_DATA;
pCommandInfo->commandParams.NoneUdmaCommand.sectorCount = 0;
pCommandInfo->commandParams.NoneUdmaCommand.device = (MV_U8)(MV_BIT6);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Sending SET FEATURES command: features %d\n",
pCommandInfo->commandParams.NoneUdmaCommand.features);
pScb->sequenceNumber++;
result = mvSataQueueCommand(pSataAdapter, pScb->bus, pCommandInfo);
if (result != MV_QUEUE_COMMAND_RESULT_OK)
{
checkQueueCommandResult(pScb, result);
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return;
}
}
MV_VOID mvSataScsiInitAdapterExt(MV_SAL_ADAPTER_EXTENSION *pAdapterExt,
MV_SATA_ADAPTER* pSataAdapter)
{
MV_U8 channelIndex;
MV_U8 PMPort;
pAdapterExt->pSataAdapter = pSataAdapter;
pAdapterExt->pHead = NULL;
pAdapterExt->UAMask = 0xFF;
for (channelIndex = 0; channelIndex < MV_SATA_CHANNELS_NUM; channelIndex++)
{
for (PMPort = 0; PMPort < MV_SATA_PM_MAX_PORTS; PMPort++)
{
pAdapterExt->ataDriveData[channelIndex][PMPort].driveReady = MV_FALSE;
/* one identify data buffer used for all the drives connected to */
/* the same channel*/
pAdapterExt->ataDriveData[channelIndex][PMPort].identifyBuffer =
pAdapterExt->identifyBuffer[channelIndex];
}
}
}
#ifdef MV_SUPPORT_ATAPI
MV_SCSI_COMMAND_STATUS_TYPE mvScsiAtaSendATAPICommand(MV_SATA_ADAPTER *pSataAdapter,
MV_SATA_SCSI_CMD_BLOCK *pScb)
{
#ifdef MV_SATA_STORE_COMMANDS_INFO_ON_IAL_STACK
MV_QUEUE_COMMAND_INFO *pCommandInfo = pScb->pCommandInfo;
#else
MV_QUEUE_COMMAND_INFO commandInfo;
MV_QUEUE_COMMAND_INFO *pCommandInfo = &commandInfo;
#endif
MV_QUEUE_COMMAND_RESULT result;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Send Packet command, adapter %d bus %d target %d lun %"
"d pScb %p\n dir(%d) Data Buffer %p (%d), cdb %p (%d)\n",
pSataAdapter->adapterId, pScb->bus, pScb->target,
pScb->lun, pScb, pScb->dataDirection,
pScb->pDataBuffer,
pScb->dataBufferLength, pScb->ScsiCdb, pScb->ScsiCdbLength);
pScb->commandType = MV_QUEUED_COMMAND_TYPE_PACKET;
pCommandInfo->type = MV_QUEUED_COMMAND_TYPE_PACKET;
pCommandInfo->PMPort = pScb->target;
pCommandInfo->commandParams.packetCommand.bufPtr = (MV_U16_PTR)pScb->pDataBuffer;
pCommandInfo->commandParams.packetCommand.buffer_len = pScb->dataBufferLength;
pCommandInfo->commandParams.packetCommand.transfered_data = 0;
pCommandInfo->commandParams.packetCommand.cdb_len = (pScb->ScsiCdbLength >> 1);
pCommandInfo->commandParams.packetCommand.cdb_buffer = (MV_U16_PTR)pScb->ScsiCdb;
pCommandInfo->commandParams.packetCommand.flags = 0;
pCommandInfo->commandParams.packetCommand.callBack = SALCommandCompletionCB;
pCommandInfo->commandParams.packetCommand.commandId = (MV_VOID_PTR) pScb;
pCommandInfo->commandParams.packetCommand.prdLowAddr = pScb->PRDTableLowPhyAddress;
pCommandInfo->commandParams.packetCommand.prdHighAddr = pScb->PRDTableHighPhyAddress;
if((pScb->dataDirection == MV_SCSI_COMMAND_DATA_DIRECTION_IN) && (pScb->pDataBuffer == NULL))
{
pCommandInfo->commandParams.packetCommand.protocolType = MV_NON_UDMA_PROTOCOL_PACKET_DMA;
}
else if((pScb->dataDirection == MV_SCSI_COMMAND_DATA_DIRECTION_OUT) && (pScb->pDataBuffer == NULL))
{
pCommandInfo->commandParams.packetCommand.protocolType = MV_NON_UDMA_PROTOCOL_PACKET_DMA;
pCommandInfo->commandParams.packetCommand.flags = MV_BIT0;
}
else
{
switch(pScb->dataDirection)
{
case MV_SCSI_COMMAND_DATA_DIRECTION_IN:
pCommandInfo->commandParams.packetCommand.protocolType = MV_NON_UDMA_PROTOCOL_PACKET_PIO_DATA_IN;
break;
case MV_SCSI_COMMAND_DATA_DIRECTION_OUT:
pCommandInfo->commandParams.packetCommand.protocolType = MV_NON_UDMA_PROTOCOL_PACKET_PIO_DATA_OUT;
break;
default:
pCommandInfo->commandParams.packetCommand.protocolType = MV_NON_UDMA_PROTOCOL_PACKET_PIO_NON_DATA;
}
}
pScb->sequenceNumber = 0;
result = mvSataQueueCommand(pSataAdapter, pScb->bus, pCommandInfo);
if (result != MV_QUEUE_COMMAND_RESULT_OK)
{
checkQueueCommandResult(pScb, result);
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
return MV_SCSI_COMMAND_STATUS_QUEUED;
}
#endif
MV_SCSI_COMMAND_STATUS_TYPE mvSataExecuteScsiCommand(MV_SATA_SCSI_CMD_BLOCK *pScb)
{
MV_U8 *cmd = pScb->ScsiCdb;
MV_BOOLEAN invalidCDB = MV_FALSE;
MV_SATA_ADAPTER *pSataAdapter = pScb->pSalAdapterExtension->pSataAdapter;
MV_SATA_SCSI_DRIVE_DATA *pDriveData;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Scsi Command Received, adapter %d bus %d target %d lun %"
"d pScb %p\n Data Buffer length %d, Sense buffer length %x\n",
pSataAdapter->adapterId, pScb->bus, pScb->target,
pScb->lun, pScb, pScb->dataBufferLength, pScb->senseBufferLength);
#ifdef MV_LOGGER
{
MV_U8 buffer[50];
MV_U32 i, index;
index = SAL_SPRINTF(buffer, "%s", "CDB:");
for (i =0 ; i < pScb->ScsiCdbLength; i++)
{
index += SAL_SPRINTF(&buffer[index], "%x ",
pScb->ScsiCdb[i]);
}
buffer[index] = '\n';
buffer[index+1] = 0;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, buffer);
}
#endif
pScb->dataTransfered = 0;
pScb->senseDataLength = 0;
pScb->ScsiStatus = 0;
if (pScb->bus >= pSataAdapter->numberOfChannels)
{
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_INVALID_BUS;
pScb->dataTransfered = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
if ((pScb->target >= MV_SATA_PM_MAX_PORTS) ||
(pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target].driveReady == MV_FALSE) ||
((pScb->lun) && (pScb->ScsiCdb[0] != SCSI_OPCODE_INQUIRY)))
{
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_NO_DEVICE;
pScb->dataTransfered = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
pDriveData = &pScb->pSalAdapterExtension->ataDriveData[pScb->bus][pScb->target];
#ifdef MV_SUPPORT_ATAPI
if(pDriveData->identifyInfo.deviceType == MV_SATA_DEVICE_TYPE_ATAPI_DEVICE)
{
return mvScsiAtaSendATAPICommand(pSataAdapter, pScb);
}
#endif
switch (cmd[0])
{
case SCSI_OPCODE_READ10:
case SCSI_OPCODE_WRITE10:
case SCSI_OPCODE_READ_CAPACITY10:
case SCSI_OPCODE_VERIFY10:
case SCSI_OPCODE_SYNCHRONIZE_CACHE10:
#ifdef MV_SATA_SUPPORT_READ_WRITE_LONG
case SCSI_OPCODE_WRITE_LONG10:
case SCSI_OPCODE_READ_LONG10:
#endif
if (cmd[1] & MV_BIT0) /* if related address*/
{
invalidCDB = MV_TRUE;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d %d: Scsi command received with "
"RELADR bit enabled - returning ILLEGAL REQUEST\n"
,pSataAdapter->adapterId, pScb->bus, pScb->target);
}
}
if (cmd[pScb->ScsiCdbLength - 1] != 0) /*if CONTROL is set*/
{
MV_BOOLEAN commandSupported = MV_TRUE;
switch (cmd[0])
{
case SCSI_OPCODE_READ6:
case SCSI_OPCODE_READ10:
case SCSI_OPCODE_READ16:
case SCSI_OPCODE_WRITE6:
case SCSI_OPCODE_WRITE10:
case SCSI_OPCODE_WRITE16:
case SCSI_OPCODE_INQUIRY:
case SCSI_OPCODE_TEST_UNIT_READY:
case SCSI_OPCODE_MODE_SELECT6:
case SCSI_OPCODE_MODE_SENSE6:
case SCSI_OPCODE_START_STOP:
case SCSI_OPCODE_READ_CAPACITY10: /* read capctiy CDB*/
case SCSI_OPCODE_REQUEST_SENSE6:
case SCSI_OPCODE_VERIFY6:
case SCSI_OPCODE_VERIFY10:
case SCSI_OPCODE_VERIFY16:
case SCSI_OPCODE_SYNCHRONIZE_CACHE10:
case SCSI_OPCODE_SYNCHRONIZE_CACHE16:
case SCSI_OPCODE_SEEK10:
case SCSI_OPCODE_REASSIGN_BLOCKS:
case SCSI_OPCODE_REPORT_LUNS:
#ifdef MV_SATA_SUPPORT_READ_WRITE_LONG
case SCSI_OPCODE_WRITE_LONG10:
case SCSI_OPCODE_READ_LONG10:
#endif
case SCSI_OPCODE_ATA12:
case SCSI_OPCODE_ATA16:
break;
default:
commandSupported = MV_FALSE;
}
if (commandSupported == MV_TRUE)
{
invalidCDB = MV_TRUE;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "[%d,%d] Scsi command received with "
"none zero CONTROL bits - returning ILLEGAL REQUEST\n"
,pSataAdapter->adapterId, pScb->bus);
}
}
if (pDriveData->UAConditionPending == MV_TRUE)
{
if (((cmd[0] != SCSI_OPCODE_INQUIRY) &&
(cmd[0] != SCSI_OPCODE_REPORT_LUNS) &&
(cmd[0] != SCSI_OPCODE_REQUEST_SENSE6)) || (invalidCDB == MV_TRUE))
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " Unit Attention condition is pending.\n");
if (pDriveData->UAEvents & MV_BIT0)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Report Bus Reset.\n");
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_UA_RESET;
setSenseData(pScb, SCSI_SENSE_UNIT_ATTENTION, SCSI_ADSENSE_BUS_RESET
, 2);
pDriveData->UAEvents &= ~MV_BIT0;
}
else if (pDriveData->UAEvents & MV_BIT1)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Report Mode Parameters Changed.\n");
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_UA_PARAMS_CHANGED;
setSenseData(pScb, SCSI_SENSE_UNIT_ATTENTION,
SCSI_ADSENSE_PARAMETERS_CHANGED, 1);
pDriveData->UAEvents &= ~MV_BIT1;
}
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
if (pDriveData->UAEvents == 0)
{
pDriveData->UAConditionPending = MV_FALSE;
}
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
}
if (invalidCDB == MV_TRUE)
{
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_INVALID_CDB,
0);
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCSI_COMMAND;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
switch (cmd[0])
{
case SCSI_OPCODE_READ6:
case SCSI_OPCODE_READ10:
case SCSI_OPCODE_READ16:
case SCSI_OPCODE_WRITE6:
case SCSI_OPCODE_WRITE10:
case SCSI_OPCODE_WRITE16:
return mvScsiAtaSendDataCommand(pSataAdapter, pScb);
case SCSI_OPCODE_START_STOP:
return mvScsiAtaStartStopCommand(pSataAdapter, pScb);
case SCSI_OPCODE_INQUIRY:
return mvScsiAtaGetInquiryData(pSataAdapter, pScb);
case SCSI_OPCODE_TEST_UNIT_READY:
return mvScsiAtaTestUnitReady(pSataAdapter, pScb);
case SCSI_OPCODE_MODE_SELECT6:
return mvScsiAtaModeSelect(pSataAdapter, pScb);
case SCSI_OPCODE_MODE_SENSE6:
return mvScsiAtaGetModeSenseData(pSataAdapter,pScb);
/* Used to detect write protected status.*/
case SCSI_OPCODE_READ_CAPACITY10: /* read capctiy CDB*/
return mvScsiAtaGetReadCapacityData(pSataAdapter, pScb);
case SCSI_OPCODE_READ_CAPACITY16: /* read capctiy CDB*/
return mvScsiAtaGetReadCapacity16Data(pSataAdapter, pScb);
case SCSI_OPCODE_REQUEST_SENSE6:
return mvScsiAtaGetRequestSenseData(pSataAdapter, pScb);
case SCSI_OPCODE_REPORT_LUNS:
return mvScsiAtaReportLuns(pSataAdapter, pScb);
case SCSI_OPCODE_VERIFY6:
case SCSI_OPCODE_VERIFY10:
case SCSI_OPCODE_VERIFY16:
return mvScsiAtaSendVerifyCommand(pSataAdapter, pScb);
case SCSI_OPCODE_SYNCHRONIZE_CACHE10:
case SCSI_OPCODE_SYNCHRONIZE_CACHE16:
return mvScsiAtaSendSyncCacheCommand(pSataAdapter, pScb);
case SCSI_OPCODE_SEEK10:
return mvScsiAtaSeek(pSataAdapter, pScb);
case SCSI_OPCODE_REASSIGN_BLOCKS:
return mvScsiAtaReassignBlocks(pSataAdapter, pScb);
#ifdef MV_SATA_SUPPORT_READ_WRITE_LONG
case SCSI_OPCODE_WRITE_LONG10:
return mvScsiAtaWriteLong(pSataAdapter, pScb);
case SCSI_OPCODE_READ_LONG10:
return mvScsiAtaReadLong(pSataAdapter, pScb);
#endif
case SCSI_OPCODE_ATA12:
case SCSI_OPCODE_ATA16:
return mvScsiAtaPassThru(pSataAdapter, pScb);
default:
{
setSenseData(pScb, SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_ADSENSE_ILLEGAL_COMMAND, 0);
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, "mvExecuteScsiCommand: ERROR: Unsupported command %02X\n", pScb->ScsiCdb[0]);
pScb->ScsiStatus = MV_SCSI_STATUS_CHECK_CONDITION;
pScb->dataTransfered = 0;
pScb->ScsiCommandCompletion = MV_SCSI_COMPLETION_BAD_SCSI_COMMAND;
#ifdef MV_LOGGER
reportScbCompletion(pSataAdapter, pScb);
#endif
pScb->completionCallBack(pSataAdapter, pScb);
return MV_SCSI_COMMAND_STATUS_COMPLETED;
}
}
return MV_SCSI_COMMAND_STATUS_FAILED;
}
MV_VOID mvSataScsiPostIntService(MV_SAL_ADAPTER_EXTENSION *pAdapterExt)
{
MV_SATA_SCSI_CMD_BLOCK *pScb = pAdapterExt->pHead;
while (pScb)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, "Post Interrupt Service: pScb %p command %x\n", pScb,
pScb->ScsiCdb[0]);
switch (pScb->ScsiCdb[0])
{
case SCSI_OPCODE_VERIFY16:
case SCSI_OPCODE_VERIFY10:
case SCSI_OPCODE_VERIFY6:
mvScsiAtaSendSplittedVerifyCommand(pScb);
break;
case SCSI_OPCODE_MODE_SELECT6:
mvScsiAtaSendReadLookAhead(pAdapterExt->pSataAdapter,
pScb);
break;
default:
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG_ERROR, " Post Interrupt Service called for bad scsi"
" command(%x)\n", pScb->ScsiCdb[0]);
}
pScb = pScb->pNext;
}
pAdapterExt->pHead = NULL;
return;
}
MV_VOID mvSataScsiSetDriveReady(MV_SAL_ADAPTER_EXTENSION *pAdapterExt,
MV_U8 channelIndex, MV_U8 PMPort,
MV_BOOLEAN isReady)
{
if (isReady == MV_TRUE)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d %d: ATA Drive is Ready.\n",
pAdapterExt->pSataAdapter->adapterId, channelIndex, PMPort);
pAdapterExt->ataDriveData[channelIndex][PMPort].driveReady = MV_TRUE;
pAdapterExt->totalAccumulatedOutstanding[channelIndex] = 0;
pAdapterExt->ataDriveData[channelIndex][PMPort].stats.totalIOs = 0;
pAdapterExt->ataDriveData[channelIndex][PMPort].stats.totalSectorsTransferred = 0;
}
else
{
if (PMPort == 0xFF)
{
MV_U8 i;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d : SATA Channel is Removed.\n",
pAdapterExt->pSataAdapter->adapterId, channelIndex);
for (i = 0; i < MV_SATA_PM_MAX_PORTS; i++)
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d %d: SATA Drive is Removed.\n",
pAdapterExt->pSataAdapter->adapterId, channelIndex,
i);
pAdapterExt->ataDriveData[channelIndex][i].driveReady = MV_FALSE;
}
}
else
{
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d %d: SATA Drive is Removed.\n",
pAdapterExt->pSataAdapter->adapterId, channelIndex,
PMPort);
pAdapterExt->ataDriveData[channelIndex][PMPort].driveReady = MV_FALSE;
}
}
}
/* notify the translation layer with Reset and Power on reset*/
MV_VOID mvSataScsiNotifyUA(MV_SAL_ADAPTER_EXTENSION *pAdapterExt,
MV_U8 channelIndex, MV_U8 PMPort)
{
/*
* disable unit attention errors, the commit "[SCSI] fix barrier failure issue" causes to
* some of those commands to be completed with error by the scsi layer.
*/
#if 0
pAdapterExt->ataDriveData[channelIndex][PMPort].UAConditionPending = MV_TRUE;
/* bit 0 - reset*/
/* bit 1 - parameters changed*/
pAdapterExt->ataDriveData[channelIndex][PMPort].UAEvents = MV_BIT1 | MV_BIT0;
pAdapterExt->ataDriveData[channelIndex][PMPort].UAEvents &=
pAdapterExt->UAMask;
mvLogMsg(MV_SAL_LOG_ID, MV_DEBUG, " %d %d %d: Notify SAL with Unit Attention condition.\n",
pAdapterExt->pSataAdapter->adapterId, channelIndex, PMPort);
#else
pAdapterExt->ataDriveData[channelIndex][PMPort].UAConditionPending = MV_FALSE;
pAdapterExt->ataDriveData[channelIndex][PMPort].UAEvents = 0;
#endif
}