Plan 9 from Bell Labs’s /usr/web/sources/patch/sorry/cpu-sdmv50xx/sdmv50xx.c.new

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
<<<<<<< sdmv50xx.c.orig
 * Marvell 88SX5040, 5041, 5080, 5081 driver
 * This is a heavily-modified version of a driver written by Coraid, Inc.
=======
 * Marvell 88SX[56]0[48][01] fileserver Serial ATA (SATA) driver
 *
 * See MV-S101357-00 Rev B Marvell PCI/PCI-X to 8-Port/4-Port
 * SATA Host Controller, ATA-5 ANSI NCITS 340-2000.
 *
 * This is a heavily-modified version (by Coraid) of a heavily-modified
 * version (from The Labs) of a driver written by Coraid, Inc.
>>>>>>> sdmv50xx.c
 * The original copyright notice appears at the end of this file.
 */
 
<<<<<<< sdmv50xx.c.orig
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include 	"io.h"
#include	"../port/error.h"
=======
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
>>>>>>> sdmv50xx.c

#include	"../port/sd.h"

<<<<<<< /sys/src/9/pc/sdmv50xx.c
#define dprint if(!0){}else iprint
#define idprint if(!0){}else iprint
#define ioprint if(!0){}else iprint

enum{
	NCtlr		= 4,
	NCtlrdrv		= 8,
	NDrive		= NCtlr*NCtlrdrv,

	Read 		= 0,
	Write,
};
||||||| sdmv50xx.c.orig
#define DPRINT	if(0)iprint
=======
#define dprint(...)	// print(__VA_ARGS__)
#define idprint(...)	
#define ioprint(...)

enum{
	NCtlr		= 4,
	NCtlrdrv		= 8,
	NDrive		= NCtlr*NCtlrdrv,

	Read 		= 0,
	Write,
};
>>>>>>> sdmv50xx.c

enum {
	SrbRing = 32,
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	/* Addresses of ATA register */
	ARcmd		= 027,
	ARdev		= 026,
	ARerr		= 021,
	ARfea		= 021,
	ARlba2		= 025,
	ARlba1		= 024,
	ARlba0		= 023,
<<<<<<< sdmv50xx.c.orig
	ARseccnt		= 022,
=======
	ARseccnt	= 022,
>>>>>>> sdmv50xx.c
	ARstat		= 027,
<<<<<<< sdmv50xx.c.orig
	
	ATAerr	= (1<<0),
	ATAdrq	= (1<<3),
	ATAdf 	= (1<<5),
=======

	ATAerr		= (1<<0),
	ATAdrq		= (1<<3),
	ATAdf 		= (1<<5),
>>>>>>> sdmv50xx.c
	ATAdrdy 	= (1<<6),
	ATAbusy 	= (1<<7),
	ATAabort	= (1<<2),
<<<<<<< sdmv50xx.c.orig
=======
	ATAobs		= (1<<1 | 1<<2 | 1<<4),
>>>>>>> sdmv50xx.c
	ATAeIEN	= (1<<1),
<<<<<<< sdmv50xx.c.orig
	ATAsrst	= (1<<2),
	ATAhob	= (1<<7),
=======
	ATAsrst		= (1<<2),
	ATAhob		= (1<<7),
	ATAbad		= (ATAbusy|ATAdf|ATAdrq|ATAerr),
>>>>>>> sdmv50xx.c

<<<<<<< sdmv50xx.c.orig
	SFdone = (1<<0),
	SFerror = (1<<1),
=======
	SFdone 		= (1<<0),
	SFerror 		= (1<<1),
>>>>>>> sdmv50xx.c

<<<<<<< sdmv50xx.c.orig
	SRBident = 0,
=======
	SRBident 	= 0,
>>>>>>> sdmv50xx.c
	SRBread,
	SRBwrite,
	SRBsmart,

	SRBnodata = 0,
	SRBdatain,
	SRBdataout,
<<<<<<< sdmv50xx.c.orig
	
	RQread	= 1,			/* data coming IN from device */
	
	PRDeot	= (1<<15),
	
=======

	RQread		= 1,			/* data coming IN from device */

	PRDeot		= (1<<15),

>>>>>>> sdmv50xx.c
	/* EDMA interrupt error cause register */

	ePrtDataErr	= (1<<0),
	ePrtPRDErr	= (1<<1),
	eDevErr		= (1<<2),
<<<<<<< sdmv50xx.c.orig
	eDevDis		= (1<<3),
	eDevCon		= (1<<4),
	eOverrun		= (1<<5),
=======
	eDevDis		= (1<<3),	
	eDevCon	= (1<<4),
	eOverrun	= (1<<5),
>>>>>>> sdmv50xx.c
	eUnderrun	= (1<<6),
	eSelfDis		= (1<<8),
	ePrtCRQBErr	= (1<<9),
	ePrtCRPBErr	= (1<<10),
<<<<<<< sdmv50xx.c.orig
	ePrtIntErr		= (1<<11),
	eIORdyErr		= (1<<12),
=======
	ePrtIntErr	= (1<<11),
	eIORdyErr	= (1<<12),

	// flags for sata 2 version
	eSelfDis2	= (1<<7),
	SerrInt		= (1<<5),
>>>>>>> sdmv50xx.c

	/* EDMA Command Register */

<<<<<<< sdmv50xx.c.orig
	eEnEDMA		= (1<<0),
=======
	eEnEDMA	= (1<<0),
>>>>>>> sdmv50xx.c
	eDsEDMA 	= (1<<1),
	eAtaRst 		= (1<<2),

	/* Interrupt mask for errors we care about */
<<<<<<< sdmv50xx.c.orig
	IEM			= (eDevDis | eDevCon | eSelfDis),
	
	Dnull = 0,
=======
	IEM		= (eDevDis | eDevCon | eSelfDis),
	IEM2		= (eDevDis | eDevCon | eSelfDis2),

	/* drive states */
	Dnull 		= 0,
>>>>>>> sdmv50xx.c
	Dnew,
<<<<<<< sdmv50xx.c.orig
	Dident,
=======
>>>>>>> sdmv50xx.c
	Dready,
	Derror,
	Dmissing,
<<<<<<< sdmv50xx.c.orig
	Dunconfig,
=======
	Dreset,
	Dlast,

	/* drive flags */
	Dext	 	= (1<<0),	/* use ext commands */
	Dpio		= (1<<1),	/* doing pio */
	Dwanted		= (1<<2),	/* someone wants an srb entry */
	Dedma		= (1<<3),	/* device in edma mode */
	Dpiowant	= (1<<4),	/* some wants to use the pio mode */

	// phyerrata magic crap
	Mpreamp	= 0x7e0,
	Dpreamp	= 0x720,

	REV60X1B2	= 0x7,
	REV60X1C0	= 0x9,
>>>>>>> sdmv50xx.c

<<<<<<< sdmv50xx.c.orig
	Dext	 	= (1<<0),		/* use ext commands */
	Dpio		= (1<<1),		/* doing pio */
	Dwanted	= (1<<2),		/* someone wants an srb entry */
	Dedma	= (1<<3),		/* device in edma mode */
	Dpiowant	= (1<<4),		/* some wants to use the pio mode */
=======
>>>>>>> sdmv50xx.c
};

<<<<<<< sdmv50xx.c.orig
static char* diskstates[] =
{
=======
static char* diskstates[Dlast] = {
>>>>>>> sdmv50xx.c
	"null",
	"new",
<<<<<<< sdmv50xx.c.orig
	"ident",
=======
>>>>>>> sdmv50xx.c
	"ready",
	"error",
	"missing",
<<<<<<< sdmv50xx.c.orig
	"unconfigured",
=======
	"reset",
>>>>>>> sdmv50xx.c
};

extern SDifc sdmv50xxifc;

typedef struct Arb Arb;
typedef struct Bridge Bridge;
typedef struct Chip Chip;
typedef struct Ctlr Ctlr;
typedef struct Drive Drive;
typedef struct Edma Edma;
typedef struct Prd Prd;
typedef struct Rx Rx;
typedef struct Srb Srb;
typedef struct Tx Tx;

<<<<<<< sdmv50xx.c.orig
struct Chip	/* pointers to per-Chip mmio */
=======
// there are 4 drives per chip.  thus an 8-port
// card has two chips.
struct Chip
>>>>>>> sdmv50xx.c
{
<<<<<<< sdmv50xx.c.orig
	Arb		*arb;
	Edma	*edma;	/* array of 4 */
=======
	Arb	*arb;
	Edma	*edma;
};

enum{
	DMautoneg,
	DMsatai,
	DMsataii,
>>>>>>> sdmv50xx.c
};

<<<<<<< sdmv50xx.c.orig
struct Drive	/* a single disk */
=======
struct Drive
>>>>>>> sdmv50xx.c
{
	Lock;

<<<<<<< sdmv50xx.c.orig
	Ctlr		*ctlr;
=======
	Ctlr	*ctlr;
>>>>>>> sdmv50xx.c
	SDunit	*unit;
<<<<<<< sdmv50xx.c.orig
	int		subno;
	char		name[10];
=======
	char	name[10];
	ulong	magic;
>>>>>>> sdmv50xx.c

	Bridge	*bridge;
	Edma	*edma;
<<<<<<< sdmv50xx.c.orig
	Chip		*chip;
	int		chipx;
	
	int		state;
	int		flag;
	uvlong	sectors;
=======
	Chip	*chip;
	int	chipx;
>>>>>>> sdmv50xx.c

<<<<<<< sdmv50xx.c.orig
	char		serial[20+1];
	char		firmware[8+1];
	char		model[40+1];
=======
	int	mediachange;
	int	state;
	int	flag;
	uvlong	sectors;
	ulong	pm2;		// phymode 2 init state
	ulong	intick;		// check for hung westerdigital drives.
	int	wait;
	int	mode;		// DMautoneg, satai or sataii.

	char	serial[20+1];
	char	firmware[8+1];
	char	model[40+1];
>>>>>>> sdmv50xx.c

	ushort	info[256];
<<<<<<< sdmv50xx.c.orig
	
	Srb		*srb[SrbRing-1];
	int		nsrb;
	Prd		*prd;
	Tx		*tx;
	Rx		*rx;
	
	Srb		*srbhead;
	Srb		*srbtail;
=======

	Srb	*srb[SrbRing-1];
	int	nsrb;
	Prd	*prd;
	Tx	*tx;
	Rx	*rx;

	Srb	*srbhead;
	Srb	*srbtail;
	int	driveno;		// ctlr*NCtlrdrv + unit
>>>>>>> sdmv50xx.c
};

<<<<<<< sdmv50xx.c.orig
struct Ctlr		/* a single PCI card */
=======
struct Ctlr
>>>>>>> sdmv50xx.c
{
	Lock;

<<<<<<< sdmv50xx.c.orig
	int		irq;
	int		tbdf;
	SDev		*sdev;
=======
	int	irq;
	int	tbdf;
	int	rid;
	ulong	magic;
	int	enabled;
	int	type;
	SDev	*sdev;
>>>>>>> sdmv50xx.c
	Pcidev	*pcidev;

	uchar	*mmio;
<<<<<<< sdmv50xx.c.orig
	Chip		chip[2];
	int		nchip;
	Drive	drive[8];
	int		ndrive;
=======
	ulong	*lmmio;
	Chip	chip[2];
	int	nchip;
	Drive	drive[NCtlrdrv];
	int	ndrive;
>>>>>>> sdmv50xx.c
};

<<<<<<< sdmv50xx.c.orig
struct Srb		/* request buffer */
=======
struct Srb			/* request buffer */
>>>>>>> sdmv50xx.c
{
	Lock;
	Rendez;
<<<<<<< sdmv50xx.c.orig
	Srb		*next;
=======
	Srb	*next;
>>>>>>> sdmv50xx.c

	Drive	*drive;
	uvlong	blockno;
<<<<<<< sdmv50xx.c.orig
	int		count;
	int		req;
	int		flag;
=======
	int	count;
	int	req;
	int	flag;
>>>>>>> sdmv50xx.c
	uchar	*data;
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	uchar	cmd;
	uchar	lba[6];
	uchar	sectors;
<<<<<<< sdmv50xx.c.orig
	int		sta;
	int		err;
=======
	int	sta;
	int	err;
>>>>>>> sdmv50xx.c
};

/*
 * Memory-mapped I/O registers in many forms.
 */
<<<<<<< sdmv50xx.c.orig
struct Bridge	/* memory-mapped per-Drive registers */
=======
struct Bridge			/* memory-mapped per-Drive registers */
>>>>>>> sdmv50xx.c
{
	ulong	status;
	ulong	serror;
	ulong	sctrl;
	ulong	phyctrl;
<<<<<<< sdmv50xx.c.orig
	char		fill1[0x2c];
=======
	ulong	phymode3;
	ulong	phymode4;
	uchar	fill0[0x14];
	ulong	phymode1;
	ulong	phymode2;
	char	fill1[8];
>>>>>>> sdmv50xx.c
	ulong	ctrl;
<<<<<<< sdmv50xx.c.orig
	char		fill2[0x34];
=======
	char	fill2[0x34];
>>>>>>> sdmv50xx.c
	ulong	phymode;
<<<<<<< sdmv50xx.c.orig
	char		fill3[0x88];	/* pad to 0x100 in length */
};
=======
	char	fill3[0x88];
};				// most be 0x100 hex in length
>>>>>>> sdmv50xx.c

