/*
 * Copyright (c) 2009, ETH Zurich. All rights reserved.
 *
 * This file is distributed under the terms in the attached LICENSE file.
 * If you do not find this file, copies can be found by writing to:
 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
 */

/*
 * ahci_port.dev
 *
 * DESCRIPTION: AHCI (SATA) Host bus adaptor, per-port registers
 *
 * Section numbers refer to the Serial ATA Advanced Host Controller
 *   Interface (AHCI) specification 1.3, June 2008
 */

device ahci_port msbfirst (addr b) "AHCI port" {

    // 3.3.1-2
    // Low 10 bits mbz
    register clb rw addr(b,0x00) "Command list base address" type(uint64);

    // 3.3.3-4
    // Low 10 bits mbz
    register fb rw addr(b,0x08) "FIS base address" type(uint64);

    // 3.3.5
    register is addr(b,0x10) "Interrupt status" {
	cpds	1 rw1c "Cold port detect";
	tfes	1 rw1c "Task file error";
	hbfs	1 rw1c "Host bus fatal error";
	hbds	1 rw1c "Host bus data error";
	ifs	1 rw1c "Interface fatal error";
	infs	1 rw1c "Interface non-fatal error";
	_	1 rsvd;
	ofs	1 rw1c "Overflow status";
	ipms	1 rw1c "Incorrect port multiplier status";
	prcs	1 ro   "PhyRdy change status";
	_	14 rsvd;
	dmps	1 rw1c "Device mechanical presence";
	pcs	1 ro   "Port connect change";
	dps	1 rw1c "Descriptor processed";
	ufs	1 ro   "Unknown FIS interrupt";
	sdbs	1 rw1c "Set device bits interrupt";
	dss	1 rw1c "DMA setup FIS interrupt";
	pss	1 rw1c "PIO setup FIS interrupt";
	dhrs	1 rw1c "Device to host register FIS interrupt";
    };

    // 3.3.6
    register ie addr(b,0x14) "Interrupt enable" {
	cpde	1 rw "Cold port detect";
	tfee	1 rw "Task file error";
	hbfe	1 rw "Host bus fatal error";
	hbde	1 rw "Host bus data error";
	ife     1 rw "Interface fatal error";
	infe	1 rw "Interface non-fatal error";
	_	1 rsvd;
	ofe	1 rw "Overflow enable";
	ipme	1 rw "Incorrect port multiplier status";
	prce	1 ro   "PhyRdy change status";
	_	14 rsvd;
	dmpe	1 rw "Device mechanical presence";
	pce	1 ro   "Port connect change";
	dpe	1 rw "Descriptor processed";
	ufe	1 ro   "Unknown FIS interrupt";
	sdbe	1 rw "Set device bits interrupt";
	dse	1 rw "DMA setup FIS interrupt";
	pse	1 rw "PIO setup FIS interrupt";
	dhre	1 rw "Device to host register FIS interrupt";
    };

    // 3.3.7
    constants icct "Interface communication control" {
	slumber	= 0x6 "Slumber";
	partial = 0x2 "Partial";
	active  = 0x1 "Active";
	idle	= 0x0 "No-Op / Idle";
    };
    register cmd addr(b,0x18) "Command and status" {
	icc	4 rw type(icct) "Interface communication control";
	asp	1 rw "Aggressive slumber / partial";
	alpe	1 rw "Aggressive link power management enable";
	dlae	1 rw "Drive LED on ATAPI enable";
	atapi	1 rw "Device is ATAPI";
	apste	1 rw "Automatic partial to slumber transitions enabled";
	fbscp	1 ro "FIS-based switching capable port";
	esp	1 ro "External SATA port";
	cpd	1 ro "Cold presence detection";
	mpsp	1 ro "Mechanical presence switch";
	hpcp	1 ro "Hot plug capable port";
	pma	1 rw "Port multiplier attached";
	cps	1 ro "Cold presence state";
	cr	1 ro "Command list running";
	fr	1 ro "FIS receive running";
	mpss	1 ro "Mechanical presence switch state";
	ccs	5 ro "Current command slot";
	_	3 rsvd;
	fre	1 rw "FIS receive enable";
	clo	1 rw "Command list override";
	pod	1 rw "Power on device";
	sud	1 rw "Spin-up device";
	st	1 rw "Start";
    };

    // 3.3.8
    register tfd ro addr(b,0x20) "Task file data" {
	_	16 rsvd;
	err	8 "Error";
    bsy 1 ro    "Indicates the interface is busy";
    cs2 3 ro    "Command specific";
    drq 1 ro    "Indicates a data transfer is requested";
    cs1 2 ro    "Command specific";
    serr 1 ro    "Indicates an error during the transfer.";
    };

    // 3.3.9
    register sig ro addr(b,0x24) "Signature" {
	lbah	8 "LBA high";
	lbam	8 "LBA mid";
	lbal	8 "LBA low";
	sectors 8 "Sector count";
    };

    // 3.3.10
    constants speed "Interface speed" {
	gen1	= 0b0001 "Gen 1 (1.5 Gbps)";
	gen2	= 0b0010 "Gen 2 (3 Gbps)";
	gen3	= 0b0011 "Gen 3 (6 Gbps)";
    };
    constants dets "Device detection state" {
	nodev	= 0x0 "No device, no PHY";
	nophy	= 0x1 "Device detected, no PHY comm. established";
	detect  = 0x3 "Device detected and PHY comm. established";
	offline = 0x4 "PHY in offline mode or loopback";
    };
    register ssts ro addr(b,0x28) "Serial ATA status" {
	_	20 rsvd;
	ipm	4 type(icct) "Interface power management";
	spd	4 type(speed) "Current interface speed";
	det	4 type(dets) "Device detection";
    };

    // 3.3.11
    constants ipmall "Interface transitions" {
	noipm	= 0x0 "No interface restrictions";
	noprtl	= 0x1 "Transitions to Partial state disabled";
	noslmb  = 0x2 "Transitions to Slumber state disabled";
	noboth	= 0x3 "Transitions to both Partial and Slumber disabled";
    };
    register sctl addr(b,0x2c) "Serial ATA control" {
	_	12 rsvd;
	_	4 rsvd "Port multiplier port (unused)";
	_	4 rsvd "Select power mgmt (unused)";
	ipm	4 rw type(ipmall) "Interface power mgmt transitions allowed";
	spd	4 rw type(speed) "Speed allowed";
	det	4 rw type(dets) "Device detection initialization";
    };

    // 3.3.12
    register serr rw1c addr(b,0x30) "Serial ATA error" {
	_	5 rsvd;
	dx	1 "Exchanged";
	df	1 "Unknown FIS type";
	dt	1 "Transport state transition error";
	ds	1 "Link sequence error";
	dh	1 "Handshake error";
	dc	1 "CRC error";
	dd	1 "Disparity error";
	db	1 "10b to 8b decode error";
	dw	1 "Comm wake";
	di	1 "Phy internal error";
	dn	1 "PhyRdy change";
	_	4 rsvd;
	ee	1 "Internal error";
	ep	1 "Protocol error";
	ec	1 "Persistent communication or data integrity error";
	et	1 "Transient data integrity error";
	_	6 rsvd;
	em	1 "Recovered communications error";
	ei	1 "Recovered data integrity error";
    };

    // 3.3.13
    register sact rw addr(b,0x34) "Serial ATA active" type(uint32);

    // 3.3.14
    register ci rw addr(b,0x38) "Command issue" type(uint32);

    // 3.3.15
    register sntf addr(b,0x3c) "Serial ATA notification" {
	_	16 mbz;
	pmn	16 rw1c "PMN notify";
    };

    // 3.3.16
    register fbs addr(b,0x40) "FIS-based switching control" {
	_	12 mbz;
	dwe	4 ro "Device with error";
	ado	4 ro "Active device optimization";
	dev	4 rw "Device to issue";
	_	5 mbz;
	sde	1 ro "Single device error";
	dec	1 rw1c "Device error clear";
	en	1 rw "Enable";
    };

    // 4.2.2 Command List Structure, elements are Command Headers
    datatype chdr msbfirst(32) "Command Header" {
	prdtl	16 "Physical region descriptor table length";
	pmp	4  "Port multiplier port";
	_	1;
	c	1 "Clear busy upon R_OK";
	b	1 "BIST";
	r	1 "Reset";
	p	1 "Prefetchable";
	w	1 "Write";
	a	1 "ATAPI";
	cfl	5 "Command FIS length";

	prdbc	32 "Physical region descriptor byte count";

	ctba	64 "Command table descriptor base address";

	_	32;
	_	32;
	_	32;
	_	32;
    };

    // 4.2.3.3 Physical Region Descriptor Table
    datatype prd msbfirst(32) "Physical region descriptor" {
	dba	32 "Data base address";
	dbau	32 "Data base address upper";
	_	32;
	i	1 "Interrupt on completion";
	_	9;
	dbc	22 "Data byte count";
    };

    // 12.2
    constants emtype "Enclosure message type" {
	led	= 0x0 "LED";
	saf_te	= 0x1 "SAF-TE";
	ses_2	= 0x2 "SES-2";
	sgpio	= 0x3 "SGPOI (register-based interface";
    };
    datatype encmsg "Enclosure management message" {
	_	4;
	mtype	4 type(emtype) "Message type";
	dsize	8 "Data size";
	msize	8 "Message size";
	_	8;
    };

    // 12.2.1
    constants emledstate "Enclosure LED state" {
	off	= 0b000 "LED shall be off";
	solid	= 0b001 "LED shall be solid on";
	vs1	= 0b100 "Vendor specific 1";
	vs2	= 0b101 "Vendor specific 2";
	vs3	= 0b110 "Vendor specific 3";
	vs4	= 0b111 "Vendor specific 4";
    };
    datatype emledmsg "Enclosure LED message" {
	_	7;
	fault	3 type(emledstate) "Vendor-specific LED (e.g. fault)";
	locate	3 type(emledstate) "Vendor-specific LED (e.g. locate)";
	activity 3 type(emledstate) "Activity LED";
	_	4;
	pmi	4 "Port multiplier information";
	_	2;
	vsm	1 "Vendor-specific enclosure message";
	hbapn	5 "HBA port number for update";
    };
};
