All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] add ahci support into qemu
@ 2010-04-30 12:48 乔崇
  2010-05-02  8:05 ` Alexander Graf
  0 siblings, 1 reply; 17+ messages in thread
From: 乔崇 @ 2010-04-30 12:48 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 287 bytes --]

Hi,everyone!
I just add AHCI Emulation into qemu.
I have tested it on linux kernel,it works well.
run like this:
qemu -hda disk ...

Now only support sata disk.

-- 

乔崇 qiaochong.ac.cn
龙芯技术服务中心
office:010-62600855-108
mobile:13521990614

2009年 11月 16日 星期一 10:31:04 CST


[-- Attachment #2: ahci.c --]
[-- Type: text/x-csrc, Size: 21266 bytes --]

/*
 * QEMU AHCI Emulation
 * Copyright (c) 2010 qiaochong@loongson.cn
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 *
 * TODO:
 *  o ahci cd support
*/
#include "hw.h"
#include "qemu-timer.h"
#include "monitor.h"
#include "pci.h"
#include "dma.h"
#include "cpu-common.h"
#include <hw/ide/internal.h>
#define DPRINTF(...) //printf
typedef struct ahci_control_regs {
uint32_t  cap;
uint32_t  ghc;
uint32_t  irqstatus;
uint32_t  impl;
uint32_t  version;
} ahci_control_regs;

typedef struct ahci_port_regs {
uint32_t lst_addr;
uint32_t lst_addr_hi;
uint32_t fis_addr;
uint32_t fis_addr_hi;
uint32_t irq_stat;
uint32_t irq_mask;
uint32_t cmd;
uint32_t unused0;
uint32_t tfdata;
uint32_t sig;
uint32_t scr_stat;
uint32_t scr_ctl;
uint32_t scr_err;
uint32_t scr_act;
uint32_t cmd_issue;
} ahci_port_regs; 

typedef struct AHCIState{
ahci_control_regs control_regs;
ahci_port_regs port_regs[2];
int mem;
QEMUTimer *timer;
IDEBus *ide;
qemu_irq irq;
} AHCIState;


enum {
	AHCI_PCI_BAR		= 5,
	AHCI_MAX_PORTS		= 32,
	AHCI_MAX_SG		= 168, /* hardware max is 64K */
	AHCI_DMA_BOUNDARY	= 0xffffffff,
	AHCI_USE_CLUSTERING	= 0,
	AHCI_MAX_CMDS		= 32,
	AHCI_CMD_SZ		= 32,
	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
	AHCI_RX_FIS_SZ		= 256,
	AHCI_CMD_TBL_CDB	= 0x40,
	AHCI_CMD_TBL_HDR_SZ	= 0x80,
	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
				  AHCI_RX_FIS_SZ,
	AHCI_IRQ_ON_SG		= (1 << 31),
	AHCI_CMD_ATAPI		= (1 << 5),
	AHCI_CMD_WRITE		= (1 << 6),
	AHCI_CMD_PREFETCH	= (1 << 7),
	AHCI_CMD_RESET		= (1 << 8),
	AHCI_CMD_CLR_BUSY	= (1 << 10),

	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */

	board_ahci		= 0,
	board_ahci_pi		= 1,
	board_ahci_vt8251	= 2,
	board_ahci_ign_iferr	= 3,
	board_ahci_sb600	= 4,

	/* global controller registers */
	HOST_CAP		= 0x00, /* host capabilities */
	HOST_CTL		= 0x04, /* global host control */
	HOST_IRQ_STAT		= 0x08, /* interrupt status */
	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */

	/* HOST_CTL bits */
	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */

	/* HOST_CAP bits */
	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */

	/* registers for each SATA port */
	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
	PORT_IRQ_STAT		= 0x10, /* interrupt status */
	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
	PORT_CMD		= 0x18, /* port command */
	PORT_TFDATA		= 0x20,	/* taskfile data */
	PORT_SIG		= 0x24,	/* device TF signature */
	PORT_CMD_ISSUE		= 0x38, /* command issue */
	PORT_SCR		= 0x28, /* SATA phy register block */
	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */

	/* PORT_IRQ_{STAT,MASK} bits */
	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */

	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */

	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
				  PORT_IRQ_IF_ERR |
				  PORT_IRQ_CONNECT |
				  PORT_IRQ_PHYRDY |
				  PORT_IRQ_UNK_FIS,
	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
				  PORT_IRQ_TF_ERR |
				  PORT_IRQ_HBUS_DATA_ERR,
	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,

	/* PORT_CMD bits */
	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
	PORT_CMD_CLO		= (1 << 3), /* Command list override */
	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */

	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */

	/* ap->flags bits */
	AHCI_FLAG_NO_NCQ		= (1 << 24),
	AHCI_FLAG_IGN_IRQ_IF_ERR	= (1 << 25), /* ignore IRQ_IF_ERR */
	AHCI_FLAG_HONOR_PI		= (1 << 26), /* honor PORTS_IMPL */
	AHCI_FLAG_IGN_SERR_INTERNAL	= (1 << 27), /* ignore SERR_INTERNAL */
	AHCI_FLAG_32BIT_ONLY		= (1 << 28), /* force 32bit */
};

/*
 * ATA Commands (only mandatory commands listed here)
 */
#define ATA_CMD_READ	0x20	/* Read Sectors (with retries)	*/
#define ATA_CMD_READN	0x21	/* Read Sectors ( no  retries)	*/
#define ATA_CMD_WRITE	0x30	/* Write Sectores (with retries)*/
#define ATA_CMD_WRITEN	0x31	/* Write Sectors  ( no  retries)*/
#define ATA_CMD_VRFY	0x40	/* Read Verify  (with retries)	*/
#define ATA_CMD_VRFYN	0x41	/* Read verify  ( no  retries)	*/
#define ATA_CMD_SEEK	0x70	/* Seek				*/
#define ATA_CMD_DIAG	0x90	/* Execute Device Diagnostic	*/
#define ATA_CMD_INIT	0x91	/* Initialize Device Parameters	*/
#define ATA_CMD_RD_MULT	0xC4	/* Read Multiple		*/
#define ATA_CMD_WR_MULT	0xC5	/* Write Multiple		*/
#define ATA_CMD_SETMULT	0xC6	/* Set Multiple Mode		*/
#define ATA_CMD_RD_DMA	0xC8	/* Read DMA (with retries)	*/
#define ATA_CMD_RD_DMAN	0xC9	/* Read DMS ( no  retries)	*/
#define ATA_CMD_WR_DMA	0xCA	/* Write DMA (with retries)	*/
#define ATA_CMD_WR_DMAN	0xCB	/* Write DMA ( no  retires)	*/
#define ATA_CMD_IDENT	0xEC	/* Identify Device		*/
#define ATA_CMD_SETF	0xEF	/* Set Features			*/
#define ATA_CMD_CHK_PWR	0xE5	/* Check Power Mode		*/

#define ATA_CMD_READ_EXT 0x24	/* Read Sectors (with retries)	with 48bit addressing */
#define ATA_CMD_WRITE_EXT	0x34	/* Write Sectores (with retries) with 48bit addressing */
#define ATA_CMD_VRFY_EXT	0x42	/* Read Verify	(with retries)	with 48bit addressing */

/*
 * ATAPI Commands
 */
#define ATAPI_CMD_IDENT 0xA1 /* Identify AT Atachment Packed Interface Device */
#define ATAPI_CMD_PACKET 0xA0 /* Packed Command */


#define ATAPI_CMD_INQUIRY 0x12
#define ATAPI_CMD_REQ_SENSE 0x03
#define ATAPI_CMD_READ_CAP 0x25
#define ATAPI_CMD_START_STOP 0x1B
#define ATAPI_CMD_READ_12 0xA8
typedef struct ahci_cmd_hdr {
	uint32_t			opts;
	uint32_t			status;
	uint32_t			tbl_addr;
	uint32_t			tbl_addr_hi;
	uint32_t			reserved[4];
} ahci_cmd_hdr;

typedef struct ahci_sg {
	uint32_t			addr;
	uint32_t			addr_hi;
	uint32_t			reserved;
	uint32_t			flags_size;
} ahci_sg;

struct ahci_pci_state {
    PCIDevice card;
	AHCIState *ahci;
};


static uint32_t  ahci_port_read(AHCIState *s,int port,int offset)
{
uint32_t val;
	uint32_t *p;
	ahci_port_regs *pr;
	pr=&s->port_regs[port];

		switch(offset)
		{
	   case PORT_SCR:
		if(s->ide && port==0) val=3;
		else val=0;
		break;
	   case PORT_IRQ_STAT:
		val=pr->irq_stat;
		break;
	   case PORT_TFDATA:

	   case PORT_SIG:

	   case PORT_CMD_ISSUE:


	   case PORT_SCR_CTL:

	   case PORT_SCR_ERR:

	   case PORT_SCR_ACT:
		default:
			p=&s->port_regs[port];
			val= p[offset>>2];
			break;
		}
	return val;
	
}

void ahci_check_irq(AHCIState *s)
{
	ahci_port_regs *pr;
	int i;
	for(i=0;i<2;i++)
	{
	pr=&s->port_regs[i];

	if(pr->irq_stat&pr->irq_mask){
		s->control_regs.irqstatus |= (1<<i);
	}
	}
	
	if(s->control_regs.irqstatus)
		qemu_irq_raise(s->irq);
	else qemu_irq_lower(s->irq);
}


static uint32_t  ahci_port_write(AHCIState *s,int port,int offset,uint32_t val)
{
	ahci_port_regs *pr=&s->port_regs[port];
	uint32_t *p;
			static int64_t time;

		switch(offset)
		{
	   case PORT_LST_ADDR:
			pr->lst_addr=val; break;
			
	   case PORT_LST_ADDR_HI:
			pr->lst_addr_hi=val; break;

	   case PORT_FIS_ADDR:
			pr->fis_addr = val; break;
	
	   case PORT_FIS_ADDR_HI:
			pr->fis_addr_hi = val; break;

	   case PORT_IRQ_STAT:
			pr->irq_stat &= ~val; 
			ahci_check_irq(s);
			break;

	   case PORT_IRQ_MASK:
			pr->irq_mask = val; 
			ahci_check_irq(s);
			break;

	   case PORT_CMD:
			pr->cmd=val&(PORT_CMD_ATAPI|PORT_CMD_LIST_ON|PORT_CMD_FIS_ON|PORT_CMD_FIS_RX|PORT_CMD_CLO|PORT_CMD_POWER_ON|PORT_CMD_SPIN_UP|PORT_CMD_START);
			if(pr->cmd&PORT_CMD_START)
			qemu_mod_timer(s->timer,qemu_get_clock(vm_clock)+muldiv64(1, get_ticks_per_sec(), 1000));
			break;


	   case PORT_CMD_ISSUE:
			pr->cmd_issue=val;
			if(pr->cmd&PORT_CMD_START)
			qemu_mod_timer(s->timer,qemu_get_clock(vm_clock)+muldiv64(1, get_ticks_per_sec(), 1000));
		break;
		
	   case PORT_TFDATA:

	   case PORT_SIG:


	   case PORT_SCR:

	   case PORT_SCR_CTL:

	   case PORT_SCR_ERR:

	   case PORT_SCR_ACT:

		
		default:
			p=pr;
			p[offset>>2]=val;
			break;
		}
	
}

static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
{
	AHCIState *s = ptr;
	uint32_t val,offset;
	uint32_t *p;
	addr=addr&0xfff;
	if(addr<0x20)
	{
		switch(addr)
		{
		case HOST_IRQ_STAT:
			
		default:
		/* genernal host control */
		p=&s->control_regs;
		val=p[addr>>2];
		}
	}
	else if(addr>=0x100 && addr<0x200)
	{
		val=ahci_port_read(s,(addr-0x100)>>7,addr&0x7f);
	}
	else val=0;


	DPRINTF("ahci_mem_readl:  (addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);

	return val;
}



static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
{
    AHCIState *s = ptr;
	uint32_t offset;
	uint32_t *p;
	addr=addr&0xfff;
    int i;

    /* Only aligned reads are allowed on OHCI */
    if (addr & 3) {
        fprintf(stderr, "ahci: Mis-aligned write to addr 0x"
            TARGET_FMT_plx "\n", addr);
        return;
    }

	if(addr<0x20)
	{
	  switch(addr)
	  {
		case HOST_IRQ_STAT:
		 s->control_regs.irqstatus &= ~val; 
		ahci_check_irq(s);
		break;
		default:
		/* genernal host control */
		p=&s->control_regs;
	  }
	}
	else if(addr>=0x100 && addr<0x200)
	{
		ahci_port_write(s,(addr-0x100)>>7,addr&0x7f,val);
	}

    DPRINTF("ahci_mem_writel:  (addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);

}

static CPUReadMemoryFunc *ahci_readfn[3]={
    ahci_mem_readl,
    ahci_mem_readl,
    ahci_mem_readl
};

static CPUWriteMemoryFunc *ahci_writefn[3]={
    ahci_mem_writel,
    ahci_mem_writel,
    ahci_mem_writel
};

void ahci_reg_init(AHCIState *s)
{
	s->control_regs.cap=2|(0x1f<<8); /*2 ports,32 cmd slot*/
	s->control_regs.ghc=1<<31;
    s->control_regs.impl=1;/*2 ports*/
	s->control_regs.version=0x10100;
}

static void padstr(char *str, const char *src, int len)
{
    int i, v;
    for(i = 0; i < len; i++) {
        if (*src)
            v = *src++;
        else
            v = ' ';
        str[i^1] = v;
    }
}

static void padstr8(uint8_t *buf, int buf_size, const char *src)
{
    int i;
    for(i = 0; i < buf_size; i++) {
        if (*src)
            buf[i] = *src++;
        else
            buf[i] = ' ';
    }
}

static void put_le16(uint16_t *p, unsigned int v)
{
    *p = cpu_to_le16(v);
}


static void ide_identify(IDEState *s)
{
    uint16_t *p;
    unsigned int oldsize;

    if (s->identify_set) {
	memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
	return;
    }

    memset(s->io_buffer, 0, 512);
    p = (uint16_t *)s->io_buffer;
    put_le16(p + 0, 0x0040);
    put_le16(p + 1, s->cylinders);
    put_le16(p + 3, s->heads);
    put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */
    put_le16(p + 5, 512); /* XXX: retired, remove ? */
    put_le16(p + 6, s->sectors);
    padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
    put_le16(p + 20, 3); /* XXX: retired, remove ? */
    put_le16(p + 21, 512); /* cache size in sectors */
    put_le16(p + 22, 4); /* ecc bytes */
    padstr((char *)(p + 23), s->version, 8); /* firmware version */
    padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */
#if MAX_MULT_SECTORS > 1
    put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
#endif
    put_le16(p + 48, 1); /* dword I/O */
    put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */
    put_le16(p + 51, 0x200); /* PIO transfer cycle */
    put_le16(p + 52, 0x200); /* DMA transfer cycle */
    put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */
    put_le16(p + 54, s->cylinders);
    put_le16(p + 55, s->heads);
    put_le16(p + 56, s->sectors);
    oldsize = s->cylinders * s->heads * s->sectors;
    put_le16(p + 57, oldsize);
    put_le16(p + 58, oldsize >> 16);
    if (s->mult_sectors)
        put_le16(p + 59, 0x100 | s->mult_sectors);
    put_le16(p + 60, s->nb_sectors);
    put_le16(p + 61, s->nb_sectors >> 16);
    put_le16(p + 62, 0x07); /* single word dma0-2 supported */
    put_le16(p + 63, 0x07); /* mdma0-2 supported */
    put_le16(p + 65, 120);
    put_le16(p + 66, 120);
    put_le16(p + 67, 120);
    put_le16(p + 68, 120);
    put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
    put_le16(p + 81, 0x16); /* conforms to ata5 */
    /* 14=NOP supported, 0=SMART supported */
    put_le16(p + 82, (1 << 14) | 1);
    /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
    put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
    /* 14=set to 1, 1=SMART self test, 0=SMART error logging */
    put_le16(p + 84, (1 << 14) | 0);
    /* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
    if (bdrv_enable_write_cache(s->bs))
         put_le16(p + 85, (1 << 14) | (1 << 5) | 1);
    else
         put_le16(p + 85, (1 << 14) | 1);
    /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
    put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
    /* 14=set to 1, 1=smart self test, 0=smart error logging */
    put_le16(p + 87, (1 << 14) | 0);
    put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
    put_le16(p + 93, 1 | (1 << 14) | 0x2000);
    put_le16(p + 100, s->nb_sectors);
    put_le16(p + 101, s->nb_sectors >> 16);
    put_le16(p + 102, s->nb_sectors >> 32);
    put_le16(p + 103, s->nb_sectors >> 48);

    memcpy(s->identify_data, p, sizeof(s->identify_data));
    s->identify_set = 1;
}

#define min(a,b) (((a)<(b))?(a):(b))

uint32_t write_to_sglist(char *buffer,uint32_t len,ahci_sg *sglist,uint32_t sgcount)
{
	uint32_t i=0;
	uint32_t total=0,once;
	for(i=0;len&&sgcount;i++)
	{
	  once=min(sglist->flags_size,len);
		cpu_physical_memory_write(sglist->addr,buffer,once);
	  sglist++;
	  sgcount--;
	  len -=once;
	  buffer += once;
	  total += once;
	}

	return total;
}

uint32_t read_from_sglist(char *buffer,uint32_t len,ahci_sg *sglist,uint32_t sgcount)
{
	uint32_t i=0;
	uint32_t total=0,once;
	for(i=0;len&&sgcount;i++)
	{
	  once=min(sglist->flags_size,len);
		cpu_physical_memory_read(sglist->addr,buffer,once);
	  sglist++;
	  sgcount--;
	  len -=once;
	  buffer += once;
	  total += once;
	}

	return total;
}

void handle_cmd(AHCIState *s,int port,int slot)
{
	int64_t sector_num;
	int nb_sectors;
	IDEState *ide_state;
	int ret;
	int cmdaddr;
	uint8_t fis[0x80];
	int cmd_len;
	int prdt_num;
	ahci_sg *prdt_buf;
	int i;
	ahci_port_regs *pr;
	ahci_cmd_hdr cmd_hdr;
	pr=&s->port_regs[port];
    cmdaddr=pr->lst_addr+slot*32;
	cpu_physical_memory_read(cmdaddr,&cmd_hdr,16);
	cmd_len=(cmd_hdr.opts&0x1f)*4;
	cpu_physical_memory_read(cmd_hdr.tbl_addr,fis,cmd_len);
	prdt_num=cmd_hdr.opts>>16;
	prdt_buf=qemu_malloc(prdt_num*32);
	cpu_physical_memory_read(cmd_hdr.tbl_addr+0x80,prdt_buf,prdt_num*32);

	for(i=0;i<cmd_len;i++)
	{
		if((i&0xf)==0)DPRINTF("\n%02x:",i);
		DPRINTF("%02x ",fis[i]);
	}

	switch(fis[0])
	{
		case 0x27:
		break;
		default:
		hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
	}

	switch(fis[1])
	{
		case 1<<7: /* cmd fis */
		break;
		case 0:
		break;
		defult:
		hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
	}
			
	if(fis[1]==0)
	{
		
	}

	if(fis[1]==(1<<7))
	{
	if(!s->ide)hw_error("no ahci sata disk now\n");
	ide_state=&s->ide->ifs[0];
	switch(fis[2])
	{
		case ATA_CMD_IDENT:
		ide_identify(ide_state);
		write_to_sglist(ide_state->identify_data, sizeof(ide_state->identify_data),prdt_buf,prdt_num);
		pr->irq_stat |= (1<<2);
	 	break;
		case WIN_SETFEATURES:
		pr->irq_stat |= (1<<2);
		break;
		case ATA_CMD_RD_DMA:
		sector_num=(fis[6]<<16)|(fis[5]<<8)|fis[4];
		nb_sectors=(fis[13]<<8)|fis[12];
		if(!nb_sectors)nb_sectors=256;
        ret = bdrv_read(ide_state->bs, sector_num, ide_state->io_buffer, nb_sectors);
		if(ret==0)
		{
		write_to_sglist(ide_state->io_buffer,nb_sectors*512,prdt_buf,prdt_num);
		}
		pr->irq_stat |= (1<<2);
		break;
		case ATA_CMD_WR_DMA:
		sector_num=(fis[6]<<16)|(fis[5]<<8)|fis[4];
		nb_sectors=(fis[13]<<8)|fis[12];
		if(!nb_sectors)nb_sectors=256;
		read_from_sglist(ide_state->io_buffer,nb_sectors*512,prdt_buf,prdt_num);
        ret = bdrv_write(ide_state->bs, sector_num, ide_state->io_buffer, nb_sectors);
		pr->irq_stat |= (1<<2);
		break;
		default:
		hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
	}

	}

	pr->cmd_issue &=~(1<<slot);
	ahci_check_irq(s);
	
			
	qemu_free(prdt_buf);
 
}

void ahci_timer_function(void *opaque)
{
	AHCIState *s = opaque;
	ahci_port_regs *pr;
	int i,j;
	for(i=0;i<2;i++)
	{
		pr=&s->port_regs[i];
		for(j=0;j<32 && pr->cmd_issue;j++)
		{
		if(pr->cmd_issue&(1<<j))
		{
			handle_cmd(s,i,j);
		}	
		}
	}
}

AHCIState *ahci_new()
{
	int mem;
	DriveInfo *dinfo;
    IDEBus  *bus = qemu_mallocz(sizeof(IDEBus));
    AHCIState *s = qemu_mallocz(sizeof(AHCIState));
	ahci_reg_init(s);
    s->mem = cpu_register_io_memory(ahci_readfn, ahci_writefn, s);
    s->timer = qemu_new_timer(vm_clock, ahci_timer_function, s);

    if ((dinfo = drive_get(IF_IDE, 0, 0)) != NULL)
	{
    ide_init2(bus, dinfo, NULL,0);
	s->ide=bus;
	}
	return s;
}

int ahci_platform(unsigned long addr,unsigned long size,qemu_irq irq)
{
	AHCIState *s;
	s=ahci_new();
	s->irq =irq;
    cpu_register_physical_memory(addr, size, s->mem);
}

static void ahci_pci_map(PCIDevice *pci_dev, int region_num,
                    pcibus_t addr, pcibus_t size, int type)
{
    int iomemtype;
    struct ahci_pci_state *d = (struct ahci_pci_state *)pci_dev;
    AHCIState *s = d->ahci;

    cpu_register_physical_memory(addr, size, s->mem);
}

#define PCI_VENDOR_MYDEVICE  0x8086
#define PCI_PRODUCT_MYDEVICE 0x2652

#define PCI_CLASS_HEADERTYPE_00h	0x00


void pci_ahci_init(PCIBus *bus)
{
    struct ahci_pci_state *d;
    d = (struct ahci_pci_state *)
        pci_register_device(bus, "QEMUware AHCI",
                sizeof(struct ahci_pci_state), -1, 0, 0);
    d->card.config[PCI_VENDOR_ID]	= PCI_VENDOR_MYDEVICE & 0xff;
    d->card.config[PCI_VENDOR_ID + 1]	= PCI_VENDOR_MYDEVICE >> 8;
    d->card.config[PCI_DEVICE_ID]	= PCI_PRODUCT_MYDEVICE & 0xff;
    d->card.config[PCI_DEVICE_ID + 1]	= PCI_PRODUCT_MYDEVICE >> 8;
    d->card.config[PCI_COMMAND]		= 0x07;		/* I/O + Memory */
    d->card.config[PCI_CLASS_DEVICE]	= 0;
    d->card.config[0x0b]		= 1;//storage
    d->card.config[0x0c]		= 0x08;		/* Cache line size */
    d->card.config[0x0d]		= 0x40;		/* Latency timer */
    d->card.config[0x0e]		= PCI_CLASS_HEADERTYPE_00h;
    d->card.config[0x3d] = 1;    /* interrupt pin 0 */



    pci_register_bar(&d->card, 5, 0x200,
                           PCI_BASE_ADDRESS_SPACE_MEMORY, ahci_pci_map);
    d->ahci=ahci_new();
	d->ahci->irq = d->card.irq[0];
}


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] add ahci support into qemu
  2010-04-30 12:48 [Qemu-devel] add ahci support into qemu 乔崇
@ 2010-05-02  8:05 ` Alexander Graf
  2010-05-02 12:52   ` [Qemu-devel] [RFC] [PATCH] " 乔崇
  0 siblings, 1 reply; 17+ messages in thread
From: Alexander Graf @ 2010-05-02  8:05 UTC (permalink / raw)
  To: 乔崇; +Cc: Joerg Roedel, qemu-devel Developers, Elek Roland


On 30.04.2010, at 14:48, 乔崇 wrote:

> Hi,everyone!
> I just add AHCI Emulation into qemu.
> I have tested it on linux kernel,it works well.
> run like this:
> qemu -hda disk ...
> 
> Now only support sata disk.


Hi Chong,

While I haven't compiled and tried it out myself, it's amazing to see someone did work on this already. We currently have a GSoC project going on to implement AHCI, so this seems like an amazing kickstart.

Elek, could you please look over this patch, comment on it and evaluate how well it looks? I'll do the same as soon as time permits (on vacation atm).

Chong, at first glace I see some formal issues:

  1) Use the unified diff format for all of the patch / patches (diff -ur or git format-patch)
  2) Add a "Signed-off-by: Chong Qiao <qiaochong@loongson.cn>" line to the patch description
  3) Split up the patch for easier review.
  4) Add "[RFC] [PATCH]" to the subject line of the mail


Alex

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [RFC] [PATCH] add ahci support into qemu
  2010-05-02  8:05 ` Alexander Graf