<<<<<<< sdmv50xx.c.orig
struct Arb		/* memory-mapped per-Chip registers */
=======
struct Arb			/* memory-mapped per-Chip registers */
>>>>>>> sdmv50xx.c
{
<<<<<<< sdmv50xx.c.orig
	ulong	fill0;
	ulong	rqop;	/* request queue out-pointer */
=======
	ulong	config;		/* satahc configuration register (sata2 only) */
	ulong	rqop;		/* request queue out-pointer */
>>>>>>> sdmv50xx.c
	ulong	rqip;		/* response queue in pointer */
	ulong	ict;		/* inerrupt caolescing threshold */
	ulong	itt;		/* interrupt timer threshold */
	ulong	ic;		/* interrupt cause */
	ulong	btc;		/* bridges test control */
	ulong	bts;		/* bridges test status */
	ulong	bpc;		/* bridges pin configuration */
<<<<<<< sdmv50xx.c.orig
	char		fill1[0xdc];
=======
	char	fill1[0xdc];
>>>>>>> sdmv50xx.c
	Bridge	bridge[4];
};

<<<<<<< sdmv50xx.c.orig
struct Edma	/* memory-mapped per-Drive DMA-related registers */
=======
struct Edma			/* memory-mapped per-Drive DMA-related registers */
>>>>>>> sdmv50xx.c
{
<<<<<<< sdmv50xx.c.orig
	ulong		config;		/* configuration register */
	ulong		timer;
	ulong		iec;			/* interrupt error cause */
	ulong		iem;			/* interrupt error mask */

	ulong		txbasehi;		/* request queue base address high */
	ulong		txi;			/* request queue in pointer */
	ulong		txo;			/* request queue out pointer */

	ulong		rxbasehi;		/* response queue base address high */
	ulong		rxi;			/* response queue in pointer */
	ulong		rxo;			/* response queue out pointer */
	
	ulong		ctl;			/* command register */
	ulong		testctl;		/* test control */
	ulong		status;
	ulong		iordyto;		/* IORDY timeout */
	char			fill[0xc8];
	ushort		pio;			/* data register */
	char			pad0[2];
	uchar		err;			/* features and error */
	char			pad1[3];
	uchar		seccnt;		/* sector count */
	char			pad2[3];
	uchar		lba0;
	char			pad3[3];
	uchar		lba1;
	char			pad4[3];
	uchar		lba2;
	char			pad5[3];
	uchar		lba3;
	char			pad6[3];
	uchar		cmdstat;		/* cmd/status */
	char			pad7[3];
	uchar		altstat;		/* alternate status */
	char			fill2[0x1edc];	/* pad to 0x2000 bytes */
=======
	ulong	config;		/* configuration register */
	ulong	timer;
	ulong	iec;		/* interrupt error cause */
	ulong	iem;		/* interrupt error mask */

	ulong	txbasehi;		/* request queue base address high */
	ulong	txi;		/* request queue in pointer */
	ulong	txo;		/* request queue out pointer */

	ulong	rxbasehi;		/* response queue base address high */
	ulong	rxi;		/* response queue in pointer */
	ulong	rxo;		/* response queue out pointer */

	ulong	ctl;		/* command register */
	ulong	testctl;		/* test control */
	ulong	status;
	ulong	iordyto;		/* IORDY timeout */
	char	fill[0x18];
	ulong	sataconfig;	/* sata 2 */
	char	fill[0xac];
	ushort	pio;		/* data register */
	char	pad0[2];
	uchar	err;		/* features and error */
	char	pad1[3];
	uchar	seccnt;		/* sector count */
	char	pad2[3];
	uchar	lba0;
	char	pad3[3];
	uchar	lba1;
	char	pad4[3];
	uchar	lba2;
	char	pad5[3];
	uchar	lba3;
	char	pad6[3];
	uchar	cmdstat;		/* cmd/status */
	char	pad7[3];
	uchar	altstat;		/* alternate status */
	uchar	fill2[0x1df];
	Bridge	port;
	char	fill3[0x1c00];	/* pad to 0x2000 bytes */
>>>>>>> sdmv50xx.c
};

/*
 * Memory structures shared with card.
 */
<<<<<<< sdmv50xx.c.orig
struct Prd		/* physical region descriptor */
=======
struct Prd			/* physical region descriptor */
>>>>>>> sdmv50xx.c
{
	ulong	pa;		/* byte address of physical memory */
	ushort	count;		/* byte count (bit0 must be 0) */
	ushort	flag;
<<<<<<< sdmv50xx.c.orig
	ulong	zero;			/* high long of 64 bit address */
=======
	ulong	zero;		/* high long of 64 bit address */
>>>>>>> sdmv50xx.c
	ulong	reserved;
};

<<<<<<< sdmv50xx.c.orig
struct Tx		/* command request block */
=======
struct Tx				/* command request block */
>>>>>>> sdmv50xx.c
{
	ulong	prdpa;		/* physical region descriptor table structures */
<<<<<<< sdmv50xx.c.orig
	ulong	zero;			/* must be zero (high long of prd address) */
	ushort	flag;			/* control flags */
=======
	ulong	zero;		/* must be zero (high long of prd address) */
	ushort	flag;		/* control flags */
>>>>>>> sdmv50xx.c
	ushort	regs[11];
};

<<<<<<< sdmv50xx.c.orig
struct Rx		/* command response block */
=======
struct Rx				/* command response block */
>>>>>>> sdmv50xx.c
{
<<<<<<< sdmv50xx.c.orig
	ushort	cid;			/* cID of response */
	uchar	cEdmaSts;		/* EDMA status */
=======
	ushort	cid;		/* cID of response */
	uchar	cEdmaSts;	/* EDMA status */
>>>>>>> sdmv50xx.c
	uchar	cDevSts;		/* status from disk */
<<<<<<< sdmv50xx.c.orig
	ulong	ts;			/* time stamp */
=======
	ulong	ts;		/* time stamp */
>>>>>>> sdmv50xx.c
};

<<<<<<< /sys/src/9/pc/sdmv50xx.c
static Drive 	*mvsatadrive[NDrive];
static int		nmvsatadrive;

||||||| sdmv50xx.c.orig
=======
static Ctlr 	*mvsatactlr[NCtlr];
static Drive 	*mvsatadrive[NDrive];
static int		nmvsatadrive;

>>>>>>> sdmv50xx.c
/*
 * Little-endian parsing for drive data.
 */
static ushort
lhgets(void *p)
{
	uchar *a = p;
	return ((ushort) a[1] << 8) | a[0];
}

static ulong
lhgetl(void *p)
{
	uchar *a = p;
	return ((ulong) lhgets(a+2) << 16) | lhgets(a);
}

static uvlong
lhgetv(void *p)
{
	uchar *a = p;
	return ((uvlong) lhgetl(a+4) << 32) | lhgetl(a);
}

static void
idmove(char *p, ushort *a, int n)
{
	char *op;
	int i;
	
	op = p;
	for(i=0; i<n/2; i++){
		*p++ = a[i]>>8;
		*p++ = a[i];
	}
	while(p>op && *--p == ' ')
		*p = 0;
}

/*
 * Request buffers.
 */
struct 
{
	Lock;
	Srb *freechain;
	int nalloc;
} srblist;

static Srb*
allocsrb(void)
{
	Srb *p;
	
	ilock(&srblist);
	if((p = srblist.freechain) == nil){
		srblist.nalloc++;
		iunlock(&srblist);
		p = smalloc(sizeof *p);
	}else{
		srblist.freechain = p->next;
		iunlock(&srblist);
	}
	return p;
}

static void
freesrb(Srb *p)
{
	ilock(&srblist);
	p->next = srblist.freechain;
	srblist.freechain = p;
	iunlock(&srblist);
}

/*
 * Wait for a byte to be a particular value.
 */
