1501 lines
44 KiB
C
1501 lines
44 KiB
C
/*
|
|
* (C) Copyright 2000-2002
|
|
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
|
*
|
|
* See file CREDITS for list of people who contributed to this
|
|
* project.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*
|
|
*/
|
|
/*******************************************************************************
|
|
Copyright (C) Marvell International Ltd. and its affiliates
|
|
|
|
********************************************************************************
|
|
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.
|
|
|
|
*******************************************************************************/
|
|
|
|
/*
|
|
* IDE support
|
|
*/
|
|
#include <common.h>
|
|
#include <config.h>
|
|
#include <watchdog.h>
|
|
#include <command.h>
|
|
#include <image.h>
|
|
#include <asm/byteorder.h>
|
|
#include <ide.h>
|
|
#include <ata.h>
|
|
#include <pci.h>
|
|
#include "mvCtrlEnvLib.h"
|
|
|
|
#if (CONFIG_COMMANDS & CFG_CMD_IDE)
|
|
|
|
#include "sata/CoreDriver/mvOsS.h"
|
|
#include "sata/CoreDriver/mvSata.h"
|
|
#include "sata/CoreDriver/mvStorageDev.h"
|
|
|
|
#ifdef MV_LOGGER
|
|
char *szModules[] = {"Core Driver",
|
|
"BIOS IAL"
|
|
};
|
|
#endif
|
|
|
|
#undef IDE_DEBUG
|
|
|
|
#ifdef IDE_DEBUG
|
|
#define DP(fmt,args...) printf (fmt ,##args)
|
|
#else
|
|
#define DP(fmt,args...)
|
|
#endif
|
|
|
|
#define SHOW_BOOT_PROGRESS(arg)
|
|
|
|
#if defined(MV_INCLUDE_INTEG_SATA)
|
|
extern MV_STATUS mvSataWinInit(void);
|
|
#endif
|
|
|
|
#ifndef MRVL_SATA_BUFF_BOUNDARY
|
|
#define MRVL_SATA_BUFF_BOUNDARY (1 << 24)
|
|
#endif /* MRVL_SATA_BUFF_BOUNDARY */
|
|
|
|
#define MRVL_SATA_BOUNDARY_MASK (MRVL_SATA_BUFF_BOUNDARY - 1)
|
|
|
|
#if (__BE)
|
|
void swapATABuffer(unsigned short *buffer, ulong count);
|
|
#endif
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
/* Current I/O Device */
|
|
static int curr_device = -1;
|
|
|
|
|
|
#define ATA_CURR_BASE(dev) (CFG_ATA_BASE_ADDR+ide_bus_offset[IDE_BUS(dev)])
|
|
#define MV_PM 0xF
|
|
|
|
typedef struct mvSataPMDeviceInfo
|
|
{
|
|
MV_U16 vendorId;
|
|
MV_U16 deviceId;
|
|
MV_U8 productRevision;
|
|
MV_U8 PMSpecRevision:4;
|
|
MV_U8 numberOfPorts:4;
|
|
} MV_SATA_PM_DEVICE_INFO;
|
|
|
|
typedef struct _MV_CHANNEL_INFO
|
|
{
|
|
MV_SATA_DEVICE_TYPE deviceType;
|
|
MV_U8 numberOfPorts;
|
|
MV_U16 connected;
|
|
}MV_CHANNEL_INFO;
|
|
typedef struct _HW_ADAPTER_DESCRIPTION
|
|
{
|
|
MV_BOOLEAN valid;
|
|
int devno;
|
|
MV_SATA_ADAPTER mvSataAdapter; /* CoreDriver Adapter data structure*/
|
|
MV_SATA_CHANNEL mvSataChannels[MV_SATA_CHANNELS_NUM];
|
|
MV_CHANNEL_INFO channelInfo[MV_SATA_PM_MAX_PORTS];
|
|
} HW_ADAPTER_DESCRIPTION, *PHW_ADAPTER_DESCRIPTION;
|
|
|
|
/* Data structure describing mvSata adapter and channels */
|
|
/* The data structure describes 4 adapters */
|
|
#define MAX_NUM_OF_ADAPTERS 4
|
|
HW_ADAPTER_DESCRIPTION sataAdapters[CFG_IDE_MAXBUS];
|
|
static block_dev_desc_t ide_dev_desc[CFG_IDE_MAXDEVICE];
|
|
static unsigned int ide_initiated=0,ide_detected=0;
|
|
|
|
MV_SATA_EDMA_PRD_ENTRY prd_table[2] __attribute__ ((aligned(32)));
|
|
unsigned char request_q[MV_EDMA_REQUEST_ENTRY_SIZE] __attribute__ ((aligned(1024)));
|
|
unsigned char response_q[MV_EDMA_RESPONSE_ENTRY_SIZE] __attribute__ ((aligned(256)));
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static MV_BOOLEAN StartPM(HW_ADAPTER_DESCRIPTION *sataAdapter, MV_U8 channelIndex);
|
|
|
|
static MV_BOOLEAN initDisk(MV_SATA_ADAPTER *pSataAdapter, MV_U8 channelIndex,
|
|
MV_U8 port, block_dev_desc_t *dev_desc);
|
|
|
|
static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
|
|
|
|
static ulong pio_read_write (MV_SATA_ADAPTER *pSataAdapter,
|
|
unsigned int channelIndex,
|
|
MV_U8 port,
|
|
lbaint_t blknr, ulong blkcnt, ulong *buffer, int read);
|
|
static
|
|
ulong dma_read_write (MV_SATA_ADAPTER *pSataAdapter,
|
|
unsigned int channelIndex,
|
|
MV_U8 port,
|
|
lbaint_t blknr, ulong blkcnt, ulong *buffer, int read);
|
|
static
|
|
ulong dma_read_write_cmd (MV_SATA_ADAPTER *pSataAdapter,
|
|
unsigned int channelIndex,
|
|
MV_U8 port,
|
|
lbaint_t blknr, ulong blkcnt, ulong *buffer, int read);
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
#ifdef CONFIG_PCI
|
|
|
|
static struct pci_device_id supported[] = {
|
|
{MV_SATA_VENDOR_ID, MV_SATA_DEVICE_ID_5080},
|
|
{MV_SATA_VENDOR_ID, MV_SATA_DEVICE_ID_5081},
|
|
{MV_SATA_VENDOR_ID, MV_SATA_DEVICE_ID_5040},
|
|
{MV_SATA_VENDOR_ID, MV_SATA_DEVICE_ID_5041},
|
|
{MV_SATA_VENDOR_ID, MV_SATA_DEVICE_ID_6041},
|
|
{MV_SATA_VENDOR_ID, MV_SATA_DEVICE_ID_6081},
|
|
{MV_SATA_VENDOR_ID, MV_SATA_DEVICE_ID_6042},
|
|
{MV_SATA_VENDOR_ID, MV_SATA_DEVICE_ID_7042},
|
|
};
|
|
|
|
#endif /* CONFIG_PCI */
|
|
|
|
|
|
int do_ide (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
|
{
|
|
int rcode = 0;
|
|
|
|
/* Check if we have already called reset or not */
|
|
if (ide_initiated == 0)
|
|
{
|
|
/* If this is not a call to reset !!!! */
|
|
if (!((argc==2)&&(strncmp(argv[1],"res",3) == 0)))
|
|
{
|
|
puts ("\nWarning: Please run 'ide reset' before running other ide commands \n\n");
|
|
return 1;
|
|
}
|
|
}
|
|
else /* We have already called reset */
|
|
{
|
|
if (ide_detected == 0)
|
|
{
|
|
puts ("\nno IDE devices available\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
switch (argc) {
|
|
case 0:
|
|
case 1:
|
|
printf ("Usage:\n%s\n", cmdtp->usage);
|
|
return 1;
|
|
case 2:
|
|
if (strncmp(argv[1],"res",3) == 0) {
|
|
puts ("\nReset IDE"
|
|
#ifdef CONFIG_IDE_8xx_DIRECT
|
|
" on PCMCIA " PCMCIA_SLOT_MSG
|
|
#endif
|
|
": ");
|
|
|
|
ide_init ();
|
|
return 0;
|
|
} else if (strncmp(argv[1],"inf",3) == 0) {
|
|
int i;
|
|
|
|
putc ('\n');
|
|
|
|
for (i=0; i<CFG_IDE_MAXDEVICE; ++i) {
|
|
if (ide_dev_desc[i].type==DEV_TYPE_UNKNOWN)
|
|
continue; /* list only known devices */
|
|
printf ("IDE device %x: ", i);
|
|
dev_print(&ide_dev_desc[i]);
|
|
}
|
|
return 0;
|
|
|
|
} else if (strncmp(argv[1],"dev",3) == 0) {
|
|
if ((curr_device < 0) || (curr_device >= CFG_IDE_MAXDEVICE)) {
|
|
puts ("\nno IDE devices available\n");
|
|
return 1;
|
|
}
|
|
printf ("\nIDE device %x: ", curr_device);
|
|
dev_print(&ide_dev_desc[curr_device]);
|
|
return 0;
|
|
} else if (strncmp(argv[1],"part",4) == 0) {
|
|
int dev, ok;
|
|
|
|
for (ok=0, dev=0; dev<CFG_IDE_MAXDEVICE; ++dev) {
|
|
if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) {
|
|
++ok;
|
|
if (dev)
|
|
putc ('\n');
|
|
print_part(&ide_dev_desc[dev]);
|
|
}
|
|
}
|
|
if (!ok) {
|
|
puts ("\nno IDE devices available\n");
|
|
rcode ++;
|
|
}
|
|
return rcode;
|
|
}
|
|
printf ("Usage:\n%s\n", cmdtp->usage);
|
|
return 1;
|
|
case 3:
|
|
if (strncmp(argv[1],"dev",3) == 0) {
|
|
int dev = (int)simple_strtoul(argv[2], NULL, 10);
|
|
|
|
printf ("\nIDE device %x: ", dev);
|
|
if (dev >= CFG_IDE_MAXDEVICE) {
|
|
puts ("unknown device\n");
|
|
return 1;
|
|
}
|
|
dev_print(&ide_dev_desc[dev]);
|
|
/*ide_print (dev);*/
|
|
|
|
if (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN) {
|
|
return 1;
|
|
}
|
|
|
|
curr_device = dev;
|
|
|
|
puts ("... is now current device\n");
|
|
|
|
return 0;
|
|
} else if (strncmp(argv[1],"part",4) == 0) {
|
|
int dev = (int)simple_strtoul(argv[2], NULL, 10);
|
|
|
|
if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) {
|
|
print_part(&ide_dev_desc[dev]);
|
|
} else {
|
|
printf ("\nIDE device %x not available\n", dev);
|
|
rcode = 1;
|
|
}
|
|
return rcode;
|
|
}
|
|
|
|
printf ("Usage:\n%s\n", cmdtp->usage);
|
|
return 1;
|
|
default:
|
|
/* at least 4 args */
|
|
|
|
if (strcmp(argv[1],"read") == 0) {
|
|
ulong addr = simple_strtoul(argv[2], NULL, 16);
|
|
ulong cnt = simple_strtoul(argv[4], NULL, 16);
|
|
ulong n;
|
|
|
|
if (curr_device == -1)
|
|
{
|
|
printf ("\n\nIDE device not available\n");
|
|
return 1;
|
|
}
|
|
#ifdef CFG_64BIT_STRTOUL
|
|
lbaint_t blk = simple_strtoull(argv[3], NULL, 16);
|
|
|
|
printf ("\nIDE read: device %x block # %qd, count %ld ... ",
|
|
curr_device, blk, cnt);
|
|
#else
|
|
lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
|
|
|
|
printf ("\nIDE read: device %x block # %ld, count %ld ... ",
|
|
curr_device, blk, cnt);
|
|
#endif
|
|
|
|
n = ide_dev_desc[curr_device].block_read (curr_device,
|
|
blk, cnt,
|
|
(ulong *)addr);
|
|
/* flush cache after read */
|
|
flush_cache (addr, cnt*ide_dev_desc[curr_device].blksz);
|
|
|
|
printf ("%ld blocks read: %s\n",
|
|
n, (n==cnt) ? "OK" : "ERROR");
|
|
if (n==cnt) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
} else if (strcmp(argv[1],"write") == 0) {
|
|
ulong addr = simple_strtoul(argv[2], NULL, 16);
|
|
ulong cnt = simple_strtoul(argv[4], NULL, 16);
|
|
ulong n;
|
|
|
|
if (curr_device == -1)
|
|
{
|
|
printf ("\n\nIDE device not available\n");
|
|
return 1;
|
|
}
|
|
#ifdef CFG_64BIT_STRTOUL
|
|
lbaint_t blk = simple_strtoull(argv[3], NULL, 16);
|
|
|
|
printf ("\nIDE write: device %x block # %qd, count %ld ... ",
|
|
curr_device, blk, cnt);
|
|
#else
|
|
lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
|
|
|
|
printf ("\nIDE write: device %x block # %ld, count %ld ... ",
|
|
curr_device, blk, cnt);
|
|
#endif
|
|
|
|
n = ide_write (curr_device, blk, cnt, (ulong *)addr);
|
|
|
|
printf ("%ld blocks written: %s\n",
|
|
n, (n==cnt) ? "OK" : "ERROR");
|
|
if (n==cnt) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
} else {
|
|
printf ("Usage:\n%s\n", cmdtp->usage);
|
|
rcode = 1;
|
|
}
|
|
|
|
return rcode;
|
|
}
|
|
}
|
|
|
|
int do_diskboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
|
{
|
|
char *boot_device = NULL;
|
|
char *ep;
|
|
int dev, part = 0;
|
|
ulong cnt;
|
|
ulong addr;
|
|
disk_partition_t info;
|
|
image_header_t *hdr;
|
|
int rcode = 0;
|
|
|
|
switch (argc) {
|
|
case 1:
|
|
addr = CFG_LOAD_ADDR;
|
|
boot_device = getenv ("bootdevice");
|
|
break;
|
|
case 2:
|
|
addr = simple_strtoul(argv[1], NULL, 16);
|
|
boot_device = getenv ("bootdevice");
|
|
break;
|
|
case 3:
|
|
addr = simple_strtoul(argv[1], NULL, 16);
|
|
boot_device = argv[2];
|
|
break;
|
|
default:
|
|
printf ("Usage:\n%s\n", cmdtp->usage);
|
|
SHOW_BOOT_PROGRESS (-1);
|
|
return 1;
|
|
}
|
|
|
|
if (!boot_device) {
|
|
puts ("\n** No boot device **\n");
|
|
SHOW_BOOT_PROGRESS (-1);
|
|
return 1;
|
|
}
|
|
|
|
dev = simple_strtoul(boot_device, &ep, 16);
|
|
|
|
if (ide_dev_desc[dev].type==DEV_TYPE_UNKNOWN) {
|
|
printf ("\n** Device %x not available\n", dev);
|
|
SHOW_BOOT_PROGRESS (-1);
|
|
return 1;
|
|
}
|
|
|
|
if (*ep) {
|
|
if (*ep != ':') {
|
|
puts ("\n** Invalid boot device, use `dev[:part]' **\n");
|
|
SHOW_BOOT_PROGRESS (-1);
|
|
return 1;
|
|
}
|
|
part = simple_strtoul(++ep, NULL, 16);
|
|
}
|
|
if (get_partition_info (&ide_dev_desc[dev], part, &info)) {
|
|
SHOW_BOOT_PROGRESS (-1);
|
|
return 1;
|
|
}
|
|
if ((strncmp((const char *)info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) &&
|
|
(strncmp((const char *)info.type, BOOT_PART_COMP, sizeof(info.type)) != 0)) {
|
|
printf ("\n** Invalid partition type \"%.32s\""
|
|
" (expect \"" BOOT_PART_TYPE "\")\n",
|
|
info.type);
|
|
SHOW_BOOT_PROGRESS (-1);
|
|
return 1;
|
|
}
|
|
|
|
printf ("\nLoading from IDE device %x, partition %d: "
|
|
"Name: %.32s Type: %.32s\n",
|
|
dev, part, info.name, info.type);
|
|
|
|
DP ("First Block: %ld, # of blocks: %ld, Block Size: %ld\n",
|
|
info.start, info.size, info.blksz);
|
|
|
|
if (ide_dev_desc[dev].block_read (dev, info.start, 1, (ulong *)addr) != 1) {
|
|
printf ("** Read error on %x:%d\n", dev, part);
|
|
SHOW_BOOT_PROGRESS (-1);
|
|
return 1;
|
|
}
|
|
|
|
hdr = (image_header_t *)addr;
|
|
|
|
if (ntohl(hdr->ih_magic) == IH_MAGIC) {
|
|
|
|
print_image_hdr (hdr);
|
|
|
|
cnt = (ntohl(hdr->ih_size) + sizeof(image_header_t));
|
|
cnt += info.blksz - 1;
|
|
cnt /= info.blksz;
|
|
cnt -= 1;
|
|
} else {
|
|
printf("\n** Bad Magic Number **\n");
|
|
SHOW_BOOT_PROGRESS (-1);
|
|
return 1;
|
|
}
|
|
|
|
if (ide_dev_desc[dev].block_read (dev, info.start+1, cnt,
|
|
(ulong *)(addr+info.blksz)) != cnt) {
|
|
printf ("** Read error on %x:%d\n", dev, part);
|
|
SHOW_BOOT_PROGRESS (-1);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* Loading ok, update default load address */
|
|
|
|
load_addr = addr;
|
|
|
|
/* Check if we should attempt an auto-start */
|
|
if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
|
|
char *local_args[2];
|
|
extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
|
|
|
|
local_args[0] = argv[0];
|
|
local_args[1] = NULL;
|
|
|
|
printf ("Automatic boot of image at addr 0x%08lX ...\n", addr);
|
|
|
|
do_bootm (cmdtp, 0, 1, local_args);
|
|
rcode = 1;
|
|
}
|
|
return rcode;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
MV_SATA_DEVICE_TYPE mvGetSataDeviceType(
|
|
MV_STORAGE_DEVICE_REGISTERS *mvStorageDevRegisters)
|
|
{
|
|
if (((mvStorageDevRegisters->sectorCountRegister & 0xff) != 1) ||
|
|
((mvStorageDevRegisters->lbaLowRegister & 0xff) != 1))
|
|
{
|
|
return MV_SATA_DEVICE_TYPE_UNKNOWN;
|
|
}
|
|
if (((mvStorageDevRegisters->lbaMidRegister & 0xff) == 0) &&
|
|
((mvStorageDevRegisters->lbaHighRegister & 0xff) == 0))
|
|
{
|
|
return MV_SATA_DEVICE_TYPE_ATA_DISK;
|
|
}
|
|
if ((((mvStorageDevRegisters->lbaMidRegister & 0xff) == 0x14) &&
|
|
((mvStorageDevRegisters->lbaHighRegister & 0xff) == 0xEB))/* ||
|
|
(((mvStorageDevRegisters->lbaMidRegister & 0xff) == 0x69) &&
|
|
((mvStorageDevRegisters->lbaHighRegister & 0xff) == 0x96))*/)
|
|
{
|
|
return MV_SATA_DEVICE_TYPE_ATAPI_DEVICE;
|
|
}
|
|
if (((mvStorageDevRegisters->lbaMidRegister & 0xff) == 0x69) &&
|
|
((mvStorageDevRegisters->lbaHighRegister & 0xff) == 0x96))
|
|
{
|
|
return MV_SATA_DEVICE_TYPE_PM;
|
|
}
|
|
return MV_SATA_DEVICE_TYPE_UNKNOWN;
|
|
}
|
|
|
|
MV_BOOLEAN mvGetPMDeviceInfo(MV_SATA_ADAPTER *pSataAdapter,
|
|
MV_U8 channelIndex,
|
|
MV_SATA_PM_DEVICE_INFO *pPMDeviceInfo)
|
|
{
|
|
MV_U32 regVal;
|
|
|
|
if (mvPMDevReadReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
|
|
MV_SATA_GSCR_ID_REG_NUM, ®Val, NULL) == MV_FALSE)
|
|
{
|
|
printf("Error [%d %d]: Failed to read PM GSCR ID register\n",
|
|
pSataAdapter->adapterId, channelIndex);
|
|
return MV_FALSE;
|
|
}
|
|
pPMDeviceInfo->vendorId = (MV_U16)(regVal & 0xffff);
|
|
pPMDeviceInfo->deviceId = (MV_U16)((regVal & 0xffff0000) >> 16);
|
|
|
|
if (mvPMDevReadReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
|
|
MV_SATA_GSCR_REVISION_REG_NUM, ®Val, NULL)== MV_FALSE)
|
|
{
|
|
printf("Error:[%d %d]: Failed to read PM GSCR REVISION register\n", pSataAdapter->adapterId,
|
|
channelIndex);
|
|
return MV_FALSE;
|
|
}
|
|
pPMDeviceInfo->PMSpecRevision = (MV_U8)(regVal & 0xff);
|
|
pPMDeviceInfo->productRevision = (MV_U8)((regVal & 0xff00) >> 8);
|
|
|
|
if (mvPMDevReadReg(pSataAdapter, channelIndex, MV_SATA_PM_CONTROL_PORT,
|
|
MV_SATA_GSCR_INFO_REG_NUM, ®Val, NULL)== MV_FALSE)
|
|
{
|
|
printf("Error: [%d %d]: Failed to read PM GSCR INFO\n", pSataAdapter->adapterId,
|
|
channelIndex);
|
|
return MV_FALSE;
|
|
}
|
|
pPMDeviceInfo->numberOfPorts = (MV_U8)(regVal & 0xf);
|
|
return MV_TRUE;
|
|
}
|
|
|
|
static MV_BOOLEAN
|
|
StartPM(HW_ADAPTER_DESCRIPTION *sataAdapter,
|
|
MV_U8 channelIndex)
|
|
{
|
|
MV_SATA_ADAPTER *pSataAdapter = &sataAdapter->mvSataAdapter;
|
|
MV_U8 PMPort;
|
|
MV_SATA_PM_DEVICE_INFO PMInfo;
|
|
|
|
if (mvGetPMDeviceInfo(pSataAdapter, channelIndex, &PMInfo) == MV_FALSE) {
|
|
printf("Error: Failed to get PortMultiplier Info\n",
|
|
pSataAdapter->adapterId, channelIndex);
|
|
return MV_FALSE;
|
|
}
|
|
printf("Port Multiplier found @ %d %d. Vendor: %04x ports: %d\n",
|
|
pSataAdapter->adapterId, channelIndex, PMInfo.vendorId,
|
|
PMInfo.numberOfPorts);
|
|
|
|
for (PMPort = 0; PMPort < PMInfo.numberOfPorts; PMPort++){
|
|
MV_U32 SStatus;
|
|
/*
|
|
* Skip PMPort #0 - this should be already enabled due to legacy mode
|
|
* transition of PM
|
|
*/
|
|
if (PMPort > 0) {
|
|
if (mvPMDevEnableStaggeredSpinUp(pSataAdapter, channelIndex,
|
|
PMPort) == MV_FALSE){
|
|
printf("Error:[%d %d %d]: EnableStaggeredSpinUp Failed\n",
|
|
pSataAdapter->adapterId, channelIndex, PMPort);
|
|
if (mvStorageDevATASoftResetDevice(pSataAdapter, channelIndex,
|
|
MV_SATA_PM_CONTROL_PORT, NULL) == MV_FALSE)
|
|
{
|
|
printf("Error: [%d %d]: failed to Soft Reset PM control port\n"
|
|
, pSataAdapter->adapterId, channelIndex);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
if (mvPMDevReadReg(pSataAdapter, channelIndex, PMPort,
|
|
MV_SATA_PSCR_SSTATUS_REG_NUM, &SStatus, NULL) ==
|
|
MV_FALSE)
|
|
{
|
|
printf("Error:[%d %d %d]: mvPMDevReadReg Failed\n",
|
|
pSataAdapter->adapterId, channelIndex, PMPort);
|
|
if (mvStorageDevATASoftResetDevice(pSataAdapter, channelIndex,
|
|
MV_SATA_PM_CONTROL_PORT, NULL) == MV_FALSE)
|
|
{
|
|
printf("Error: [%d %d]: failed to Soft Reset PM control port\n"
|
|
, pSataAdapter->adapterId, channelIndex);
|
|
}
|
|
continue;
|
|
}
|
|
DP("[%d %d %x]: S-Status: 0x%x\n", pSataAdapter->adapterId,
|
|
channelIndex, PMPort, SStatus);
|
|
if ((SStatus & 0xf) == 3){
|
|
if (mvPMDevWriteReg(pSataAdapter, channelIndex, PMPort,
|
|
MV_SATA_PSCR_SERROR_REG_NUM, 0xffffffff, NULL) ==
|
|
MV_FALSE)
|
|
{
|
|
printf("Error [%d %d %d]: PM Write SERROR Failed\n",
|
|
pSataAdapter->adapterId, channelIndex, PMPort);
|
|
continue;
|
|
}
|
|
|
|
sataAdapter->channelInfo[channelIndex].connected |= 1 << PMPort;
|
|
}
|
|
}
|
|
sataAdapter->channelInfo[channelIndex].numberOfPorts = PMInfo.numberOfPorts;
|
|
return MV_TRUE;
|
|
}
|
|
|
|
|
|
static MV_BOOLEAN StartChannel(HW_ADAPTER_DESCRIPTION *sataAdapter,
|
|
MV_U8 channelIndex)
|
|
{
|
|
MV_SATA_ADAPTER *pSataAdapter = &sataAdapter->mvSataAdapter;
|
|
MV_STORAGE_DEVICE_REGISTERS ATARegs;
|
|
MV_SATA_CHANNEL *pSataChannel;
|
|
MV_SATA_DEVICE_TYPE deviceType;
|
|
|
|
pSataChannel = pSataAdapter->sataChannel[channelIndex];
|
|
if (!pSataChannel)
|
|
{
|
|
printf ("Error in StartChannel - Channel data structure is null\n");
|
|
return MV_FALSE;
|
|
}
|
|
if (mvStorageDevATASoftResetDevice(pSataAdapter,
|
|
channelIndex, MV_PM, &ATARegs) == MV_FALSE)
|
|
{
|
|
printf("Error - Failed initializing(SRST) drive on channel %d\n", channelIndex);
|
|
return MV_FALSE;
|
|
}
|
|
deviceType = mvGetSataDeviceType(&ATARegs);
|
|
mvStorageDevSetDeviceType(pSataAdapter, channelIndex,deviceType);
|
|
sataAdapter->channelInfo[channelIndex].deviceType = deviceType;
|
|
sataAdapter->channelInfo[channelIndex].numberOfPorts = 0;
|
|
sataAdapter->channelInfo[channelIndex].connected = 0;
|
|
switch(deviceType)
|
|
{
|
|
case MV_SATA_DEVICE_TYPE_UNKNOWN:
|
|
printf("Error - unknown device at channel %d\n", channelIndex);
|
|
return MV_FALSE;
|
|
case MV_SATA_DEVICE_TYPE_ATAPI_DEVICE:
|
|
printf("Error - unknown device at channel %d\n", channelIndex);
|
|
return MV_FALSE;
|
|
case MV_SATA_DEVICE_TYPE_ATA_DISK:
|
|
sataAdapter->channelInfo[channelIndex].numberOfPorts = 1;
|
|
sataAdapter->channelInfo[channelIndex].connected = 1;
|
|
return MV_TRUE;
|
|
case MV_SATA_DEVICE_TYPE_PM:
|
|
return StartPM(sataAdapter, channelIndex);
|
|
}
|
|
|
|
return MV_TRUE;
|
|
}
|
|
static MV_BOOLEAN initDisk(MV_SATA_ADAPTER *pSataAdapter, MV_U8 channelIndex,
|
|
MV_U8 port, block_dev_desc_t *dev_desc)
|
|
{
|
|
MV_STORAGE_DEVICE_REGISTERS ATARegs;
|
|
ulong identifyBuffer[ATA_SECTORWORDS];
|
|
hd_driveid_t *iop = (hd_driveid_t *)identifyBuffer;
|
|
MV_U16_PTR iden = (MV_U16_PTR) identifyBuffer;
|
|
MV_U8 PIOMode;
|
|
//Patch by QNAP:fix SATA DOM issue
|
|
MV_U8 UDMAMode=0;
|
|
///////////////////////////////////
|
|
MV_SATA_DEVICE_TYPE deviceType = mvStorageDevGetDeviceType(pSataAdapter,channelIndex);
|
|
if (deviceType == MV_SATA_DEVICE_TYPE_PM)
|
|
{
|
|
if (mvStorageDevATASoftResetDevice(pSataAdapter,
|
|
channelIndex, port, &ATARegs) == MV_FALSE)
|
|
{
|
|
printf("Error - SRST for port %d on channel %d failed\n", port, channelIndex);
|
|
return MV_FALSE;
|
|
}
|
|
if(mvGetSataDeviceType(&ATARegs) != MV_SATA_DEVICE_TYPE_ATA_DISK)
|
|
{
|
|
// printf("Error: device at %d %d %d not supported\n", pSataAdapter->adapterId, channelIndex, port);
|
|
|
|
return MV_FALSE;
|
|
}
|
|
}
|
|
|
|
/* identify device*/
|
|
memset(&ATARegs, 0, sizeof(ATARegs));
|
|
ATARegs.commandRegister = MV_ATA_COMMAND_IDENTIFY;
|
|
if (mvStorageDevATAIdentifyDevice(pSataAdapter, channelIndex, port,
|
|
(unsigned short *)identifyBuffer) == MV_FALSE)
|
|
{
|
|
printf("[%d %d %d]: failed to perform ATA Identify command\n", pSataAdapter->adapterId,
|
|
channelIndex, port);
|
|
return MV_FALSE;
|
|
}
|
|
/* Check if read look ahead is supported. If so enable it */
|
|
if (iden[IDEN_SUPPORTED_COMMANDS1] & MV_BIT6)
|
|
{
|
|
if (mvStorageDevATASetFeatures(pSataAdapter, channelIndex, port,
|
|
MV_ATA_SET_FEATURES_ENABLE_RLA,0,0,0, 0) == MV_FALSE)
|
|
{
|
|
printf("[%d %d %d]: failed to perform Enable RLA command\n", pSataAdapter->adapterId,
|
|
channelIndex, port);
|
|
return MV_FALSE;
|
|
}
|
|
}
|
|
if ((iden[IDEN_VALID] & MV_BIT1) == 0)
|
|
{
|
|
printf("[%d %d %d]: Unable to find PIO Mode\n", pSataAdapter->adapterId, channelIndex, port);
|
|
return MV_FALSE;
|
|
}
|
|
else if (iden[IDEN_PIO_MODE_SPPORTED] & MV_BIT0)
|
|
{
|
|
PIOMode = MV_ATA_TRANSFER_PIO_3;
|
|
}
|
|
else if (iden[IDEN_PIO_MODE_SPPORTED] & MV_BIT1)
|
|
{
|
|
PIOMode = MV_ATA_TRANSFER_PIO_4;
|
|
}
|
|
else
|
|
{
|
|
printf("[%d %d %d]: PIO modes 3 and 4 are not supported\n", pSataAdapter->adapterId, channelIndex, port);
|
|
PIOMode = MV_ATA_TRANSFER_PIO_SLOW;
|
|
}
|
|
if (mvStorageDevATASetFeatures(pSataAdapter, channelIndex, port,
|
|
MV_ATA_SET_FEATURES_TRANSFER,PIOMode,0,0, 0) == MV_FALSE)
|
|
{
|
|
printf("[%d %d %d]: failed to enable PIO mode\n",
|
|
pSataAdapter->adapterId, channelIndex, port);
|
|
return MV_FALSE;
|
|
}
|
|
|
|
//Patch by QNAP:fix SATA DOM issue
|
|
/*
|
|
if (mvStorageDevATASetFeatures(pSataAdapter, channelIndex, port,
|
|
MV_ATA_SET_FEATURES_TRANSFER,
|
|
MV_ATA_TRANSFER_UDMA_5,
|
|
0,0, 0) == MV_FALSE)
|
|
{
|
|
printf("[%d %d %d]: failed to perform Enable DMA mode\n",
|
|
pSataAdapter->adapterId, channelIndex, port);
|
|
return MV_FALSE;
|
|
}
|
|
*/
|
|
if ((iden[IDEN_VALID] & MV_BIT2) == 0)
|
|
{
|
|
printf("[%d %d %d]: Unable to find UDMA Mode\n", pSataAdapter->adapterId, channelIndex, port);
|
|
return MV_FALSE;
|
|
}
|
|
else if (iden[IDEN_UDMA_MODE] & MV_BIT6)
|
|
{
|
|
UDMAMode = MV_ATA_TRANSFER_UDMA_6;
|
|
}
|
|
else if (iden[IDEN_UDMA_MODE] & MV_BIT5)
|
|
{
|
|
UDMAMode = MV_ATA_TRANSFER_UDMA_5;
|
|
}
|
|
else if (iden[IDEN_UDMA_MODE] & MV_BIT4)
|
|
{
|
|
UDMAMode = MV_ATA_TRANSFER_UDMA_4;
|
|
}
|
|
else if (iden[IDEN_UDMA_MODE] & MV_BIT3)
|
|
{
|
|
UDMAMode = MV_ATA_TRANSFER_UDMA_3;
|
|
}
|
|
else if (iden[IDEN_UDMA_MODE] & MV_BIT2)
|
|
{
|
|
UDMAMode = MV_ATA_TRANSFER_UDMA_2;
|
|
}
|
|
else if (iden[IDEN_UDMA_MODE] & MV_BIT1)
|
|
{
|
|
UDMAMode = MV_ATA_TRANSFER_UDMA_1;
|
|
}
|
|
else if (iden[IDEN_UDMA_MODE] & MV_BIT0)
|
|
{
|
|
UDMAMode = MV_ATA_TRANSFER_UDMA_0;
|
|
}
|
|
if (UDMAMode != 0 && mvStorageDevATASetFeatures(pSataAdapter, channelIndex, port,
|
|
MV_ATA_SET_FEATURES_TRANSFER,
|
|
UDMAMode,
|
|
0,0, 0) == MV_FALSE)
|
|
{
|
|
printf("[%d %d %d]: failed to perform Enable DMA mode\n",
|
|
pSataAdapter->adapterId, channelIndex, port);
|
|
return MV_FALSE;
|
|
}
|
|
/////////////////////////////////
|
|
printf("[%d %d %d]: Enable DMA mode\n", pSataAdapter->adapterId, channelIndex, port);
|
|
/* Continue parsing identify buffer*/
|
|
int device;
|
|
device=dev_desc->dev;
|
|
printf (" Device %d @ %d %d", device, pSataAdapter->adapterId, channelIndex);
|
|
if(deviceType == MV_SATA_DEVICE_TYPE_PM)
|
|
printf(" %d:\n", port);
|
|
else
|
|
printf(":\n");
|
|
|
|
ident_cpy (dev_desc->revision, iop->fw_rev, sizeof(dev_desc->revision));
|
|
ident_cpy (dev_desc->vendor, iop->model, sizeof(dev_desc->vendor));
|
|
ident_cpy (dev_desc->product, iop->serial_no, sizeof(dev_desc->product));
|
|
|
|
if ((iop->config & 0x0080)==0x0080)
|
|
dev_desc->removable = 1;
|
|
else
|
|
dev_desc->removable = 0;
|
|
|
|
#ifdef __BIG_ENDIAN
|
|
/* swap shorts */
|
|
dev_desc->lba = (iop->lba_capacity << 16) | (iop->lba_capacity >> 16);
|
|
#else /* ! __BIG_ENDIAN */
|
|
dev_desc->lba = iop->lba_capacity;
|
|
#endif /* __BIG_ENDIAN */
|
|
|
|
#ifdef CONFIG_LBA48
|
|
if (iop->command_set_2 & 0x0400) { /* LBA 48 support */
|
|
dev_desc->lba48 = 1;
|
|
dev_desc->lba = (unsigned long long)iop->lba48_capacity[0] |
|
|
((unsigned long long)iop->lba48_capacity[1] << 16) |
|
|
((unsigned long long)iop->lba48_capacity[2] << 32) |
|
|
((unsigned long long)iop->lba48_capacity[3] << 48);
|
|
} else {
|
|
dev_desc->lba48 = 0;
|
|
}
|
|
#endif /* CONFIG_LBA48 */
|
|
|
|
/* assuming HD */
|
|
dev_desc->type=DEV_TYPE_HARDDISK;
|
|
dev_desc->blksz=ATA_BLOCKSIZE;
|
|
dev_desc->lun=0; /* just to fill something in... */
|
|
|
|
return MV_TRUE;
|
|
}
|
|
|
|
void
|
|
InitChannel(
|
|
PHW_ADAPTER_DESCRIPTION HwDeviceExtension,
|
|
MV_U8 channelIndex)
|
|
{
|
|
MV_SATA_ADAPTER *pSataAdapter = &(HwDeviceExtension->mvSataAdapter);
|
|
MV_SATA_CHANNEL *pSataChannel;
|
|
|
|
pSataChannel = &HwDeviceExtension->mvSataChannels[channelIndex];
|
|
pSataAdapter->sataChannel[channelIndex] = pSataChannel;
|
|
pSataChannel->channelNumber = channelIndex;
|
|
pSataChannel->requestQueue = (struct mvDmaRequestQueueEntry *)request_q;
|
|
pSataChannel->requestQueuePciLowAddress = (MV_U32)request_q;
|
|
pSataChannel->requestQueuePciHiAddress = 0;
|
|
pSataChannel->responseQueue = (struct mvDmaResponseQueueEntry *) response_q;
|
|
pSataChannel->responseQueuePciLowAddress = (MV_U32)response_q;
|
|
pSataChannel->responseQueuePciHiAddress = 0;
|
|
}
|
|
|
|
MV_BOOLEAN
|
|
mvSataEventNotify(MV_SATA_ADAPTER *pSataAdapter, MV_EVENT_TYPE eventType,
|
|
MV_U32 param1, MV_U32 param2)
|
|
{
|
|
|
|
switch (eventType)
|
|
{
|
|
case MV_EVENT_TYPE_SATA_CABLE:
|
|
switch(param1)
|
|
{
|
|
case MV_SATA_CABLE_EVENT_CONNECT:
|
|
printf("[%d,%d]: device connected event received\n",
|
|
pSataAdapter->adapterId, param2);
|
|
break;
|
|
case MV_SATA_CABLE_EVENT_DISCONNECT:
|
|
printf("[%d,%d]: device disconnected event received \n",
|
|
pSataAdapter->adapterId, param2);
|
|
break;
|
|
case MV_SATA_CABLE_EVENT_PM_HOT_PLUG:
|
|
printf("[%d,%d]: Port Multiplier hotplug event received \n",
|
|
pSataAdapter->adapterId, param2);
|
|
break;
|
|
default:
|
|
printf( "illegal value for param1(%d) at "
|
|
"connect/disconect event, host=%d\n", param1,
|
|
pSataAdapter->adapterId );
|
|
}
|
|
break;
|
|
case MV_EVENT_TYPE_ADAPTER_ERROR:
|
|
printf("DEVICE error event received, pci cause "
|
|
"reg=%x, don't know how to handle this\n", param1);
|
|
return MV_TRUE;
|
|
case MV_EVENT_TYPE_SATA_ERROR:
|
|
switch (param1)
|
|
{
|
|
case MV_SATA_RECOVERABLE_COMMUNICATION_ERROR:
|
|
printf(" [%d %d] sata recoverable error occured\n",
|
|
pSataAdapter->adapterId, param2);
|
|
break;
|
|
case MV_SATA_UNRECOVERABLE_COMMUNICATION_ERROR:
|
|
printf(" [%d %d] sata unrecoverable error occured, restart channel\n",
|
|
pSataAdapter->adapterId, param2);
|
|
break;
|
|
case MV_SATA_DEVICE_ERROR:
|
|
printf( " [%d %d] device error occured\n",
|
|
pSataAdapter->adapterId, param2);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
printf(" adapter %d unknown event %d"
|
|
" param1= %x param2 = %x\n", pSataAdapter->adapterId,
|
|
eventType - MV_EVENT_TYPE_ADAPTER_ERROR, param1, param2);
|
|
return MV_FALSE;
|
|
|
|
}/*switch*/
|
|
|
|
return MV_TRUE;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
#define bus_to_phys(devno, a) pci_mem_to_phys(devno, a)
|
|
|
|
void ide_init (void)
|
|
{
|
|
int j, numOfDrives;
|
|
int idx = 0;
|
|
unsigned int temp, initAdapterResult, pciCommand;
|
|
unsigned short stemp;
|
|
MV_SATA_ADAPTER *pMvSataAdapter;
|
|
int devno = 0;
|
|
unsigned char channelIndex;
|
|
unsigned int numOfIdeDev = 0;
|
|
unsigned int numOfAdapters = 0;
|
|
MV_BOOLEAN integratedSataDetected = MV_FALSE;
|
|
MV_BOOLEAN integratedSataInitialized = MV_FALSE;
|
|
|
|
#ifdef MV_LOGGER
|
|
#if defined (MV_LOG_DEBUG)
|
|
mvLogRegisterModule(MV_CORE_DRIVER_LOG_ID, 0x1FF,
|
|
szModules[MV_CORE_DRIVER_LOG_ID]);
|
|
#elif defined (MV_LOG_ERROR)
|
|
mvLogRegisterModule(MV_CORE_DRIVER_LOG_ID, MV_DEBUG_ERROR,
|
|
szModules[MV_CORE_DRIVER_LOG_ID]);
|
|
#endif
|
|
#endif
|
|
printf("\nMarvell Serial ATA Adapter\n");
|
|
curr_device = -1;
|
|
|
|
memset(sataAdapters,0, sizeof(HW_ADAPTER_DESCRIPTION)*CFG_IDE_MAXBUS);
|
|
/* Init ide structure */
|
|
for(j = 0; j < CFG_IDE_MAXDEVICE; j++)
|
|
{
|
|
ide_dev_desc[j].type=DEV_TYPE_UNKNOWN;
|
|
ide_dev_desc[j].if_type=IF_TYPE_IDE;
|
|
ide_dev_desc[j].dev=j;
|
|
ide_dev_desc[j].part_type=PART_TYPE_UNKNOWN;
|
|
ide_dev_desc[j].blksz=0;
|
|
ide_dev_desc[j].lba=0;
|
|
ide_dev_desc[j].block_read=ide_read;
|
|
}
|
|
|
|
while ((numOfIdeDev < CFG_IDE_MAXDEVICE) && (numOfAdapters < CFG_IDE_MAXBUS)) {
|
|
MV_BOOLEAN integratedSataDevice = MV_FALSE;
|
|
numOfDrives = 0;
|
|
|
|
#if defined(MV_INCLUDE_INTEG_SATA)
|
|
|
|
if (integratedSataInitialized != MV_TRUE)
|
|
{
|
|
if (MV_FALSE == mvCtrlPwrClckGet(SATA_UNIT_ID, 0))
|
|
{
|
|
printf("Warning Integrated SATA is Powered Off\n");
|
|
}
|
|
else
|
|
{
|
|
integratedSataDetected = MV_TRUE;
|
|
integratedSataDevice = MV_TRUE;
|
|
|
|
mvSataWinInit();
|
|
printf("Integrated Sata device found\n");
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_PCI
|
|
if ((integratedSataDetected == MV_FALSE) ||
|
|
(integratedSataInitialized == MV_TRUE))
|
|
{
|
|
/* Find PCI device(s) */
|
|
if ((devno = pci_find_devices(supported, idx++)) < 0) {
|
|
if(!numOfAdapters) printf("no device found \n");
|
|
break;
|
|
}
|
|
}
|
|
#endif /* CONFIG_PCI */
|
|
|
|
integratedSataInitialized = MV_TRUE;
|
|
sataAdapters[numOfAdapters].devno = devno;
|
|
sataAdapters[numOfAdapters].valid = MV_TRUE;
|
|
|
|
memset (&sataAdapters[numOfAdapters].mvSataAdapter, 0, sizeof(MV_SATA_ADAPTER));
|
|
pMvSataAdapter = &sataAdapters[numOfAdapters].mvSataAdapter;
|
|
|
|
if (integratedSataDevice == MV_TRUE){
|
|
pMvSataAdapter->adapterIoBaseAddress = INTER_REGS_BASE + SATA_REG_BASE - 0x20000;
|
|
pMvSataAdapter->pciConfigDeviceId = mvCtrlModelGet();
|
|
pMvSataAdapter->pciConfigRevisionId = 0;
|
|
}
|
|
#ifdef CONFIG_PCI
|
|
else{
|
|
pci_read_config_dword(devno, PCI_BASE_ADDRESS_0 ,&temp);
|
|
pMvSataAdapter->adapterIoBaseAddress = bus_to_phys(devno, (temp & 0xfffffff0));
|
|
pci_read_config_word(devno, PCI_DEVICE_ID, &stemp);
|
|
pMvSataAdapter->pciConfigDeviceId = stemp;
|
|
pci_read_config_word(devno, PCI_REVISION_ID, &stemp);
|
|
pMvSataAdapter->pciConfigRevisionId = stemp & 0xff;
|
|
}
|
|
#endif /*CONFIG_PCI */
|
|
|
|
pMvSataAdapter->adapterId = numOfAdapters;
|
|
|
|
pMvSataAdapter->intCoalThre[0]= 4;
|
|
pMvSataAdapter->intCoalThre[1]= 4;
|
|
pMvSataAdapter->intTimeThre[0] = 150*50 ;
|
|
pMvSataAdapter->intTimeThre[1] = 150*50;
|
|
pMvSataAdapter->mvSataEventNotify = mvSataEventNotify;
|
|
pMvSataAdapter->IALData = (void *)&sataAdapters[numOfAdapters];
|
|
pMvSataAdapter->pciSerrMask = MV_PCI_SERR_MASK_REG_ENABLE_ALL;
|
|
pMvSataAdapter->pciInterruptMask = 0;
|
|
pMvSataAdapter->pciCommand = MV_PCI_COMMAND_REG_DEFAULT;
|
|
|
|
#ifdef CONFIG_PCI
|
|
if (integratedSataDevice != MV_TRUE) {
|
|
/* Enable master / IO / Memory accesses */
|
|
pci_read_config_dword(devno, PCI_COMMAND ,&pciCommand);
|
|
pci_write_config_dword(devno, PCI_COMMAND, pciCommand | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
|
|
|
|
printf("Found adapter at bus %d, device %d ... Scanning channels\n",PCI_BUS(devno), PCI_DEV(devno));
|
|
}
|
|
#endif /*CONFIG_PCI */
|
|
/* Init adapter */
|
|
initAdapterResult = mvSataInitAdapter(pMvSataAdapter);
|
|
if (initAdapterResult == MV_FALSE){
|
|
printf("Error Initializing SATA Adapter\n");
|
|
sataAdapters[numOfAdapters].valid = MV_FALSE;
|
|
numOfAdapters ++;
|
|
continue;
|
|
}
|
|
|
|
/* Enable staggered spin-up of all SATA channels */
|
|
if (mvSataEnableStaggeredSpinUpAll(pMvSataAdapter) == MV_FALSE) {
|
|
printf("Error in mvSataEnableStaggeredSpinUpAll\n");
|
|
sataAdapters[numOfAdapters].valid = MV_FALSE;
|
|
numOfAdapters ++;
|
|
continue;
|
|
}
|
|
/* when sending DMA command we poll interrupt for completion*/
|
|
mvSataUnmaskAdapterInterrupt(pMvSataAdapter);
|
|
|
|
/* find and init channels */
|
|
for (channelIndex = 0 ; channelIndex < pMvSataAdapter->numberOfChannels ; channelIndex++) {
|
|
if (mvSataIsStorageDeviceConnected(pMvSataAdapter, channelIndex, NULL) ==
|
|
MV_TRUE){
|
|
DP("Channel %x is connected ... ", channelIndex);
|
|
InitChannel(&sataAdapters[numOfAdapters], channelIndex);
|
|
if (mvSataConfigureChannel(pMvSataAdapter, channelIndex) ==
|
|
MV_FALSE)
|
|
{
|
|
printf("Error in mvSataConfigureChannel on channel %d\n",channelIndex);
|
|
pMvSataAdapter->sataChannel[channelIndex] = NULL;
|
|
numOfIdeDev++;
|
|
|
|
}
|
|
else if (StartChannel(&sataAdapters[numOfAdapters],
|
|
channelIndex) == MV_FALSE){
|
|
printf ("Failed initializing storage deivce connected "
|
|
"to SATA channel %d\n",channelIndex);
|
|
pMvSataAdapter->sataChannel[channelIndex] = NULL;
|
|
numOfIdeDev++;
|
|
}else{
|
|
int port;
|
|
MV_CHANNEL_INFO *channelInfo=&sataAdapters[numOfAdapters].channelInfo[channelIndex];
|
|
for(port = 0; port < channelInfo->numberOfPorts; port++){
|
|
if(!(channelInfo->connected & (1 << port)))
|
|
{
|
|
numOfIdeDev++;
|
|
continue;
|
|
}
|
|
|
|
if(initDisk(pMvSataAdapter, channelIndex, port, &ide_dev_desc[numOfIdeDev]) == MV_FALSE){
|
|
/* mark it as not connected */
|
|
sataAdapters[numOfAdapters].channelInfo[channelIndex].connected &= ~(1 << port);
|
|
numOfIdeDev++;
|
|
continue;
|
|
}
|
|
// printf("OK\n");
|
|
dev_print(&ide_dev_desc[numOfIdeDev]);
|
|
if ((ide_dev_desc[numOfIdeDev].lba > 0) &&
|
|
(ide_dev_desc[numOfIdeDev].blksz > 0))
|
|
{
|
|
init_part (&ide_dev_desc[numOfIdeDev]); /* initialize partition type */
|
|
if (curr_device < 0)
|
|
curr_device = numOfIdeDev;
|
|
}
|
|
numOfDrives++;
|
|
numOfIdeDev++;
|
|
}
|
|
}
|
|
}else{
|
|
pMvSataAdapter->sataChannel[channelIndex] = NULL;
|
|
sataAdapters[numOfAdapters].channelInfo[channelIndex].numberOfPorts = 1;
|
|
numOfIdeDev++;
|
|
}
|
|
|
|
}
|
|
|
|
numOfAdapters++;
|
|
}
|
|
|
|
ide_detected = numOfIdeDev;
|
|
ide_initiated=1;
|
|
|
|
putc ('\n');
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
block_dev_desc_t * ide_get_dev(int dev)
|
|
{
|
|
return ((block_dev_desc_t *)&ide_dev_desc[dev]);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
ulong ide_read_write (int device, lbaint_t blknr, ulong blkcnt, ulong *buffer, int read)
|
|
{
|
|
MV_SATA_ADAPTER *pSataAdapter = NULL;
|
|
unsigned int channelIndex = 0;
|
|
unsigned int adapter;
|
|
int port;
|
|
char *env;
|
|
|
|
/* read count is 0 no read is needed */
|
|
if(blkcnt == 0) {
|
|
return 0;
|
|
}
|
|
|
|
/* data buffer must be 2 bytes aligned */
|
|
if((long)buffer & 1) {
|
|
printf("\nide error: address (0x%08p) is not 2 bytes aligned!\n",buffer);
|
|
return 0;
|
|
}
|
|
|
|
|
|
DP("ide %s: device %x, blknr %x blkcnt %x, buffer %x\n",
|
|
((read)?"read":"write"),device, (unsigned int)blknr, blkcnt, (unsigned int)buffer);
|
|
/* find device */
|
|
for(adapter = 0 ; adapter < CFG_IDE_MAXBUS; adapter++)
|
|
{
|
|
if(sataAdapters[adapter].valid == MV_FALSE)
|
|
continue;
|
|
|
|
pSataAdapter = &(sataAdapters[adapter].mvSataAdapter);
|
|
|
|
for(channelIndex = 0; channelIndex < pSataAdapter->numberOfChannels; channelIndex++)
|
|
{
|
|
for(port = 0; port < sataAdapters[adapter].channelInfo[channelIndex].numberOfPorts; port++)
|
|
{
|
|
if(device == 0)
|
|
goto found_device;
|
|
|
|
device--;
|
|
}
|
|
}
|
|
}
|
|
|
|
found_device:
|
|
if(adapter == CFG_IDE_MAXBUS)
|
|
{
|
|
printf("Error didn't find requested device (%d).\n", device);
|
|
return 0;
|
|
}
|
|
if(pSataAdapter->sataChannel[channelIndex] == NULL)
|
|
{
|
|
printf("Error No HD connection \n");
|
|
return 0;
|
|
}
|
|
|
|
env = getenv("sata_dma_mode");
|
|
if(( (strcmp(env,"yes") == 0) || (strcmp(env,"Yes") == 0) )){
|
|
return dma_read_write(pSataAdapter, channelIndex, port,
|
|
blknr, blkcnt, buffer, read);
|
|
}else {
|
|
return pio_read_write(pSataAdapter, channelIndex, port,
|
|
blknr, blkcnt, buffer, read);
|
|
}
|
|
}
|
|
|
|
static
|
|
ulong pio_read_write (MV_SATA_ADAPTER *pSataAdapter,
|
|
unsigned int channelIndex,
|
|
MV_U8 port,
|
|
lbaint_t blknr, ulong blkcnt, ulong *buffer, int read)
|
|
{
|
|
MV_STORAGE_DEVICE_REGISTERS inATARegs;
|
|
MV_STORAGE_DEVICE_REGISTERS outATARegs;
|
|
MV_BOOLEAN isExt = MV_FALSE;
|
|
unsigned int command;
|
|
ulong blk_transferred = 0;
|
|
|
|
|
|
#if (__BE)
|
|
if(read == 0)
|
|
swapATABuffer((unsigned short *)buffer, blkcnt * ATA_SECTOR_SIZE);
|
|
#endif
|
|
|
|
/* read all blocks */
|
|
while(blkcnt > 0) {
|
|
ulong cmd_blkcnt = (blkcnt > 128 ) ? 128 : blkcnt;
|
|
|
|
/* Set transfer mode */
|
|
memset(&inATARegs, 0, sizeof(inATARegs));
|
|
memset(&outATARegs, 0, sizeof(outATARegs));
|
|
inATARegs.commandRegister = (read)? MV_ATA_COMMAND_READ_SECTORS: MV_ATA_COMMAND_WRITE_SECTORS;
|
|
inATARegs.sectorCountRegister = cmd_blkcnt;
|
|
inATARegs.lbaLowRegister = ((blknr >> 0) & 0xFF);
|
|
inATARegs.lbaMidRegister = ((blknr >> 8) & 0xFF);
|
|
inATARegs.lbaHighRegister = ((blknr >> 16) & 0xFF);
|
|
inATARegs.deviceRegister = BIT6 | ((blknr >> 24) & 0xF);
|
|
|
|
#ifdef CONFIG_LBA48
|
|
/* more than 28 bits used, use 48bit mode */
|
|
if (blknr & IDE_BLOCK_NUMBER_MASK) {
|
|
inATARegs.commandRegister = (read)? MV_ATA_COMMAND_READ_SECTORS_EXT : MV_ATA_COMMAND_WRITE_SECTORS_EXT;
|
|
inATARegs.lbaLowRegister |= ((blknr >> LBA_LOW_REG_SHIFT) & 0xFF) << 8;
|
|
inATARegs.lbaMidRegister |= ((blknr >> LBA_MID_REG_SHIFT) & 0xFF) << 8;
|
|
inATARegs.lbaHighRegister |= ((blknr >> LBA_HIGH_REG_SHIFT) & 0xFF) << 8;
|
|
inATARegs.deviceRegister = BIT6;
|
|
isExt = MV_TRUE;
|
|
}
|
|
#endif
|
|
command = (read)? MV_NON_UDMA_PROTOCOL_PIO_DATA_IN: MV_NON_UDMA_PROTOCOL_PIO_DATA_OUT;
|
|
if (mvStorageDevExecutePIO(pSataAdapter, channelIndex, port, command,
|
|
isExt, (MV_U16 *)buffer, (cmd_blkcnt * 512)/2 , &inATARegs, &outATARegs) == MV_FALSE)
|
|
{
|
|
printf("[%d %d]: %s Fail for PIO\n",
|
|
pSataAdapter->adapterId, channelIndex, ((read)?"Read":"Write"));
|
|
return 0;
|
|
}
|
|
blknr += cmd_blkcnt;
|
|
blkcnt = blkcnt - cmd_blkcnt;
|
|
buffer += (cmd_blkcnt * ATA_SECTORWORDS);
|
|
blk_transferred += cmd_blkcnt;
|
|
}
|
|
#if (__BE)
|
|
swapATABuffer((unsigned short *)buffer, blkcnt * ATA_SECTOR_SIZE);
|
|
#endif
|
|
|
|
return blk_transferred;
|
|
}
|
|
static int command_completed;
|
|
static MV_COMPLETION_TYPE completion_type;
|
|
static
|
|
MV_BOOLEAN cmd_callback(struct mvSataAdapter *pSataAdapter,
|
|
MV_U8 channel_index,
|
|
MV_COMPLETION_TYPE type,
|
|
MV_VOID_PTR command_id, MV_U16 edma_error_cause,
|
|
MV_U32 time_stamp,
|
|
struct mvStorageDevRegisters *deviceRegs){
|
|
command_completed = 1;
|
|
completion_type = type;
|
|
return MV_TRUE;
|
|
}
|
|
ulong dma_read_write (MV_SATA_ADAPTER *pSataAdapter,
|
|
unsigned int channelIndex,
|
|
MV_U8 port,
|
|
lbaint_t blknr, ulong blkcnt, ulong *buffer, int read)
|
|
{
|
|
int res = 0;
|
|
int transfered_blks = 0;
|
|
|
|
/* we use single PRD table entry (limited to 64KB - 128 sector) */
|
|
while(blkcnt){
|
|
int chunk = (blkcnt > 128) ? 128: blkcnt;
|
|
|
|
res = dma_read_write_cmd(pSataAdapter, channelIndex, port, blknr, chunk,
|
|
buffer, read) ;
|
|
|
|
if(res != chunk)
|
|
return transfered_blks;
|
|
|
|
transfered_blks += res;
|
|
buffer += res << 7; //buffer is in long
|
|
blknr += res;
|
|
blkcnt -= res;
|
|
}
|
|
return transfered_blks;
|
|
}
|
|
|
|
static
|
|
ulong dma_read_write_cmd (MV_SATA_ADAPTER *pSataAdapter,
|
|
unsigned int channelIndex,
|
|
MV_U8 port,
|
|
lbaint_t blknr, ulong blkcnt, ulong *buffer, int read)
|
|
{
|
|
MV_QUEUE_COMMAND_INFO q_cmd_info;
|
|
MV_UDMA_COMMAND_PARAMS *udmaCommand = &q_cmd_info.commandParams.udmaCommand;
|
|
MV_SATA_DEVICE_TYPE deviceType;
|
|
MV_U32 byte_count = blkcnt << 9;
|
|
MV_U32 buffer_addr = (MV_U32) buffer;
|
|
|
|
if ( blkcnt > 128){
|
|
printf("error in %s: blk count %d exceeded max limit\n",
|
|
__func__, blkcnt);
|
|
}
|
|
|
|
// mvSataDisableChannelDma(pSataAdapter, channelIndex);
|
|
/* reset the request/response pointers as we allcated one entry*/
|
|
/* but some info need to be preserved */
|
|
deviceType = mvStorageDevGetDeviceType(pSataAdapter, channelIndex);
|
|
mvSataConfigureChannel(pSataAdapter, channelIndex);
|
|
mvStorageDevSetDeviceType(pSataAdapter, channelIndex,deviceType);
|
|
mvSataConfigEdmaMode(pSataAdapter, channelIndex,
|
|
MV_EDMA_MODE_NOT_QUEUED, 2);
|
|
mvSataEnableChannelDma(pSataAdapter, channelIndex);
|
|
|
|
|
|
memset(&q_cmd_info, 0, sizeof(MV_QUEUE_COMMAND_INFO));
|
|
memset(prd_table, 0, 2 * sizeof(MV_SATA_EDMA_PRD_ENTRY));
|
|
|
|
/* buffer must not cross address decode window */
|
|
if(((buffer_addr & MRVL_SATA_BOUNDARY_MASK) + byte_count) > MRVL_SATA_BUFF_BOUNDARY)
|
|
{
|
|
MV_U32 chunk_len = MRVL_SATA_BUFF_BOUNDARY -
|
|
(buffer_addr & MRVL_SATA_BOUNDARY_MASK);
|
|
|
|
memset(prd_table + 1, 0, sizeof(MV_SATA_EDMA_PRD_ENTRY));
|
|
prd_table[0].lowBaseAddr = cpu_to_le32(buffer_addr);
|
|
prd_table[0].byteCount = cpu_to_le16(chunk_len & 0xFFFF);
|
|
|
|
byte_count -= chunk_len;
|
|
buffer_addr += chunk_len;
|
|
prd_table[1].lowBaseAddr = cpu_to_le32(buffer_addr);
|
|
prd_table[1].byteCount = cpu_to_le16(byte_count & 0xFFFF);
|
|
prd_table[1].flags = cpu_to_le16(MV_EDMA_PRD_EOT_FLAG);
|
|
|
|
}
|
|
else
|
|
{
|
|
prd_table[0].lowBaseAddr = cpu_to_le32(buffer_addr);
|
|
prd_table[0].byteCount = cpu_to_le16(byte_count & 0xFFFF);
|
|
prd_table[0].flags = cpu_to_le16(MV_EDMA_PRD_EOT_FLAG);
|
|
}
|
|
|
|
q_cmd_info.type = MV_QUEUED_COMMAND_TYPE_UDMA;
|
|
q_cmd_info.PMPort = port;
|
|
udmaCommand->readWrite = (read)? MV_UDMA_TYPE_READ : MV_UDMA_TYPE_WRITE;
|
|
udmaCommand->isEXT = MV_FALSE;
|
|
|
|
#ifdef CONFIG_LBA48
|
|
/* more than 28 bits used, use 48bit mode */
|
|
if (blknr & IDE_BLOCK_NUMBER_MASK) {
|
|
udmaCommand->isEXT = MV_TRUE;
|
|
}
|
|
#endif
|
|
|
|
udmaCommand->FUA = MV_FALSE;
|
|
udmaCommand->lowLBAAddress = blknr & 0xFFFFFFFF;
|
|
udmaCommand->highLBAAddress = (blknr >> 32 )& 0xFFFFFFFF;
|
|
udmaCommand->numOfSectors = blkcnt;
|
|
udmaCommand->prdLowAddr = (MV_U32)prd_table;
|
|
udmaCommand->callBack = cmd_callback;
|
|
#if 0
|
|
printf("send dma command: %s lba %x sect %x addr %x\n", read?"read":"write",
|
|
udmaCommand->lowLBAAddress, udmaCommand->numOfSectors,
|
|
prd_table[0].lowBaseAddr);
|
|
#endif
|
|
command_completed = 0;
|
|
if(mvSataQueueCommand(pSataAdapter,
|
|
channelIndex,
|
|
&q_cmd_info) != MV_QUEUE_COMMAND_RESULT_OK){
|
|
printf("error in mv_ide: queue command failed\n");
|
|
mvSataDisableChannelDma(pSataAdapter, channelIndex);
|
|
return 0;
|
|
}
|
|
|
|
do{
|
|
mvSataInterruptServiceRoutine(pSataAdapter);
|
|
udelay(1000);
|
|
|
|
}while(!command_completed);
|
|
|
|
mvSataDisableChannelDma(pSataAdapter, channelIndex);
|
|
if(completion_type == MV_COMPLETION_TYPE_NORMAL)
|
|
return blkcnt;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
#if (__BE)
|
|
void swapATABuffer(unsigned short *buffer, ulong count)
|
|
{
|
|
count >>= 1;
|
|
while(count--)
|
|
{
|
|
buffer[count] = MV_CPU_TO_LE16(buffer[count]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ulong ide_read (int device, lbaint_t blknr, ulong blkcnt, ulong *buffer)
|
|
{
|
|
return ide_read_write (device, blknr, blkcnt, buffer, MV_TRUE);
|
|
}
|
|
|
|
ulong ide_write (int device, lbaint_t blknr, ulong blkcnt, ulong *buffer)
|
|
{
|
|
return ide_read_write (device, blknr, blkcnt, buffer, MV_FALSE);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* copy src to dest, skipping leading and trailing blanks and null
|
|
* terminate the string
|
|
* "len" is the size of available memory including the terminating '\0'
|
|
*/
|
|
static void ident_cpy (unsigned char *dst, unsigned char *src, unsigned int len)
|
|
{
|
|
unsigned char *end, *last;
|
|
|
|
last = dst;
|
|
|
|
/* Make sure lenis multiple of 2 + 1 for '\0'*/
|
|
if( !(len % 2) || (len == 0))
|
|
goto OUT;
|
|
|
|
end = src + len - 1;
|
|
|
|
while ((*src) && (src<end)) {
|
|
if(((unsigned int)src % 2) == 0)
|
|
{
|
|
#if defined(__BE)
|
|
*dst = *src;
|
|
#else
|
|
*(dst+1) = *src;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(__BE)
|
|
*(dst+1) = *src;
|
|
#else
|
|
*dst = *src;
|
|
#endif
|
|
|
|
dst+=2;
|
|
last = dst;
|
|
|
|
}
|
|
src++;
|
|
}
|
|
OUT:
|
|
*last = '\0';
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
|
U_BOOT_CMD(
|
|
ide, 5, 1, do_ide,
|
|
"ide - IDE sub-system\n",
|
|
"reset - reset IDE controller\n"
|
|
"ide info - show available IDE devices\n"
|
|
"ide device [dev] - show or set current device\n"
|
|
"ide part [dev] - print partition table of one or all IDE devices\n"
|
|
"ide read addr blk# cnt\n"
|
|
"ide write addr blk# cnt - read/write `cnt'"
|
|
" blocks starting at block `blk#'\n"
|
|
" to/from memory address `addr'\n"
|
|
);
|
|
|
|
U_BOOT_CMD(
|
|
diskboot, 3, 1, do_diskboot,
|
|
"diskboot- boot from IDE device\n",
|
|
"loadAddr dev:part\n"
|
|
);
|
|
|
|
#endif /* CONFIG_COMMANDS & CFG_CMD_IDE */
|