@ 2010-05-02 12:52   ` 乔崇
  2010-05-02 15:36     ` [Qemu-devel] " Sebastian Herbszt
                       ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: 乔崇 @ 2010-05-02 12:52 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Joerg Roedel, qemu-devel Developers, Elek Roland

[-- Attachment #1: Type: text/html, Size: 2757 bytes --]

[-- Attachment #2: 0001-add-ahci-support-into-qemu-only-support-sata-disk.patch --]
[-- Type: text/x-patch, Size: 23238 bytes --]

>From 2844d2ea0ead3bcf5382e578a2d658902b0314c8 Mon Sep 17 00:00:00 2001
From: QiaoChong <qiaochong@loongson.cn>
Date: Sun, 2 May 2010 20:07:32 +0800
Subject: [PATCH] add ahci support into qemu,only support sata disk.

use -drive if=sd,file=diskname to add a ahci disk into qemu.

Signed-off-by: QiaoChong <qiaochong@loongson.cn>
---
 Makefile.target |    4 +
 hw/ahci.c       |  805 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 809 insertions(+), 0 deletions(-)
 create mode 100644 hw/ahci.c

diff --git a/Makefile.target b/Makefile.target
index 65beed5..189a776 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -186,6 +186,10 @@ obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 obj-y += rtl8139.o
 obj-y += e1000.o
 
+# ahci
+#
+obj-$(CONFIG_AHCI) += ahci.o
+
 # Hardware support
 obj-i386-y = pckbd.o dma.o
 obj-i386-y += vga.o
diff --git a/hw/ahci.c b/hw/ahci.c
new file mode 100644
index 0000000..a332a45
--- /dev/null
+++ b/hw/ahci.c
@@ -0,0 +1,805 @@
+/*
+ * QEMU AHCI Emulation
+ * Copyright (c) 2010 qiaochong@loongson.cn
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * TODO:
+ *  o ahci cd support
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "monitor.h"
+#include "sysbus.h"
+#include "pci.h"
+#include "dma.h"
+#include "cpu-common.h"
+#include <hw/ide/internal.h>
+#define DPRINTF(...)
+
+
+enum {
+	AHCI_PCI_BAR		= 5,
+	AHCI_MAX_PORTS		= 32,
+	AHCI_MAX_SG		= 168, /* hardware max is 64K */
+	AHCI_DMA_BOUNDARY	= 0xffffffff,
+	AHCI_USE_CLUSTERING	= 0,
+	AHCI_MAX_CMDS		= 32,
+	AHCI_CMD_SZ		= 32,
+	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
+	AHCI_RX_FIS_SZ		= 256,
+	AHCI_CMD_TBL_CDB	= 0x40,
+	AHCI_CMD_TBL_HDR_SZ	= 0x80,
+	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
+	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
+	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
+		AHCI_RX_FIS_SZ,
+	AHCI_IRQ_ON_SG		= (1 << 31),
+	AHCI_CMD_ATAPI		= (1 << 5),
+	AHCI_CMD_WRITE		= (1 << 6),
+	AHCI_CMD_PREFETCH	= (1 << 7),
+	AHCI_CMD_RESET		= (1 << 8),
+	AHCI_CMD_CLR_BUSY	= (1 << 10),
+
+	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
+	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
+	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
+
+	board_ahci		= 0,
+	board_ahci_pi		= 1,
+	board_ahci_vt8251	= 2,
+	board_ahci_ign_iferr	= 3,
+	board_ahci_sb600	= 4,
+
+	/* global controller registers */
+	HOST_CAP		= 0x00, /* host capabilities */
+	HOST_CTL		= 0x04, /* global host control */
+	HOST_IRQ_STAT		= 0x08, /* interrupt status */
+	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
+	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
+
+	/* HOST_CTL bits */
+	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
+	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
+	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
+
+	/* HOST_CAP bits */
+	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
+	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
+	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
+	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
+	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
+
+	/* registers for each SATA port */
+	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
+	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
+	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
+	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
+	PORT_IRQ_STAT		= 0x10, /* interrupt status */
+	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
+	PORT_CMD		= 0x18, /* port command */
+	PORT_TFDATA		= 0x20,	/* taskfile data */
+	PORT_SIG		= 0x24,	/* device TF signature */
+	PORT_CMD_ISSUE		= 0x38, /* command issue */
+	PORT_SCR		= 0x28, /* SATA phy register block */
+	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
+	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
+	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
+	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
+
+	/* PORT_IRQ_{STAT,MASK} bits */
+	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
+	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
+	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
+	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
+	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
+	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
+	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
+	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
+
+	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
+	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
+	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
+	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
+	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
+	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
+	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
+	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
+	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
+
+	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
+		PORT_IRQ_IF_ERR |
+		PORT_IRQ_CONNECT |
+		PORT_IRQ_PHYRDY |
+		PORT_IRQ_UNK_FIS,
+	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
+		PORT_IRQ_TF_ERR |
+		PORT_IRQ_HBUS_DATA_ERR,
+	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
+		PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
+		PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
+
+	/* PORT_CMD bits */
+	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
+	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
+	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
+	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
+	PORT_CMD_CLO		= (1 << 3), /* Command list override */
+	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
+	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
+	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
+
+	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
+	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
+	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
+	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
+
+	/* ap->flags bits */
+	AHCI_FLAG_NO_NCQ		= (1 << 24),
+	AHCI_FLAG_IGN_IRQ_IF_ERR	= (1 << 25), /* ignore IRQ_IF_ERR */
+	AHCI_FLAG_HONOR_PI		= (1 << 26), /* honor PORTS_IMPL */
+	AHCI_FLAG_IGN_SERR_INTERNAL	= (1 << 27), /* ignore SERR_INTERNAL */
+	AHCI_FLAG_32BIT_ONLY		= (1 << 28), /* force 32bit */
+};
+
+/*
+ * ATA Commands (only mandatory commands listed here)
+ */
+#define ATA_CMD_READ	0x20	/* Read Sectors (with retries)	*/
+#define ATA_CMD_READN	0x21	/* Read Sectors ( no  retries)	*/
+#define ATA_CMD_WRITE	0x30	/* Write Sectores (with retries)*/
+#define ATA_CMD_WRITEN	0x31	/* Write Sectors  ( no  retries)*/
+#define ATA_CMD_VRFY	0x40	/* Read Verify  (with retries)	*/
+#define ATA_CMD_VRFYN	0x41	/* Read verify  ( no  retries)	*/
+#define ATA_CMD_SEEK	0x70	/* Seek				*/
+#define ATA_CMD_DIAG	0x90	/* Execute Device Diagnostic	*/
+#define ATA_CMD_INIT	0x91	/* Initialize Device Parameters	*/
+#define ATA_CMD_RD_MULT	0xC4	/* Read Multiple		*/
+#define ATA_CMD_WR_MULT	0xC5	/* Write Multiple		*/
+#define ATA_CMD_SETMULT	0xC6	/* Set Multiple Mode		*/
+#define ATA_CMD_RD_DMA	0xC8	/* Read DMA (with retries)	*/
+#define ATA_CMD_RD_DMAN	0xC9	/* Read DMS ( no  retries)	*/
+#define ATA_CMD_WR_DMA	0xCA	/* Write DMA (with retries)	*/
+#define ATA_CMD_WR_DMAN	0xCB	/* Write DMA ( no  retires)	*/
+#define ATA_CMD_IDENT	0xEC	/* Identify Device		*/
+#define ATA_CMD_SETF	0xEF	/* Set Features			*/
+#define ATA_CMD_CHK_PWR	0xE5	/* Check Power Mode		*/
+
+#define ATA_CMD_READ_EXT 0x24	/* Read Sectors (with retries)	with 48bit addressing */
+#define ATA_CMD_WRITE_EXT	0x34	/* Write Sectores (with retries) with 48bit addressing */
+#define ATA_CMD_VRFY_EXT	0x42	/* Read Verify	(with retries)	with 48bit addressing */
+
+/*
+ * ATAPI Commands
+ */
+#define ATAPI_CMD_IDENT 0xA1 /* Identify AT Atachment Packed Interface Device */
+#define ATAPI_CMD_PACKET 0xA0 /* Packed Command */
+
+
+#define ATAPI_CMD_INQUIRY 0x12
+#define ATAPI_CMD_REQ_SENSE 0x03
+#define ATAPI_CMD_READ_CAP 0x25
+#define ATAPI_CMD_START_STOP 0x1B
+#define ATAPI_CMD_READ_12 0xA8
+
+
+
+typedef struct ahci_control_regs {
+	uint32_t  cap;
+	uint32_t  ghc;
+	uint32_t  irqstatus;
+	uint32_t  impl;
+	uint32_t  version;
+} ahci_control_regs;
+
+typedef struct ahci_port_regs {
+	uint32_t lst_addr;
+	uint32_t lst_addr_hi;
+	uint32_t fis_addr;
+	uint32_t fis_addr_hi;
+	uint32_t irq_stat;
+	uint32_t irq_mask;
+	uint32_t cmd;
+	uint32_t unused0;
+	uint32_t tfdata;
+	uint32_t sig;
+	uint32_t scr_stat;
+	uint32_t scr_ctl;
+	uint32_t scr_err;
+	uint32_t scr_act;
+	uint32_t cmd_issue;
+} ahci_port_regs; 
+
+
+typedef struct ahci_cmd_hdr {
+	uint32_t			opts;
+	uint32_t			status;
+	uint32_t			tbl_addr;
+	uint32_t			tbl_addr_hi;
+	uint32_t			reserved[4];
+} ahci_cmd_hdr;
+
+typedef struct ahci_sg {
+	uint32_t			addr;
+	uint32_t			addr_hi;
+	uint32_t			reserved;
+	uint32_t			flags_size;
+} ahci_sg;
+
+
+typedef struct AHCIState{
+	ahci_control_regs control_regs;
+	ahci_port_regs port_regs[2];
+	int mem;
+	QEMUTimer *timer;
+	IDEBus *ide;
+	ahci_sg *prdt_buf;
+	qemu_irq irq;
+} AHCIState;
+
+typedef struct ahci_pci_state {
+	PCIDevice card;
+	AHCIState *ahci;
+} ahci_pci_state;
+
+typedef struct ahci_sysbus_state {
+	SysBusDevice busdev;
+	AHCIState *ahci;
+} ahci_sysbus_state;
+
+static uint32_t  ahci_port_read(AHCIState *s,int port,int offset)
+{
+	uint32_t val;
+	uint32_t *p;
+	ahci_port_regs *pr;
+	pr=&s->port_regs[port];
+
+	switch(offset)
+	{
+		case PORT_SCR:
+			if(s->ide && port==0) val=3;
+			else val=0;
+			break;
+		case PORT_IRQ_STAT:
+			val=pr->irq_stat;
+			break;
+		case PORT_TFDATA:
+
+		case PORT_SIG:
+
+		case PORT_CMD_ISSUE:
+
+
+		case PORT_SCR_CTL:
+
+		case PORT_SCR_ERR:
+
+		case PORT_SCR_ACT:
+		default:
+			p=(uint32_t *)&s->port_regs[port];
+			val= p[offset>>2];
+			break;
+	}
+	return val;
+
+}
+
+static void ahci_check_irq(AHCIState *s)
+{
+	ahci_port_regs *pr;
+	int i;
+	for(i=0;i<2;i++)
+	{
+		pr=&s->port_regs[i];
+
+		if(pr->irq_stat&pr->irq_mask){
+			s->control_regs.irqstatus |= (1<<i);
+		}
+	}
+
+	if(s->control_regs.irqstatus)
+		qemu_irq_raise(s->irq);
+	else qemu_irq_lower(s->irq);
+}
+
+
+static void  ahci_port_write(AHCIState *s,int port,int offset,uint32_t val)
+{
+	ahci_port_regs *pr=&s->port_regs[port];
+	uint32_t *p;
+
+	switch(offset)
+	{
+		case PORT_LST_ADDR:
+			pr->lst_addr=val; break;
+
+		case PORT_LST_ADDR_HI:
+			pr->lst_addr_hi=val; break;
+
+		case PORT_FIS_ADDR:
+			pr->fis_addr = val; break;
+
+		case PORT_FIS_ADDR_HI:
+			pr->fis_addr_hi = val; break;
+
+		case PORT_IRQ_STAT:
+			pr->irq_stat &= ~val; 
+			ahci_check_irq(s);
+			break;
+
+		case PORT_IRQ_MASK:
+			pr->irq_mask = val; 
+			ahci_check_irq(s);
+			break;
+
+		case PORT_CMD:
+			pr->cmd=val&(PORT_CMD_ATAPI|PORT_CMD_LIST_ON|PORT_CMD_FIS_ON|PORT_CMD_FIS_RX|PORT_CMD_CLO|PORT_CMD_POWER_ON|PORT_CMD_SPIN_UP|PORT_CMD_START);
+			if(pr->cmd&PORT_CMD_START)
+				qemu_mod_timer(s->timer,qemu_get_clock(vm_clock)+muldiv64(1, get_ticks_per_sec(), 1000));
+			break;
+
+
+		case PORT_CMD_ISSUE:
+			pr->cmd_issue=val;
+			if(pr->cmd&PORT_CMD_START)
+				qemu_mod_timer(s->timer,qemu_get_clock(vm_clock)+muldiv64(1, get_ticks_per_sec(), 1000));
+			break;
+
+		case PORT_TFDATA:
+
+		case PORT_SIG:
+
+
+		case PORT_SCR:
+
+		case PORT_SCR_CTL:
+
+		case PORT_SCR_ERR:
+
+		case PORT_SCR_ACT:
+
+
+		default:
+			p=(uint32_t *)pr;
+			p[offset>>2]=val;
+			break;
+	}
+
+}
+
+static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
+{
+	AHCIState *s = ptr;
+	uint32_t val;
+	uint32_t *p;
+	addr=addr&0xfff;
+	if(addr<0x20)
+	{
+		switch(addr)
+		{
+			case HOST_IRQ_STAT:
+
+			default:
+				/* genernal host control */
+				p=(uint32_t *)&s->control_regs;
+				val=p[addr>>2];
+		}
+	}
+	else if(addr>=0x100 && addr<0x200)
+	{
+		val=ahci_port_read(s,(addr-0x100)>>7,addr&0x7f);
+	}
+	else val=0;
+
+
+	DPRINTF("ahci_mem_readl:  (addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
+
+	return val;
+}
+
+
+
+static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
+{
+	AHCIState *s = ptr;
+	uint32_t *p;
+	addr=addr&0xfff;
+
+	/* Only aligned reads are allowed on OHCI */
+	if (addr & 3) {
+		fprintf(stderr, "ahci: Mis-aligned write to addr 0x"
+				TARGET_FMT_plx "\n", addr);
+		return;
+	}
+
+	if(addr<0x20)
+	{
+		switch(addr)
+		{
+			case HOST_IRQ_STAT:
+				s->control_regs.irqstatus &= ~val; 
+				ahci_check_irq(s);
+				break;
+			default:
+				/* genernal host control */
+				p=(uint32_t *)&s->control_regs;
+		}
+	}
+	else if(addr>=0x100 && addr<0x200)
+	{
+		ahci_port_write(s,(addr-0x100)>>7,addr&0x7f,val);
+	}
+
+	DPRINTF("ahci_mem_writel:  (addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
+
+}
+
+static CPUReadMemoryFunc *ahci_readfn[3]={
+	ahci_mem_readl,
+	ahci_mem_readl,
+	ahci_mem_readl
+};
+
+static CPUWriteMemoryFunc *ahci_writefn[3]={
+	ahci_mem_writel,
+	ahci_mem_writel,
+	ahci_mem_writel
+};
+
+static void ahci_reg_init(AHCIState *s)
+{
+	s->control_regs.cap=2|(0x1f<<8); /*2 ports,32 cmd slot*/
+	s->control_regs.ghc=1<<31;
+	s->control_regs.impl=1;/*2 ports*/
+	s->control_regs.version=0x10100;
+}
+
+static void padstr(char *str, const char *src, int len)
+{
+	int i, v;
+	for(i = 0; i < len; i++) {
+		if (*src)
+			v = *src++;
+		else
+			v = ' ';
+		str[i^1] = v;
+	}
+}
+
+
+static void put_le16(uint16_t *p, unsigned int v)
+{
+	*p = cpu_to_le16(v);
+}
+
+
+static void ide_identify(IDEState *s)
+{
+	uint16_t *p;
+	unsigned int oldsize;
+
+	if (s->identify_set) {
+		memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
+		return;
+	}
+
+	memset(s->io_buffer, 0, 512);
+	p = (uint16_t *)s->io_buffer;
+	put_le16(p + 0, 0x0040);
+	put_le16(p + 1, s->cylinders);
+	put_le16(p + 3, s->heads);
+	put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */
+	put_le16(p + 5, 512); /* XXX: retired, remove ? */
+	put_le16(p + 6, s->sectors);
+	padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
+	put_le16(p + 20, 3); /* XXX: retired, remove ? */
+	put_le16(p + 21, 512); /* cache size in sectors */
+	put_le16(p + 22, 4); /* ecc bytes */
+	padstr((char *)(p + 23), s->version, 8); /* firmware version */
+	padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */
+#if MAX_MULT_SECTORS > 1
+	put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
+#endif
+	put_le16(p + 48, 1); /* dword I/O */
+	put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */
+	put_le16(p + 51, 0x200); /* PIO transfer cycle */
+	put_le16(p + 52, 0x200); /* DMA transfer cycle */
+	put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */
+	put_le16(p + 54, s->cylinders);
+	put_le16(p + 55, s->heads);
+	put_le16(p + 56, s->sectors);
+	oldsize = s->cylinders * s->heads * s->sectors;
+	put_le16(p + 57, oldsize);
+	put_le16(p + 58, oldsize >> 16);
+	if (s->mult_sectors)
+		put_le16(p + 59, 0x100 | s->mult_sectors);
+	put_le16(p + 60, s->nb_sectors);
+	put_le16(p + 61, s->nb_sectors >> 16);
+	put_le16(p + 62, 0x07); /* single word dma0-2 supported */
+	put_le16(p + 63, 0x07); /* mdma0-2 supported */
+	put_le16(p + 65, 120);
+	put_le16(p + 66, 120);
+	put_le16(p + 67, 120);
+	put_le16(p + 68, 120);
+	put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
+	put_le16(p + 81, 0x16); /* conforms to ata5 */
+	/* 14=NOP supported, 0=SMART supported */
+	put_le16(p + 82, (1 << 14) | 1);
+	/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
+	put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
+	/* 14=set to 1, 1=SMART self test, 0=SMART error logging */
+	put_le16(p + 84, (1 << 14) | 0);
+	/* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
+	if (bdrv_enable_write_cache(s->bs))
+		put_le16(p + 85, (1 << 14) | (1 << 5) | 1);
+	else
+		put_le16(p + 85, (1 << 14) | 1);
+	/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
+	put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
+	/* 14=set to 1, 1=smart self test, 0=smart error logging */
+	put_le16(p + 87, (1 << 14) | 0);
+	put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
+	put_le16(p + 93, 1 | (1 << 14) | 0x2000);
+	put_le16(p + 100, s->nb_sectors);
+	put_le16(p + 101, s->nb_sectors >> 16);
+	put_le16(p + 102, s->nb_sectors >> 32);
+	put_le16(p + 103, s->nb_sectors >> 48);
+
+	memcpy(s->identify_data, p, sizeof(s->identify_data));
+	s->identify_set = 1;
+}
+
+#define min(a,b) (((a)<(b))?(a):(b))
+
+static uint32_t write_to_sglist(uint8_t *buffer,uint32_t len,ahci_sg *sglist,uint32_t sgcount)
+{
+	uint32_t i=0;
+	uint32_t total=0,once;
+	for(i=0;len&&sgcount;i++)
+	{
+		once=min(sglist->flags_size+1,len);
+		cpu_physical_memory_write(sglist->addr,buffer,once);
+		sglist++;
+		sgcount--;
+		len -= once;
+		buffer += once;
+		total += once;
+	}
+
+	return total;
+}
+
+static uint32_t read_from_sglist(uint8_t *buffer,uint32_t len,ahci_sg *sglist,uint32_t sgcount)
+{
+	uint32_t i=0;
+	uint32_t total=0,once;
+	for(i=0;len&&sgcount;i++)
+	{
+		once=min(sglist->flags_size+1,len);
+		cpu_physical_memory_read(sglist->addr,buffer,once);
+		sglist++;
+		sgcount--;
+		len -= once;
+		buffer += once;
+		total += once;
+	}
+
+	return total;
+}
+
+static void handle_cmd(AHCIState *s,int port,int slot)
+{
+	int64_t sector_num;
+	int nb_sectors;
+	IDEState *ide_state;
+	int ret;
+	int cmdaddr;
+	uint8_t fis[0x80];
+	int cmd_len;
+	int prdt_num;
+	int i;
+	ahci_port_regs *pr;
+	ahci_cmd_hdr cmd_hdr;
+	pr=&s->port_regs[port];
+	cmdaddr=pr->lst_addr+slot*32;
+	cpu_physical_memory_read(cmdaddr,(uint8_t *)&cmd_hdr,16);
+	cmd_len=(cmd_hdr.opts&0x1f)*4;
+	cpu_physical_memory_read(cmd_hdr.tbl_addr,fis,cmd_len);
+	prdt_num=cmd_hdr.opts>>16;
+	if(prdt_num) cpu_physical_memory_read(cmd_hdr.tbl_addr+0x80,(uint8_t *)s->prdt_buf,prdt_num*32);
+
+
+	for(i=0;i<cmd_len;i++)
+	{
+		if((i&0xf)==0)DPRINTF("\n%02x:",i);
+		DPRINTF("%02x ",fis[i]);
+	}
+
+	switch(fis[0])
+	{
+		case 0x27:
+			break;
+		default:
+			hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+	}
+
+	switch(fis[1])
+	{
+		case 1<<7: /* cmd fis */
+			break;
+		case 0:
+			break;
+		default:
+			hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+	}
+
+	if(fis[1]==0)
+	{
+
+	}
+
+	if(fis[1]==(1<<7))
+	{
+		if(!s->ide)hw_error("no ahci sata disk now\n");
+		ide_state=&s->ide->ifs[0];
+		switch(fis[2])
+		{
+			case ATA_CMD_IDENT:
+				ide_identify(ide_state);
+				write_to_sglist(ide_state->identify_data, sizeof(ide_state->identify_data),s->prdt_buf,prdt_num);
+				pr->irq_stat |= (1<<2);
+				break;
+			case WIN_SETFEATURES:
+				pr->irq_stat |= (1<<2);
+				break;
+			case ATA_CMD_RD_DMA:
+				sector_num=(((int64_t)fis[10])<<40)|(((int64_t)fis[9])<<32)|(fis[8]<<24)|(fis[6]<<16)|(fis[5]<<8)|fis[4];
+				nb_sectors=(fis[13]<<8)|fis[12];
+				if(!nb_sectors)nb_sectors=256;
+				printf("nb_sectors=%x,prdt_num=%x\n",nb_sectors,prdt_num);
+				ret = bdrv_read(ide_state->bs, sector_num, ide_state->io_buffer, nb_sectors);
+				if(ret==0)
+				{
+					write_to_sglist(ide_state->io_buffer,nb_sectors*512,s->prdt_buf,prdt_num);
+				}
+				pr->irq_stat |= (1<<2);
+				break;
+			case ATA_CMD_WR_DMA:
+				sector_num=(((int64_t)fis[10])<<40)|(((int64_t)fis[9])<<32)|(fis[8]<<24)|(fis[6]<<16)|(fis[5]<<8)|fis[4];
+				nb_sectors=(fis[13]<<8)|fis[12];
+				if(!nb_sectors)nb_sectors=256;
+				read_from_sglist(ide_state->io_buffer,nb_sectors*512,s->prdt_buf,prdt_num);
+				ret = bdrv_write(ide_state->bs, sector_num, ide_state->io_buffer, nb_sectors);
+				pr->irq_stat |= (1<<2);
+				break;
+			default:
+				hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+		}
+
+	}
+
+	pr->cmd_issue &=~(1<<slot);
+	ahci_check_irq(s);
+}
+
+static void ahci_timer_function(void *opaque)
+{
+	AHCIState *s = opaque;
+	ahci_port_regs *pr;
+	int i,j;
+	for(i=0;i<2;i++)
+	{
+		pr=&s->port_regs[i];
+		for(j=0;j<32 && pr->cmd_issue;j++)
+		{
+			if(pr->cmd_issue&(1<<j))
+			{
+				handle_cmd(s,i,j);
+			}	
+		}
+	}
+}
+
+static AHCIState *ahci_new(void)
+{
+	DriveInfo *dinfo;
+	IDEBus  *bus = qemu_mallocz(sizeof(IDEBus));
+	AHCIState *s = qemu_mallocz(sizeof(AHCIState));
+	ahci_reg_init(s);
+	s->mem = cpu_register_io_memory(ahci_readfn, ahci_writefn, s);
+	s->timer = qemu_new_timer(vm_clock, ahci_timer_function, s);
+	s->prdt_buf = qemu_malloc(65535*32);
+
+	if ((dinfo = drive_get(IF_SD, 0, 0)) != NULL)
+	{
+		ide_init2(bus, dinfo, NULL,0);
+		s->ide=bus;
+	}
+	return s;
+}
+
+static void ahci_pci_map(PCIDevice *pci_dev, int region_num,
+		pcibus_t addr, pcibus_t size, int type)
+{
+	struct ahci_pci_state *d = (struct ahci_pci_state *)pci_dev;
+	AHCIState *s = d->ahci;
+
+	cpu_register_physical_memory(addr, size, s->mem);
+}
+
+#define PCI_VENDOR_MYDEVICE  0x8086
+#define PCI_PRODUCT_MYDEVICE 0x2652
+
+#define PCI_CLASS_HEADERTYPE_00h	0x00
+
+static int pci_ahci_init(PCIDevice *dev)
+{
+	struct ahci_pci_state *d;
+	d = DO_UPCAST(struct ahci_pci_state, card, dev);
+	pci_config_set_vendor_id(d->card.config,PCI_VENDOR_MYDEVICE);
+	pci_config_set_device_id(d->card.config,PCI_PRODUCT_MYDEVICE);
+	d->card.config[PCI_COMMAND]		= 0x07;		/* I/O + Memory */
+	d->card.config[PCI_CLASS_DEVICE]	= 0;
+	d->card.config[0x0b]		= 1;//storage
+	d->card.config[0x0c]		= 0x08;		/* Cache line size */
+	d->card.config[0x0d]		= 0x40;		/* Latency timer */
+	d->card.config[0x0e]		= PCI_CLASS_HEADERTYPE_00h;
+	d->card.config[0x3d] = 1;    /* interrupt pin 0 */
+
+	pci_register_bar(&d->card, 5, 0x200,
+			PCI_BASE_ADDRESS_SPACE_MEMORY, ahci_pci_map);
+	d->ahci=ahci_new();
+	d->ahci->irq = d->card.irq[0];
+	return 0;
+}
+
+static int pci_ahci_uninit(PCIDevice *dev)
+{
+	return 0;
+}
+
+static PCIDeviceInfo ahci_info = {
+	.qdev.name  = "ahci",
+	.qdev.size  = sizeof(ahci_pci_state),
+	.init       = pci_ahci_init,
+	.exit       = pci_ahci_uninit,
+	.qdev.props = (Property[]) {
+		DEFINE_PROP_END_OF_LIST(),
+	}
+};
+
+static void ahci_pci_register_devices(void)
+{
+	pci_qdev_register(&ahci_info);
+}
+
+device_init(ahci_pci_register_devices)
+
+
+
+static int ahci_sysbus_init(SysBusDevice *dev)
+{
+    ahci_sysbus_state *d = FROM_SYSBUS(ahci_sysbus_state, dev);
+	d->ahci=ahci_new();
+    sysbus_init_mmio(dev, 0x200, d->ahci->mem);
+    sysbus_init_irq(dev, &d->ahci->irq);
+    return 0;
+}
+
+static void ahci_sysbus_register_devices(void)
+{
+    sysbus_register_dev("ahci", sizeof(ahci_sysbus_state), ahci_sysbus_init);
+}
+
+device_init(ahci_sysbus_register_devices)
-- 
1.5.6.5


[-- Attachment #3: 0002-add-ahci-device-into-i386-pc-just-for-test.patch --]
[-- Type: text/x-patch, Size: 1305 bytes --]

>From 446cce5657bf570fc612dea513f5bedcdc3be275 Mon Sep 17 00:00:00 2001
From: QiaoChong <qiaochong@loongson.cn>
Date: Sun, 2 May 2010 16:53:43 +0800
Subject: [PATCH] add ahci device into i386 pc just for test.

test like this:

dd if=/dev/zero of=/tmp/disk bs=1M count=100
./i386-softmmu/qemu  -cdrom /mnt/hdb1/knoppix-dvd/KNOPPIX_V6.0.1CD-2009-02-08-EN.iso -boot d -drive if=sd,file=/tmp/disk

Signed-off-by: QiaoChong <qiaochong@loongson.cn>
---
 default-configs/i386-softmmu.mak |    2 ++
 hw/pc.c                          |    1 +
 2 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 4c1495f..bd72f39 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -20,3 +20,5 @@ CONFIG_NE2000_ISA=y
 CONFIG_PIIX_PCI=y
 CONFIG_SOUND=y
 CONFIG_VIRTIO_PCI=y
+CONFIG_AHCI=y
+
diff --git a/hw/pc.c b/hw/pc.c
index b659344..7ea437f 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1005,6 +1005,7 @@ static void pc_init1(ram_addr_t ram_size,
 
     if (pci_enabled) {
         pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
+		pci_create_simple(pci_bus,-1,"ahci");
     } else {
         for(i = 0; i < MAX_IDE_BUS; i++) {
             isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-02 12:52   ` [Qemu-devel] [RFC] [PATCH] " 乔崇
@ 2010-05-02 15:36     ` Sebastian Herbszt
  2010-05-02 15:49       ` Avi Kivity
  2010-05-02 15:56       ` Elek Roland
  2010-05-02 22:13     ` Sebastian Herbszt
  2010-05-04  0:01     ` [Qemu-devel] " Alexander Graf
  2 siblings, 2 replies; 17+ messages in thread
From: Sebastian Herbszt @ 2010-05-02 15:36 UTC (permalink / raw)
  To: 乔崇
  Cc: Alexander Graf, Joerg Roedel, qemu-devel Developers, Elek Roland

Hi,

乔崇  wrote:
> Hi,Alexander Graf.
>
>  I am very glad you noticed my patch about ahci.I love qemu just like I love linux.I wish I could do much more work on 
> qemu development.
>
> I had cloned qemu from master branch,add my patch into it,and tested ahci on i386 softmmu.
>
> If anyone is interested on ahci,you can test my patch like this:
>
> git-clone -ls git://git.savannah.nongnu.org/qemu
> patch -p1 -i 0001-add-ahci-support-into-qemu-only-support-sata-disk.patch
> patch -p1 -i 0002-add-ahci-device-into-i386-pc-just-for-test.patch

The last submission was missing the qemu "glue", but this one looks complete. Nonetheless the old one was working fine 
enough.

> ./configure --target-list=i386-softmmu
> make
>
> dd if=/dev/zero of=/tmp/disk bs=1M count=100
> ./i386-softmmu/qemu  -cdrom KNOPPIX_V6.0.1CD-2009-02-08-EN.iso -boot d -drive if=sd,file=/tmp/disk
>
> After linux boot,you will find a ahci device named sda.
>
> Now this patch only support sata disk.
> Most ahci registers and operations which are not necessary on linux are ignored.
> Now this patch support disk identify,dma read,dma write,ignore other opertions.

Do you intent to work on this and complet the support?
There are also some minor changes needed like moving PCI_VENDOR_MYDEVICE
and PCI_PRODUCT_MYDEVICE to pci.h and others.

Did you use the Intel document #301473 for reference?

> By the way how you send patch to mail list?

Try "git send-email".


Regards,
Sebastian

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-02 15:36     ` [Qemu-devel] " Sebastian Herbszt
@ 2010-05-02 15:49       ` Avi Kivity
  2010-05-02 15:56       ` Elek Roland
  1 sibling, 0 replies; 17+ messages in thread
From: Avi Kivity @ 2010-05-02 15:49 UTC (permalink / raw)
  To: Sebastian Herbszt
  Cc: 乔崇,
	Joerg Roedel, Elek Roland, Alexander Graf, qemu-devel Developers

On 05/02/2010 06:36 PM, Sebastian Herbszt wrote:
>
>> ./configure --target-list=i386-softmmu
>> make
>>
>> dd if=/dev/zero of=/tmp/disk bs=1M count=100
>> ./i386-softmmu/qemu  -cdrom KNOPPIX_V6.0.1CD-2009-02-08-EN.iso -boot 
>> d -drive if=sd,file=/tmp/disk
>>
>> After linux boot,you will find a ahci device named sda.
>>
>> Now this patch only support sata disk.
>> Most ahci registers and operations which are not necessary on linux 
>> are ignored.
>> Now this patch support disk identify,dma read,dma write,ignore other 
>> opertions.
>
> Do you intent to work on this and complet the support?

At the very least, unsupported registers and features should print out a 
warning instead of silently failing.

-- 
error compiling committee.c: too many arguments to function

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-02 15:36     ` [Qemu-devel] " Sebastian Herbszt
  2010-05-02 15:49       ` Avi Kivity
@ 2010-05-02 15:56       ` Elek Roland
  2010-05-03 21:08         ` Elek Roland
  1 sibling, 1 reply; 17+ messages in thread
From: Elek Roland @ 2010-05-02 15:56 UTC (permalink / raw)
  To: Sebastian Herbszt
  Cc: 乔崇, Joerg Roedel, qemu-devel Developers, Alexander Graf

Hi all,

I am the GSoC student working on the project. I haven't tried the patch
yet, but I've read the code. It could use general cleanup and a lot of
development indeed, but otherwise it looks like a good base to build
complete support on so far. I'm going to try the patch in practice as
soon as I finish my university project. (It's due today.)

Chong, I'd be happy to stay in touch with you. I'm going to work on this
in the summer full time.

Regards,
Roland

On v, 2010-05-02 at 17:36 +0200, Sebastian Herbszt wrote:
> Hi,
> 
> 乔崇  wrote:
> > Hi,Alexander Graf.
> >
> >  I am very glad you noticed my patch about ahci.I love qemu just like I love linux.I wish I could do much more work on 
> > qemu development.
> >
> > I had cloned qemu from master branch,add my patch into it,and tested ahci on i386 softmmu.
> >
> > If anyone is interested on ahci,you can test my patch like this:
> >
> > git-clone -ls git://git.savannah.nongnu.org/qemu
> > patch -p1 -i 0001-add-ahci-support-into-qemu-only-support-sata-disk.patch
> > patch -p1 -i 0002-add-ahci-device-into-i386-pc-just-for-test.patch
> 
> The last submission was missing the qemu "glue", but this one looks complete. Nonetheless the old one was working fine 
> enough.
> 
> > ./configure --target-list=i386-softmmu
> > make
> >
> > dd if=/dev/zero of=/tmp/disk bs=1M count=100
> > ./i386-softmmu/qemu  -cdrom KNOPPIX_V6.0.1CD-2009-02-08-EN.iso -boot d -drive if=sd,file=/tmp/disk
> >
> > After linux boot,you will find a ahci device named sda.
> >
> > Now this patch only support sata disk.
> > Most ahci registers and operations which are not necessary on linux are ignored.
> > Now this patch support disk identify,dma read,dma write,ignore other opertions.
> 
> Do you intent to work on this and complet the support?
> There are also some minor changes needed like moving PCI_VENDOR_MYDEVICE
> and PCI_PRODUCT_MYDEVICE to pci.h and others.
> 
> Did you use the Intel document #301473 for reference?
> 
> > By the way how you send patch to mail list?
> 
> Try "git send-email".
> 
> 
> Regards,
> Sebastian
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-02 12:52   ` [Qemu-devel] [RFC] [PATCH] " 乔崇
  2010-05-02 15:36     ` [Qemu-devel] " Sebastian Herbszt
@ 2010-05-02 22:13     ` Sebastian Herbszt
  2010-05-04  1:07       ` 乔崇
  2010-05-04  0:01     ` [Qemu-devel] " Alexander Graf
  2 siblings, 1 reply; 17+ messages in thread
From: Sebastian Herbszt @ 2010-05-02 22:13 UTC (permalink / raw)
  To: 乔崇
  Cc: Alexander Graf, Joerg Roedel, qemu-devel Developers, Elek Roland

[-- Attachment #1: Type: text/plain, Size: 5691 bytes --]

Hi again,

please consider the following minor changes:
- debug output with DEBUG_AHCI
- set port count to 4
- change return value of PxSSTS to include SPD and IPM
- change cap and version default values according to Intel #301473-002

Regards,
Sebastian

--- hw/ahci.c.orig Sun May  2 15:43:58 2010
+++ hw/ahci.c Sun May  2 22:03:26 2010
@@ -26,8 +26,15 @@
 #include "dma.h"
 #include "cpu-common.h"
 #include <hw/ide/internal.h>
-#define DPRINTF(...)
 
+#define DEBUG_AHCI
+
+#ifdef DEBUG_AHCI
+#define DPRINTF(fmt, ...) \
+do { printf("ahci: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
 
 enum {
  AHCI_PCI_BAR  = 5,
@@ -203,6 +210,8 @@
  uint32_t  version;
 } ahci_control_regs;
 
+#define SATA_PORTS 4
+
 typedef struct ahci_port_regs {
  uint32_t lst_addr;
  uint32_t lst_addr_hi;
@@ -240,7 +249,7 @@
 
 typedef struct AHCIState{
  ahci_control_regs control_regs;
- ahci_port_regs port_regs[2];
+ ahci_port_regs port_regs[SATA_PORTS];
  int mem;
  QEMUTimer *timer;
  IDEBus *ide;
@@ -268,8 +277,10 @@
  switch(offset)
  {
   case PORT_SCR:
-   if(s->ide && port==0) val=3;
-   else val=0;
+   if(s->ide && port==0)
+    val= 3 /* DET */ | (1 << 4) /* SPD */ | (1 << 8) /* IPM */;
+   else
+    val=0;
    break;
   case PORT_IRQ_STAT:
    val=pr->irq_stat;
@@ -291,6 +302,7 @@
    val= p[offset>>2];
    break;
  }
+ DPRINTF("ahci_port_read: port: 0x%x offset: 0x%x val: 0x%x\n", port, offset, val);
  return val;
 
 }
@@ -299,7 +311,7 @@
 {
  ahci_port_regs *pr;
  int i;
- for(i=0;i<2;i++)
+ for(i=0;i<SATA_PORTS;i++)
  {
   pr=&s->port_regs[i];
 
@@ -319,6 +331,7 @@
  ahci_port_regs *pr=&s->port_regs[port];
  uint32_t *p;
 
+ DPRINTF("ahci_port_write: port: 0x%x offset: 0x%x val: 0x%x\n", port, offset, val);
  switch(offset)
  {
   case PORT_LST_ADDR:
@@ -396,7 +409,7 @@
     val=p[addr>>2];
   }
  }
- else if(addr>=0x100 && addr<0x200)
+ else if(addr>=0x100 && addr<0x300)
  {
   val=ahci_port_read(s,(addr-0x100)>>7,addr&0x7f);
  }
@@ -436,7 +449,7 @@
     p=(uint32_t *)&s->control_regs;
   }
  }
- else if(addr>=0x100 && addr<0x200)
+ else if(addr>=0x100 && addr<0x300)
  {
   ahci_port_write(s,(addr-0x100)>>7,addr&0x7f,val);
  }
@@ -459,10 +472,10 @@
 
 static void ahci_reg_init(AHCIState *s)
 {
- s->control_regs.cap=2|(0x1f<<8); /*2 ports,32 cmd slot*/
- s->control_regs.ghc=1<<31;
- s->control_regs.impl=1;/*2 ports*/
- s->control_regs.version=0x10100;
+ s->control_regs.cap = 3 | (0x1f << 8) | (1 << 20) ; /* 4 ports, 32 command slots, 1.5 Gb/s */
+ s->control_regs.ghc = 1 << 31; /* AHCI Enable */
+ s->control_regs.impl = 1; /* Port 0 implemented */
+ s->control_regs.version = 0x10000;
 }
 
 static void padstr(char *str, const char *src, int len)
@@ -619,19 +632,22 @@
  prdt_num=cmd_hdr.opts>>16;
  if(prdt_num) cpu_physical_memory_read(cmd_hdr.tbl_addr+0x80,(uint8_t *)s->prdt_buf,prdt_num*32);
 
-
+#ifdef DEBUG_AHCI
+        DPRINTF("fis:");
  for(i=0;i<cmd_len;i++)
  {
-  if((i&0xf)==0)DPRINTF("\n%02x:",i);
-  DPRINTF("%02x ",fis[i]);
+  if((i&0xf)==0) printf("\n%02x:",i);
+  printf("%02x ",fis[i]);
  }
+        printf("\n");
+#endif
 
  switch(fis[0])
  {
   case 0x27:
    break;
   default:
-   hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+   hw_error("unknown command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
  }
 
  switch(fis[1])
@@ -641,7 +657,7 @@
   case 0:
    break;
   default:
-   hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+   hw_error("unknown command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
  }
 
  if(fis[1]==0)
@@ -684,7 +700,7 @@
     pr->irq_stat |= (1<<2);
     break;
    default:
-    hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+    hw_error("unknown command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
   }
 
  }
@@ -698,7 +714,7 @@
  AHCIState *s = opaque;
  ahci_port_regs *pr;
  int i,j;
- for(i=0;i<2;i++)
+ for(i=0;i<SATA_PORTS;i++)
  {
   pr=&s->port_regs[i];
   for(j=0;j<32 && pr->cmd_issue;j++)
@@ -741,23 +757,21 @@
 #define PCI_VENDOR_MYDEVICE  0x8086
 #define PCI_PRODUCT_MYDEVICE 0x2652
 
-#define PCI_CLASS_HEADERTYPE_00h 0x00
-
 static int pci_ahci_init(PCIDevice *dev)
 {
  struct ahci_pci_state *d;
  d = DO_UPCAST(struct ahci_pci_state, card, dev);
  pci_config_set_vendor_id(d->card.config,PCI_VENDOR_MYDEVICE);
  pci_config_set_device_id(d->card.config,PCI_PRODUCT_MYDEVICE);
- d->card.config[PCI_COMMAND]  = 0x07;  /* I/O + Memory */
+ d->card.config[PCI_COMMAND]  = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
  d->card.config[PCI_CLASS_DEVICE] = 0;
  d->card.config[0x0b]  = 1;//storage
- d->card.config[0x0c]  = 0x08;  /* Cache line size */
- d->card.config[0x0d]  = 0x40;  /* Latency timer */
- d->card.config[0x0e]  = PCI_CLASS_HEADERTYPE_00h;
- d->card.config[0x3d] = 1;    /* interrupt pin 0 */
+ d->card.config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */
+ d->card.config[PCI_LATENCY_TIMER] = 0x00; /* Latency timer */
+ d->card.config[PCI_HEADER_TYPE]  = PCI_HEADER_TYPE_NORMAL;
+ d->card.config[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */
 
- pci_register_bar(&d->card, 5, 0x200,
+ pci_register_bar(&d->card, 5, 0x400,
    PCI_BASE_ADDRESS_SPACE_MEMORY, ahci_pci_map);
  d->ahci=ahci_new();
  d->ahci->irq = d->card.irq[0];
@@ -792,7 +806,7 @@
 {
     ahci_sysbus_state *d = FROM_SYSBUS(ahci_sysbus_state, dev);
  d->ahci=ahci_new();
-    sysbus_init_mmio(dev, 0x200, d->ahci->mem);
+    sysbus_init_mmio(dev, 0x400, d->ahci->mem);
     sysbus_init_irq(dev, &d->ahci->irq);
     return 0;
 }

[-- Attachment #2: ahci1.diff --]
[-- Type: application/octet-stream, Size: 5636 bytes --]

--- hw/ahci.c.orig	Sun May  2 15:43:58 2010
+++ hw/ahci.c	Sun May  2 22:03:26 2010
@@ -26,8 +26,15 @@
 #include "dma.h"
 #include "cpu-common.h"
 #include <hw/ide/internal.h>
-#define DPRINTF(...)
 
+#define DEBUG_AHCI
+
+#ifdef DEBUG_AHCI
+#define DPRINTF(fmt, ...) \
+do { printf("ahci: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
 
 enum {
 	AHCI_PCI_BAR		= 5,
@@ -203,6 +210,8 @@
 	uint32_t  version;
 } ahci_control_regs;
 
+#define SATA_PORTS 4
+
 typedef struct ahci_port_regs {
 	uint32_t lst_addr;
 	uint32_t lst_addr_hi;
@@ -240,7 +249,7 @@
 
 typedef struct AHCIState{
 	ahci_control_regs control_regs;
-	ahci_port_regs port_regs[2];
+	ahci_port_regs port_regs[SATA_PORTS];
 	int mem;
 	QEMUTimer *timer;
 	IDEBus *ide;
@@ -268,8 +277,10 @@
 	switch(offset)
 	{
 		case PORT_SCR:
-			if(s->ide && port==0) val=3;
-			else val=0;
+			if(s->ide && port==0)
+				val= 3 /* DET */ | (1 << 4) /* SPD */ | (1 << 8) /* IPM */;
+			else
+				val=0;
 			break;
 		case PORT_IRQ_STAT:
 			val=pr->irq_stat;
@@ -291,6 +302,7 @@
 			val= p[offset>>2];
 			break;
 	}
+	DPRINTF("ahci_port_read: port: 0x%x offset: 0x%x val: 0x%x\n", port, offset, val);
 	return val;
 
 }
@@ -299,7 +311,7 @@
 {
 	ahci_port_regs *pr;
 	int i;
-	for(i=0;i<2;i++)
+	for(i=0;i<SATA_PORTS;i++)
 	{
 		pr=&s->port_regs[i];
 
@@ -319,6 +331,7 @@
 	ahci_port_regs *pr=&s->port_regs[port];
 	uint32_t *p;
 
+	DPRINTF("ahci_port_write: port: 0x%x offset: 0x%x val: 0x%x\n", port, offset, val);
 	switch(offset)
 	{
 		case PORT_LST_ADDR:
@@ -396,7 +409,7 @@
 				val=p[addr>>2];
 		}
 	}
-	else if(addr>=0x100 && addr<0x200)
+	else if(addr>=0x100 && addr<0x300)
 	{
 		val=ahci_port_read(s,(addr-0x100)>>7,addr&0x7f);
 	}
@@ -436,7 +449,7 @@
 				p=(uint32_t *)&s->control_regs;
 		}
 	}
-	else if(addr>=0x100 && addr<0x200)
+	else if(addr>=0x100 && addr<0x300)
 	{
 		ahci_port_write(s,(addr-0x100)>>7,addr&0x7f,val);
 	}
@@ -459,10 +472,10 @@
 
 static void ahci_reg_init(AHCIState *s)
 {
-	s->control_regs.cap=2|(0x1f<<8); /*2 ports,32 cmd slot*/
-	s->control_regs.ghc=1<<31;
-	s->control_regs.impl=1;/*2 ports*/
-	s->control_regs.version=0x10100;
+	s->control_regs.cap = 3 | (0x1f << 8) | (1 << 20) ; /* 4 ports, 32 command slots, 1.5 Gb/s */
+	s->control_regs.ghc = 1 << 31; /* AHCI Enable */
+	s->control_regs.impl = 1; /* Port 0 implemented */
+	s->control_regs.version = 0x10000;
 }
 
 static void padstr(char *str, const char *src, int len)
@@ -619,19 +632,22 @@
 	prdt_num=cmd_hdr.opts>>16;
 	if(prdt_num) cpu_physical_memory_read(cmd_hdr.tbl_addr+0x80,(uint8_t *)s->prdt_buf,prdt_num*32);
 
-
+#ifdef DEBUG_AHCI
+        DPRINTF("fis:");
 	for(i=0;i<cmd_len;i++)
 	{
-		if((i&0xf)==0)DPRINTF("\n%02x:",i);
-		DPRINTF("%02x ",fis[i]);
+		if((i&0xf)==0) printf("\n%02x:",i);
+		printf("%02x ",fis[i]);
 	}
+        printf("\n");
+#endif
 
 	switch(fis[0])
 	{
 		case 0x27:
 			break;
 		default:
-			hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+			hw_error("unknown command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
 	}
 
 	switch(fis[1])
@@ -641,7 +657,7 @@
 		case 0:
 			break;
 		default:
-			hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+			hw_error("unknown command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
 	}
 
 	if(fis[1]==0)
@@ -684,7 +700,7 @@
 				pr->irq_stat |= (1<<2);
 				break;
 			default:
-				hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+				hw_error("unknown command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
 		}
 
 	}
@@ -698,7 +714,7 @@
 	AHCIState *s = opaque;
 	ahci_port_regs *pr;
 	int i,j;
-	for(i=0;i<2;i++)
+	for(i=0;i<SATA_PORTS;i++)
 	{
 		pr=&s->port_regs[i];
 		for(j=0;j<32 && pr->cmd_issue;j++)
@@ -741,23 +757,21 @@
 #define PCI_VENDOR_MYDEVICE  0x8086
 #define PCI_PRODUCT_MYDEVICE 0x2652
 
-#define PCI_CLASS_HEADERTYPE_00h	0x00
-
 static int pci_ahci_init(PCIDevice *dev)
 {
 	struct ahci_pci_state *d;
 	d = DO_UPCAST(struct ahci_pci_state, card, dev);
 	pci_config_set_vendor_id(d->card.config,PCI_VENDOR_MYDEVICE);
 	pci_config_set_device_id(d->card.config,PCI_PRODUCT_MYDEVICE);
-	d->card.config[PCI_COMMAND]		= 0x07;		/* I/O + Memory */
+	d->card.config[PCI_COMMAND]		= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
 	d->card.config[PCI_CLASS_DEVICE]	= 0;
 	d->card.config[0x0b]		= 1;//storage
-	d->card.config[0x0c]		= 0x08;		/* Cache line size */
-	d->card.config[0x0d]		= 0x40;		/* Latency timer */
-	d->card.config[0x0e]		= PCI_CLASS_HEADERTYPE_00h;
-	d->card.config[0x3d] = 1;    /* interrupt pin 0 */
+	d->card.config[PCI_CACHE_LINE_SIZE]	= 0x08;	/* Cache line size */
+	d->card.config[PCI_LATENCY_TIMER]	= 0x00;	/* Latency timer */
+	d->card.config[PCI_HEADER_TYPE]		= PCI_HEADER_TYPE_NORMAL;
+	d->card.config[PCI_INTERRUPT_PIN]	= 1; /* interrupt pin 0 */
 
-	pci_register_bar(&d->card, 5, 0x200,
+	pci_register_bar(&d->card, 5, 0x400,
 			PCI_BASE_ADDRESS_SPACE_MEMORY, ahci_pci_map);
 	d->ahci=ahci_new();
 	d->ahci->irq = d->card.irq[0];
@@ -792,7 +806,7 @@
 {
     ahci_sysbus_state *d = FROM_SYSBUS(ahci_sysbus_state, dev);
 	d->ahci=ahci_new();
-    sysbus_init_mmio(dev, 0x200, d->ahci->mem);
+    sysbus_init_mmio(dev, 0x400, d->ahci->mem);
     sysbus_init_irq(dev, &d->ahci->irq);
     return 0;
 }

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-02 15:56       ` Elek Roland
@ 2010-05-03 21:08         ` Elek Roland
  2010-05-04 20:56           ` Sebastian Herbszt
  0 siblings, 1 reply; 17+ messages in thread
From: Elek Roland @ 2010-05-03 21:08 UTC (permalink / raw)
  To: qemu-devel Developers; +Cc: Joerg Roedel, Alexander Graf

On v, 2010-05-02 at 17:56 +0200, Elek Roland wrote:
> I'm going to try the patch in practice as
> soon as I finish my university project. (It's due today.)

I've tried the patch, and I can confirm that it does provide an AHCI
device and a SATA disk. It shows up in qemu as an Intel Corporation
82801FR/FRW (ICH6R/ICH6RW) SATA Controller, which is consistent with the
device and vendor IDs in the code. I could successfully create an ext2
filesystem on the virtual disk, mount it, write a text file on it and
read it back.
I've noticed the following errors:
 - The source code claims to implement 2 ports, Linux reports 3.
 - When I halt the guest OS, the AHCI device throws a hardware error
about an unimplemented command.

I think we could clean up the code and use it as a basis for full
support.

Regards,
Roland

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-02 12:52   ` [Qemu-devel] [RFC] [PATCH] " 乔崇
  2010-05-02 15:36     ` [Qemu-devel] " Sebastian Herbszt
  2010-05-02 22:13     ` Sebastian Herbszt
@ 2010-05-04  0:01     ` Alexander Graf
  2010-05-04  0:28       ` 乔崇
  2 siblings, 1 reply; 17+ messages in thread
From: Alexander Graf @ 2010-05-04  0:01 UTC (permalink / raw)
  To: 乔崇; +Cc: Joerg Roedel, qemu-devel Developers, Elek Roland

Hi Chong (or Qiao? Which one is your first name?),

Upfront - please don't top post. Top posting is when you write your reply at the top of the mail. This is considered bad style on most open source mailing lists. Instead, people here usually send "inline" comments. So they put their reply below the text they're referring to. That makes it easier to jump into a discussion for others.

On 02.05.2010, at 14:52, 乔崇 wrote:

> Hi,Alexander Graf.
>   
>   I am very glad you noticed my patch about ahci.I love qemu just like I love linux.I wish I could do much more work on qemu development.

Yes, please! This looks like an amazing start.

In case any of my comments sound harsh or unfriendly, please don't interpret them that way. I very much appreciate you working on this and I hope you, Roland, Joerg and me can bring this code base to a ready to use state for everything within the next few months.

> I had cloned qemu from master branch,add my patch into it,and tested ahci on i386 softmmu.
> 
> If anyone is interested on ahci,you can test my patch like this:
> 
> git-clone -ls git://git.savannah.nongnu.org/qemu

I would do a "git checkout -b ahci" here to switch to a new branch called "ahci". That way you can work in the branch and compare things to the master branch later on using "git diff master" or even "git checkout master; git pull; git checkout ahci; git rebase master" to get your patches on top of the current master tree.

> patch -p1 -i 0001-add-ahci-support-into-qemu-only-support-sata-disk.patch
> patch -p1 -i 0002-add-ahci-device-into-i386-pc-just-for-test.patch

As a hint: "git am" is the counterpart to "git format-patch" :)

I'd also suggest we set up a git tree somewhere so we can work on this together with everyone pushing to it until we deem it ready.

> ./configure --target-list=i386-softmmu
> make
> 
> dd if=/dev/zero of=/tmp/disk bs=1M count=100
> ./i386-softmmu/qemu  -cdrom KNOPPIX_V6.0.1CD-2009-02-08-EN.iso -boot d -drive if=sd,file=/tmp/disk

if=sd? I thought that was used for sd card emulation on embedded boards.

> 
> After linux boot,you will find a ahci device named sda.
> 
> Now this patch only support sata disk.
> Most ahci registers and operations which are not necessary on linux are ignored.
> Now this patch support disk identify,dma read,dma write,ignore other opertions.
> 
> By the way how you send patch to mail list?

I usually use "git format-patch --cover-letter -n -o <patch directory> master" while in my working branch. Then I go to the patch directory and use "git send-email" to send off the generated files.

> 2009年 11月 16日 星期一 10:31:04 CST
> From 2844d2ea0ead3bcf5382e578a2d658902b0314c8 Mon Sep 17 00:00:00 2001
> From: QiaoChong <qiaochong@loongson.cn>
> Date: Sun, 2 May 2010 20:07:32 +0800
> Subject: [PATCH] add ahci support into qemu,only support sata disk.
> 
> use -drive if=sd,file=diskname to add a ahci disk into qemu.
> 
> Signed-off-by: QiaoChong <qiaochong@loongson.cn>
> ---
> Makefile.target |    4 +
> hw/ahci.c       |  805 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 809 insertions(+), 0 deletions(-)
> create mode 100644 hw/ahci.c
> 
> diff --git a/Makefile.target b/Makefile.target
> index 65beed5..189a776 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -186,6 +186,10 @@ obj-$(CONFIG_USB_OHCI) += usb-ohci.o
> obj-y += rtl8139.o
> obj-y += e1000.o
> 
> +# ahci
> +#
> +obj-$(CONFIG_AHCI) += ahci.o
> +
> # Hardware support
> obj-i386-y = pckbd.o dma.o
> obj-i386-y += vga.o
> diff --git a/hw/ahci.c b/hw/ahci.c
> new file mode 100644
> index 0000000..a332a45
> --- /dev/null
> +++ b/hw/ahci.c
> @@ -0,0 +1,805 @@
> +/*
> + * QEMU AHCI Emulation
> + * Copyright (c) 2010 qiaochong@loongson.cn
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library 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
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + *
> + * TODO:
> + *  o ahci cd support
> + */
> +#include "hw.h"
> +#include "qemu-timer.h"
> +#include "monitor.h"
> +#include "sysbus.h"
> +#include "pci.h"
> +#include "dma.h"
> +#include "cpu-common.h"
> +#include <hw/ide/internal.h>
> +#define DPRINTF(...)
> +
> +
> +enum {


This looks like it's not really an enum. You munge together quite some definitions that don't belong in the same namespace, as is indicated by the different mid-names (CMD, IRQ, PCI, ...). Please just use #define statements here.

Also keep in mind that in qemu code, there are no tabs. Use spaces for everything.

> +	AHCI_PCI_BAR		= 5,
> +	AHCI_MAX_PORTS		= 32,
> +	AHCI_MAX_SG		= 168, /* hardware max is 64K */
> +	AHCI_DMA_BOUNDARY	= 0xffffffff,
> +	AHCI_USE_CLUSTERING	= 0,
> +	AHCI_MAX_CMDS		= 32,
> +	AHCI_CMD_SZ		= 32,
> +	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
> +	AHCI_RX_FIS_SZ		= 256,
> +	AHCI_CMD_TBL_CDB	= 0x40,
> +	AHCI_CMD_TBL_HDR_SZ	= 0x80,
> +	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),

Why 16?

> +	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
> +	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
> +		AHCI_RX_FIS_SZ,
> +	AHCI_IRQ_ON_SG		= (1 << 31),
> +	AHCI_CMD_ATAPI		= (1 << 5),
> +	AHCI_CMD_WRITE		= (1 << 6),
> +	AHCI_CMD_PREFETCH	= (1 << 7),
> +	AHCI_CMD_RESET		= (1 << 8),
> +	AHCI_CMD_CLR_BUSY	= (1 << 10),
> +
> +	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
> +	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
> +	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
> +
> +	board_ahci		= 0,

lower case? Also what do the different boards mean?

> +	board_ahci_pi		= 1,
> +	board_ahci_vt8251	= 2,
> +	board_ahci_ign_iferr	= 3,
> +	board_ahci_sb600	= 4,
> +
> +	/* global controller registers */
> +	HOST_CAP		= 0x00, /* host capabilities */
> +	HOST_CTL		= 0x04, /* global host control */
> +	HOST_IRQ_STAT		= 0x08, /* interrupt status */
> +	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
> +	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */

These are register numbers, right? Please mark them as such in the define. I imagine REG_HOST_CAP, REG_HOST_CTL, ... would be a good fit?

> +
> +	/* HOST_CTL bits */
> +	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
> +	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
> +	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */

HOST_CTL_RESET, HOST_CTL_IRQ_EN, ...

> +
> +	/* HOST_CAP bits */
> +	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
> +	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
> +	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
> +	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
> +	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
> +
> +	/* registers for each SATA port */
> +	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
> +	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
> +	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
> +	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
> +	PORT_IRQ_STAT		= 0x10, /* interrupt status */
> +	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
> +	PORT_CMD		= 0x18, /* port command */
> +	PORT_TFDATA		= 0x20,	/* taskfile data */
> +	PORT_SIG		= 0x24,	/* device TF signature */
> +	PORT_CMD_ISSUE		= 0x38, /* command issue */
> +	PORT_SCR		= 0x28, /* SATA phy register block */
> +	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
> +	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
> +	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
> +	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */

REG_PORT_

> +
> +	/* PORT_IRQ_{STAT,MASK} bits */
> +	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
> +	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
> +	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
> +	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
> +	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
> +	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
> +	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
> +	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
> +
> +	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
> +	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
> +	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
> +	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
> +	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
> +	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
> +	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
> +	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
> +	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */

Please try to sort them descending.

> +
> +	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
> +		PORT_IRQ_IF_ERR |
> +		PORT_IRQ_CONNECT |
> +		PORT_IRQ_PHYRDY |
> +		PORT_IRQ_UNK_FIS,
> +	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
> +		PORT_IRQ_TF_ERR |
> +		PORT_IRQ_HBUS_DATA_ERR,
> +	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
> +		PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
> +		PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
> +
> +	/* PORT_CMD bits */
> +	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
> +	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
> +	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
> +	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
> +	PORT_CMD_CLO		= (1 << 3), /* Command list override */
> +	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
> +	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
> +	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */

descending

> +
> +	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
> +	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
> +	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
> +	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
> +
> +	/* ap->flags bits */
> +	AHCI_FLAG_NO_NCQ		= (1 << 24),
> +	AHCI_FLAG_IGN_IRQ_IF_ERR	= (1 << 25), /* ignore IRQ_IF_ERR */
> +	AHCI_FLAG_HONOR_PI		= (1 << 26), /* honor PORTS_IMPL */
> +	AHCI_FLAG_IGN_SERR_INTERNAL	= (1 << 27), /* ignore SERR_INTERNAL */
> +	AHCI_FLAG_32BIT_ONLY		= (1 << 28), /* force 32bit */
> +};
> +
> +/*
> + * ATA Commands (only mandatory commands listed here)
> + */
> +#define ATA_CMD_READ	0x20	/* Read Sectors (with retries)	*/
> +#define ATA_CMD_READN	0x21	/* Read Sectors ( no  retries)	*/
> +#define ATA_CMD_WRITE	0x30	/* Write Sectores (with retries)*/
> +#define ATA_CMD_WRITEN	0x31	/* Write Sectors  ( no  retries)*/
> +#define ATA_CMD_VRFY	0x40	/* Read Verify  (with retries)	*/
> +#define ATA_CMD_VRFYN	0x41	/* Read verify  ( no  retries)	*/
> +#define ATA_CMD_SEEK	0x70	/* Seek				*/
> +#define ATA_CMD_DIAG	0x90	/* Execute Device Diagnostic	*/
> +#define ATA_CMD_INIT	0x91	/* Initialize Device Parameters	*/
> +#define ATA_CMD_RD_MULT	0xC4	/* Read Multiple		*/
> +#define ATA_CMD_WR_MULT	0xC5	/* Write Multiple		*/
> +#define ATA_CMD_SETMULT	0xC6	/* Set Multiple Mode		*/
> +#define ATA_CMD_RD_DMA	0xC8	/* Read DMA (with retries)	*/
> +#define ATA_CMD_RD_DMAN	0xC9	/* Read DMS ( no  retries)	*/
> +#define ATA_CMD_WR_DMA	0xCA	/* Write DMA (with retries)	*/
> +#define ATA_CMD_WR_DMAN	0xCB	/* Write DMA ( no  retires)	*/
> +#define ATA_CMD_IDENT	0xEC	/* Identify Device		*/
> +#define ATA_CMD_SETF	0xEF	/* Set Features			*/
> +#define ATA_CMD_CHK_PWR	0xE5	/* Check Power Mode		*/
> +
> +#define ATA_CMD_READ_EXT 0x24	/* Read Sectors (with retries)	with 48bit addressing */
> +#define ATA_CMD_WRITE_EXT	0x34	/* Write Sectores (with retries) with 48bit addressing */
> +#define ATA_CMD_VRFY_EXT	0x42	/* Read Verify	(with retries)	with 48bit addressing */

This is the same as in ide, right? We should think about how to reuse that code.

> +
> +/*
> + * ATAPI Commands
> + */
> +#define ATAPI_CMD_IDENT 0xA1 /* Identify AT Atachment Packed Interface Device */
> +#define ATAPI_CMD_PACKET 0xA0 /* Packed Command */
> +
> +
> +#define ATAPI_CMD_INQUIRY 0x12
> +#define ATAPI_CMD_REQ_SENSE 0x03
> +#define ATAPI_CMD_READ_CAP 0x25
> +#define ATAPI_CMD_START_STOP 0x1B
> +#define ATAPI_CMD_READ_12 0xA8

These are all in ide already too.

> +
> +
> +
> +typedef struct ahci_control_regs {
> +	uint32_t  cap;
> +	uint32_t  ghc;
> +	uint32_t  irqstatus;
> +	uint32_t  impl;
> +	uint32_t  version;
> +} ahci_control_regs;
> +
> +typedef struct ahci_port_regs {
> +	uint32_t lst_addr;
> +	uint32_t lst_addr_hi;
> +	uint32_t fis_addr;
> +	uint32_t fis_addr_hi;
> +	uint32_t irq_stat;
> +	uint32_t irq_mask;
> +	uint32_t cmd;
> +	uint32_t unused0;
> +	uint32_t tfdata;
> +	uint32_t sig;
> +	uint32_t scr_stat;
> +	uint32_t scr_ctl;
> +	uint32_t scr_err;
> +	uint32_t scr_act;
> +	uint32_t cmd_issue;
> +} ahci_port_regs; 
> +
> +
> +typedef struct ahci_cmd_hdr {
> +	uint32_t			opts;
> +	uint32_t			status;
> +	uint32_t			tbl_addr;
> +	uint32_t			tbl_addr_hi;
> +	uint32_t			reserved[4];
> +} ahci_cmd_hdr;
> +
> +typedef struct ahci_sg {
> +	uint32_t			addr;
> +	uint32_t			addr_hi;
> +	uint32_t			reserved;
> +	uint32_t			flags_size;
> +} ahci_sg;

Structs can be difficult if you want to map guest data on them, as you might have to do byte swapping for endianness conversion. IMHO the easiest way to get the best of both worlds (endianness conversion and structs) is to use for example something like "addr = ldw_phys(offsetof(ahci_sg, addr))"

> +
> +
> +typedef struct AHCIState{
> +	ahci_control_regs control_regs;
> +	ahci_port_regs port_regs[2];
> +	int mem;
> +	QEMUTimer *timer;
> +	IDEBus *ide;
> +	ahci_sg *prdt_buf;
> +	qemu_irq irq;
> +} AHCIState;
> +
> +typedef struct ahci_pci_state {
> +	PCIDevice card;
> +	AHCIState *ahci;
> +} ahci_pci_state;
> +
> +typedef struct ahci_sysbus_state {
> +	SysBusDevice busdev;
> +	AHCIState *ahci;
> +} ahci_sysbus_state;
> +
> +static uint32_t  ahci_port_read(AHCIState *s,int port,int offset)
> +{
> +	uint32_t val;
> +	uint32_t *p;
> +	ahci_port_regs *pr;
> +	pr=&s->port_regs[port];
> +
> +	switch(offset)
> +	{
> +		case PORT_SCR:
> +			if(s->ide && port==0) val=3;
> +			else val=0;
> +			break;
> +		case PORT_IRQ_STAT:
> +			val=pr->irq_stat;
> +			break;
> +		case PORT_TFDATA:
> +
> +		case PORT_SIG:
> +
> +		case PORT_CMD_ISSUE:
> +
> +
> +		case PORT_SCR_CTL:
> +
> +		case PORT_SCR_ERR:
> +
> +		case PORT_SCR_ACT:
> +		default:
> +			p=(uint32_t *)&s->port_regs[port];
> +			val= p[offset>>2];

val = p[offset / sizeof(uint32_t)];

> +			break;
> +	}
> +	return val;
> +
> +}
> +
> +static void ahci_check_irq(AHCIState *s)
> +{
> +	ahci_port_regs *pr;
> +	int i;
> +	for(i=0;i<2;i++)

ARRAY_SIZE(s->port_regs)

> +	{
> +		pr=&s->port_regs[i];
> +
> +		if(pr->irq_stat&pr->irq_mask){
> +			s->control_regs.irqstatus |= (1<<i);
> +		}
> +	}
> +
> +	if(s->control_regs.irqstatus)
> +		qemu_irq_raise(s->irq);
> +	else qemu_irq_lower(s->irq);
> +}
> +
> +
> +static void  ahci_port_write(AHCIState *s,int port,int offset,uint32_t val)
> +{
> +	ahci_port_regs *pr=&s->port_regs[port];
> +	uint32_t *p;
> +
> +	switch(offset)
> +	{
> +		case PORT_LST_ADDR:
> +			pr->lst_addr=val; break;
> +
> +		case PORT_LST_ADDR_HI:
> +			pr->lst_addr_hi=val; break;
> +
> +		case PORT_FIS_ADDR:
> +			pr->fis_addr = val; break;
> +
> +		case PORT_FIS_ADDR_HI:
> +			pr->fis_addr_hi = val; break;

Any reason why you don't do the default trick on these?
I also prefer having the "break" on a new line.

> +
> +		case PORT_IRQ_STAT:
> +			pr->irq_stat &= ~val; 
> +			ahci_check_irq(s);
> +			break;
> +
> +		case PORT_IRQ_MASK:
> +			pr->irq_mask = val; 
> +			ahci_check_irq(s);
> +			break;
> +
> +		case PORT_CMD:
> +			pr->cmd=val&(PORT_CMD_ATAPI|PORT_CMD_LIST_ON|PORT_CMD_FIS_ON|PORT_CMD_FIS_RX|PORT_CMD_CLO|PORT_CMD_POWER_ON|PORT_CMD_SPIN_UP|PORT_CMD_START);
> +			if(pr->cmd&PORT_CMD_START)
> +				qemu_mod_timer(s->timer,qemu_get_clock(vm_clock)+muldiv64(1, get_ticks_per_sec(), 1000));

Enlighten me - what exactly do we need a timer for here?

> +			break;
> +
> +
> +		case PORT_CMD_ISSUE:
> +			pr->cmd_issue=val;
> +			if(pr->cmd&PORT_CMD_START)
> +				qemu_mod_timer(s->timer,qemu_get_clock(vm_clock)+muldiv64(1, get_ticks_per_sec(), 1000));
> +			break;
> +
> +		case PORT_TFDATA:
> +
> +		case PORT_SIG:
> +
> +
> +		case PORT_SCR:
> +
> +		case PORT_SCR_CTL:
> +
> +		case PORT_SCR_ERR:
> +
> +		case PORT_SCR_ACT:
> +
> +
> +		default:
> +			p=(uint32_t *)pr;
> +			p[offset>>2]=val;

see above

> +			break;
> +	}
> +
> +}
> +
> +static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
> +{
> +	AHCIState *s = ptr;
> +	uint32_t val;
> +	uint32_t *p;
> +	addr=addr&0xfff;
> +	if(addr<0x20)

see my comment on writel

> +	{
> +		switch(addr)
> +		{
> +			case HOST_IRQ_STAT:
> +
> +			default:
> +				/* genernal host control */
> +				p=(uint32_t *)&s->control_regs;
> +				val=p[addr>>2];

see above

> +		}
> +	}
> +	else if(addr>=0x100 && addr<0x200)
> +	{

doesn't belong on a new line. Please read the file "CODING_STYLE".

> +		val=ahci_port_read(s,(addr-0x100)>>7,addr&0x7f);
> +	}
> +	else val=0;

coding style

> +
> +
> +	DPRINTF("ahci_mem_readl:  (addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
> +
> +	return val;
> +}
> +
> +
> +
> +static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
> +{
> +	AHCIState *s = ptr;
> +	uint32_t *p;
> +	addr=addr&0xfff;
> +
> +	/* Only aligned reads are allowed on OHCI */

How does OHCI come in here? This is also about writes.

> +	if (addr & 3) {
> +		fprintf(stderr, "ahci: Mis-aligned write to addr 0x"
> +				TARGET_FMT_plx "\n", addr);
> +		return;
> +	}
> +
> +	if(addr<0x20)

Please make a define for this. I suppose it's REG_HOST_MAX?

> +	{
> +		switch(addr)
> +		{
> +			case HOST_IRQ_STAT:
> +				s->control_regs.irqstatus &= ~val; 
> +				ahci_check_irq(s);
> +				break;
> +			default:
> +				/* genernal host control */
> +				p=(uint32_t *)&s->control_regs;

huh?

> +		}
> +	}
> +	else if(addr>=0x100 && addr<0x200)
> +	{
> +		ahci_port_write(s,(addr-0x100)>>7,addr&0x7f,val);
> +	}
> +
> +	DPRINTF("ahci_mem_writel:  (addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
> +
> +}
> +
> +static CPUReadMemoryFunc *ahci_readfn[3]={
> +	ahci_mem_readl,
> +	ahci_mem_readl,
> +	ahci_mem_readl
> +};
> +
> +static CPUWriteMemoryFunc *ahci_writefn[3]={
> +	ahci_mem_writel,
> +	ahci_mem_writel,
> +	ahci_mem_writel
> +};
> +
> +static void ahci_reg_init(AHCIState *s)
> +{
> +	s->control_regs.cap=2|(0x1f<<8); /*2 ports,32 cmd slot*/
> +	s->control_regs.ghc=1<<31;
> +	s->control_regs.impl=1;/*2 ports*/
> +	s->control_regs.version=0x10100;

Too much magic. These should all be constants defined above.

> +}
> +
> +static void padstr(char *str, const char *src, int len)
> +{
> +	int i, v;
> +	for(i = 0; i < len; i++) {
> +		if (*src)
> +			v = *src++;
> +		else
> +			v = ' ';
> +		str[i^1] = v;
> +	}
> +}
> +
> +
> +static void put_le16(uint16_t *p, unsigned int v)
> +{
> +	*p = cpu_to_le16(v);
> +}

stw_p?

> +
> +
> +static void ide_identify(IDEState *s)

This is all in the ide code already. We should reuse it.

> +{
> +	uint16_t *p;
> +	unsigned int oldsize;
> +
> +	if (s->identify_set) {
> +		memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
> +		return;
> +	}
> +
> +	memset(s->io_buffer, 0, 512);
> +	p = (uint16_t *)s->io_buffer;
> +	put_le16(p + 0, 0x0040);
> +	put_le16(p + 1, s->cylinders);
> +	put_le16(p + 3, s->heads);
> +	put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */
> +	put_le16(p + 5, 512); /* XXX: retired, remove ? */
> +	put_le16(p + 6, s->sectors);
> +	padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
> +	put_le16(p + 20, 3); /* XXX: retired, remove ? */
> +	put_le16(p + 21, 512); /* cache size in sectors */
> +	put_le16(p + 22, 4); /* ecc bytes */
> +	padstr((char *)(p + 23), s->version, 8); /* firmware version */
> +	padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */
> +#if MAX_MULT_SECTORS > 1
> +	put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
> +#endif
> +	put_le16(p + 48, 1); /* dword I/O */
> +	put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */
> +	put_le16(p + 51, 0x200); /* PIO transfer cycle */
> +	put_le16(p + 52, 0x200); /* DMA transfer cycle */
> +	put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */
> +	put_le16(p + 54, s->cylinders);
> +	put_le16(p + 55, s->heads);
> +	put_le16(p + 56, s->sectors);
> +	oldsize = s->cylinders * s->heads * s->sectors;
> +	put_le16(p + 57, oldsize);
> +	put_le16(p + 58, oldsize >> 16);
> +	if (s->mult_sectors)
> +		put_le16(p + 59, 0x100 | s->mult_sectors);
> +	put_le16(p + 60, s->nb_sectors);
> +	put_le16(p + 61, s->nb_sectors >> 16);
> +	put_le16(p + 62, 0x07); /* single word dma0-2 supported */
> +	put_le16(p + 63, 0x07); /* mdma0-2 supported */
> +	put_le16(p + 65, 120);
> +	put_le16(p + 66, 120);
> +	put_le16(p + 67, 120);
> +	put_le16(p + 68, 120);
> +	put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
> +	put_le16(p + 81, 0x16); /* conforms to ata5 */
> +	/* 14=NOP supported, 0=SMART supported */
> +	put_le16(p + 82, (1 << 14) | 1);
> +	/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
> +	put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
> +	/* 14=set to 1, 1=SMART self test, 0=SMART error logging */
> +	put_le16(p + 84, (1 << 14) | 0);
> +	/* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
> +	if (bdrv_enable_write_cache(s->bs))
> +		put_le16(p + 85, (1 << 14) | (1 << 5) | 1);
> +	else
> +		put_le16(p + 85, (1 << 14) | 1);
> +	/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
> +	put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
> +	/* 14=set to 1, 1=smart self test, 0=smart error logging */
> +	put_le16(p + 87, (1 << 14) | 0);
> +	put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
> +	put_le16(p + 93, 1 | (1 << 14) | 0x2000);
> +	put_le16(p + 100, s->nb_sectors);
> +	put_le16(p + 101, s->nb_sectors >> 16);
> +	put_le16(p + 102, s->nb_sectors >> 32);
> +	put_le16(p + 103, s->nb_sectors >> 48);
> +
> +	memcpy(s->identify_data, p, sizeof(s->identify_data));
> +	s->identify_set = 1;
> +}
> +
> +#define min(a,b) (((a)<(b))?(a):(b))
> +
> +static uint32_t write_to_sglist(uint8_t *buffer,uint32_t len,ahci_sg *sglist,uint32_t sgcount)
> +{
> +	uint32_t i=0;
> +	uint32_t total=0,once;
> +	for(i=0;len&&sgcount;i++)
> +	{
> +		once=min(sglist->flags_size+1,len);
> +		cpu_physical_memory_write(sglist->addr,buffer,once);
> +		sglist++;
> +		sgcount--;
> +		len -= once;
> +		buffer += once;
> +		total += once;
> +	}
> +
> +	return total;
> +}
> +
> +static uint32_t read_from_sglist(uint8_t *buffer,uint32_t len,ahci_sg *sglist,uint32_t sgcount)
> +{
> +	uint32_t i=0;
> +	uint32_t total=0,once;
> +	for(i=0;len&&sgcount;i++)
> +	{
> +		once=min(sglist->flags_size+1,len);
> +		cpu_physical_memory_read(sglist->addr,buffer,once);
> +		sglist++;
> +		sgcount--;
> +		len -= once;
> +		buffer += once;
> +		total += once;
> +	}
> +
> +	return total;
> +}
> +
> +static void handle_cmd(AHCIState *s,int port,int slot)
> +{
> +	int64_t sector_num;
> +	int nb_sectors;
> +	IDEState *ide_state;
> +	int ret;
> +	int cmdaddr;
> +	uint8_t fis[0x80];
> +	int cmd_len;
> +	int prdt_num;
> +	int i;
> +	ahci_port_regs *pr;
> +	ahci_cmd_hdr cmd_hdr;
> +	pr=&s->port_regs[port];
> +	cmdaddr=pr->lst_addr+slot*32;
> +	cpu_physical_memory_read(cmdaddr,(uint8_t *)&cmd_hdr,16);

Breaks on big endian hosts

> +	cmd_len=(cmd_hdr.opts&0x1f)*4;
> +	cpu_physical_memory_read(cmd_hdr.tbl_addr,fis,cmd_len);

Breaks on big endian hosts.

> +	prdt_num=cmd_hdr.opts>>16;
> +	if(prdt_num) cpu_physical_memory_read(cmd_hdr.tbl_addr+0x80,(uint8_t *)s->prdt_buf,prdt_num*32);

Breaks on big endian hosts.
Also, why keep the prdt_buf in the struct? Can't that stay on stack?

> +
> +
> +	for(i=0;i<cmd_len;i++)
> +	{
> +		if((i&0xf)==0)DPRINTF("\n%02x:",i);
> +		DPRINTF("%02x ",fis[i]);
> +	}
> +
> +	switch(fis[0])

Magic constant?

> +	{
> +		case 0x27:

Magic constant?

> +			break;
> +		default:
> +			hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
> +	}
> +
> +	switch(fis[1])

Magic constant?

> +	{
> +		case 1<<7: /* cmd fis */

Magic constant?

> +			break;
> +		case 0:
> +			break;
> +		default:
> +			hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
> +	}
> +
> +	if(fis[1]==0)

Magic constant? Why not reuse the switch from above?

> +	{
> +
> +	}
> +
> +	if(fis[1]==(1<<7))

Magic constant?

> +	{
> +		if(!s->ide)hw_error("no ahci sata disk now\n");
> +		ide_state=&s->ide->ifs[0];
> +		switch(fis[2])

Magic constant?

> +		{
> +			case ATA_CMD_IDENT:

These should directly go to the ide command interpreter.

> +				ide_identify(ide_state);
> +				write_to_sglist(ide_state->identify_data, sizeof(ide_state->identify_data),s->prdt_buf,prdt_num);
> +				pr->irq_stat |= (1<<2);
> +				break;
> +			case WIN_SETFEATURES:
> +				pr->irq_stat |= (1<<2);
> +				break;
> +			case ATA_CMD_RD_DMA:
> +				sector_num=(((int64_t)fis[10])<<40)|(((int64_t)fis[9])<<32)|(fis[8]<<24)|(fis[6]<<16)|(fis[5]<<8)|fis[4];
> +				nb_sectors=(fis[13]<<8)|fis[12];
> +				if(!nb_sectors)nb_sectors=256;
> +				printf("nb_sectors=%x,prdt_num=%x\n",nb_sectors,prdt_num);
> +				ret = bdrv_read(ide_state->bs, sector_num, ide_state->io_buffer, nb_sectors);
> +				if(ret==0)
> +				{
> +					write_to_sglist(ide_state->io_buffer,nb_sectors*512,s->prdt_buf,prdt_num);
> +				}
> +				pr->irq_stat |= (1<<2);
> +				break;
> +			case ATA_CMD_WR_DMA:
> +				sector_num=(((int64_t)fis[10])<<40)|(((int64_t)fis[9])<<32)|(fis[8]<<24)|(fis[6]<<16)|(fis[5]<<8)|fis[4];
> +				nb_sectors=(fis[13]<<8)|fis[12];
> +				if(!nb_sectors)nb_sectors=256;
> +				read_from_sglist(ide_state->io_buffer,nb_sectors*512,s->prdt_buf,prdt_num);
> +				ret = bdrv_write(ide_state->bs, sector_num, ide_state->io_buffer, nb_sectors);
> +				pr->irq_stat |= (1<<2);
> +				break;
> +			default:
> +				hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
> +		}
> +
> +	}
> +
> +	pr->cmd_issue &=~(1<<slot);
> +	ahci_check_irq(s);
> +}
> +
> +static void ahci_timer_function(void *opaque)
> +{
> +	AHCIState *s = opaque;
> +	ahci_port_regs *pr;
> +	int i,j;
> +	for(i=0;i<2;i++)
> +	{
> +		pr=&s->port_regs[i];
> +		for(j=0;j<32 && pr->cmd_issue;j++)
> +		{
> +			if(pr->cmd_issue&(1<<j))
> +			{
> +				handle_cmd(s,i,j);

So the register trigger above just waits for some milliseconds and then checks if there's a new command? Can't the command checking be done immediately?

> +			}	
> +		}
> +	}
> +}
> +
> +static AHCIState *ahci_new(void)
> +{
> +	DriveInfo *dinfo;
> +	IDEBus  *bus = qemu_mallocz(sizeof(IDEBus));
> +	AHCIState *s = qemu_mallocz(sizeof(AHCIState));
> +	ahci_reg_init(s);
> +	s->mem = cpu_register_io_memory(ahci_readfn, ahci_writefn, s);
> +	s->timer = qemu_new_timer(vm_clock, ahci_timer_function, s);
> +	s->prdt_buf = qemu_malloc(65535*32);

Oh, it can get this big? I guess I'll have to read again what this really is.

> +
> +	if ((dinfo = drive_get(IF_SD, 0, 0)) != NULL)

SATA should be a new if type. Please don't reuse the SD one.

> +	{
> +		ide_init2(bus, dinfo, NULL,0);
> +		s->ide=bus;
> +	}
> +	return s;
> +}
> +
> +static void ahci_pci_map(PCIDevice *pci_dev, int region_num,
> +		pcibus_t addr, pcibus_t size, int type)
> +{
> +	struct ahci_pci_state *d = (struct ahci_pci_state *)pci_dev;
> +	AHCIState *s = d->ahci;
> +
> +	cpu_register_physical_memory(addr, size, s->mem);
> +}
> +
> +#define PCI_VENDOR_MYDEVICE  0x8086
> +#define PCI_PRODUCT_MYDEVICE 0x2652

See hw/pci_ids.h

> +
> +#define PCI_CLASS_HEADERTYPE_00h	0x00

Please have a look at hw/pci_regs.h.

> +
> +static int pci_ahci_init(PCIDevice *dev)
> +{
> +	struct ahci_pci_state *d;
> +	d = DO_UPCAST(struct ahci_pci_state, card, dev);
> +	pci_config_set_vendor_id(d->card.config,PCI_VENDOR_MYDEVICE);
> +	pci_config_set_device_id(d->card.config,PCI_PRODUCT_MYDEVICE);
> +	d->card.config[PCI_COMMAND]		= 0x07;		/* I/O + Memory */

Magic constant?

> +	d->card.config[PCI_CLASS_DEVICE]	= 0;
> +	d->card.config[0x0b]		= 1;//storage

Magic constant?

> +	d->card.config[0x0c]		= 0x08;		/* Cache line size */
> +	d->card.config[0x0d]		= 0x40;		/* Latency timer */
> +	d->card.config[0x0e]		= PCI_CLASS_HEADERTYPE_00h;

d->card.config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;

> +	d->card.config[0x3d] = 1;    /* interrupt pin 0 */
> +
> +	pci_register_bar(&d->card, 5, 0x200,
> +			PCI_BASE_ADDRESS_SPACE_MEMORY, ahci_pci_map);
> +	d->ahci=ahci_new();
> +	d->ahci->irq = d->card.irq[0];
> +	return 0;
> +}
> +
> +static int pci_ahci_uninit(PCIDevice *dev)
> +{
> +	return 0;
> +}
> +
> +static PCIDeviceInfo ahci_info = {
> +	.qdev.name  = "ahci",
> +	.qdev.size  = sizeof(ahci_pci_state),
> +	.init       = pci_ahci_init,
> +	.exit       = pci_ahci_uninit,
> +	.qdev.props = (Property[]) {
> +		DEFINE_PROP_END_OF_LIST(),
> +	}
> +};

The ahci device is pretty similar to a virtio-blk device from a topology point of view. It is basically a proxy for IDE. So the qdev structure should be pretty similar as well.

> +
> +static void ahci_pci_register_devices(void)
> +{
> +	pci_qdev_register(&ahci_info);
> +}
> +
> +device_init(ahci_pci_register_devices)
> +
> +
> +
> +static int ahci_sysbus_init(SysBusDevice *dev)
> +{
> +    ahci_sysbus_state *d = FROM_SYSBUS(ahci_sysbus_state, dev);
> +	d->ahci=ahci_new();
> +    sysbus_init_mmio(dev, 0x200, d->ahci->mem);
> +    sysbus_init_irq(dev, &d->ahci->irq);
> +    return 0;
> +}
> +
> +static void ahci_sysbus_register_devices(void)
> +{
> +    sysbus_register_dev("ahci", sizeof(ahci_sysbus_state), ahci_sysbus_init);
> +}
> +
> +device_init(ahci_sysbus_register_devices)
> -- 
> 1.5.6.5
> 
> From 446cce5657bf570fc612dea513f5bedcdc3be275 Mon Sep 17 00:00:00 2001
> From: QiaoChong <qiaochong@loongson.cn>
> Date: Sun, 2 May 2010 16:53:43 +0800
> Subject: [PATCH] add ahci device into i386 pc just for test.
> 
> test like this:
> 
> dd if=/dev/zero of=/tmp/disk bs=1M count=100
> ./i386-softmmu/qemu  -cdrom /mnt/hdb1/knoppix-dvd/KNOPPIX_V6.0.1CD-2009-02-08-EN.iso -boot d -drive if=sd,file=/tmp/disk
> 
> Signed-off-by: QiaoChong <qiaochong@loongson.cn>
> ---
> default-configs/i386-softmmu.mak |    2 ++
> hw/pc.c                          |    1 +
> 2 files changed, 3 insertions(+), 0 deletions(-)
> 
> diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
> index 4c1495f..bd72f39 100644
> --- a/default-configs/i386-softmmu.mak
> +++ b/default-configs/i386-softmmu.mak
> @@ -20,3 +20,5 @@ CONFIG_NE2000_ISA=y
> CONFIG_PIIX_PCI=y
> CONFIG_SOUND=y
> CONFIG_VIRTIO_PCI=y
> +CONFIG_AHCI=y

This should also be enabled for x86_64.

> +
> diff --git a/hw/pc.c b/hw/pc.c
> index b659344..7ea437f 100644
> --- a/hw/pc.c
> +++ b/hw/pc.c
> @@ -1005,6 +1005,7 @@ static void pc_init1(ram_addr_t ram_size,
> 
>     if (pci_enabled) {
>         pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
> +		pci_create_simple(pci_bus,-1,"ahci");

Hrm. Isn't there a way to only instantiate it when used? How does if=scsi work? The same logic should apply here.


So far for a quick glimpse through the code. It all looks very good for a first revision :)

Alex

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-04  0:01     ` [Qemu-devel] " Alexander Graf
@ 2010-05-04  0:28       ` 乔崇
  2010-05-09 19:16         ` Alexander Graf
  0 siblings, 1 reply; 17+ messages in thread
From: 乔崇 @ 2010-05-04  0:28 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Joerg Roedel, qemu-devel Developers, Elek Roland

[-- Attachment #1: Type: text/html, Size: 38108 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-02 22:13     ` Sebastian Herbszt
@ 2010-05-04  1:07       ` 乔崇
  2010-05-04 20:51         ` Sebastian Herbszt
  0 siblings, 1 reply; 17+ messages in thread
From: 乔崇 @ 2010-05-04  1:07 UTC (permalink / raw)
  To: Sebastian Herbszt
  Cc: Joerg Roedel, Elek Roland, Alexander Graf, qemu-devel Developers

[-- Attachment #1: Type: text/plain, Size: 6354 bytes --]

I add Sebastian Herbsz's patch,add WIN_WIN_STANDBYNOW1 support to fix 
hw_error on linux shut down etc.

I am  not familiar with  git send-email,I am studying it now :).


Sebastian Herbszt 写道:
> Hi again,
>
> please consider the following minor changes:
> - debug output with DEBUG_AHCI
> - set port count to 4
> - change return value of PxSSTS to include SPD and IPM
> - change cap and version default values according to Intel #301473-002
>
> Regards,
> Sebastian
>
> --- hw/ahci.c.orig Sun May  2 15:43:58 2010
> +++ hw/ahci.c Sun May  2 22:03:26 2010
> @@ -26,8 +26,15 @@
> #include "dma.h"
> #include "cpu-common.h"
> #include <hw/ide/internal.h>
> -#define DPRINTF(...)
>
> +#define DEBUG_AHCI
> +
> +#ifdef DEBUG_AHCI
> +#define DPRINTF(fmt, ...) \
> +do { printf("ahci: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF(fmt, ...) do {} while(0)
> +#endif
>
> enum {
>  AHCI_PCI_BAR  = 5,
> @@ -203,6 +210,8 @@
>  uint32_t  version;
> } ahci_control_regs;
>
> +#define SATA_PORTS 4
> +
> typedef struct ahci_port_regs {
>  uint32_t lst_addr;
>  uint32_t lst_addr_hi;
> @@ -240,7 +249,7 @@
>
> typedef struct AHCIState{
>  ahci_control_regs control_regs;
> - ahci_port_regs port_regs[2];
> + ahci_port_regs port_regs[SATA_PORTS];
>  int mem;
>  QEMUTimer *timer;
>  IDEBus *ide;
> @@ -268,8 +277,10 @@
>  switch(offset)
>  {
>   case PORT_SCR:
> -   if(s->ide && port==0) val=3;
> -   else val=0;
> +   if(s->ide && port==0)
> +    val= 3 /* DET */ | (1 << 4) /* SPD */ | (1 << 8) /* IPM */;
> +   else
> +    val=0;
>    break;
>   case PORT_IRQ_STAT:
>    val=pr->irq_stat;
> @@ -291,6 +302,7 @@
>    val= p[offset>>2];
>    break;
>  }
> + DPRINTF("ahci_port_read: port: 0x%x offset: 0x%x val: 0x%x\n", port, 
> offset, val);
>  return val;
>
> }
> @@ -299,7 +311,7 @@
> {
>  ahci_port_regs *pr;
>  int i;
> - for(i=0;i<2;i++)
> + for(i=0;i<SATA_PORTS;i++)
>  {
>   pr=&s->port_regs[i];
>
> @@ -319,6 +331,7 @@
>  ahci_port_regs *pr=&s->port_regs[port];
>  uint32_t *p;
>
> + DPRINTF("ahci_port_write: port: 0x%x offset: 0x%x val: 0x%x\n", 
> port, offset, val);
>  switch(offset)
>  {
>   case PORT_LST_ADDR:
> @@ -396,7 +409,7 @@
>     val=p[addr>>2];
>   }
>  }
> - else if(addr>=0x100 && addr<0x200)
> + else if(addr>=0x100 && addr<0x300)
>  {
>   val=ahci_port_read(s,(addr-0x100)>>7,addr&0x7f);
>  }
> @@ -436,7 +449,7 @@
>     p=(uint32_t *)&s->control_regs;
>   }
>  }
> - else if(addr>=0x100 && addr<0x200)
> + else if(addr>=0x100 && addr<0x300)
>  {
>   ahci_port_write(s,(addr-0x100)>>7,addr&0x7f,val);
>  }
> @@ -459,10 +472,10 @@
>
> static void ahci_reg_init(AHCIState *s)
> {
> - s->control_regs.cap=2|(0x1f<<8); /*2 ports,32 cmd slot*/
> - s->control_regs.ghc=1<<31;
> - s->control_regs.impl=1;/*2 ports*/
> - s->control_regs.version=0x10100;
> + s->control_regs.cap = 3 | (0x1f << 8) | (1 << 20) ; /* 4 ports, 32 
> command slots, 1.5 Gb/s */
> + s->control_regs.ghc = 1 << 31; /* AHCI Enable */
> + s->control_regs.impl = 1; /* Port 0 implemented */
> + s->control_regs.version = 0x10000;
> }
>
> static void padstr(char *str, const char *src, int len)
> @@ -619,19 +632,22 @@
>  prdt_num=cmd_hdr.opts>>16;
>  if(prdt_num) cpu_physical_memory_read(cmd_hdr.tbl_addr+0x80,(uint8_t 
> *)s->prdt_buf,prdt_num*32);
>
> -
> +#ifdef DEBUG_AHCI
> +        DPRINTF("fis:");
>  for(i=0;i<cmd_len;i++)
>  {
> -  if((i&0xf)==0)DPRINTF("\n%02x:",i);
> -  DPRINTF("%02x ",fis[i]);
> +  if((i&0xf)==0) printf("\n%02x:",i);
> +  printf("%02x ",fis[i]);
>  }
> +        printf("\n");
> +#endif
>
>  switch(fis[0])
>  {
>   case 0x27:
>    break;
>   default:
> -   hw_error("unkonow command fis[0]=%02x fis[1]=%02x 
> fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
> +   hw_error("unknown command fis[0]=%02x fis[1]=%02x 
> fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
>  }
>
>  switch(fis[1])
> @@ -641,7 +657,7 @@
>   case 0:
>    break;
>   default:
> -   hw_error("unkonow command fis[0]=%02x fis[1]=%02x 
> fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
> +   hw_error("unknown command fis[0]=%02x fis[1]=%02x 
> fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
>  }
>
>  if(fis[1]==0)
> @@ -684,7 +700,7 @@
>     pr->irq_stat |= (1<<2);
>     break;
>    default:
> -    hw_error("unkonow command fis[0]=%02x fis[1]=%02x 
> fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
> +    hw_error("unknown command fis[0]=%02x fis[1]=%02x 
> fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
>   }
>
>  }
> @@ -698,7 +714,7 @@
>  AHCIState *s = opaque;
>  ahci_port_regs *pr;
>  int i,j;
> - for(i=0;i<2;i++)
> + for(i=0;i<SATA_PORTS;i++)
>  {
>   pr=&s->port_regs[i];
>   for(j=0;j<32 && pr->cmd_issue;j++)
> @@ -741,23 +757,21 @@
> #define PCI_VENDOR_MYDEVICE  0x8086
> #define PCI_PRODUCT_MYDEVICE 0x2652
>
> -#define PCI_CLASS_HEADERTYPE_00h 0x00
> -
> static int pci_ahci_init(PCIDevice *dev)
> {
>  struct ahci_pci_state *d;
>  d = DO_UPCAST(struct ahci_pci_state, card, dev);
>  pci_config_set_vendor_id(d->card.config,PCI_VENDOR_MYDEVICE);
>  pci_config_set_device_id(d->card.config,PCI_PRODUCT_MYDEVICE);
> - d->card.config[PCI_COMMAND]  = 0x07;  /* I/O + Memory */
> + d->card.config[PCI_COMMAND]  = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | 
> PCI_COMMAND_MASTER;
>  d->card.config[PCI_CLASS_DEVICE] = 0;
>  d->card.config[0x0b]  = 1;//storage
> - d->card.config[0x0c]  = 0x08;  /* Cache line size */
> - d->card.config[0x0d]  = 0x40;  /* Latency timer */
> - d->card.config[0x0e]  = PCI_CLASS_HEADERTYPE_00h;
> - d->card.config[0x3d] = 1;    /* interrupt pin 0 */
> + d->card.config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */
> + d->card.config[PCI_LATENCY_TIMER] = 0x00; /* Latency timer */
> + d->card.config[PCI_HEADER_TYPE]  = PCI_HEADER_TYPE_NORMAL;
> + d->card.config[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */
>
> - pci_register_bar(&d->card, 5, 0x200,
> + pci_register_bar(&d->card, 5, 0x400,
>    PCI_BASE_ADDRESS_SPACE_MEMORY, ahci_pci_map);
>  d->ahci=ahci_new();
>  d->ahci->irq = d->card.irq[0];
> @@ -792,7 +806,7 @@
> {
>     ahci_sysbus_state *d = FROM_SYSBUS(ahci_sysbus_state, dev);
>  d->ahci=ahci_new();
> -    sysbus_init_mmio(dev, 0x200, d->ahci->mem);
> +    sysbus_init_mmio(dev, 0x400, d->ahci->mem);
>     sysbus_init_irq(dev, &d->ahci->irq);
>     return 0;
> }


-- 

乔崇 qiaochong.ac.cn
龙芯技术服务中心
office:010-62600855-108
mobile:13521990614

2009年 11月 16日 星期一 10:31:04 CST

[-- Attachment #2: 0001-fix-port-count-cap-and-version-etc-to-ahci.patch --]
[-- Type: text/x-patch, Size: 6857 bytes --]

>From 30cc6d82d4b3ad71672801f6126934a84ec39925 Mon Sep 17 00:00:00 2001
From: Sebastian Herbszt <herbszt@gmx.de>
Date: Tue, 4 May 2010 07:17:47 +0800
Subject: [PATCH] fix port count,cap and version etc to ahci.

- debug output with DEBUG_AHCI
- set port count to 4
- change return value of PxSSTS to include SPD and IPM
- change cap and version default values according to Intel #301473-002

Signed-off-by: QiaoChong <qiaochong@loongson.cn>
---
 hw/ahci.c |   68 ++++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 41 insertions(+), 27 deletions(-)

diff --git a/hw/ahci.c b/hw/ahci.c
index a332a45..b6a81af 100644
--- a/hw/ahci.c
+++ b/hw/ahci.c
@@ -26,8 +26,15 @@
 #include "dma.h"
 #include "cpu-common.h"
 #include <hw/ide/internal.h>
-#define DPRINTF(...)
 
+#define DEBUG_AHCI
+
+#ifdef DEBUG_AHCI
+#define DPRINTF(fmt, ...) \
+do { printf("ahci: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
 
 enum {
 	AHCI_PCI_BAR		= 5,
@@ -203,6 +210,8 @@ typedef struct ahci_control_regs {
 	uint32_t  version;
 } ahci_control_regs;
 
+#define SATA_PORTS 4
+
 typedef struct ahci_port_regs {
 	uint32_t lst_addr;
 	uint32_t lst_addr_hi;
@@ -240,7 +249,7 @@ typedef struct ahci_sg {
 
 typedef struct AHCIState{
 	ahci_control_regs control_regs;
-	ahci_port_regs port_regs[2];
+	ahci_port_regs port_regs[SATA_PORTS];
 	int mem;
 	QEMUTimer *timer;
 	IDEBus *ide;
@@ -268,8 +277,10 @@ static uint32_t  ahci_port_read(AHCIState *s,int port,int offset)
 	switch(offset)
 	{
 		case PORT_SCR:
-			if(s->ide && port==0) val=3;
-			else val=0;
+			if(s->ide && port==0)
+				val= 3 /* DET */ | (1 << 4) /* SPD */ | (1 << 8) /* IPM */;
+			else
+				val=0;
 			break;
 		case PORT_IRQ_STAT:
 			val=pr->irq_stat;
@@ -291,6 +302,7 @@ static uint32_t  ahci_port_read(AHCIState *s,int port,int offset)
 			val= p[offset>>2];
 			break;
 	}
+	DPRINTF("ahci_port_read: port: 0x%x offset: 0x%x val: 0x%x\n", port, offset, val);
 	return val;
 
 }
@@ -299,7 +311,7 @@ static void ahci_check_irq(AHCIState *s)
 {
 	ahci_port_regs *pr;
 	int i;
-	for(i=0;i<2;i++)
+	for(i=0;i<SATA_PORTS;i++)
 	{
 		pr=&s->port_regs[i];
 
@@ -319,6 +331,7 @@ static void  ahci_port_write(AHCIState *s,int port,int offset,uint32_t val)
 	ahci_port_regs *pr=&s->port_regs[port];
 	uint32_t *p;
 
+	DPRINTF("ahci_port_write: port: 0x%x offset: 0x%x val: 0x%x\n", port, offset, val);
 	switch(offset)
 	{
 		case PORT_LST_ADDR:
@@ -396,7 +409,7 @@ static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
 				val=p[addr>>2];
 		}
 	}
-	else if(addr>=0x100 && addr<0x200)
+	else if(addr>=0x100 && addr<0x300)
 	{
 		val=ahci_port_read(s,(addr-0x100)>>7,addr&0x7f);
 	}
@@ -436,7 +449,7 @@ static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
 				p=(uint32_t *)&s->control_regs;
 		}
 	}
-	else if(addr>=0x100 && addr<0x200)
+	else if(addr>=0x100 && addr<0x300)
 	{
 		ahci_port_write(s,(addr-0x100)>>7,addr&0x7f,val);
 	}
@@ -459,10 +472,10 @@ static CPUWriteMemoryFunc *ahci_writefn[3]={
 
 static void ahci_reg_init(AHCIState *s)
 {
-	s->control_regs.cap=2|(0x1f<<8); /*2 ports,32 cmd slot*/
-	s->control_regs.ghc=1<<31;
-	s->control_regs.impl=1;/*2 ports*/
-	s->control_regs.version=0x10100;
+	s->control_regs.cap = 3 | (0x1f << 8) | (1 << 20) ; /* 4 ports, 32 command slots, 1.5 Gb/s */
+	s->control_regs.ghc = 1 << 31; /* AHCI Enable */
+	s->control_regs.impl = 1; /* Port 0 implemented */
+	s->control_regs.version = 0x10000;
 }
 
 static void padstr(char *str, const char *src, int len)
@@ -619,19 +632,22 @@ static void handle_cmd(AHCIState *s,int port,int slot)
 	prdt_num=cmd_hdr.opts>>16;
 	if(prdt_num) cpu_physical_memory_read(cmd_hdr.tbl_addr+0x80,(uint8_t *)s->prdt_buf,prdt_num*32);
 
-
+#ifdef DEBUG_AHCI
+        DPRINTF("fis:");
 	for(i=0;i<cmd_len;i++)
 	{
-		if((i&0xf)==0)DPRINTF("\n%02x:",i);
-		DPRINTF("%02x ",fis[i]);
+		if((i&0xf)==0) printf("\n%02x:",i);
+		printf("%02x ",fis[i]);
 	}
+        printf("\n");
+#endif
 
 	switch(fis[0])
 	{
 		case 0x27:
 			break;
 		default:
-			hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+			hw_error("unknown command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
 	}
 
 	switch(fis[1])
@@ -641,7 +657,7 @@ static void handle_cmd(AHCIState *s,int port,int slot)
 		case 0:
 			break;
 		default:
-			hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+			hw_error("unknown command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
 	}
 
 	if(fis[1]==0)
@@ -684,7 +700,7 @@ static void handle_cmd(AHCIState *s,int port,int slot)
 				pr->irq_stat |= (1<<2);
 				break;
 			default:
-				hw_error("unkonow command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
+				hw_error("unknown command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);break;
 		}
 
 	}
@@ -698,7 +714,7 @@ static void ahci_timer_function(void *opaque)
 	AHCIState *s = opaque;
 	ahci_port_regs *pr;
 	int i,j;
-	for(i=0;i<2;i++)
+	for(i=0;i<SATA_PORTS;i++)
 	{
 		pr=&s->port_regs[i];
 		for(j=0;j<32 && pr->cmd_issue;j++)
@@ -741,23 +757,21 @@ static void ahci_pci_map(PCIDevice *pci_dev, int region_num,
 #define PCI_VENDOR_MYDEVICE  0x8086
 #define PCI_PRODUCT_MYDEVICE 0x2652
 
-#define PCI_CLASS_HEADERTYPE_00h	0x00
-
 static int pci_ahci_init(PCIDevice *dev)
 {
 	struct ahci_pci_state *d;
 	d = DO_UPCAST(struct ahci_pci_state, card, dev);
 	pci_config_set_vendor_id(d->card.config,PCI_VENDOR_MYDEVICE);
 	pci_config_set_device_id(d->card.config,PCI_PRODUCT_MYDEVICE);
-	d->card.config[PCI_COMMAND]		= 0x07;		/* I/O + Memory */
+	d->card.config[PCI_COMMAND]		= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
 	d->card.config[PCI_CLASS_DEVICE]	= 0;
 	d->card.config[0x0b]		= 1;//storage
-	d->card.config[0x0c]		= 0x08;		/* Cache line size */
-	d->card.config[0x0d]		= 0x40;		/* Latency timer */
-	d->card.config[0x0e]		= PCI_CLASS_HEADERTYPE_00h;
-	d->card.config[0x3d] = 1;    /* interrupt pin 0 */
+	d->card.config[PCI_CACHE_LINE_SIZE]	= 0x08;	/* Cache line size */
+	d->card.config[PCI_LATENCY_TIMER]	= 0x00;	/* Latency timer */
+	d->card.config[PCI_HEADER_TYPE]		= PCI_HEADER_TYPE_NORMAL;
+	d->card.config[PCI_INTERRUPT_PIN]	= 1; /* interrupt pin 0 */
 
-	pci_register_bar(&d->card, 5, 0x200,
+	pci_register_bar(&d->card, 5, 0x400,
 			PCI_BASE_ADDRESS_SPACE_MEMORY, ahci_pci_map);
 	d->ahci=ahci_new();
 	d->ahci->irq = d->card.irq[0];
@@ -792,7 +806,7 @@ static int ahci_sysbus_init(SysBusDevice *dev)
 {
     ahci_sysbus_state *d = FROM_SYSBUS(ahci_sysbus_state, dev);
 	d->ahci=ahci_new();
-    sysbus_init_mmio(dev, 0x200, d->ahci->mem);
+    sysbus_init_mmio(dev, 0x400, d->ahci->mem);
     sysbus_init_irq(dev, &d->ahci->irq);
     return 0;
 }
-- 
1.5.6.5


[-- Attachment #3: 0002-add-WIN_STANDBYNOW1-process-into-ahci.patch --]
[-- Type: text/x-patch, Size: 753 bytes --]

>From c07ddd1f9c9ec664a0ef3ee4ad43d930045c9ff7 Mon Sep 17 00:00:00 2001
From: QiaoChong <qiaochong@loongson.cn>
Date: Sun, 2 May 2010 21:54:14 +0800
Subject: [PATCH] add  WIN_STANDBYNOW1 process into ahci.

Signed-off-by: QiaoChong <qiaochong@loongson.cn>
---
 hw/ahci.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/hw/ahci.c b/hw/ahci.c
index b6a81af..cb4a851 100644
--- a/hw/ahci.c
+++ b/hw/ahci.c
@@ -676,6 +676,7 @@ static void handle_cmd(AHCIState *s,int port,int slot)
 				write_to_sglist(ide_state->identify_data, sizeof(ide_state->identify_data),s->prdt_buf,prdt_num);
 				pr->irq_stat |= (1<<2);
 				break;
+			case WIN_STANDBYNOW1:
 			case WIN_SETFEATURES:
 				pr->irq_stat |= (1<<2);
 				break;
-- 
1.5.6.5


[-- Attachment #4: 0003-ahci-pci-ids-into-pci_ids.h-add-warning-messages.patch --]
[-- Type: text/x-patch, Size: 1933 bytes --]

>From e94912b03ed33080d550eb5764fc99911498101b Mon Sep 17 00:00:00 2001
From: QiaoChong <qiaochong@loongson.cn>
Date: Tue, 4 May 2010 07:31:30 +0800
Subject: [PATCH] ahci pci ids  into pci_ids.h,add warning messages.

move ahci pci device id define into pci_ids.h,add warning messages for
unsupported features.

Signed-off-by: QiaoChong <qiaochong@loongson.cn>
---
 hw/ahci.c    |   10 +++++-----
 hw/pci_ids.h |    1 +
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/hw/ahci.c b/hw/ahci.c
index cb4a851..e1aed4a 100644
--- a/hw/ahci.c
+++ b/hw/ahci.c
@@ -662,7 +662,9 @@ static void handle_cmd(AHCIState *s,int port,int slot)
 
 	if(fis[1]==0)
 	{
-
+#ifdef DEBUG_AHCI
+			printf("now,just ignore command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);
+#endif
 	}
 
 	if(fis[1]==(1<<7))
@@ -755,15 +757,13 @@ static void ahci_pci_map(PCIDevice *pci_dev, int region_num,
 	cpu_register_physical_memory(addr, size, s->mem);
 }
 
-#define PCI_VENDOR_MYDEVICE  0x8086
-#define PCI_PRODUCT_MYDEVICE 0x2652
 
 static int pci_ahci_init(PCIDevice *dev)
 {
 	struct ahci_pci_state *d;
 	d = DO_UPCAST(struct ahci_pci_state, card, dev);
-	pci_config_set_vendor_id(d->card.config,PCI_VENDOR_MYDEVICE);
-	pci_config_set_device_id(d->card.config,PCI_PRODUCT_MYDEVICE);
+	pci_config_set_vendor_id(d->card.config,PCI_VENDOR_ID_INTEL);
+	pci_config_set_device_id(d->card.config,PCI_DEVICE_ID_INTEL_ICH6R_AHCI);
 	d->card.config[PCI_COMMAND]		= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
 	d->card.config[PCI_CLASS_DEVICE]	= 0;
 	d->card.config[0x0b]		= 1;//storage
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index fe7a121..4d4de93 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -97,3 +97,4 @@
 #define PCI_DEVICE_ID_INTEL_82371AB      0x7111
 #define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
 #define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
+#define PCI_DEVICE_ID_INTEL_ICH6R_AHCI    0x2652
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-04  1:07       ` 乔崇
@ 2010-05-04 20:51         ` Sebastian Herbszt
  2010-05-05 19:37           ` Stuart Brady
  0 siblings, 1 reply; 17+ messages in thread
From: Sebastian Herbszt @ 2010-05-04 20:51 UTC (permalink / raw)
  To: 乔崇
  Cc: Joerg Roedel, Elek Roland, Alexander Graf, qemu-devel Developers

乔崇 wrote:
>I add Sebastian Herbsz's patch,add WIN_WIN_STANDBYNOW1 support to fix
> hw_error on linux shut down etc.
>
> I am  not familiar with  git send-email,I am studying it now :).

[snip]

> >From e94912b03ed33080d550eb5764fc99911498101b Mon Sep 17 00:00:00 2001
> From: QiaoChong <qiaochong@loongson.cn>
> Date: Tue, 4 May 2010 07:31:30 +0800
> Subject: [PATCH] ahci pci ids  into pci_ids.h,add warning messages.
>
> move ahci pci device id define into pci_ids.h,add warning messages for
> unsupported features.
>
> Signed-off-by: QiaoChong <qiaochong@loongson.cn>
> ---
> hw/ahci.c    |   10 +++++-----
> hw/pci_ids.h |    1 +
> 2 files changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/hw/ahci.c b/hw/ahci.c
> index cb4a851..e1aed4a 100644
> --- a/hw/ahci.c
> +++ b/hw/ahci.c
> @@ -662,7 +662,9 @@ static void handle_cmd(AHCIState *s,int port,int slot)
>
>  if(fis[1]==0)
>  {
> -
> +#ifdef DEBUG_AHCI
> + printf("now,just ignore command fis[0]=%02x fis[1]=%02x fis[2]=%02x\n",fis[0],fis[1],fis[2]);
> +#endif
>  }
>
>  if(fis[1]==(1<<7))
> @@ -755,15 +757,13 @@ static void ahci_pci_map(PCIDevice *pci_dev, int region_num,
>  cpu_register_physical_memory(addr, size, s->mem);
> }
>
> -#define PCI_VENDOR_MYDEVICE  0x8086
> -#define PCI_PRODUCT_MYDEVICE 0x2652
>
> static int pci_ahci_init(PCIDevice *dev)
> {
>  struct ahci_pci_state *d;
>  d = DO_UPCAST(struct ahci_pci_state, card, dev);
> - pci_config_set_vendor_id(d->card.config,PCI_VENDOR_MYDEVICE);
> - pci_config_set_device_id(d->card.config,PCI_PRODUCT_MYDEVICE);
> + pci_config_set_vendor_id(d->card.config,PCI_VENDOR_ID_INTEL);
> + pci_config_set_device_id(d->card.config,PCI_DEVICE_ID_INTEL_ICH6R_AHCI);
>  d->card.config[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
>  d->card.config[PCI_CLASS_DEVICE] = 0;
>  d->card.config[0x0b] = 1;//storage
> diff --git a/hw/pci_ids.h b/hw/pci_ids.h
> index fe7a121..4d4de93 100644
> --- a/hw/pci_ids.h
> +++ b/hw/pci_ids.h
> @@ -97,3 +97,4 @@
> #define PCI_DEVICE_ID_INTEL_82371AB      0x7111
> #define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
> #define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
> +#define PCI_DEVICE_ID_INTEL_ICH6R_AHCI    0x2652

The list is sorted by vendor and device id. This entry should go
after "PCI_DEVICE_ID_INTEL_ESB_9". The naming scheme seems
to be VENDOR_DEVICE_FUNCTION, so i suggest something like
PCI_DEVICE_ID_INTEL_ICH6R_2 or PCI_DEVICE_ID_INTEL_82801FR_2.

Sebastian

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-03 21:08         ` Elek Roland
@ 2010-05-04 20:56           ` Sebastian Herbszt
  0 siblings, 0 replies; 17+ messages in thread
From: Sebastian Herbszt @ 2010-05-04 20:56 UTC (permalink / raw)
  To: Elek Roland, qemu-devel Developers; +Cc: Joerg Roedel, Alexander Graf

Elek Roland wrote:
> On v, 2010-05-02 at 17:56 +0200, Elek Roland wrote:
>> I'm going to try the patch in practice as
>> soon as I finish my university project. (It's due today.)
> 
> I've tried the patch, and I can confirm that it does provide an AHCI
> device and a SATA disk. It shows up in qemu as an Intel Corporation
> 82801FR/FRW (ICH6R/ICH6RW) SATA Controller, which is consistent with the
> device and vendor IDs in the code. I could successfully create an ext2
> filesystem on the virtual disk, mount it, write a text file on it and
> read it back.
> I've noticed the following errors:
> - The source code claims to implement 2 ports, Linux reports 3.
> - When I halt the guest OS, the AHCI device throws a hardware error
> about an unimplemented command.

Those issues should be fixed now by the following two patches:

0001-fix-port-count-cap-and-version-etc-to-ahci.patch
0002-add-WIN_STANDBYNOW1-process-into-ahci.patch

Sebastian

> I think we could clean up the code and use it as a basis for full
> support.
> 
> Regards,
> Roland
> 
> 
> 
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-04 20:51         ` Sebastian Herbszt
@ 2010-05-05 19:37           ` Stuart Brady
  2010-05-06 19:10             ` [Qemu-devel] " Sebastian Herbszt
  0 siblings, 1 reply; 17+ messages in thread
From: Stuart Brady @ 2010-05-05 19:37 UTC (permalink / raw)
  To: qemu-devel

On Tue, May 04, 2010 at 10:51:37PM +0200, Sebastian Herbszt wrote:
> >diff --git a/hw/pci_ids.h b/hw/pci_ids.h
> >index fe7a121..4d4de93 100644
> >--- a/hw/pci_ids.h
> >+++ b/hw/pci_ids.h
> >@@ -97,3 +97,4 @@
> >#define PCI_DEVICE_ID_INTEL_82371AB      0x7111
> >#define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
> >#define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
> >+#define PCI_DEVICE_ID_INTEL_ICH6R_AHCI    0x2652
> 
> The list is sorted by vendor and device id. This entry should go
> after "PCI_DEVICE_ID_INTEL_ESB_9". The naming scheme seems
> to be VENDOR_DEVICE_FUNCTION, so i suggest something like
> PCI_DEVICE_ID_INTEL_ICH6R_2 or PCI_DEVICE_ID_INTEL_82801FR_2.

Linux seems to have called this PCI_DEVICE_ID_INTEL_ICH6_4 at one point.

So this should be function 4, no?

Cheers,
-- 
Stuart Brady

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] Re: Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-05 19:37           ` Stuart Brady
@ 2010-05-06 19:10             ` Sebastian Herbszt
  0 siblings, 0 replies; 17+ messages in thread
From: Sebastian Herbszt @ 2010-05-06 19:10 UTC (permalink / raw)
  To: Stuart Brady, qemu-devel

Stuart Brady wrote:
> On Tue, May 04, 2010 at 10:51:37PM +0200, Sebastian Herbszt wrote:
>> >diff --git a/hw/pci_ids.h b/hw/pci_ids.h
>> >index fe7a121..4d4de93 100644
>> >--- a/hw/pci_ids.h
>> >+++ b/hw/pci_ids.h
>> >@@ -97,3 +97,4 @@
>> >#define PCI_DEVICE_ID_INTEL_82371AB      0x7111
>> >#define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
>> >#define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
>> >+#define PCI_DEVICE_ID_INTEL_ICH6R_AHCI    0x2652
>> 
>> The list is sorted by vendor and device id. This entry should go
>> after "PCI_DEVICE_ID_INTEL_ESB_9". The naming scheme seems
>> to be VENDOR_DEVICE_FUNCTION, so i suggest something like
>> PCI_DEVICE_ID_INTEL_ICH6R_2 or PCI_DEVICE_ID_INTEL_82801FR_2.
> 
> Linux seems to have called this PCI_DEVICE_ID_INTEL_ICH6_4 at one point.
> 
> So this should be function 4, no?

Well, i am not sure if the last part is the function number. pci_ids.h from the linux
kernel got this:

#define PCI_DEVICE_ID_INTEL_ICH6_0      0x2640
#define PCI_DEVICE_ID_INTEL_ICH6_1      0x2641
#define PCI_DEVICE_ID_INTEL_ICH6_2      0x2642
#define PCI_DEVICE_ID_INTEL_ICH6_16     0x266a
#define PCI_DEVICE_ID_INTEL_ICH6_17     0x266d
#define PCI_DEVICE_ID_INTEL_ICH6_18     0x266e
#define PCI_DEVICE_ID_INTEL_ICH6_19     0x266f

According to the Intel spec the SATA controller is D31:F2. So we got device 31
and function 2. The IDE controller is D31:F1, but above it's ICH6_19.

Sebastian

> Cheers,
> -- 
> Stuart Brady
> 
> 
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-04  0:28       ` 乔崇
@ 2010-05-09 19:16         ` Alexander Graf
  2010-05-10 11:24           ` 乔崇
  0 siblings, 1 reply; 17+ messages in thread
From: Alexander Graf @ 2010-05-09 19:16 UTC (permalink / raw)
  To: 乔崇; +Cc: Joerg Roedel, qemu-devel Developers, Elek Roland

Hi Chong,


乔崇 wrote:
> Alexander Graf 写道:
>> Hi Chong (or Qiao? Which one is your first name?),
>>
>>   
> Thanks your advice,My first name is Chong.
>> Upfront - please don't top post. Top posting is when you write your reply at the top of the mail. This is considered bad style on most open source mailing lists. Instead, people here usually send "inline" comments. So they put their reply below the text they're referring to. That makes it easier to jump into a discussion for others.
>>
>> On 02.05.2010, at 14:52, 乔崇 wrote:
>>
>>   
>>> Hi,Alexander Graf.
>>>   
>>>   I am very glad you noticed my patch about ahci.I love qemu just like I love linux.I wish I could do much more work on qemu development.
>>>     
>>
>> Yes, please! This looks like an amazing start.
>>
>> In case any of my comments sound harsh or unfriendly, please don't interpret them that way. I very much appreciate you working on this and I hope you, Roland, Joerg and me can bring this code base to a ready to use state for everything within the next few months.
>>
>>   
> I will work on ahci at weekend.I am a OS software engineer.I wrote
> ahci support just for testing my ahci driver transplanting on pmon and
> linux kernel for loongson cpu. Qemu is import tool,it help me a lot.
> So I am glad to share my work on qemu to others.

That sounds great. Roland will start working on this heavily soon, so
he'll hopefully make a lot of progress on the code. Nevertheless I would
love to keep you around on it as well. This patch was an amazing
kickstart and you seem like a clever guy which is always great to have
for projects like Qemu! :)

I'll try to get a public ahci branch ready this week. A mail announcing
that follows.
Do you think you'll have time to continue contributing on this
significantly within the next months?


Alex

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] Re: [RFC] [PATCH] add ahci support into qemu
  2010-05-09 19:16         ` Alexander Graf
@ 2010-05-10 11:24           ` 乔崇
  0 siblings, 0 replies; 17+ messages in thread
From: 乔崇 @ 2010-05-10 11:24 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Joerg Roedel, qemu-devel Developers, Elek Roland

[-- Attachment #1: Type: text/html, Size: 2916 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2010-05-10 11:25 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-30 12:48 [Qemu-devel] add ahci support into qemu 乔崇
2010-05-02  8:05 ` Alexander Graf
2010-05-02 12:52   ` [Qemu-devel] [RFC] [PATCH] " 乔崇
2010-05-02 15:36     ` [Qemu-devel] " Sebastian Herbszt
2010-05-02 15:49       ` Avi Kivity
2010-05-02 15:56       ` Elek Roland
2010-05-03 21:08         ` Elek Roland
2010-05-04 20:56           ` Sebastian Herbszt
2010-05-02 22:13     ` Sebastian Herbszt
2010-05-04  1:07       ` 乔崇
2010-05-04 20:51         ` Sebastian Herbszt
2010-05-05 19:37           ` Stuart Brady
2010-05-06 19:10             ` [Qemu-devel] " Sebastian Herbszt
2010-05-04  0:01     ` [Qemu-devel] " Alexander Graf
2010-05-04  0:28       ` 乔崇
2010-05-09 19:16         ` Alexander Graf
2010-05-10 11:24           ` 乔崇

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.