static int
satawait(uchar *p, uchar mask, uchar v, int ms)
{
	int i;

<<<<<<< sdmv50xx.c.orig
//	DPRINT("satawait %p %#x %#x %d...", p, mask, v, ms);
//	DPRINT("!%#x...", *p);
	for(i=0; i<ms && (*p & mask) != v; i++){
		if(i%1000 == 0)
			DPRINT("!%#x", *p);
=======
	for(i=0; i<ms && (*p & mask) != v; i++)
>>>>>>> sdmv50xx.c
		microdelay(1000);
<<<<<<< sdmv50xx.c.orig
	}
=======
>>>>>>> sdmv50xx.c
	return (*p & mask) == v;
}

/*
 * Drive initialization
 */
<<<<<<< sdmv50xx.c.orig
static int
configdrive(Ctlr *ctlr, Drive *d, SDunit *unit)
=======
// unmask in the pci registers err done
static void
unmask(ulong *mmio, int port, int coal)
{
	port &= 7;
	if(coal)
		coal = 1;
	if (port < 4)
		mmio[0x1d64/4] |= (3 << (((port&3)*2)) | (coal<<8));
	else
		mmio[0x1d64/4] |= (3 << (((port&3)*2+9)) | (coal<<17));
}

static void
mask(ulong *mmio, int port, int coal)
{
	port &= 7;
	if(coal)
		coal = 1;
	if (port < 4)
		mmio[0x1d64/4] &= ~(3 << (((port&3)*2)) | (coal<<8));
	else
		mmio[0x1d64/4] &= ~(3 << (((port&3)*2+9)) | (coal<<17));
}

/* I give up, marvell.  You win. */
static void
phyerrata(Drive *d)
{
	ulong n, m;
	enum { BadAutoCal = 0xf << 26, };

	if (d->ctlr->type == 1)
		return;
	microdelay(200);
	n = d->bridge->phymode2;
	while ((n & BadAutoCal) == BadAutoCal) {
		dprint("%s: badautocal\n", d->unit->name);
		n &= ~(1<<16);
		n |= (1<<31);
		d->bridge->phymode2 = n;
		microdelay(200);
		d->bridge->phymode2 &= ~((1<<16) | (1<<31));
		microdelay(200);
		n = d->bridge->phymode2;
	}
	n &= ~(1<<31);
	d->bridge->phymode2 = n;
	microdelay(200);

	/* abra cadabra!  (random magic) */
	m = d->bridge->phymode3;
	m &= ~0x7f800000;
	m |= 0x2a800000;
	d->bridge->phymode3 = m;

	/* fix phy mode 4 */
	m = d->bridge->phymode3;
	n = d->bridge->phymode4;
	n &= ~(1<<1);
	n |= 1;
	switch(d->ctlr->rid){
	case REV60X1B2:
	default:
		d->bridge->phymode4 = n;
		d->bridge->phymode3 = m;
		break;
	case REV60X1C0:
		d->bridge->phymode4 = n;
		break;
	}

	/* revert values of pre-emphasis and signal amps to the saved ones */
	n = d->bridge->phymode2;
	n &= ~Mpreamp;
	n |= d->pm2;
	n &= ~(1<<16);
	d->bridge->phymode2 = n;
}

