| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714 | // SPDX-License-Identifier: GPL-2.0+/* * Copyright (C) 2011 Freescale Semiconductor, Inc. * Author: Tang Yuantian <b29983@freescale.com> */#include <common.h>#include <pci.h>#include <command.h>#include <asm/byteorder.h>#include <malloc.h>#include <asm/io.h>#include <fis.h>#include <sata.h>#include <libata.h>#include <sata.h>#include "sata_sil.h"/* Convert sectorsize to wordsize */#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2)#define virt_to_bus(devno, v)	pci_virt_to_mem(devno, (void *) (v))static struct sata_info sata_info;static struct pci_device_id supported[] = {	{PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3131},	{PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3132},	{PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3124},	{}};static void sil_sata_dump_fis(struct sata_fis_d2h *s){	printf("Status FIS dump:\n");	printf("fis_type:		%02x\n", s->fis_type);	printf("pm_port_i:		%02x\n", s->pm_port_i);	printf("status:			%02x\n", s->status);	printf("error:			%02x\n", s->error);	printf("lba_low:		%02x\n", s->lba_low);	printf("lba_mid:		%02x\n", s->lba_mid);	printf("lba_high:		%02x\n", s->lba_high);	printf("device:			%02x\n", s->device);	printf("lba_low_exp:		%02x\n", s->lba_low_exp);	printf("lba_mid_exp:		%02x\n", s->lba_mid_exp);	printf("lba_high_exp:		%02x\n", s->lba_high_exp);	printf("res1:			%02x\n", s->res1);	printf("sector_count:		%02x\n", s->sector_count);	printf("sector_count_exp:	%02x\n", s->sector_count_exp);}static const char *sata_spd_string(unsigned int speed){	static const char * const spd_str[] = {		"1.5 Gbps",		"3.0 Gbps",		"6.0 Gbps",	};	if ((speed - 1) > 2)		return "<unknown>";	return spd_str[speed - 1];}static u32 ata_wait_register(void *reg, u32 mask,			 u32 val, int timeout_msec){	u32 tmp;	tmp = readl(reg);	while ((tmp & mask) == val && timeout_msec > 0) {		mdelay(1);		timeout_msec--;		tmp = readl(reg);	}	return tmp;}static void sil_config_port(void *port){	/* configure IRQ WoC */	writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);	/* zero error counters. */	writew(0x8000, port + PORT_DECODE_ERR_THRESH);	writew(0x8000, port + PORT_CRC_ERR_THRESH);	writew(0x8000, port + PORT_HSHK_ERR_THRESH);	writew(0x0000, port + PORT_DECODE_ERR_CNT);	writew(0x0000, port + PORT_CRC_ERR_CNT);	writew(0x0000, port + PORT_HSHK_ERR_CNT);	/* always use 64bit activation */	writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);	/* clear port multiplier enable and resume bits */	writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);}static int sil_init_port(void *port){	u32 tmp;	writel(PORT_CS_INIT, port + PORT_CTRL_STAT);	ata_wait_register(port + PORT_CTRL_STAT,			  PORT_CS_INIT, PORT_CS_INIT, 100);	tmp = ata_wait_register(port + PORT_CTRL_STAT,				PORT_CS_RDY, 0, 100);	if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)		return 1;	return 0;}static void sil_read_fis(int dev, int tag, struct sata_fis_d2h *fis){	struct sil_sata *sata = sata_dev_desc[dev].priv;	void *port = sata->port;	struct sil_prb *prb;	int i;	u32 *src, *dst;	prb = port + PORT_LRAM + tag * PORT_LRAM_SLOT_SZ;	src = (u32 *)&prb->fis;	dst = (u32 *)fis;	for (i = 0; i < sizeof(struct sata_fis_h2d); i += 4)		*dst++ = readl(src++);}static int sil_exec_cmd(int dev, struct sil_cmd_block *pcmd, int tag){	struct sil_sata *sata = sata_dev_desc[dev].priv;	void *port = sata->port;	u64 paddr = virt_to_bus(sata->devno, pcmd);	u32 irq_mask, irq_stat;	int rc;	writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);	/* better to add momery barrior here */	writel((u32)paddr, port + PORT_CMD_ACTIVATE + tag * 8);	writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + tag * 8 + 4);	irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;	irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask,			0, 10000);	/* clear IRQs */	writel(irq_mask, port + PORT_IRQ_STAT);	irq_stat >>= PORT_IRQ_RAW_SHIFT;	if (irq_stat & PORT_IRQ_COMPLETE)		rc = 0;	else {		/* force port into known state */		sil_init_port(port);		if (irq_stat & PORT_IRQ_ERROR)			rc = 1; /* error */		else			rc = 2; /* busy */	}	return rc;}static int sil_cmd_set_feature(int dev){	struct sil_sata *sata = sata_dev_desc[dev].priv;	struct sil_cmd_block cmdb, *pcmd = &cmdb;	struct sata_fis_d2h fis;	u8 udma_cap;	int ret;	memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block));	pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;	pcmd->prb.fis.pm_port_c = (1 << 7);	pcmd->prb.fis.command = ATA_CMD_SET_FEATURES;	pcmd->prb.fis.features = SETFEATURES_XFER;	/* First check the device capablity */	udma_cap = (u8)(sata->udma & 0xff);	debug("udma_cap %02x\n", udma_cap);	if (udma_cap == ATA_UDMA6)		pcmd->prb.fis.sector_count = XFER_UDMA_6;	if (udma_cap == ATA_UDMA5)		pcmd->prb.fis.sector_count = XFER_UDMA_5;	if (udma_cap == ATA_UDMA4)		pcmd->prb.fis.sector_count = XFER_UDMA_4;	if (udma_cap == ATA_UDMA3)		pcmd->prb.fis.sector_count = XFER_UDMA_3;	ret = sil_exec_cmd(dev, pcmd, 0);	if (ret) {		sil_read_fis(dev, 0, &fis);		printf("Err: exe cmd(0x%x).\n",				readl(sata->port + PORT_SERROR));		sil_sata_dump_fis(&fis);		return 1;	}	return 0;}static int sil_cmd_identify_device(int dev, u16 *id){	struct sil_sata *sata = sata_dev_desc[dev].priv;	struct sil_cmd_block cmdb, *pcmd = &cmdb;	struct sata_fis_d2h fis;	int ret;	memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block));	pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL);	pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ);	pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;	pcmd->prb.fis.pm_port_c = (1 << 7);	pcmd->prb.fis.command = ATA_CMD_ID_ATA;	pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, id));	pcmd->sge.cnt = cpu_to_le32(sizeof(id[0]) * ATA_ID_WORDS);	pcmd->sge.flags = cpu_to_le32(SGE_TRM);	ret = sil_exec_cmd(dev, pcmd, 0);	if (ret) {		sil_read_fis(dev, 0, &fis);		printf("Err: id cmd(0x%x).\n", readl(sata->port + PORT_SERROR));		sil_sata_dump_fis(&fis);		return 1;	}	ata_swap_buf_le16(id, ATA_ID_WORDS);	return 0;}static int sil_cmd_soft_reset(int dev){	struct sil_cmd_block cmdb, *pcmd = &cmdb;	struct sil_sata *sata = sata_dev_desc[dev].priv;	struct sata_fis_d2h fis;	void *port = sata->port;	int ret;	/* put the port into known state */	if (sil_init_port(port)) {		printf("SRST: port %d not ready\n", dev);		return 1;	}	memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block));	pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_SRST);	pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;	pcmd->prb.fis.pm_port_c = 0xf;	ret = sil_exec_cmd(dev, &cmdb, 0);	if (ret) {		sil_read_fis(dev, 0, &fis);		printf("SRST cmd error.\n");		sil_sata_dump_fis(&fis);		return 1;	}	return 0;}static ulong sil_sata_rw_cmd(int dev, ulong start, ulong blkcnt,		u8 *buffer, int is_write){	struct sil_sata *sata = sata_dev_desc[dev].priv;	struct sil_cmd_block cmdb, *pcmd = &cmdb;	struct sata_fis_d2h fis;	u64 block;	int ret;	block = (u64)start;	memset(pcmd, 0, sizeof(struct sil_cmd_block));	pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL);	pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;	pcmd->prb.fis.pm_port_c = (1 << 7);	if (is_write) {		pcmd->prb.fis.command = ATA_CMD_WRITE;		pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE);	} else {		pcmd->prb.fis.command = ATA_CMD_READ;		pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ);	}	pcmd->prb.fis.device = ATA_LBA;	pcmd->prb.fis.device |= (block >> 24) & 0xf;	pcmd->prb.fis.lba_high = (block >> 16) & 0xff;	pcmd->prb.fis.lba_mid = (block >> 8) & 0xff;	pcmd->prb.fis.lba_low = block & 0xff;	pcmd->prb.fis.sector_count = (u8)blkcnt & 0xff;	pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer));	pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE);	pcmd->sge.flags = cpu_to_le32(SGE_TRM);	ret = sil_exec_cmd(dev, pcmd, 0);	if (ret) {		sil_read_fis(dev, 0, &fis);		printf("Err: rw cmd(0x%08x).\n",				readl(sata->port + PORT_SERROR));		sil_sata_dump_fis(&fis);		return 1;	}	return blkcnt;}static ulong sil_sata_rw_cmd_ext(int dev, ulong start, ulong blkcnt,		u8 *buffer, int is_write){	struct sil_sata *sata = sata_dev_desc[dev].priv;	struct sil_cmd_block cmdb, *pcmd = &cmdb;	struct sata_fis_d2h fis;	u64 block;	int ret;	block = (u64)start;	memset(pcmd, 0, sizeof(struct sil_cmd_block));	pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL);	pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;	pcmd->prb.fis.pm_port_c = (1 << 7);	if (is_write) {		pcmd->prb.fis.command = ATA_CMD_WRITE_EXT;		pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE);	} else {		pcmd->prb.fis.command = ATA_CMD_READ_EXT;		pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ);	}	pcmd->prb.fis.lba_high_exp = (block >> 40) & 0xff;	pcmd->prb.fis.lba_mid_exp = (block >> 32) & 0xff;	pcmd->prb.fis.lba_low_exp = (block >> 24) & 0xff;	pcmd->prb.fis.lba_high = (block >> 16) & 0xff;	pcmd->prb.fis.lba_mid = (block >> 8) & 0xff;	pcmd->prb.fis.lba_low = block & 0xff;	pcmd->prb.fis.device = ATA_LBA;	pcmd->prb.fis.sector_count_exp = (blkcnt >> 8) & 0xff;	pcmd->prb.fis.sector_count = blkcnt & 0xff;	pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer));	pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE);	pcmd->sge.flags = cpu_to_le32(SGE_TRM);	ret = sil_exec_cmd(dev, pcmd, 0);	if (ret) {		sil_read_fis(dev, 0, &fis);		printf("Err: rw ext cmd(0x%08x).\n",				readl(sata->port + PORT_SERROR));		sil_sata_dump_fis(&fis);		return 1;	}	return blkcnt;}static ulong sil_sata_rw_lba28(int dev, ulong blknr, lbaint_t blkcnt,			       const void *buffer, int is_write){	ulong start, blks, max_blks;	u8 *addr;	start = blknr;	blks = blkcnt;	addr = (u8 *)buffer;	max_blks = ATA_MAX_SECTORS;	do {		if (blks > max_blks) {			sil_sata_rw_cmd(dev, start, max_blks, addr, is_write);			start += max_blks;			blks -= max_blks;			addr += ATA_SECT_SIZE * max_blks;		} else {			sil_sata_rw_cmd(dev, start, blks, addr, is_write);			start += blks;			blks = 0;			addr += ATA_SECT_SIZE * blks;		}	} while (blks != 0);	return blkcnt;}static ulong sil_sata_rw_lba48(int dev, ulong blknr, lbaint_t blkcnt,			       const void *buffer, int is_write){	ulong start, blks, max_blks;	u8 *addr;	start = blknr;	blks = blkcnt;	addr = (u8 *)buffer;	max_blks = ATA_MAX_SECTORS_LBA48;	do {		if (blks > max_blks) {			sil_sata_rw_cmd_ext(dev, start, max_blks,					addr, is_write);			start += max_blks;			blks -= max_blks;			addr += ATA_SECT_SIZE * max_blks;		} else {			sil_sata_rw_cmd_ext(dev, start, blks,					addr, is_write);			start += blks;			blks = 0;			addr += ATA_SECT_SIZE * blks;		}	} while (blks != 0);	return blkcnt;}static void sil_sata_cmd_flush_cache(int dev){	struct sil_cmd_block cmdb, *pcmd = &cmdb;	memset((void *)pcmd, 0, sizeof(struct sil_cmd_block));	pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;	pcmd->prb.fis.pm_port_c = (1 << 7);	pcmd->prb.fis.command = ATA_CMD_FLUSH;	sil_exec_cmd(dev, pcmd, 0);}static void sil_sata_cmd_flush_cache_ext(int dev){	struct sil_cmd_block cmdb, *pcmd = &cmdb;	memset((void *)pcmd, 0, sizeof(struct sil_cmd_block));	pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;	pcmd->prb.fis.pm_port_c = (1 << 7);	pcmd->prb.fis.command = ATA_CMD_FLUSH_EXT;	sil_exec_cmd(dev, pcmd, 0);}static void sil_sata_init_wcache(int dev, u16 *id){	struct sil_sata *sata = sata_dev_desc[dev].priv;	if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id))		sata->wcache = 1;	if (ata_id_has_flush(id))		sata->flush = 1;	if (ata_id_has_flush_ext(id))		sata->flush_ext = 1;}static int sil_sata_get_wcache(int dev){	struct sil_sata *sata = sata_dev_desc[dev].priv;	return sata->wcache;}static int sil_sata_get_flush(int dev){	struct sil_sata *sata = sata_dev_desc[dev].priv;	return sata->flush;}static int sil_sata_get_flush_ext(int dev){	struct sil_sata *sata = sata_dev_desc[dev].priv;	return sata->flush_ext;}/* * SATA interface between low level driver and command layer */ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer){	struct sil_sata *sata = sata_dev_desc[dev].priv;	ulong rc;	if (sata->lba48)		rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD);	else		rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD);	return rc;}/* * SATA interface between low level driver and command layer */ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer){	struct sil_sata *sata = sata_dev_desc[dev].priv;	ulong rc;	if (sata->lba48) {		rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD);		if (sil_sata_get_wcache(dev) && sil_sata_get_flush_ext(dev))			sil_sata_cmd_flush_cache_ext(dev);	} else {		rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD);		if (sil_sata_get_wcache(dev) && sil_sata_get_flush(dev))			sil_sata_cmd_flush_cache(dev);	}	return rc;}/* * SATA interface between low level driver and command layer */int init_sata(int dev){	static int init_done, idx;	pci_dev_t devno;	u16 word;	if (init_done == 1 && dev < sata_info.maxport)		return 0;	init_done = 1;	/* Find PCI device(s) */	devno = pci_find_devices(supported, idx++);	if (devno == -1)		return 1;	pci_read_config_word(devno, PCI_DEVICE_ID, &word);	/* get the port count */	word &= 0xf;	sata_info.portbase = sata_info.maxport;	sata_info.maxport = sata_info.portbase + word;	sata_info.devno = devno;	/* Read out all BARs */	sata_info.iobase[0] = (ulong)pci_map_bar(devno,			PCI_BASE_ADDRESS_0, PCI_REGION_MEM);	sata_info.iobase[1] = (ulong)pci_map_bar(devno,			PCI_BASE_ADDRESS_2, PCI_REGION_MEM);	sata_info.iobase[2] = (ulong)pci_map_bar(devno,			PCI_BASE_ADDRESS_4, PCI_REGION_MEM);	/* mask out the unused bits */	sata_info.iobase[0] &= 0xffffff80;	sata_info.iobase[1] &= 0xfffffc00;	sata_info.iobase[2] &= 0xffffff80;	/* Enable Bus Mastering and memory region */	pci_write_config_word(devno, PCI_COMMAND,			PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);	/* Check if mem accesses and Bus Mastering are enabled. */	pci_read_config_word(devno, PCI_COMMAND, &word);	if (!(word & PCI_COMMAND_MEMORY) ||			(!(word & PCI_COMMAND_MASTER))) {		printf("Error: Can not enable MEM access or Bus Mastering.\n");		debug("PCI command: %04x\n", word);		return 1;	}	/* GPIO off */	writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD));	/* clear global reset & mask interrupts during initialization */	writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL));	return 0;}int reset_sata(int dev){	return 0;}/* * SATA interface between low level driver and command layer */int scan_sata(int dev){	unsigned char serial[ATA_ID_SERNO_LEN + 1];	unsigned char firmware[ATA_ID_FW_REV_LEN + 1];	unsigned char product[ATA_ID_PROD_LEN + 1];	struct sil_sata *sata;	void *port;	int cnt;	u16 *id;	u32 tmp;	if (dev >= sata_info.maxport) {		printf("SATA#%d is not present\n", dev);		return 1;	}	printf("SATA#%d\n", dev);	port = (void *)sata_info.iobase[1] +		PORT_REGS_SIZE * (dev - sata_info.portbase);	/* Initial PHY setting */	writel(0x20c, port + PORT_PHY_CFG);	/* clear port RST */	tmp = readl(port + PORT_CTRL_STAT);	if (tmp & PORT_CS_PORT_RST) {		writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);		tmp = ata_wait_register(port + PORT_CTRL_STAT,				PORT_CS_PORT_RST, PORT_CS_PORT_RST, 100);		if (tmp & PORT_CS_PORT_RST)			printf("Err: Failed to clear port RST\n");	}	/* Check if device is present */	for (cnt = 0; cnt < 100; cnt++) {		tmp = readl(port + PORT_SSTATUS);		if ((tmp & 0xF) == 0x3)			break;		mdelay(1);	}	tmp = readl(port + PORT_SSTATUS);	if ((tmp & 0xf) != 0x3) {		printf("	(No RDY)\n");		return 1;	}	/* Wait for port ready */	tmp = ata_wait_register(port + PORT_CTRL_STAT,				PORT_CS_RDY, PORT_CS_RDY, 100);	if ((tmp & PORT_CS_RDY) != PORT_CS_RDY) {		printf("%d port not ready.\n", dev);		return 1;	}	/* configure port */	sil_config_port(port);	/* Reset port */	writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);	readl(port + PORT_CTRL_STAT);	tmp = ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_DEV_RST,				PORT_CS_DEV_RST, 100);	if (tmp & PORT_CS_DEV_RST) {		printf("%d port reset failed.\n", dev);		return 1;	}	sata = (struct sil_sata *)malloc(sizeof(struct sil_sata));	if (!sata) {		printf("%d no memory.\n", dev);		return 1;	}	memset((void *)sata, 0, sizeof(struct sil_sata));	/* turn on port interrupt */	tmp = readl((void *)(sata_info.iobase[0] + HOST_CTRL));	tmp |= (1 << (dev - sata_info.portbase));	writel(tmp, (void *)(sata_info.iobase[0] + HOST_CTRL));	/* Save the private struct to block device struct */	sata_dev_desc[dev].priv = (void *)sata;	sata->port = port;	sata->devno = sata_info.devno;	sprintf(sata->name, "SATA#%d", dev);	sil_cmd_soft_reset(dev);	tmp = readl(port + PORT_SSTATUS);	tmp = (tmp >> 4) & 0xf;	printf("	(%s)\n", sata_spd_string(tmp));	id = (u16 *)malloc(ATA_ID_WORDS * 2);	if (!id) {		printf("Id malloc failed\n");		free((void *)sata);		return 1;	}	sil_cmd_identify_device(dev, id);#ifdef CONFIG_LBA48	/* Check if support LBA48 */	if (ata_id_has_lba48(id)) {		sata_dev_desc[dev].lba48 = 1;		sata->lba48 = 1;		debug("Device supports LBA48\n");	} else		debug("Device supports LBA28\n");#endif	/* Serial number */	ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));	memcpy(sata_dev_desc[dev].product, serial, sizeof(serial));	/* Firmware version */	ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));	memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware));	/* Product model */	ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));	memcpy(sata_dev_desc[dev].vendor, product, sizeof(product));	/* Totoal sectors */	sata_dev_desc[dev].lba = ata_id_n_sectors(id);	sil_sata_init_wcache(dev, id);	sil_cmd_set_feature(dev);#ifdef DEBUG	sil_cmd_identify_device(dev, id);	ata_dump_id(id);#endif	free((void *)id);	return 0;}
 |