static void
edmacleanout(Drive *d)
>>>>>>> sdmv50xx.c
{
	int i;
<<<<<<< sdmv50xx.c.orig
	ulong *r;
	
	DPRINT("%s: configdrive\n", unit->name);
	d->unit = unit;
	d->ctlr = ctlr;
	d->chipx = unit->subno%4;
	d->chip = &ctlr->chip[unit->subno/4];
	d->bridge = &d->chip->arb->bridge[d->chipx];
	d->edma = &d->chip->edma[d->chipx];

	if(d->tx == nil){
		d->tx = mallocalign(32*sizeof(Tx), 1024, 0, 0);
		d->rx = mallocalign(32*sizeof(Rx), 256, 0, 0);
		d->prd = mallocalign(32*sizeof(Prd), 32, 0, 0);
		if(d->tx == nil || d->rx == nil || d->prd == nil){
			iprint("%s: out of memory allocating ring buffers\n",
				unit->name);
			free(d->tx);
			d->tx = nil;
			free(d->rx);
			d->rx = nil;
			free(d->prd);
			d->prd = nil;
			d->state = Dunconfig;
			return 0;
=======
	Srb *srb;

	for(i=0; i<nelem(d->srb); i++){
		if(srb = d->srb[i]){
			d->srb[i] = nil;
			d->nsrb--;
			srb->flag |= SFerror|SFdone;
			wakeup(srb);
>>>>>>> sdmv50xx.c
		}
<<<<<<< sdmv50xx.c.orig
		for(i=0; i<32; i++)
			d->tx[i].prdpa = PADDR(&d->prd[i]);
		coherence();
=======
>>>>>>> sdmv50xx.c
	}
<<<<<<< sdmv50xx.c.orig
	
	/* leave disk interrupts turned off until we use it ... */
	d->edma->iem = 0;
	
	/* ... but enable them on the controller */
	r = (ulong*)(d->ctlr->mmio + 0x1D64);
	if(d->unit->subno < 4)
		*r |= 3 << (d->chipx*2);
	else
		*r |= 3 << (d->chipx*2+9);
=======
	while(srb = d->srbhead){
		d->srbhead = srb->next;
		srb->flag |= SFerror|SFdone;
		wakeup(srb);
	}
}
>>>>>>> sdmv50xx.c

<<<<<<< /sys/src/9/pc/sdmv50xx.c
static void
resetdisk(Drive *d)
{
	ulong n;

	d->sectors = 0;
	d->unit->sectors = 0;
	if (d->ctlr->type == 2) {
		// without bit 8 we can boot without disks, but
		// inserted disks will never appear.  :-X
		n = d->edma->sataconfig;
		n &= 0xff;
		n |= 0x9b1100;
		d->edma->sataconfig = n;
		n = d->edma->sataconfig;	//flush
		USED(n);
	}
	d->edma->ctl = eDsEDMA;
	microdelay(1);
	d->edma->ctl = eAtaRst;
	microdelay(25);
	d->edma->ctl = 0;
	if (satawait((uchar *)&d->edma->ctl, eEnEDMA, 0, 3*1000) == 0)
		print("%s: eEnEDMA never cleared on reset\n", d->unit->name);
	edmacleanout(d);
	phyerrata(d);
	d->bridge->sctrl = 0x301 | (d->mode << 4);
	d->state = Dmissing;
}

static void
edmainit(Drive *d)
{
	int i;

	if(d->tx != nil)
		return;

	d->tx = xspanalloc(32*sizeof(Tx), 1024, 0);
	d->rx = xspanalloc(32*sizeof(Rx), 256, 0);
	d->prd = xspanalloc(32*sizeof(Prd), 32, 0);
	for(i = 0; i < 32; i++)
		d->tx[i].prdpa = PADDR(&d->prd[i]);
	coherence();
}

static int
configdrive(Ctlr *ctlr, Drive *d, SDunit *unit)
{
	dprint("%s: configdrive\n", unit->name);
	if(d->driveno < 0)
		panic("mv50xx: configdrive: unset driveno\n");
	d->unit = unit;
	edmainit(d);
	d->mode = DMsatai;
	if(d->ctlr->type == 1){
		d->edma->iem = IEM;
		d->bridge = &d->chip->arb->bridge[d->chipx];
	}else{
		d->edma->iem = IEM2;
		d->bridge = &d->chip->edma[d->chipx].port;
		d->edma->iem = ~(1<<6);
		d->pm2 = Dpreamp;
		if(d->ctlr->lmmio[0x180d8/4] & 1)
			d->pm2 = d->bridge->phymode2 & Mpreamp;
	}
	resetdisk(d);
	unmask(ctlr->lmmio, d->driveno, 0);
	delay(100);
	if(d->bridge->status){
		dprint("%s: configdrive: found drive %lx\n", unit->name, d->bridge->status);
		return 0;
	}
	return -1;
||||||| sdmv50xx.c.orig
	return 1;
=======
static void
resetdisk(Drive *d)
{
	ulong n;

	d->sectors = 0;
	d->unit->sectors = 0;
	if (d->ctlr->type == 2) {
		// without bit 8 we can boot without disks, but
		// inserted disks will never appear.  :-X
		n = d->edma->sataconfig;
		n &= 0xff;
		n |= 0x9b1100;
		d->edma->sataconfig = n;
		n = d->edma->sataconfig;	//flush
		USED(n);
	}
	d->edma->ctl = eDsEDMA;
	microdelay(1);
	d->edma->ctl = eAtaRst;
	microdelay(25);
	d->edma->ctl = 0;
	if (satawait((uchar *)&d->edma->ctl, eEnEDMA, 0, 3*1000) == 0)
		print("%s: eEnEDMA never cleared on reset\n", d->unit->name);
	edmacleanout(d);
	phyerrata(d);
	d->bridge->sctrl = 0x301 | (d->mode << 4);
	d->state = Dmissing;
}

static void
edmainit(Drive *d)
{
	int i;

	if(d->tx != nil)
		return;

	d->tx = xspanalloc(32*sizeof(Tx), 1024, 0);
	d->rx = xspanalloc(32*sizeof(Rx), 256, 0);
	d->prd = xspanalloc(32*sizeof(Prd), 32, 0);
	for(i = 0; i < 32; i++)
		d->tx[i].prdpa = PADDR(&d->prd[i]);
	coherence();
}

static int
configdrive(Ctlr *ctlr, Drive *d, SDunit *unit)
{
	Rendez r;

	dprint("%s: configdrive\n", unit->name);
	if (d->driveno < 0)
		panic("mv50xx: configdrive: unset driveno\n");
	d->unit = unit;
	edmainit(d);
	d->mode = DMsatai;
	if(d->ctlr->type == 1){
		d->edma->iem = IEM;
		d->bridge = &d->chip->arb->bridge[d->chipx];
	}else{
		d->edma->iem = IEM2;
		d->bridge = &d->chip->edma[d->chipx].port;
		d->edma->iem = ~(1<<6);
		d->pm2 = Dpreamp;
		if(d->ctlr->lmmio[0x180d8/4] & 1)
			d->pm2 = d->bridge->phymode2 & Mpreamp;
	}
	resetdisk(d);
	unmask(ctlr->lmmio, d->driveno, 0);
	delay(100);
	if(d->bridge->status){
		dprint("%s: configdrive: found drive %lx\n", unit->name, d->bridge->status);
		memset(&r, 0, sizeof r);
		tsleep(&r, return0, 0, 1400);	// don't burn out the power supply.
	}
	return 0;
>>>>>>> sdmv50xx.c
}

static int
enabledrive(Drive *d)
{
	Edma *edma;
<<<<<<< sdmv50xx.c.orig
	
	DPRINT("%s: enabledrive\n", d->unit->name);
=======
>>>>>>> sdmv50xx.c

<<<<<<< sdmv50xx.c.orig
	if((d->bridge->status & 0xF) != 0x3){	/* Det */
		DPRINT("%s: not present\n", d->unit->name);
=======
	dprint("%s: enabledrive..", d->unit->name);

	if((d->bridge->status & 0xf) != 3){
		dprint("%s: not present\n", d->unit->name);
>>>>>>> sdmv50xx.c
		d->state = Dmissing;
<<<<<<< sdmv50xx.c.orig
		return 0;
=======
		return -1;
>>>>>>> sdmv50xx.c
	}
	edma = d->edma;
<<<<<<< sdmv50xx.c.orig
	if(satawait(&edma->cmdstat, ATAbusy, 0, 10*1000) == 0){
		print("%s: busy timeout\n", d->unit->name);
=======
	if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0){
		dprint("%s: busy timeout\n", d->unit->name);
>>>>>>> sdmv50xx.c
		d->state = Dmissing;
<<<<<<< sdmv50xx.c.orig
		return 0;
=======
		return -1;
>>>>>>> sdmv50xx.c
	}
<<<<<<< sdmv50xx.c.orig

=======
>>>>>>> sdmv50xx.c
	edma->iec = 0;
	d->chip->arb->ic &= ~(0x101 << d->chipx);
<<<<<<< sdmv50xx.c.orig
	edma->config = 0x11F;
=======
	edma->config = 0x51f;
	if (d->ctlr->type == 2)
		edma->config |= 7<<11;
>>>>>>> sdmv50xx.c
	edma->txi = PADDR(d->tx);
<<<<<<< sdmv50xx.c.orig
	edma->txo = (ulong)d->tx & 0x3E0;
	edma->rxi = (ulong)d->rx & 0xF8;
=======
	edma->txo = (ulong)d->tx & 0x3e0;
	edma->rxi = (ulong)d->rx & 0xf8;
>>>>>>> sdmv50xx.c
	edma->rxo = PADDR(d->rx);
	edma->ctl |= 1;		/* enable dma */

<<<<<<< sdmv50xx.c.orig
	DPRINT("%s: enable interrupts\n", d->unit->name);
	if(d->bridge->status = 0x113)
=======
	if(d->bridge->status = 0x113){
		dprint("%s: new\n", d->unit->name);
>>>>>>> sdmv50xx.c
		d->state = Dnew;
<<<<<<< sdmv50xx.c.orig
	d->edma->iem = IEM;
	return 1;
=======
	}else
		print("%s: status not forced (should be okay)\n", d->unit->name);
	return 0;
>>>>>>> sdmv50xx.c
}

static void
disabledrive(Drive *d)
{
	int i;
	ulong *r;

<<<<<<< sdmv50xx.c.orig
	DPRINT("%s: disabledrive\n", d->unit->name);
=======
	dprint("%s: disabledrive\n", d->unit->name);
>>>>>>> sdmv50xx.c

	if(d->tx == nil)	/* never enabled */
		return;

	d->edma->ctl = 0;
	d->edma->iem = 0;

<<<<<<< sdmv50xx.c.orig
	r = (ulong*)(d->ctlr->mmio + 0x1D64);
=======
	r = (ulong*)(d->ctlr->mmio + 0x1d64);
>>>>>>> sdmv50xx.c
	i = d->chipx;
	if(d->chipx < 4)
		*r &= ~(3 << (i*2));
	else
		*r |= ~(3 << (i*2+9));
}

static int
setudmamode(Drive *d, uchar mode)
{
	Edma *edma;
<<<<<<< sdmv50xx.c.orig
	
	DPRINT("%s: setudmamode %d\n", d->unit->name, mode);
=======

	dprint("%s: setudmamode %d\n", d->unit->name, mode);
>>>>>>> sdmv50xx.c

	edma = d->edma;
<<<<<<< sdmv50xx.c.orig
	if(satawait(&edma->cmdstat, ATAerr|ATAdrq|ATAdf|ATAdrdy|ATAbusy, ATAdrdy, 15*1000) == 0){
		iprint("%s: cmdstat 0x%.2ux ready timeout\n",
			d->unit->name, edma->cmdstat);
=======
	if (edma == nil) {
		iprint("setudamode(m%d): zero d->edma\m", d->driveno);
		return 0;
	}
	if(satawait(&edma->cmdstat, ~ATAobs, ATAdrdy, 9*1000) == 0){
		iprint("%s: cmdstat 0x%.2ux ready timeout\n", d->unit->name, edma->cmdstat);
>>>>>>> sdmv50xx.c
		return 0;
	}
	edma->altstat = ATAeIEN;
	edma->err = 3;
	edma->seccnt = 0x40 | mode;
<<<<<<< sdmv50xx.c.orig
	edma->cmdstat = 0xEF;
=======
	edma->cmdstat = 0xef;
>>>>>>> sdmv50xx.c
	microdelay(1);
<<<<<<< sdmv50xx.c.orig
	if(satawait(&edma->cmdstat, ATAbusy, 0, 15*1000) == 0){
		iprint("%s: cmdstat 0x%.2ux busy timeout\n", 
			d->unit->name, edma->cmdstat);
=======
	if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0){
		iprint("%s: cmdstat 0x%.2ux busy timeout\n", d->unit->name, edma->cmdstat);
>>>>>>> sdmv50xx.c
		return 0;
	}
	return 1;
}

<<<<<<< sdmv50xx.c.orig
static void
=======
static int
>>>>>>> sdmv50xx.c
identifydrive(Drive *d)
{
	int i;
	ushort *id;
	Edma *edma;
	SDunit *unit;
<<<<<<< sdmv50xx.c.orig
	
	DPRINT("%s: identifydrive\n", d->unit->name);
=======

	dprint("%s: identifydrive\n", d->unit->name);
>>>>>>> sdmv50xx.c

	if(setudmamode(d, 5) == 0)	/* do all SATA support 5? */
		goto Error;

	id = d->info;
	memset(d->info, 0, sizeof d->info);
	edma = d->edma;
<<<<<<< sdmv50xx.c.orig
	if(satawait(&edma->cmdstat, 0xE9, 0x40, 15*1000) == 0)
=======
	if(satawait(&edma->cmdstat, ~ATAobs, ATAdrdy, 5*1000) == 0)
>>>>>>> sdmv50xx.c
		goto Error;

	edma->altstat = ATAeIEN;	/* no interrupts */
<<<<<<< sdmv50xx.c.orig
	edma->cmdstat = 0xEC;
=======
	edma->cmdstat = 0xec;
>>>>>>> sdmv50xx.c
	microdelay(1);
<<<<<<< sdmv50xx.c.orig
	if(satawait(&edma->cmdstat, ATAbusy, 0, 15*1000) == 0)
=======
	if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0)
>>>>>>> sdmv50xx.c
		goto Error;
<<<<<<< sdmv50xx.c.orig
	for(i=0; i<256; i++)
=======
	for(i = 0; i < 256; i++)
>>>>>>> sdmv50xx.c
		id[i] = edma->pio;
<<<<<<< sdmv50xx.c.orig
	if(edma->cmdstat & (ATAerr|ATAdf))
=======
	if(edma->cmdstat & ATAbad)
>>>>>>> sdmv50xx.c
		goto Error;
	i = lhgets(id+83) | lhgets(id+86);
	if(i & (1<<10)){
		d->flag |= Dext;
		d->sectors = lhgetv(id+100);
	}else{
		d->flag &= ~Dext;
		d->sectors = lhgetl(id+60);
	}
	idmove(d->serial, id+10, 20);
	idmove(d->firmware, id+23, 8);
	idmove(d->model, id+27, 40);
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	unit = d->unit;
	memset(unit->inquiry, 0, sizeof unit->inquiry);
	unit->inquiry[2] = 2;
	unit->inquiry[3] = 2;
	unit->inquiry[4] = sizeof(unit->inquiry)-4;
	idmove((char*)unit->inquiry+8, id+27, 40);

<<<<<<< sdmv50xx.c.orig
	if(enabledrive(d))
=======
	if(enabledrive(d) == 0) {
>>>>>>> sdmv50xx.c
		d->state = Dready;
<<<<<<< /sys/src/9/pc/sdmv50xx.c
		d->mediachange = 1;
		idprint("%s: LLBA %lld sectors\n", d->unit->name, d->sectors);
	} else
||||||| sdmv50xx.c.orig
	else
=======
		d->mediachange = 1;
		iprint("%s: LLBA %lld sectors\n", d->unit->name, d->sectors);
	} else
>>>>>>> sdmv50xx.c
		d->state = Derror;
<<<<<<< sdmv50xx.c.orig
	return;

=======
	if(d->state == Dready)
		return 0;
	return -1;
>>>>>>> sdmv50xx.c
Error:
<<<<<<< sdmv50xx.c.orig
	DPRINT("error...");
=======
	dprint("error...");
>>>>>>> sdmv50xx.c
	d->state = Derror;
<<<<<<< sdmv50xx.c.orig
=======
	return -1;
}

/* p. 163:
	M	recovered error
	P	protocol error
	N	PhyRdy change
	W	CommWake
	B	8-to-10 encoding error
	D	disparity error
	C	crc error
	H	handshake error
	S	link sequence error
	T	transport state transition error
	F	unrecognized fis type
	X	device changed
*/

static char stab[] = {
[1]	'M',
[10]	'P',
[16]	'N',
[18]	'W', 'B', 'D', 'C', 'H', 'S', 'T', 'F', 'X'
};
static ulong sbad = (7<<20)|(3<<23);

static void
serrdecode(ulong r, char *s, char *e)
{
	int i;

	e -= 3;
	for(i = 0; i < nelem(stab) && s < e; i++){
		if((r&(1<<i)) && stab[i]){
			*s++ = stab[i];
			if(sbad&(1<<i))
				*s++ = '*';
		}
	}
	*s = 0;
>>>>>>> sdmv50xx.c
}

<<<<<<< sdmv50xx.c.orig
static void abortallsrb(Drive*);
=======
char *iectab[] = {
	"ePrtDataErr",
	"ePrtPRDErr",
	"eDevErr",
	"eDevDis",
	"eDevCon",
	"SerrInt",
	"eUnderrun",
	"eSelfDis2",
	"eSelfDis",
	"ePrtCRQBErr",
	"ePrtCRPBErr",
	"ePrtIntErr",
	"eIORdyErr",
};

static char*
iecdecode(ulong cause)
{
	int i;

	for(i = 0; i < nelem(iectab); i++)
		if(cause&(1<<i))
			return iectab[i];
	return "";
}

enum{
	Cerror	= ePrtDataErr|ePrtPRDErr|eDevErr|eSelfDis2|ePrtCRPBErr|ePrtIntErr,
};
>>>>>>> sdmv50xx.c

static void
<<<<<<< sdmv50xx.c.orig
updatedrive(Drive *d, ulong cause)
=======
updatedrive(Drive *d)
>>>>>>> sdmv50xx.c
{
	int x;
<<<<<<< sdmv50xx.c.orig
=======
	ulong cause;
>>>>>>> sdmv50xx.c
	Edma *edma;
<<<<<<< sdmv50xx.c.orig
	
	if(cause == 0)
		return;

	DPRINT("%s: updatedrive %#lux\n", d->unit->name, cause);
=======
	char buf[32+4+1];
>>>>>>> sdmv50xx.c

	edma = d->edma;
<<<<<<< sdmv50xx.c.orig
	if(cause & eDevDis){
		d->state = Dmissing;
		edma->ctl |= eAtaRst;
		microdelay(25);
		edma->ctl &= ~eAtaRst;
		microdelay(25);
=======
	if((edma->ctl&eEnEDMA) == 0){
		// FEr SATA#4 40xx
		x = d->edma->cmdstat;
		USED(x);
>>>>>>> sdmv50xx.c
	}
<<<<<<< sdmv50xx.c.orig
	if(cause & eDevCon){
		d->bridge->sctrl = (d->bridge->sctrl & ~0xF) | 1;
=======
	cause = edma->iec;
	if(cause == 0)
		return;
	dprint("%s: cause %08ulx [%s]\n", d->unit->name, cause, iecdecode(cause));
	if(cause & eDevCon)
>>>>>>> sdmv50xx.c
		d->state = Dnew;
<<<<<<< sdmv50xx.c.orig
=======
	if(cause&eDevDis && d->state == Dready)
		iprint("%s: pulled: st=%08ulx\n", d->unit->name, cause);
	switch(d->ctlr->type){
	case 1:
		if(cause&eSelfDis)
			d->state = Derror;
		break;
	case 2:
		if(cause&Cerror)
			d->state = Derror;
		if(cause&SerrInt){
			serrdecode(d->bridge->serror, buf, buf+sizeof buf);
			dprint("%s: serror %08ulx [%s]\n", d->unit->name, (ulong)d->bridge->serror, buf);
			d->bridge->serror = d->bridge->serror;
		}
>>>>>>> sdmv50xx.c
	}
<<<<<<< sdmv50xx.c.orig
	if(cause & eSelfDis)
		d->state = Derror;
	edma->iec = 0;
	d->sectors = 0;
	d->unit->sectors = 0;
	abortallsrb(d);
	x = edma->cmdstat;
	USED(x);
=======
	edma->iec = ~cause;
>>>>>>> sdmv50xx.c
}

/*
 * Requests
 */
static Srb*
srbrw(int req, Drive *d, uchar *data, uint sectors, uvlong lba)
{
	int i;
	Srb *srb;
	static uchar cmd[2][2] = { 0xC8, 0x25, 0xCA, 0x35 };

<<<<<<< sdmv50xx.c.orig
	switch(req){
	case SRBread:
	case SRBwrite:
		break;
	default:
		return nil;
	}
	
=======
>>>>>>> sdmv50xx.c
	srb = allocsrb();
	srb->req = req;
	srb->drive = d;
	srb->blockno = lba;
	srb->sectors = sectors;
	srb->count = sectors*512;
	srb->flag = 0;
	srb->data = data;

	for(i=0; i<6; i++)
		srb->lba[i] = lba >> (8*i);
	srb->cmd = cmd[srb->req!=SRBread][(d->flag&Dext)!=0];
	return srb;
}

static uintptr
advance(uintptr pa, int shift)
{
	int n, mask;
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	mask = 0x1F<<shift;
	n = (pa & mask) + (1<<shift);
	return (pa & ~mask) | (n & mask);
}

#define CMD(r, v) (((r)<<8) | ((v)&0xFF))
static void
<<<<<<< sdmv50xx.c.orig
atarequest(ushort *cmd, Srb *srb, int ext)
=======
mvsatarequest(ushort *cmd, Srb *srb, int ext)
>>>>>>> sdmv50xx.c
{
	*cmd++ = CMD(ARseccnt, 0);
	*cmd++ = CMD(ARseccnt, srb->sectors);
	*cmd++ = CMD(ARfea, 0);
	if(ext){
		*cmd++ = CMD(ARlba0, srb->lba[3]);
		*cmd++ = CMD(ARlba0, srb->lba[0]);
		*cmd++ = CMD(ARlba1, srb->lba[4]);
		*cmd++ = CMD(ARlba1, srb->lba[1]);
		*cmd++ = CMD(ARlba2, srb->lba[5]);
		*cmd++ = CMD(ARlba2, srb->lba[2]);
<<<<<<< sdmv50xx.c.orig
		*cmd++ = CMD(ARdev, 0xE0);
=======
		*cmd++ = CMD(ARdev, 0xe0);
>>>>>>> sdmv50xx.c
	}else{
		*cmd++ = CMD(ARlba0, srb->lba[0]);
		*cmd++ = CMD(ARlba1, srb->lba[1]);
		*cmd++ = CMD(ARlba2, srb->lba[2]);
<<<<<<< sdmv50xx.c.orig
		*cmd++ = CMD(ARdev, srb->lba[3] | 0xE0);
=======
		*cmd++ = CMD(ARdev, srb->lba[3] | 0xe0);
>>>>>>> sdmv50xx.c
	}
<<<<<<< sdmv50xx.c.orig
	*cmd++ = CMD(ARcmd, srb->cmd) | (1<<15);
	USED(cmd);
=======
	*cmd = CMD(ARcmd, srb->cmd) | (1<<15);
>>>>>>> sdmv50xx.c
}

static void
startsrb(Drive *d, Srb *srb)
{
	int i;
	Edma *edma;
	Prd *prd;
	Tx *tx;
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	if(d->nsrb >= nelem(d->srb)){
		srb->next = nil;
		if(d->srbhead)
			d->srbtail->next = srb;
		else
			d->srbhead = srb;
		d->srbtail = srb;
		return;
	}
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	d->nsrb++;
	for(i=0; i<nelem(d->srb); i++)
		if(d->srb[i] == nil)
			break;
	if(i == nelem(d->srb))
		panic("sdmv50xx: no free srbs");
<<<<<<< sdmv50xx.c.orig
=======
	d->intick = MACHP(0)->ticks;
>>>>>>> sdmv50xx.c
	d->srb[i] = srb;
	edma = d->edma;
	tx = (Tx*)KADDR(edma->txi);
	tx->flag = (i<<1) | (srb->req == SRBread);
	prd = KADDR(tx->prdpa);
	prd->pa = PADDR(srb->data);
	prd->count = srb->count;
	prd->flag = PRDeot;
<<<<<<< sdmv50xx.c.orig
	atarequest(tx->regs, srb, d->flag&Dext);
=======
	mvsatarequest(tx->regs, srb, d->flag&Dext);
>>>>>>> sdmv50xx.c
	coherence();
	edma->txi = advance(edma->txi, 5);
<<<<<<< sdmv50xx.c.orig
=======
	d->intick = MACHP(0)->ticks;
>>>>>>> sdmv50xx.c
}

<<<<<<< sdmv50xx.c.orig
=======
enum{
	Rpidx	= 0x1f<<3,
};

>>>>>>> sdmv50xx.c
static void
completesrb(Drive *d)
{
	Edma *edma;
	Rx *rx;
	Srb *srb;
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	edma = d->edma;
	if((edma->ctl & eEnEDMA) == 0)
		return;
<<<<<<< sdmv50xx.c.orig
	
	while((edma->rxo & (0x1F<<3)) != (edma->rxi & (0x1F<<3))){
=======

	while((edma->rxo&Rpidx) != (edma->rxi&Rpidx)){
>>>>>>> sdmv50xx.c
		rx = (Rx*)KADDR(edma->rxo);
		if(srb = d->srb[rx->cid]){
			d->srb[rx->cid] = nil;
			d->nsrb--;
<<<<<<< sdmv50xx.c.orig
			if(rx->cDevSts & (ATAerr|ATAdf))
=======
			if(rx->cDevSts & ATAbad)
>>>>>>> sdmv50xx.c
				srb->flag |= SFerror;
<<<<<<< sdmv50xx.c.orig
			srb->flag |= SFdone;
=======
			if (rx->cEdmaSts)
				iprint("cEdmaSts: %02ux\n", rx->cEdmaSts);
>>>>>>> sdmv50xx.c
			srb->sta = rx->cDevSts;
<<<<<<< sdmv50xx.c.orig
=======
			srb->flag |= SFdone;
>>>>>>> sdmv50xx.c
			wakeup(srb);
		}else
			iprint("srb missing\n");
		edma->rxo = advance(edma->rxo, 3);
		if(srb = d->srbhead){
			d->srbhead = srb->next;
			startsrb(d, srb);
		}
	}
}
			
<<<<<<< sdmv50xx.c.orig
static void
abortallsrb(Drive *d)
{
	int i;
	Srb *srb;

	for(i=0; i<nelem(d->srb); i++){
		if(srb = d->srb[i]){
			d->srb[i] = nil;
			d->nsrb--;
			srb->flag |= SFerror|SFdone;
			wakeup(srb);
		}
	}
	while(srb = d->srbhead){
		d->srbhead = srb->next;
		srb->flag |= SFerror|SFdone;
		wakeup(srb);
	}	
}

=======
>>>>>>> sdmv50xx.c
static int
srbdone(void *v)
{
	Srb *srb;
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	srb = v;
	return srb->flag & SFdone;
}

/*
 * Interrupts
 */
static void
mv50interrupt(Ureg*, void *a)
{
	int i;
	ulong cause;
	Ctlr *ctlr;
	Drive *drive;
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	ctlr = a;
	ilock(ctlr);
<<<<<<< sdmv50xx.c.orig
	cause = *(ulong*)(ctlr->mmio + 0x1D60);
	DPRINT("sd%c: mv50interrupt: 0x%lux\n", ctlr->sdev->idno, cause);
	for(i=0; i<ctlr->ndrive; i++){
=======
	cause = ctlr->lmmio[0x1d60/4];
//	dprint("sd%c: mv50interrupt: 0x%lux\n", ctlr->sdev->idno, cause);
	for(i=0; i<ctlr->ndrive; i++)
>>>>>>> sdmv50xx.c
		if(cause & (3<<(i*2+i/4))){
			drive = &ctlr->drive[i];
<<<<<<< sdmv50xx.c.orig
			if(drive->edma == nil)
				continue;		/* not ready yet */
=======
			if(drive->edma == 0)
				continue;	// not ready yet.
>>>>>>> sdmv50xx.c
			ilock(drive);
<<<<<<< sdmv50xx.c.orig
			updatedrive(drive, drive->edma->iec);
=======
			updatedrive(drive);
>>>>>>> sdmv50xx.c
			while(ctlr->chip[i/4].arb->ic & (0x0101 << (i%4))){
				ctlr->chip[i/4].arb->ic = ~(0x101 << (i%4));
				completesrb(drive);
			}
			iunlock(drive);
		}
<<<<<<< sdmv50xx.c.orig
	}
=======
>>>>>>> sdmv50xx.c
	iunlock(ctlr);
}

<<<<<<< /sys/src/9/pc/sdmv50xx.c
enum{
	Nms		= 256,
	Midwait		= 16*1024/Nms-1,
	Mphywait	= 512/Nms-1,
};

static void
westerndigitalhung(Drive *d)
{
	Edma *e;

	e = d->edma;
	if(d->srb
	&& TK2MS(MACHP(0)->ticks-d->intick) > 5*1000
	&& (e->rxo&Rpidx) == (e->rxi&Rpidx)){
		dprint("westerndigital drive hung; resetting\n");
		d->state = Dreset;
	}
}

static void
checkdrive(Drive *d, int i)
{
	static ulong s, olds[NCtlr*NCtlrdrv];
	char *name;

	ilock(d);
	name = d->unit->name;
	s = d->bridge->status;
	if(s != olds[i]){
		dprint("%s: status: %08lx -> %08lx: %s\n", name, olds[i], s, diskstates[d->state]);
		olds[i] = s;
	}
	// westerndigitalhung(d);
	switch(d->state){
	case Dnew:
	case Dmissing:
		switch(s){
		case 0x000:
			break;
		default:
			dprint("%s: unknown state %8lx\n", name, s);
		case 0x100:
			if(++d->wait&Mphywait)
				break;
		reset:	d->mode ^= 1;
			dprint("%s: reset; new mode %d\n", name, d->mode);
			resetdisk(d);
			break;
		case 0x123:
		case 0x113:
			s = d->edma->cmdstat;
			if(s == 0x7f || (s&~ATAobs) != ATAdrdy){
				if((++d->wait&Midwait) == 0)
					goto reset;
			}else if(identifydrive(d) == -1)
				goto reset;
		}
		break;
	case Dready:
		if(s != 0)
			break;
		iprint("%s: pulled: st=%08ulx\n", name, s); // never happens
	case Dreset:
	case Derror:
		dprint("%s reset: mode %d\n", name, d->mode);
		resetdisk(d);
		break;
	}
	iunlock(d);
}

static void
satakproc(void*)
{
	int i;

	while(waserror())
		;

	for(;;){
		tsleep(&up->sleep, return0, 0, Nms);
		for(i = 0; i < nmvsatadrive; i++)
			checkdrive(mvsatadrive[i], i);
	}
}

||||||| sdmv50xx.c.orig
=======
enum{
	Nms		= 256,
	Midwait		= 16*1024/Nms-1,
	Mphywait	= 512/Nms-1,
};

static void
westerndigitalhung(Drive *d)
{
	Edma *e;

	e = d->edma;
	if(d->srb
	&& TK2MS(MACHP(0)->ticks-d->intick) > 5*1000
	&& (e->rxo&Rpidx) == (e->rxi&Rpidx)){
		dprint("westerndigital drive hung; resetting\n");
		d->state = Dreset;
	}
}

static void
checkdrive(Drive *d, int i)
{
	static ulong s, olds[NCtlr*NCtlrdrv];
	char *name;

	ilock(d);
	name = d->unit->name;
	s = d->bridge->status;
	if(s != olds[i]){
		dprint("%s: status: %08lx -> %08lx: %s\n", name, olds[i], s, diskstates[d->state]);
		olds[i] = s;
	}
	// westerndigitalhung(d);
	switch(d->state){
	case Dnew:
	case Dmissing:
		switch(s){
		case 0x000:
			break;
		default:
			dprint("%s: unknown state %8lx\n", name, s);
		case 0x100:
			if(++d->wait&Mphywait)
				break;
		reset:	d->mode ^= 1;
			dprint("%s: reset; new mode %d\n", name, d->mode);
			resetdisk(d);
			break;
		case 0x123:
		case 0x113:
			s = d->edma->cmdstat;
			if(s == 0x7f || (s&~ATAobs) != ATAdrdy){
				if((++d->wait&Midwait) == 0)
					goto reset;
			}else if(identifydrive(d) == -1)
				goto reset;
		}
		break;
	case Dready:
		if(s != 0)
			break;
		iprint("%s: pulled: st=%08ulx\n", name, s); // never happens
	case Dreset:
	case Derror:
		dprint("%s reset: mode %d\n", name, d->mode);
		resetdisk(d);
		break;
	}
	iunlock(d);
}

static void
satakproc(void*)
{
	int i;
	static Rendez r;

	memset(&r, 0, sizeof r);
	for(;;){
		tsleep(&r, return0, 0, Nms);
		for(i = 0; i < nmvsatadrive; i++)
			checkdrive(mvsatadrive[i], i);
	}
}

>>>>>>> sdmv50xx.c
/*
 * Device discovery
 */
static SDev*
mv50pnp(void)
{
	int i, dno, nunit;
	uchar *base;
<<<<<<< sdmv50xx.c.orig
	ulong io;
	void *mem;
=======
	ulong io, n, *mem;
>>>>>>> sdmv50xx.c
	Ctlr *ctlr;
	Pcidev *p;
	SDev *head, *tail, *sdev;
<<<<<<< sdmv50xx.c.orig
=======
	Drive *d;
	static int ctlrno, done;
>>>>>>> sdmv50xx.c

<<<<<<< sdmv50xx.c.orig
	DPRINT("mv50pnp\n");
=======
	dprint("mv50pnp\n");
	if(done++)
		return nil;
>>>>>>> sdmv50xx.c

	p = nil;
	head = nil;
	tail = nil;
<<<<<<< sdmv50xx.c.orig
	while((p = pcimatch(p, 0x11AB, 0)) != nil){
=======
	while((p = pcimatch(p, 0x11ab, 0)) != nil){
>>>>>>> sdmv50xx.c
		switch(p->did){
<<<<<<< sdmv50xx.c.orig
=======
		case 0x5040:
>>>>>>> sdmv50xx.c
		case 0x5041:
<<<<<<< sdmv50xx.c.orig
			nunit = 4;
			break;
=======
		case 0x5080:
>>>>>>> sdmv50xx.c
		case 0x5081:
<<<<<<< sdmv50xx.c.orig
			nunit = 8;
=======
		case 0x6041:
		case 0x6081:
>>>>>>> sdmv50xx.c
			break;
		default:
<<<<<<< sdmv50xx.c.orig
=======
			print("mv50pnp: unknown did %ux ignored\n", (ushort)p->did);
>>>>>>> sdmv50xx.c
			continue;
		}
<<<<<<< sdmv50xx.c.orig
=======
		if (ctlrno >= NCtlr) {
			print("mv50pnp: too many controllers\n");
			break;
		}
		nunit = (p->did&0xf0) >> 4;
		print("Marvell 88SX%ux: %d SATA-%s ports with%s flash\n",
			(ushort)p->did, nunit,
			((p->did&0xf000)==0x6000? "II": "I"),
			(p->did&1? "": "out"));
>>>>>>> sdmv50xx.c
		if((sdev = malloc(sizeof(SDev))) == nil)
			continue;
		if((ctlr = malloc(sizeof(Ctlr))) == nil){
			free(sdev);
			continue;
		}
<<<<<<< sdmv50xx.c.orig
=======
		memset(sdev, 0, sizeof *sdev);
		memset(ctlr, 0, sizeof *ctlr);

>>>>>>> sdmv50xx.c
		io = p->mem[0].bar & ~0x0F;
<<<<<<< sdmv50xx.c.orig
		mem = vmap(io, p->mem[0].size);
=======
		mem = (ulong*)vmap(io, p->mem[0].size);
>>>>>>> sdmv50xx.c
		if(mem == 0){
			print("sdmv50xx: address 0x%luX in use\n", io);
			free(sdev);
			free(ctlr);
			continue;
		}
<<<<<<< sdmv50xx.c.orig
=======
		ctlr->rid = p->rid;

		// avert thine eyes!  (what does this do?)
		mem[0x104f0/4] = 0;
		ctlr->type = (p->did >> 12) & 3;
		if(ctlr->type == 1){
			n = mem[0xc00/4];
			n &= ~(3<<4);
			mem[0xc00/4] = n;
		}

>>>>>>> sdmv50xx.c
		sdev->ifc = &sdmv50xxifc;
		sdev->ctlr = ctlr;
		sdev->nunit = nunit;
		sdev->idno = 'E' + ctlrno;
		ctlr->sdev = sdev;
		ctlr->irq = p->intl;
		ctlr->tbdf = p->tbdf;
		ctlr->pcidev = p;
<<<<<<< sdmv50xx.c.orig
		ctlr->mmio = mem;
=======
		ctlr->lmmio = mem;
		ctlr->mmio = (uchar*)mem;
>>>>>>> sdmv50xx.c
		ctlr->nchip = (nunit+3)/4;
		ctlr->ndrive = nunit;
<<<<<<< sdmv50xx.c.orig
		for(i=0; i<ctlr->nchip; i++){
=======
		ctlr->enabled = 0;
		for(i = 0; i < ctlr->nchip; i++){
>>>>>>> sdmv50xx.c
			base = ctlr->mmio+0x20000+0x10000*i;
			ctlr->chip[i].arb = (Arb*)base;
			ctlr->chip[i].edma = (Edma*)(base + 0x2000);
		}
<<<<<<< /sys/src/9/pc/sdmv50xx.c
		for (i = 0; i < nunit; i++) {
			d = &ctlr->drive[i];
			d->sectors = 0;
			d->ctlr = ctlr;
			d->driveno = ctlrno*NCtlrdrv + i;
			d->chipx = i%4;
			d->chip = &ctlr->chip[i/4];
			d->edma = &d->chip->edma[d->chipx];
			mvsatadrive[d->driveno] = d;
		}
		nmvsatadrive += nunit;
		ctlrno++;
||||||| sdmv50xx.c.orig
=======
		for (i = 0; i < nunit; i++) {
			d = &ctlr->drive[i];
			d->sectors = 0;
			d->ctlr = ctlr;
			d->driveno = dno = ctlrno*NCtlrdrv + i;
			d->chipx = dno%4;
			d->chip =&ctlr->chip[dno/4];
			d->edma = &d->chip->edma[d->chipx];
			mvsatadrive[d->driveno] = d;
		}
		mvsatactlr[ctlrno] = ctlr;
		nmvsatadrive += i;
		ctlrno++;
>>>>>>> sdmv50xx.c
		if(head)
			tail->next = sdev;
		else
			head = sdev;
		tail = sdev;
	}
	return head;
}

/*
 * Enable the controller.  Each disk has its own interrupt mask,
 * and those get enabled as the disks are brought online.
 */
static int
mv50enable(SDev *sdev)
{
	char name[32];
	Ctlr *ctlr;

<<<<<<< sdmv50xx.c.orig
	DPRINT("sd%c: enable\n", sdev->idno);
=======
	dprint("sd%c: enable\n", sdev->idno);
>>>>>>> sdmv50xx.c

	ctlr = sdev->ctlr;
<<<<<<< sdmv50xx.c.orig
=======
	if (ctlr->enabled)
		return 1;
>>>>>>> sdmv50xx.c
	snprint(name, sizeof name, "%s (%s)", sdev->name, sdev->ifc->name);
	intrenable(ctlr->irq, mv50interrupt, ctlr, ctlr->tbdf, name);
<<<<<<< sdmv50xx.c.orig
=======
	ctlr->enabled = 1;
>>>>>>> sdmv50xx.c
	return 1;
}

/*
 * Disable the controller.
 */
static int
mv50disable(SDev *sdev)
{
	char name[32];
	int i;
	Ctlr *ctlr;
	Drive *drive;
<<<<<<< sdmv50xx.c.orig
	
	DPRINT("sd%c: disable\n", sdev->idno);
=======

	dprint("sd%c: disable\n", sdev->idno);
>>>>>>> sdmv50xx.c

	ctlr = sdev->ctlr;
	ilock(ctlr);
	for(i=0; i<ctlr->sdev->nunit; i++){
		drive = &ctlr->drive[i];
		ilock(drive);
		disabledrive(drive);
		iunlock(drive);
	}
	iunlock(ctlr);
	snprint(name, sizeof name, "%s (%s)", sdev->name, sdev->ifc->name);
	intrdisable(ctlr->irq, mv50interrupt, ctlr, ctlr->tbdf, name);
	return 0;
}

/*
 * Clean up all disk structures.  Already disabled.
 * Could keep count of number of allocated controllers
 * and free the srblist when it drops to zero.
 */
static void
mv50clear(SDev *sdev)
{
	int i;
	Ctlr *ctlr;
	Drive *d;

<<<<<<< sdmv50xx.c.orig
	DPRINT("sd%c: clear\n", sdev->idno);
=======
	dprint("sd%c: clear\n", sdev->idno);
>>>>>>> sdmv50xx.c

	ctlr = sdev->ctlr;
	for(i=0; i<ctlr->ndrive; i++){
		d = &ctlr->drive[i];
		free(d->tx);
		free(d->rx);
		free(d->prd);
	}
	free(ctlr);
}

/*
 * Check that there is a disk or at least a hot swap bay in the drive.
 */
static int
mv50verify(SDunit *unit)
{
	Ctlr *ctlr;
	Drive *drive;
	int i;

<<<<<<< sdmv50xx.c.orig
	DPRINT("%s: verify\n", unit->name);

	/*
	 * First access of unit.
	 */

=======
	dprint("%s: verify\n", unit->name);
>>>>>>> sdmv50xx.c
	ctlr = unit->dev->ctlr;
	drive = &ctlr->drive[unit->subno];
	ilock(ctlr);
	ilock(drive);
<<<<<<< /sys/src/9/pc/sdmv50xx.c
	i = configdrive(ctlr, drive, unit);
||||||| sdmv50xx.c.orig

	if(!configdrive(ctlr, drive, unit) || !enabledrive(drive)){
		iunlock(drive);
		iunlock(ctlr);
		return 0;
	}
	/*
	 * Need to reset the drive before the first call to 
	 * identifydrive, or else the satawait in setudma will 
	 * freeze the machine when accessing edma->cmdstat.
	 * I do not understand this.		-rsc
	 */
	updatedrive(drive, eDevDis);

=======
	configdrive(ctlr, drive, unit);
>>>>>>> sdmv50xx.c
	iunlock(drive);
	iunlock(ctlr);
<<<<<<< /sys/src/9/pc/sdmv50xx.c

	/*
	 * If ctlr->type == 1, then the drives spin up whenever
	 * the controller feels like it; if ctlr->type != 1, then 
	 * they spin up as a result of configdrive.
	 * 
	 * If there is a drive in the slot, give it 1.5s to spin up
	 * before returning.  There is a noticeable drag on the
	 * power supply when spinning up fifteen drives 
	 * all at once (like in the Coraid enclosures).
	 */
	if(ctlr->type != 1 && i == 0){
		if(!waserror()){
			tsleep(&up->sleep, return0, 0, 1500);
			poperror();
		}
	}
||||||| sdmv50xx.c.orig

=======
>>>>>>> sdmv50xx.c
	return 1;
}

/*
 * Check whether the disk is online.
 */
static int
mv50online(SDunit *unit)
{
	Ctlr *ctlr;
<<<<<<< sdmv50xx.c.orig
	Drive *drive;
=======
	Drive *d;
	int r, s0;
	static int once;

	if(once++ == 0)
		kproc("mvsata", satakproc, 0);
>>>>>>> sdmv50xx.c

	ctlr = unit->dev->ctlr;
<<<<<<< /sys/src/9/pc/sdmv50xx.c
	d = &ctlr->drive[unit->subno];
	r = 0;
	ilock(d);
	s0 = d->state;
	USED(s0);
	if(d->state == Dnew)
		identifydrive(d);
	if(d->mediachange){
		idprint("%s: online: %s -> %s\n", unit->name, diskstates[s0], diskstates[d->state]);
		r = 2;
		unit->sectors = d->sectors;
||||||| sdmv50xx.c.orig
	drive = &ctlr->drive[unit->subno];
	ilock(drive);
	if(drive->state == Dready){
		unit->sectors = drive->sectors;
=======
	d = &ctlr->drive[unit->subno];
	r = 0;
	ilock(d);
	s0 = d->state;
	if(d->state == Dnew)
		identifydrive(d);
	if(d->mediachange){
		iprint("%s: online: %s -> %s\n", unit->name, diskstates[s0], diskstates[d->state]);
		r = 2;
		unit->sectors = d->sectors;
>>>>>>> sdmv50xx.c
		unit->secsize = 512;
<<<<<<< sdmv50xx.c.orig
		iunlock(drive);
		return 1;
	}

	DPRINT("%s: online %s\n", unit->name, diskstates[drive->state]);

	if(drive->state == Dnew){
		identifydrive(drive);
		if(drive->state == Dready){
			unit->sectors = drive->sectors;
			unit->secsize = 512;
			iunlock(drive);
			return 2;	/* media changed */
		}
	}
	iunlock(drive);
	return 0;
=======
		d->mediachange = 0;
	} else if(d->state == Dready)
		r = 1;
	iunlock(d);
	return r;
>>>>>>> sdmv50xx.c
}

/*
 * Register dumps
 */
typedef struct Regs Regs;
struct Regs
{
	ulong offset;
	char *name;
};

static Regs regsctlr[] =
{
	0x0C28, "pci serr# mask",
	0x1D40, "pci err addr low",
	0x1D44, "pci err addr hi",
	0x1D48, "pci err attr",
	0x1D50, "pci err cmd",
	0x1D58, "pci intr cause",
	0x1D5C, "pci mask cause",
	0x1D60, "device micr",
	0x1D64, "device mimr",
};

static Regs regsarb[] =
{
	0x0004,	"arb rqop",
	0x0008,	"arb rqip",
	0x000C,	"arb ict",
	0x0010,	"arb itt",
	0x0014,	"arb ic",
	0x0018,	"arb btc",
	0x001C,	"arb bts",
	0x0020,	"arb bpc",
};

static Regs regsbridge[] =
{
	0x0000,	"bridge status",
	0x0004,	"bridge serror",
	0x0008,	"bridge sctrl",
	0x000C,	"bridge phyctrl",
	0x003C,	"bridge ctrl",
	0x0074,	"bridge phymode",
};

static Regs regsedma[] =
{
	0x0000,	"edma config",
	0x0004,	"edma timer",
	0x0008,	"edma iec",
	0x000C,	"edma iem",
	0x0010,	"edma txbasehi",
	0x0014,	"edma txi",
	0x0018,	"edma txo",
	0x001C,	"edma rxbasehi",
	0x0020,	"edma rxi",
	0x0024,	"edma rxo",
	0x0028,	"edma c",
	0x002C,	"edma tc",
	0x0030,	"edma status",
	0x0034,	"edma iordyto",
/*	0x0100,	"edma pio",
	0x0104,	"edma err",
	0x0108,	"edma sectors",
	0x010C,	"edma lba0",
	0x0110,	"edma lba1",
	0x0114,	"edma lba2",
	0x0118,	"edma lba3",
	0x011C,	"edma cmdstat",
	0x0120,	"edma altstat",
*/
};

static char*
rdregs(char *p, char *e, void *base, Regs *r, int n, char *prefix)
{
	int i;
	
	for(i=0; i<n; i++)
		p = seprint(p, e, "%s%s%-19s %.8ux\n", 
			prefix ? prefix : "", prefix ? ": " : "",
			r[i].name, *(u32int*)((uchar*)base+r[i].offset));
	return p;
}

static char*
rdinfo(char *p, char *e, ushort *info)
{
	int i;
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	p = seprint(p, e, "info");
	for(i=0; i<256; i++){
<<<<<<< sdmv50xx.c.orig
		p = seprint(p, e, "%s%.4ux%s", 
=======
		p = seprint(p, e, "%s%.4ux%s",
>>>>>>> sdmv50xx.c
			i%8==0 ? "\t" : "",
<<<<<<< sdmv50xx.c.orig
			info[i], 
=======
			info[i],
>>>>>>> sdmv50xx.c
			i%8==7 ? "\n" : "");
	}
	return p;
}

static int
mv50rctl(SDunit *unit, char *p, int l)
{
	char *e, *op;
	Ctlr *ctlr;
	Drive *drive;
	
	if((ctlr = unit->dev->ctlr) == nil)
		return 0;
	drive = &ctlr->drive[unit->subno];
	
	e = p+l;
	op = p;
	if(drive->state == Dready){
		p = seprint(p, e, "model    %s\n", drive->model);
		p = seprint(p, e, "serial   %s\n", drive->serial);
		p = seprint(p, e, "firmware %s\n", drive->firmware);
	}else
		p = seprint(p, e, "no disk present\n");
	p = seprint(p, e, "geometry %llud 512\n", drive->sectors);
	p = rdinfo(p, e, drive->info);
	
	p = rdregs(p, e, drive->chip->arb, regsarb, nelem(regsarb), nil);
	p = rdregs(p, e, drive->bridge, regsbridge, nelem(regsbridge), nil);
	p = rdregs(p, e, drive->edma, regsedma, nelem(regsedma), nil);

	return p-op;
}

static int
mv50wctl(SDunit *unit, Cmdbuf *cb)
{
	Ctlr *ctlr;
	Drive *drive;
	
	USED(unit);
	if(strcmp(cb->f[0], "reset") == 0){
		ctlr = unit->dev->ctlr;
		drive = &ctlr->drive[unit->subno];
		ilock(drive);
<<<<<<< sdmv50xx.c.orig
		updatedrive(drive, eDevDis);
=======
		drive->state = Dreset;
>>>>>>> sdmv50xx.c
		iunlock(drive);
		return 0;
	}
	cmderror(cb, Ebadctl);
	return -1;
}

static char*
mv50rtopctl(SDev *sdev, char *p, char *e)
{
	char name[10];
	Ctlr *ctlr;
	
	ctlr = sdev->ctlr;
	if(ctlr == nil)
		return p;

	snprint(name, sizeof name, "sd%c", sdev->idno);
	p = rdregs(p, e, ctlr->mmio, regsctlr, nelem(regsctlr), name);
	/* info for first disk */
	p = rdregs(p, e, ctlr->chip[0].arb, regsarb, nelem(regsarb), name);
	p = rdregs(p, e, &ctlr->chip[0].arb->bridge[0], regsbridge, nelem(regsbridge), name);
	p = rdregs(p, e, &ctlr->chip[0].edma[0], regsedma, nelem(regsedma), name);
	
	return p;
}

static int
<<<<<<< /sys/src/9/pc/sdmv50xx.c
waitready(Drive *d)
{
	ulong s, i;

	for(i = 0; i < 120; i++){
		ilock(d);
		s = d->bridge->status;
		iunlock(d);
		if(s == 0)
			return SDeio;
		if (d->state == Dready)
			return SDok;
		if ((i+1)%60 == 0){
			ilock(d);
			resetdisk(d);
			iunlock(d);
		}
		if(!waserror()){
			tsleep(&up->sleep, return0, 0, 1000);
			poperror();
		}
	}
	print("%s: not responding after 2 minutes\n", d->unit->name);
	return SDeio;
}

static int
||||||| sdmv50xx.c.orig
=======
waitready(Drive *d)
{
	ulong s, i;
	Rendez r;

	for(i = 0; i < 120; i++){
		ilock(d);
		s = d->bridge->status;
		iunlock(d);
		if(s == 0)
			return SDeio;
		if (d->state == Dready)
			return SDok;
		if ((i+1)%60 == 0){
			ilock(d);
			resetdisk(d);
			iunlock(d);
		}
		memset(&r, 0, sizeof r);
		tsleep(&r, return0, 0, 1000);
	}
	print("%s: not responding after 2 minutes\n", d->unit->name);
	return SDeio;
}

static int
>>>>>>> sdmv50xx.c
mv50rio(SDreq *r)
{
<<<<<<< sdmv50xx.c.orig
	int count, max, n, status;
=======
	int count, max, n, status, try, flag;
>>>>>>> sdmv50xx.c
	uchar *cmd, *data;
	uvlong lba;
	Ctlr *ctlr;
	Drive *drive;
	SDunit *unit;
	Srb *srb;
<<<<<<< /sys/src/9/pc/sdmv50xx.c

||||||| sdmv50xx.c.orig
	
=======
	Rendez rz;

>>>>>>> sdmv50xx.c
	unit = r->unit;
	ctlr = unit->dev->ctlr;
	drive = &ctlr->drive[unit->subno];
	cmd = r->cmd;
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	if((status = sdfakescsi(r, drive->info, sizeof drive->info)) != SDnostatus){
		/* XXX check for SDcheck here */
		r->status = status;
		return status;
	}

	switch(cmd[0]){
	case 0x28:	/* read */
	case 0x2A:	/* write */
		break;
	default:
<<<<<<< sdmv50xx.c.orig
		print("sdmv50xx: bad cmd 0x%.2ux\n", cmd[0]);
=======
		iprint("%s: bad cmd 0x%.2ux\n", drive->unit->name, cmd[0]);
>>>>>>> sdmv50xx.c
		r->status = SDcheck;
		return SDcheck;
	}
<<<<<<< sdmv50xx.c.orig
	
=======

>>>>>>> sdmv50xx.c
	lba = (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5];
	count = (cmd[7]<<8)|cmd[8];
	if(r->data == nil)
		return SDok;
	if(r->dlen < count*unit->secsize)
		count = r->dlen/unit->secsize;
<<<<<<< sdmv50xx.c.orig
	
	/* 
=======

	try = 0;
retry:
	if(waitready(drive) != SDok)
		return SDeio;
	/*
>>>>>>> sdmv50xx.c
	 * Could arrange here to have an Srb always outstanding:
	 *
	 *	lsrb = nil;
	 *	while(count > 0 || lsrb != nil){
	 *		srb = nil;
	 *		if(count > 0){
	 *			srb = issue next srb;
	 *		}
	 *		if(lsrb){
	 *			sleep on lsrb and handle it
	 *		}
	 *	}
	 *
	 * On the disks I tried, this didn't help.  If anything,
	 * it's a little slower.		-rsc
	 */
	data = r->data;
	while(count > 0){
		/*
		 * Max is 128 sectors (64kB) because prd->count is 16 bits.
		 */
		max = 128;
		n = count;
		if(n > max)
			n = max;
<<<<<<< sdmv50xx.c.orig
=======
		if((drive->edma->ctl&eEnEDMA) == 0)
			goto tryagain;
>>>>>>> sdmv50xx.c
		srb = srbrw(cmd[0]==0x28 ? SRBread : SRBwrite, drive, data, n, lba);
		ilock(drive);
		startsrb(drive, srb);
		iunlock(drive);

<<<<<<< /sys/src/9/pc/sdmv50xx.c
		/* Don't let user interrupt DMA. */
		while(waserror())
			;
		sleep(srb, srbdone, srb);
		poperror();

		flag = srb->flag;
		freesrb(srb);
		if(flag == 0){
	tryagain:		if(++try == 10){
				print("%s: bad disk\n", drive->unit->name); 
				return SDeio;
||||||| sdmv50xx.c.orig
		/*
		 * Cannot let user interrupt the DMA.
		 */
		while(waserror())
			;
		tsleep(srb, srbdone, srb, 60*1000);
		poperror();
		
		if(!(srb->flag & SFdone)){
			ilock(drive);
			if(!(srb->flag & SFdone)){
				/*
				 * DMA didn't finish but we have to let go of
				 * the data buffer.  Reset the drive to (try to) keep it
				 * from using the buffer after we're gone.
				 */
				iprint("%s: i/o timeout\n", unit->name);
				updatedrive(drive, eDevDis);
				enabledrive(drive);
				freesrb(srb);
				iunlock(drive);
				error("i/o timeout");
=======
		sleep(&srb->Rendez, srbdone, srb);
		flag = srb->flag;
		freesrb(srb);
		if(flag == 0){
	tryagain:		if(++try == 10){
				print("%s: bad disk\n", drive->unit->name); 
				return SDeio;
>>>>>>> sdmv50xx.c
			}
<<<<<<< /sys/src/9/pc/sdmv50xx.c
			dprint("%s: retry\n", drive->unit->name);
			if(!waserror()){
				tsleep(&up->sleep, return0, 0, 1000);
				poperror();
			}
			goto retry;
||||||| sdmv50xx.c.orig
			iunlock(drive);
=======
			dprint("%s: retry\n", drive->unit->name);
			memset(&rz, 0, sizeof rz);
			tsleep(&rz, return0, 0, 1000);
			goto retry;
>>>>>>> sdmv50xx.c
		}
<<<<<<< /sys/src/9/pc/sdmv50xx.c
		if(flag & SFerror){
			print("%s: i/o error\n", drive->unit->name);
			return SDeio;
||||||| sdmv50xx.c.orig

		if(srb->flag & SFerror){
			freesrb(srb);
			error("i/o error");
=======
		if(srb->flag & SFerror){
			print("%s: i/o error\n", drive->unit->name);
			return SDeio;
>>>>>>> sdmv50xx.c
		}
<<<<<<< sdmv50xx.c.orig
		freesrb(srb);
=======
>>>>>>> sdmv50xx.c
		count -= n;
		lba += n;
		data += n*unit->secsize;
	}
	r->rlen = data - (uchar*)r->data;
<<<<<<< sdmv50xx.c.orig
	return SDok;	
=======
	return SDok;
>>>>>>> sdmv50xx.c
}

SDifc sdmv50xxifc = {
<<<<<<< sdmv50xx.c.orig
	"mv50xx",				/* name */
=======
	"mv50xx",			/* name */
>>>>>>> sdmv50xx.c

	mv50pnp,			/* pnp */
	nil,				/* legacy */
<<<<<<< sdmv50xx.c.orig
	mv50enable,		/* enable */
	mv50disable,		/* disable */
=======
	mv50enable,			/* enable */
	mv50disable,			/* disable */
>>>>>>> sdmv50xx.c

	mv50verify,			/* verify */
	mv50online,			/* online */
	mv50rio,				/* rio */
	mv50rctl,			/* rctl */
	mv50wctl,			/* wctl */

	scsibio,			/* bio */
	nil,				/* probe */
	mv50clear,			/* clear */
	mv50rtopctl,			/* rtopctl */
<<<<<<< sdmv50xx.c.orig
	nil,				/* wtopctl */
=======
>>>>>>> sdmv50xx.c
};

/*
 * The original driver on which this one is based came with the 
 * following notice:
 *
 * Copyright 2005
 * Coraid, Inc.
 *
 * This software is provided `as-is,' without any express or implied
 * warranty.  In no event will the author be held liable for any damages
 * arising from the use of this software.
 * 
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 * 
 * 1.  The origin of this software must not be misrepresented; you must
 * not claim that you wrote the original software.  If you use this
 * software in a product, an acknowledgment in the product documentation
 * would be appreciated but is not required.
 * 
 * 2.  Altered source versions must be plainly marked as such, and must
 * not be misrepresented as being the original software.
 * 
 * 3.  This notice may not be removed or altered from any source
 * distribution.
 */

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].